blob: 19291da52932f110134bbd7005e4807bd19fef5d [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.
library dart2js.common.codegen;
import 'package:js_ast/src/precedence.dart' as js show PRIMARY;
import '../common_elements.dart';
import '../constants/values.dart';
import '../elements/entities.dart';
import '../elements/types.dart' show DartType, InterfaceType;
import '../js/js.dart' as js;
import '../native/behavior.dart';
import '../universe/feature.dart';
import '../universe/use.dart' show ConstantUse, DynamicUse, StaticUse, TypeUse;
import '../universe/world_impact.dart'
show WorldImpact, WorldImpactBuilderImpl, WorldImpactVisitor;
import '../util/enumset.dart';
import '../util/util.dart';
class CodegenImpact extends WorldImpact {
const CodegenImpact();
Iterable<Pair<DartType, DartType>> get typeVariableBoundsSubtypeChecks {
return const <Pair<DartType, DartType>>[];
}
Iterable<String> get constSymbols => const <String>[];
Iterable<Set<ClassEntity>> get specializedGetInterceptors {
return const <Set<ClassEntity>>[];
}
bool get usesInterceptor => false;
Iterable<AsyncMarker> get asyncMarkers => const <AsyncMarker>[];
Iterable<GenericInstantiation> get genericInstantiations =>
const <GenericInstantiation>[];
Iterable<NativeBehavior> get nativeBehaviors => const [];
Iterable<FunctionEntity> get nativeMethods => const [];
}
class _CodegenImpact extends WorldImpactBuilderImpl implements CodegenImpact {
Setlet<Pair<DartType, DartType>> _typeVariableBoundsSubtypeChecks;
Setlet<String> _constSymbols;
List<Set<ClassEntity>> _specializedGetInterceptors;
bool _usesInterceptor = false;
EnumSet<AsyncMarker> _asyncMarkers;
Set<GenericInstantiation> _genericInstantiations;
List<NativeBehavior> _nativeBehaviors;
Set<FunctionEntity> _nativeMethods;
_CodegenImpact();
@override
void apply(WorldImpactVisitor visitor) {
staticUses.forEach(visitor.visitStaticUse);
dynamicUses.forEach(visitor.visitDynamicUse);
typeUses.forEach(visitor.visitTypeUse);
}
void registerTypeVariableBoundsSubtypeCheck(
DartType subtype, DartType supertype) {
_typeVariableBoundsSubtypeChecks ??= new Setlet<Pair<DartType, DartType>>();
_typeVariableBoundsSubtypeChecks
.add(new Pair<DartType, DartType>(subtype, supertype));
}
@override
Iterable<Pair<DartType, DartType>> get typeVariableBoundsSubtypeChecks {
return _typeVariableBoundsSubtypeChecks != null
? _typeVariableBoundsSubtypeChecks
: const <Pair<DartType, DartType>>[];
}
void registerConstSymbol(String name) {
_constSymbols ??= new Setlet<String>();
_constSymbols.add(name);
}
@override
Iterable<String> get constSymbols {
return _constSymbols != null ? _constSymbols : const <String>[];
}
void registerSpecializedGetInterceptor(Set<ClassEntity> classes) {
_specializedGetInterceptors ??= <Set<ClassEntity>>[];
_specializedGetInterceptors.add(classes);
}
@override
Iterable<Set<ClassEntity>> get specializedGetInterceptors {
return _specializedGetInterceptors != null
? _specializedGetInterceptors
: const <Set<ClassEntity>>[];
}
void registerUseInterceptor() {
_usesInterceptor = true;
}
@override
bool get usesInterceptor => _usesInterceptor;
void registerAsyncMarker(AsyncMarker asyncMarker) {
_asyncMarkers ??= new EnumSet<AsyncMarker>();
_asyncMarkers.add(asyncMarker);
}
@override
Iterable<AsyncMarker> get asyncMarkers {
return _asyncMarkers != null
? _asyncMarkers.iterable(AsyncMarker.values)
: const <AsyncMarker>[];
}
void registerGenericInstantiation(GenericInstantiation instantiation) {
_genericInstantiations ??= new Set<GenericInstantiation>();
_genericInstantiations.add(instantiation);
}
@override
Iterable<GenericInstantiation> get genericInstantiations {
return _genericInstantiations ?? const <GenericInstantiation>[];
}
void registerNativeBehavior(NativeBehavior nativeBehavior) {
_nativeBehaviors ??= [];
_nativeBehaviors.add(nativeBehavior);
}
@override
Iterable<NativeBehavior> get nativeBehaviors {
return _nativeBehaviors ?? const <NativeBehavior>[];
}
void registerNativeMethod(FunctionEntity function) {
_nativeMethods ??= {};
_nativeMethods.add(function);
}
@override
Iterable<FunctionEntity> get nativeMethods {
return _nativeMethods ?? const [];
}
}
// TODO(johnniwinther): Split this class into interface and implementation.
// TODO(johnniwinther): Move this implementation to the JS backend.
class CodegenRegistry {
final ElementEnvironment _elementEnvironment;
final MemberEntity _currentElement;
final _CodegenImpact _worldImpact;
List<ModularName> _names;
List<ModularExpression> _expressions;
CodegenRegistry(this._elementEnvironment, this._currentElement)
: this._worldImpact = new _CodegenImpact();
@override
String toString() => 'CodegenRegistry for $_currentElement';
@deprecated
void registerInstantiatedClass(ClassEntity element) {
registerInstantiation(_elementEnvironment.getRawType(element));
}
void registerStaticUse(StaticUse staticUse) {
_worldImpact.registerStaticUse(staticUse);
}
void registerDynamicUse(DynamicUse dynamicUse) {
_worldImpact.registerDynamicUse(dynamicUse);
}
void registerTypeUse(TypeUse typeUse) {
_worldImpact.registerTypeUse(typeUse);
}
void registerConstantUse(ConstantUse constantUse) {
_worldImpact.registerConstantUse(constantUse);
}
void registerTypeVariableBoundsSubtypeCheck(
DartType subtype, DartType supertype) {
_worldImpact.registerTypeVariableBoundsSubtypeCheck(subtype, supertype);
}
void registerInstantiatedClosure(FunctionEntity element) {
_worldImpact.registerStaticUse(new StaticUse.callMethod(element));
}
void registerConstSymbol(String name) {
_worldImpact.registerConstSymbol(name);
}
void registerSpecializedGetInterceptor(Set<ClassEntity> classes) {
_worldImpact.registerSpecializedGetInterceptor(classes);
}
void registerUseInterceptor() {
_worldImpact.registerUseInterceptor();
}
void registerInstantiation(InterfaceType type) {
registerTypeUse(new TypeUse.instantiation(type));
}
void registerAsyncMarker(AsyncMarker asyncMarker) {
_worldImpact.registerAsyncMarker(asyncMarker);
}
void registerGenericInstantiation(GenericInstantiation instantiation) {
_worldImpact.registerGenericInstantiation(instantiation);
}
void registerNativeBehavior(NativeBehavior nativeBehavior) {
_worldImpact.registerNativeBehavior(nativeBehavior);
}
void registerNativeMethod(FunctionEntity function) {
_worldImpact.registerNativeMethod(function);
}
void registerModularName(ModularName name) {
_names ??= [];
_names.add(name);
}
void registerModularExpression(ModularExpression expression) {
_expressions ??= [];
_expressions.add(expression);
}
CodegenResult close(js.Fun code) {
return new CodegenResult(
code, _worldImpact, _names ?? const [], _expressions ?? const []);
}
}
class CodegenResult {
final js.Fun code;
final CodegenImpact impact;
final Iterable<ModularName> modularNames;
final Iterable<ModularExpression> modularExpressions;
CodegenResult(
this.code, this.impact, this.modularNames, this.modularExpressions);
@override
String toString() {
StringBuffer sb = new StringBuffer();
sb.write('CodegenResult(code=');
sb.write(code != null ? js.DebugPrint(code) : '<null>,');
sb.write('impact=$impact,');
sb.write('modularNames=$modularNames,');
sb.write('modularExpressions=$modularExpressions');
sb.write(')');
return sb.toString();
}
}
enum ModularNameKind {
rtiField,
runtimeTypeName,
className,
aliasedSuperMember,
staticClosure,
methodProperty,
operatorIs,
operatorIsType,
substitution,
instanceMethod,
instanceField,
invocation,
lazyInitializer,
globalPropertyNameForClass,
globalPropertyNameForType,
globalPropertyNameForMember,
nameForGetInterceptor,
nameForGetOneShotInterceptor,
asName,
}
class ModularName extends js.Name implements js.AstContainer {
final ModularNameKind kind;
js.Name _value;
final Object data;
final Set<ClassEntity> set;
ModularName(this.kind, {this.data, this.set});
js.Name get value {
assert(_value != null);
return _value;
}
void set value(js.Name node) {
assert(_value == null);
assert(node != null);
_value = node.withSourceInformation(sourceInformation);
}
@override
String get key {
assert(_value != null);
return _value.key;
}
@override
String get name {
assert(_value != null);
return _value.name;
}
@override
bool get allowRename {
assert(_value != null);
return _value.allowRename;
}
@override
int compareTo(js.Name other) {
assert(_value != null);
return _value.compareTo(other);
}
@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)';
}
enum ModularExpressionKind {
globalObjectForLibrary,
globalObjectForClass,
globalObjectForType,
globalObjectForMember,
constant,
embeddedGlobalAccess,
}
class ModularExpression extends js.DeferredExpression
implements js.AstContainer {
final ModularExpressionKind kind;
final Object data;
js.Expression _value;
ModularExpression(this.kind, this.data);
@override
js.Expression get value {
assert(_value != null);
return _value;
}
void set value(js.Expression node) {
assert(_value == null);
assert(node != null);
_value = node.withSourceInformation(sourceInformation);
}
@override
int get precedenceLevel => _value?.precedenceLevel ?? js.PRIMARY;
@override
Iterable<js.Node> get containedNodes {
return _value != null ? [_value] : const [];
}
@override
int get hashCode {
return Hashing.objectsHash(kind, data);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is ModularExpression &&
kind == other.kind &&
data == other.data;
}
@override
String toString() {
StringBuffer sb = new StringBuffer();
sb.write('ModularExpression(kind=$kind,data=');
if (data is ConstantValue) {
sb.write((data as ConstantValue).toStructuredText());
} else {
sb.write(data);
}
sb.write(',value=$_value)');
return sb.toString();
}
}