Emit declarations for typedefs that are needed by reflection.
Typedefs are encoded like closure classes, but without a call-method and a superclass.
For example, the typedef `typedef int Foo(String s);` is emitted as:
Foo: {'^': ':15'},
where `15` is the index into `init.metadata` at which the function type is emitted.
BUG= http://dartbug.com/16939
R=floitsch@google.com
Committed: https://code.google.com/p/dart/source/detail?r=37814
Reverted in https://code.google.com/p/dart/source/detail?r=37848
Review URL: https://codereview.chromium.org//360493002
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@37939 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
@@ -10,6 +10,9 @@ class EnqueueTask extends CompilerTask {
|
||||
final ResolutionEnqueuer resolution;
|
||||
final CodegenEnqueuer codegen;
|
||||
|
||||
} else if (element.isTypedef) {
|
||||
TypedefElement typedef = element;
|
||||
typedef.ensureResolved(compiler);
|
||||
String get name => 'Enqueue';
|
||||
|
||||
EnqueueTask(Compiler compiler)
|
||||
|
||||
@@ -326,9 +326,6 @@ class JavaScriptBackend extends Backend {
|
||||
/// List of elements that the backend may use.
|
||||
final Set<Element> helpersUsed = new Set<Element>();
|
||||
|
||||
/// Set of typedefs that are used as type literals.
|
||||
final Set<TypedefElement> typedefTypeLiterals = new Set<TypedefElement>();
|
||||
|
||||
/// All the checked mode helpers.
|
||||
static const checkedModeHelpers = CheckedModeHelper.helpers;
|
||||
|
||||
@@ -2137,7 +2134,7 @@ class JavaScriptionResolutionCallbacks extends ResolutionCallbacks {
|
||||
// when reflection is used. However, as long as we disable tree-shaking
|
||||
// eagerly it doesn't matter.
|
||||
if (type.isTypedef) {
|
||||
backend.typedefTypeLiterals.add(type.element);
|
||||
backend.compiler.world.allTypedefs.add(type.element);
|
||||
}
|
||||
backend.customElementsAnalysis.registerTypeLiteral(type, registry);
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ class NativeEmitter {
|
||||
emitter.classEmitter.emitClassBuilderWithReflectionData(
|
||||
backend.namer.getNameOfClass(classElement),
|
||||
classElement, builders[classElement],
|
||||
emitter.getElementDecriptor(classElement));
|
||||
emitter.getElementDescriptor(classElement));
|
||||
emitter.needsDefineClass = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@ class CodeEmitterTask extends CompilerTask {
|
||||
// TODO(ngeoffray): remove this field.
|
||||
Set<ClassElement> instantiatedClasses;
|
||||
|
||||
List<TypedefElement> typedefsNeededForReflection;
|
||||
|
||||
JavaScriptBackend get backend => compiler.backend;
|
||||
TypeVariableHandler get typeVariableHandler => backend.typeVariableHandler;
|
||||
|
||||
@@ -63,9 +65,12 @@ class CodeEmitterTask extends CompilerTask {
|
||||
String get n => compiler.enableMinification ? "" : "\n";
|
||||
String get N => compiler.enableMinification ? "\n" : ";\n";
|
||||
|
||||
CodeBuffer getBuffer(OutputUnit outputUnit) {
|
||||
return outputBuffers.putIfAbsent(outputUnit, () => new CodeBuffer());
|
||||
}
|
||||
|
||||
CodeBuffer get mainBuffer {
|
||||
return outputBuffers.putIfAbsent(compiler.deferredLoadTask.mainOutputUnit,
|
||||
() => new CodeBuffer());
|
||||
return getBuffer(compiler.deferredLoadTask.mainOutputUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -750,6 +755,8 @@ class CodeEmitterTask extends CompilerTask {
|
||||
ClassElement cls = element;
|
||||
if (cls.isUnnamedMixinApplication) return null;
|
||||
return cls.name;
|
||||
} else if (element.isTypedef) {
|
||||
return element.name;
|
||||
}
|
||||
throw compiler.internalError(element,
|
||||
'Do not know how to reflect on this $element.');
|
||||
@@ -859,7 +866,7 @@ class CodeEmitterTask extends CompilerTask {
|
||||
for (Element element in Elements.sortedByPosition(elements)) {
|
||||
ClassBuilder builder = new ClassBuilder(namer);
|
||||
containerBuilder.addMember(element, builder);
|
||||
getElementDecriptor(element).properties.addAll(builder.properties);
|
||||
getElementDescriptor(element).properties.addAll(builder.properties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1145,10 +1152,15 @@ class CodeEmitterTask extends CompilerTask {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute all the classes that must be emitted.
|
||||
*/
|
||||
void computeNeededClasses() {
|
||||
/// Compute all the classes and typedefs that must be emitted.
|
||||
void computeNeededDeclarations() {
|
||||
// Compute needed typedefs.
|
||||
typedefsNeededForReflection = Elements.sortedByPosition(
|
||||
compiler.world.allTypedefs
|
||||
.where(backend.isNeededForReflection)
|
||||
.toList());
|
||||
|
||||
// Compute needed classes.
|
||||
instantiatedClasses =
|
||||
compiler.codegenWorld.instantiatedClasses.where(computeClassFilter())
|
||||
.toSet();
|
||||
@@ -1303,21 +1315,17 @@ class CodeEmitterTask extends CompilerTask {
|
||||
if (uri.scheme == 'file' && compiler.outputUri != null) {
|
||||
uri = relativize(compiler.outputUri, library.canonicalUri, false);
|
||||
}
|
||||
Map<OutputUnit, ClassBuilder> descriptors =
|
||||
elementDescriptors[library];
|
||||
Map<OutputUnit, ClassBuilder> descriptors = elementDescriptors[library];
|
||||
|
||||
for (OutputUnit outputUnit in compiler.deferredLoadTask.allOutputUnits) {
|
||||
ClassBuilder descriptor =
|
||||
descriptors.putIfAbsent(outputUnit, () => new ClassBuilder(namer));
|
||||
if (descriptor.properties.isEmpty) continue;
|
||||
bool isDeferred =
|
||||
outputUnit != compiler.deferredLoadTask.mainOutputUnit;
|
||||
if (!descriptors.containsKey(outputUnit)) continue;
|
||||
|
||||
ClassBuilder descriptor = descriptors[outputUnit];
|
||||
jsAst.Fun metadata = metadataEmitter.buildMetadataFunction(library);
|
||||
|
||||
jsAst.ObjectInitializer initializers =
|
||||
descriptor.toObjectInitializer();
|
||||
CodeBuffer outputBuffer =
|
||||
outputBuffers.putIfAbsent(outputUnit, () => new CodeBuffer());
|
||||
jsAst.ObjectInitializer initializers = descriptor.toObjectInitializer();
|
||||
CodeBuffer outputBuffer = getBuffer(outputUnit);
|
||||
|
||||
int sizeBefore = outputBuffer.length;
|
||||
outputBuffers[outputUnit]
|
||||
..write('["${library.getLibraryName()}",$_')
|
||||
@@ -1343,7 +1351,7 @@ class CodeEmitterTask extends CompilerTask {
|
||||
// 'is$' method.
|
||||
typeTestEmitter.computeRequiredTypeChecks();
|
||||
|
||||
computeNeededClasses();
|
||||
computeNeededDeclarations();
|
||||
|
||||
mainBuffer.add(buildGeneratedBy());
|
||||
addComment(HOOKS_API_USAGE, mainBuffer);
|
||||
@@ -1402,7 +1410,7 @@ class CodeEmitterTask extends CompilerTask {
|
||||
// Might create methodClosures.
|
||||
for (List<ClassElement> outputClassList in outputClassLists.values) {
|
||||
for (ClassElement element in outputClassList) {
|
||||
generateClass(element, getElementDecriptor(element));
|
||||
generateClass(element, getElementDescriptor(element));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1422,6 +1430,8 @@ class CodeEmitterTask extends CompilerTask {
|
||||
mainBuffer.write(';');
|
||||
}
|
||||
|
||||
// TODO(karlklose): document what kinds of fields this loop adds to the
|
||||
// library class builder.
|
||||
for (Element element in elementDescriptors.keys) {
|
||||
// TODO(ahe): Should iterate over all libraries. Otherwise, we will
|
||||
// not see libraries that only have fields.
|
||||
@@ -1437,6 +1447,28 @@ class CodeEmitterTask extends CompilerTask {
|
||||
}
|
||||
}
|
||||
|
||||
// Emit all required typedef declarations into the main output unit.
|
||||
// TODO(karlklose): unify required classes and typedefs to declarations
|
||||
// and have builders for each kind.
|
||||
for (TypedefElement typedef in typedefsNeededForReflection) {
|
||||
OutputUnit mainUnit = compiler.deferredLoadTask.mainOutputUnit;
|
||||
LibraryElement library = typedef.library;
|
||||
// TODO(karlklose): add a TypedefBuilder and move this code there.
|
||||
DartType type = typedef.alias;
|
||||
int typeIndex = metadataEmitter.reifyType(type);
|
||||
String typeReference =
|
||||
encoding.encodeTypedefFieldDescriptor(typeIndex);
|
||||
jsAst.Property descriptor = new jsAst.Property(
|
||||
js.string(namer.classDescriptorProperty),
|
||||
js.string(typeReference));
|
||||
jsAst.Node declaration = new jsAst.ObjectInitializer([descriptor]);
|
||||
String mangledName = namer.getNameX(typedef);
|
||||
String reflectionName = getReflectionName(typedef, mangledName);
|
||||
getElementDescriptorForOutputUnit(library, mainUnit)
|
||||
..addProperty(mangledName, declaration)
|
||||
..addProperty("+$reflectionName", js.string(''));
|
||||
}
|
||||
|
||||
if (!mangledFieldNames.isEmpty) {
|
||||
var keys = mangledFieldNames.keys.toList();
|
||||
keys.sort();
|
||||
@@ -1689,7 +1721,7 @@ class CodeEmitterTask extends CompilerTask {
|
||||
() => new ClassBuilder(namer));
|
||||
}
|
||||
|
||||
ClassBuilder getElementDecriptor(Element element) {
|
||||
ClassBuilder getElementDescriptor(Element element) {
|
||||
Element owner = element.library;
|
||||
if (!element.isTopLevel && !element.isNative) {
|
||||
// For static (not top level) elements, record their code in a buffer
|
||||
|
||||
@@ -65,6 +65,8 @@ import '../util/util.dart' show
|
||||
import '../deferred_load.dart' show
|
||||
OutputUnit;
|
||||
|
||||
import '../runtime_data.dart' as encoding;
|
||||
|
||||
part 'class_builder.dart';
|
||||
part 'class_emitter.dart';
|
||||
part 'code_emitter_helper.dart';
|
||||
|
||||
@@ -90,20 +90,8 @@ class MetadataEmitter extends CodeEmitterHelper {
|
||||
}
|
||||
|
||||
void emitMetadata(CodeBuffer buffer) {
|
||||
var literals = backend.typedefTypeLiterals.toList();
|
||||
Elements.sortedByPosition(literals);
|
||||
var properties = [];
|
||||
for (TypedefElement literal in literals) {
|
||||
var key = namer.getNameX(literal);
|
||||
var value = js.number(reifyType(literal.rawType));
|
||||
properties.add(new jsAst.Property(js.string(key), value));
|
||||
}
|
||||
var map = new jsAst.ObjectInitializer(properties);
|
||||
buffer.write(
|
||||
jsAst.prettyPrint(
|
||||
js.statement('init.functionAliases = #', map), compiler));
|
||||
buffer.write('${N}init.metadata$_=$_[');
|
||||
for (var metadata in globalMetadata) {
|
||||
buffer.write('init.metadata$_=$_[');
|
||||
for (String metadata in globalMetadata) {
|
||||
if (metadata is String) {
|
||||
if (metadata != 'null') {
|
||||
buffer.write(metadata);
|
||||
|
||||
@@ -1189,6 +1189,7 @@ class ResolverTask extends CompilerTask {
|
||||
|
||||
TreeElements resolveTypedef(TypedefElementX element) {
|
||||
if (element.isResolved) return element.treeElements;
|
||||
compiler.world.allTypedefs.add(element);
|
||||
return _resolveTypeDeclaration(element, () {
|
||||
ResolutionRegistry registry = new ResolutionRegistry(compiler, element);
|
||||
return compiler.withCurrentElement(element, () {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/// Contains encoding, decoding and detection functionality for the
|
||||
/// representation of program data at runtime.
|
||||
///
|
||||
/// This library is shared between the compiler and the runtime system.
|
||||
library dart2js.runtime_data;
|
||||
|
||||
|
||||
String encodeTypedefFieldDescriptor(int typeIndex) {
|
||||
return ":$typeIndex;";
|
||||
}
|
||||
|
||||
bool isTypedefDescriptor(String descriptor) {
|
||||
return descriptor.startsWith(':');
|
||||
}
|
||||
|
||||
int getTypeFromTypedef(String descriptor) {
|
||||
return int.parse(descriptor.substring(1, descriptor.length - 1));
|
||||
}
|
||||
@@ -10,6 +10,8 @@ class World {
|
||||
final Set<Element> functionsCalledInLoop = new Set<Element>();
|
||||
final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>();
|
||||
|
||||
final Set<TypedefElement> allTypedefs = new Set<TypedefElement>();
|
||||
|
||||
final Map<ClassElement, Set<MixinApplicationElement>> mixinUses =
|
||||
new Map<ClassElement, Set<MixinApplicationElement>>();
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
library dart._js_mirrors;
|
||||
|
||||
import 'dart:async';
|
||||
import '../compiler/implementation/runtime_data.dart' as encoding;
|
||||
|
||||
import 'dart:collection' show
|
||||
UnmodifiableListView,
|
||||
@@ -319,10 +319,12 @@ class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror
|
||||
var cls = reflectClassByMangledName(className);
|
||||
if (cls is ClassMirror) {
|
||||
cls = cls.originalDeclaration;
|
||||
if (cls is JsClassMirror) {
|
||||
result[cls.simpleName] = cls;
|
||||
cls._owner = this;
|
||||
}
|
||||
}
|
||||
if (cls is JsClassMirror) {
|
||||
result[cls.simpleName] = cls;
|
||||
cls._owner = this;
|
||||
} else if (cls is JsTypedefMirror) {
|
||||
result[cls.simpleName] = cls;
|
||||
}
|
||||
}
|
||||
return _cachedClasses =
|
||||
@@ -557,12 +559,6 @@ TypeMirror reflectClassByName(Symbol symbol, String mangledName) {
|
||||
}
|
||||
var constructor = JS('var', 'init.allClasses[#]', mangledName);
|
||||
if (constructor == null) {
|
||||
int index = JS('int|Null', 'init.functionAliases[#]', mangledName);
|
||||
if (index != null) {
|
||||
mirror = new JsTypedefMirror(symbol, mangledName, getMetadata(index));
|
||||
JsCache.update(classMirrors, mangledName, mirror);
|
||||
return mirror;
|
||||
}
|
||||
// Probably an intercepted class.
|
||||
// TODO(ahe): How to handle intercepted classes?
|
||||
throw new UnsupportedError('Cannot find class for: ${n(symbol)}');
|
||||
@@ -587,23 +583,28 @@ TypeMirror reflectClassByName(Symbol symbol, String mangledName) {
|
||||
}
|
||||
}
|
||||
|
||||
var superclassName = fields.split(';')[0];
|
||||
var mixins = superclassName.split('+');
|
||||
if (mixins.length > 1 && mangledGlobalNames[mangledName] == null) {
|
||||
mirror = reflectMixinApplication(mixins, mangledName);
|
||||
if (encoding.isTypedefDescriptor(fields)) {
|
||||
int index = encoding.getTypeFromTypedef(fields);
|
||||
mirror = new JsTypedefMirror(symbol, mangledName, getMetadata(index));
|
||||
} else {
|
||||
ClassMirror classMirror = new JsClassMirror(
|
||||
symbol, mangledName, constructor, fields, fieldsMetadata);
|
||||
List typeVariables =
|
||||
JS('JSExtendableArray|Null', '#.prototype["<>"]', constructor);
|
||||
if (typeVariables == null || typeVariables.length == 0) {
|
||||
mirror = classMirror;
|
||||
var superclassName = fields.split(';')[0];
|
||||
var mixins = superclassName.split('+');
|
||||
if (mixins.length > 1 && mangledGlobalNames[mangledName] == null) {
|
||||
mirror = reflectMixinApplication(mixins, mangledName);
|
||||
} else {
|
||||
String typeArguments = 'dynamic';
|
||||
for (int i = 1; i < typeVariables.length; i++) {
|
||||
typeArguments += ',dynamic';
|
||||
ClassMirror classMirror = new JsClassMirror(
|
||||
symbol, mangledName, constructor, fields, fieldsMetadata);
|
||||
List typeVariables =
|
||||
JS('JSExtendableArray|Null', '#.prototype["<>"]', constructor);
|
||||
if (typeVariables == null || typeVariables.length == 0) {
|
||||
mirror = classMirror;
|
||||
} else {
|
||||
String typeArguments = 'dynamic';
|
||||
for (int i = 1; i < typeVariables.length; i++) {
|
||||
typeArguments += ',dynamic';
|
||||
}
|
||||
mirror = new JsTypeBoundClassMirror(classMirror, typeArguments);
|
||||
}
|
||||
mirror = new JsTypeBoundClassMirror(classMirror, typeArguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@ const Map<String, List<String>> WHITE_LIST = const {
|
||||
// Some things in dart_printer are not yet used
|
||||
"implementation/dart_backend/dart_printer.dart" : const [" is never "],
|
||||
|
||||
// dart2js uses only the encoding functions, the decoding functions are used
|
||||
// from the generated code.
|
||||
"implementation/runtime_data.dart": const [" is never "],
|
||||
|
||||
// Setlet implements the Set interface: Issue 18959.
|
||||
"implementation/util/setlet.dart": const [" is never "],
|
||||
};
|
||||
|
||||
@@ -201,7 +201,6 @@ async/schedule_microtask6_test: Fail # Issue 10957 - may be related
|
||||
convert/json_lib_test: Fail # Issue 10961
|
||||
|
||||
[ $compiler == dart2js && $minified ]
|
||||
mirrors/typedef_test/01: Fail # http://dartbug.com/6490
|
||||
mirrors/mirrors_used_get_name_test: RuntimeError
|
||||
mirrors/mirrors_used_get_name2_test: RuntimeError
|
||||
|
||||
@@ -249,6 +248,8 @@ mirrors/mirrors_used_inheritance_test: RuntimeError # Issue 16048
|
||||
|
||||
async/timer_not_available_test: SkipByDesign # only meant to test when there is no way to implement timer (currently only in d8)
|
||||
|
||||
mirrors/typedef_declaration_test/01: Fail # dartbug.com/16048. Remove multitest marker when it passes.
|
||||
|
||||
[ $compiler == none && ( $runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
|
||||
async/schedule_microtask6_test: Fail # Issue 10910
|
||||
async/timer_test: Fail, Pass # Issue 15487
|
||||
|
||||
@@ -57,13 +57,12 @@ test(MirrorSystem mirrors) {
|
||||
Expect.isFalse(Obj.isSubclassOf(Func));
|
||||
|
||||
// Function typedef.
|
||||
// TODO(16939): retrieve via declaration when dart2js supports it.
|
||||
var NumPred = reflectType(NumberPredicate);
|
||||
var IntPred = reflectType(IntegerPredicate);
|
||||
var DubPred = reflectType(DoublePredicate);
|
||||
var NumGen = reflectType(NumberGenerator);
|
||||
var IntGen = reflectType(IntegerGenerator);
|
||||
var DubGen = reflectType(DoubleGenerator);
|
||||
var NumPred = thisLibrary.declarations[#NumberPredicate];
|
||||
var IntPred = thisLibrary.declarations[#IntegerPredicate];
|
||||
var DubPred = thisLibrary.declarations[#DoublePredicate];
|
||||
var NumGen = thisLibrary.declarations[#NumberGenerator];
|
||||
var IntGen = thisLibrary.declarations[#IntegerGenerator];
|
||||
var DubGen = thisLibrary.declarations[#DoubleGenerator];
|
||||
|
||||
isArgumentOrTypeError(e) => e is ArgumentError || e is TypeError;
|
||||
Expect.throws(() => Func.isSubclassOf(NumPred), isArgumentOrTypeError);
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2014, 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 test;
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
@MirrorsUsed(targets: "Foo")
|
||||
import 'dart:mirrors';
|
||||
|
||||
typedef int Foo(String x);
|
||||
typedef int Bar();
|
||||
|
||||
main() {
|
||||
LibraryMirror thisLibrary = currentMirrorSystem().findLibrary(#test);
|
||||
|
||||
Mirror fooMirror = thisLibrary.declarations[#Foo];
|
||||
|
||||
Expect.isTrue(fooMirror != null, 'Foo not found.');
|
||||
Expect.isTrue(thisLibrary.declarations[#Foo] is TypedefMirror,
|
||||
'TypedefMirror expected, found $fooMirror');
|
||||
|
||||
// The following code does not currenty work on the VM, because it does not
|
||||
// support MirrorsUsed (see dartbug.com/16048).
|
||||
Mirror barMirror = thisLibrary.declarations[#Bar]; /// 01: ok
|
||||
Expect.isTrue(barMirror == null, /// 01: continued
|
||||
'Bar should not be emitted due to MirrorsUsed.'); /// 01: continued
|
||||
}
|
||||
Reference in New Issue
Block a user