blob: 0b78045a70874ac59d4b0fe48a9d3b53b0b265e1 [file] [log] [blame]
// 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.
import '../elements/entities.dart';
import '../inferrer/types.dart';
import '../js/js.dart' as js;
import '../js_backend/codegen_inputs.dart';
import '../js_backend/namer.dart' show operatorNameToIdentifier;
import '../js_model/elements.dart' show JGeneratorBody;
import '../serialization/serialization.dart';
import '../universe/selector.dart';
import '../util/util.dart';
import 'codegen_interfaces.dart' as interfaces;
enum ModularNameKind {
rtiField,
className,
aliasedSuperMember,
staticClosure,
methodProperty,
operatorIs,
instanceMethod,
instanceField,
invocation,
lazyInitializer,
globalPropertyNameForClass,
globalPropertyNameForMember,
globalNameForInterfaceTypeVariable,
nameForGetInterceptor,
nameForOneShotInterceptor,
asName,
}
class ModularName extends js.Name implements js.AstContainer {
static const String tag = 'modular-name';
final ModularNameKind kind;
js.Name? _value;
final Object? data;
final Set<ClassEntity>? set;
ModularName(this.kind, {this.data, this.set});
factory ModularName.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ModularNameKind kind = source.readEnum(ModularNameKind.values);
Object? data;
Set<ClassEntity>? set;
switch (kind) {
case ModularNameKind.rtiField:
break;
case ModularNameKind.className:
case ModularNameKind.operatorIs:
case ModularNameKind.globalPropertyNameForClass:
data = source.readClass();
break;
case ModularNameKind.aliasedSuperMember:
case ModularNameKind.staticClosure:
case ModularNameKind.methodProperty:
case ModularNameKind.instanceField:
case ModularNameKind.instanceMethod:
case ModularNameKind.lazyInitializer:
case ModularNameKind.globalPropertyNameForMember:
data = source.readMember();
break;
case ModularNameKind.invocation:
data = Selector.readFromDataSource(source);
break;
case ModularNameKind.globalNameForInterfaceTypeVariable:
data = source.readTypeVariable();
break;
case ModularNameKind.nameForGetInterceptor:
set = source.readClasses().toSet();
break;
case ModularNameKind.nameForOneShotInterceptor:
data = Selector.readFromDataSource(source);
set = source.readClasses().toSet();
break;
case ModularNameKind.asName:
data = source.readString();
break;
}
source.end(tag);
return ModularName(kind, data: data, set: set);
}
void writeToDataSink(DataSinkWriter sink) {
sink.begin(tag);
sink.writeEnum(kind);
switch (kind) {
case ModularNameKind.rtiField:
break;
case ModularNameKind.className:
case ModularNameKind.operatorIs:
case ModularNameKind.globalPropertyNameForClass:
sink.writeClass(data as ClassEntity);
break;
case ModularNameKind.aliasedSuperMember:
case ModularNameKind.staticClosure:
case ModularNameKind.methodProperty:
case ModularNameKind.instanceField:
case ModularNameKind.instanceMethod:
case ModularNameKind.lazyInitializer:
case ModularNameKind.globalPropertyNameForMember:
sink.writeMember(data as MemberEntity);
break;
case ModularNameKind.invocation:
final selector = data as Selector;
selector.writeToDataSink(sink);
break;
case ModularNameKind.globalNameForInterfaceTypeVariable:
final typeVariable = data as TypeVariableEntity;
sink.writeTypeVariable(typeVariable);
break;
case ModularNameKind.nameForGetInterceptor:
sink.writeClasses(set);
break;
case ModularNameKind.nameForOneShotInterceptor:
final selector = data as Selector;
selector.writeToDataSink(sink);
sink.writeClasses(set);
break;
case ModularNameKind.asName:
sink.writeString(data as String);
break;
}
sink.end(tag);
}
@override
bool get isFinalized => _value != null;
js.Name get value {
assert(isFinalized, 'value not set for $this');
return _value!;
}
void set value(js.Name node) {
assert(!isFinalized);
assert((node as dynamic) != null);
_value = node.withSourceInformation(sourceInformation) as js.Name;
}
@override
String get key {
assert(isFinalized);
return _value!.key;
}
@override
String get name {
assert(isFinalized, 'value not set for $this');
return _value!.name;
}
@override
bool get allowRename {
assert(isFinalized, 'value not set for $this');
return _value!.allowRename;
}
@override
Iterable<js.Node> get containedNodes {
return _value != null ? [_value!] : const [];
}
@override
int get hashCode {
return Hashing.setHash(set, Hashing.objectsHash(kind, data));
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is ModularName &&
kind == other.kind &&
data == other.data &&
equalSets(set, other.set);
}
@override
String toString() =>
'ModularName(kind=$kind, data=$data, value=${_value?.key})';
@override
String nonfinalizedDebugText() {
switch (kind) {
case ModularNameKind.rtiField:
return r'ModularName"$ti"';
case ModularNameKind.instanceField:
return 'ModularName"field:${(data as Entity).name}"';
case ModularNameKind.instanceMethod:
return 'ModularName"${_instanceMethodName(data as MemberEntity)}"';
case ModularNameKind.methodProperty:
return 'ModularName"methodProperty:${(data as Entity).name}"';
case ModularNameKind.operatorIs:
return 'ModularName"is:${_className(data as ClassEntity)}"';
case ModularNameKind.className:
return 'ModularName"class:${_className(data as ClassEntity)}"';
case ModularNameKind.globalPropertyNameForClass:
return 'ModularName"classref:${_className(data as ClassEntity)}"';
case ModularNameKind.aliasedSuperMember:
MemberEntity member = (data as MemberEntity);
String className = _className(member.enclosingClass!);
String invocationName = operatorNameToIdentifier(member.name)!;
final description = "$className.$invocationName";
return 'ModularName"alias:$description"';
case ModularNameKind.staticClosure:
return 'ModularName"closure:${_qualifiedStaticName(data as MemberEntity)}"';
case ModularNameKind.lazyInitializer:
return 'ModularName"lazy:${(data as MemberEntity).name}"';
case ModularNameKind.globalPropertyNameForMember:
MemberEntity member = data as MemberEntity;
return 'ModularName"ref:${_qualifiedStaticName(member)}"';
case ModularNameKind.invocation:
return 'ModularName"selector:${_selectorText(data as Selector)}"';
case ModularNameKind.nameForOneShotInterceptor:
return 'ModularName"oneshot:${_selectorText(data as Selector)}"';
case ModularNameKind.globalNameForInterfaceTypeVariable:
break;
case ModularNameKind.nameForGetInterceptor:
return 'ModularName"getInterceptor"';
case ModularNameKind.asName:
return 'ModularName"asName:$data"';
}
return super.nonfinalizedDebugText();
}
String _className(ClassEntity cls) {
return cls.name.replaceAll('&', '_');
}
String _qualifiedStaticName(MemberEntity member) {
if (member is ConstructorEntity || member.isStatic) {
return '${_className(member.enclosingClass!)}.${member.name!}';
}
return member.name!;
}
String _instanceMethodInvocationName(MemberEntity member) {
String invocationName = operatorNameToIdentifier(member.name)!;
if (member.isGetter) invocationName = r'get$' + invocationName;
if (member.isSetter) invocationName = r'set$' + invocationName;
return invocationName;
}
String _instanceMethodName(MemberEntity member) {
if (member is ConstructorBodyEntity) {
return 'constructorBody:${_qualifiedStaticName(member.constructor)}';
}
if (member is JGeneratorBody) {
MemberEntity function = member.function;
return 'generatorBody:'
'${_className(function.enclosingClass!)}.'
'${_instanceMethodInvocationName(function)}';
}
return 'instanceMethod:${_instanceMethodInvocationName(member)}';
}
String _selectorText(Selector selector) {
// Approximation to unminified selector.
if (selector.isGetter) return r'get$' + selector.name;
if (selector.isSetter) return r'set$' + selector.name;
if (selector.isOperator || selector.isIndex || selector.isIndexSet) {
return operatorNameToIdentifier(selector.name)!;
}
List<String> parts = [
selector.name,
if (selector.callStructure.typeArgumentCount > 0)
'${selector.callStructure.typeArgumentCount}',
'${selector.callStructure.argumentCount}',
...selector.callStructure.getOrderedNamedArguments()
];
return parts.join(r'$');
}
}
/// Interface for reading the code generation results for all [MemberEntity]s.
abstract class CodegenResults {
GlobalTypeInferenceResults get globalTypeInferenceResults;
CodegenInputs get codegenInputs;
interfaces.CodegenResult getCodegenResults(MemberEntity member);
}
/// Deserialized code generation results.
///
/// This is used for modular code generation.
class DeserializedCodegenResults extends CodegenResults {
@override
final GlobalTypeInferenceResults globalTypeInferenceResults;
@override
final CodegenInputs codegenInputs;
final Map<MemberEntity, interfaces.CodegenResult> _map;
DeserializedCodegenResults(
this.globalTypeInferenceResults, this.codegenInputs, this._map);
@override
interfaces.CodegenResult getCodegenResults(MemberEntity member) {
return _map[member]!;
}
}