| Index: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
|
| index e7eb3ce1eb92696f13a5652c252591e0ddb73983..4e45ae9ecd9d50ab67c635d3bda650cee081d06c 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
|
| @@ -287,6 +287,7 @@ class CodeEmitterTask extends CompilerTask {
|
| static const RANGE2_LAST = 0x7e;
|
| static const RANGE3_FIRST = 0x25; // %&'()*+ encodes 10..16
|
| static const RANGE3_LAST = 0x2b;
|
| + static const REFLECTION_MARKER = 0x2d;
|
|
|
| jsAst.FunctionDeclaration get generateAccessorFunction {
|
| const RANGE1_SIZE = RANGE1_LAST - RANGE1_FIRST + 1;
|
| @@ -298,11 +299,19 @@ class CodeEmitterTask extends CompilerTask {
|
|
|
| String receiverParamName = compiler.enableMinification ? "r" : "receiver";
|
| String valueParamName = compiler.enableMinification ? "v" : "value";
|
| + String reflectableField = namer.reflectableField;
|
|
|
| // function generateAccessor(field, prototype) {
|
| jsAst.Fun fun = js.fun(['field', 'prototype'], [
|
| js('var len = field.length'),
|
| js('var code = field.charCodeAt(len - 1)'),
|
| + js('var reflectable = false'),
|
| + js.if_('code == $REFLECTION_MARKER', [
|
| + js('len--'),
|
| + js('code = field.charCodeAt(len - 1)'),
|
| + js('field = field.substring(0, len)'),
|
| + js('reflectable = true')
|
| + ]),
|
| js('code = ((code >= $RANGE1_FIRST) && (code <= $RANGE1_LAST))'
|
| ' ? code - $RANGE1_ADJUST'
|
| ' : ((code >= $RANGE2_FIRST) && (code <= $RANGE2_LAST))'
|
| @@ -329,7 +338,10 @@ class CodeEmitterTask extends CompilerTask {
|
| js('var receiver = (getterCode & 1) ? "this" : "$receiverParamName"'),
|
| js('var body = "return " + receiver + "." + field'),
|
| js('prototype["${namer.getterPrefix}" + accessorName] = '
|
| - 'new Function(args, body)')
|
| + 'new Function(args, body)'),
|
| + js.if_('!reflectable', [
|
| + js('prototype["${namer.getterPrefix}" + accessorName].'
|
| + '$reflectableField = false')])
|
| ]),
|
|
|
| // if (needsSetter) {
|
| @@ -340,7 +352,10 @@ class CodeEmitterTask extends CompilerTask {
|
| js('var receiver = (setterCode & 1) ? "this" : "$receiverParamName"'),
|
| js('var body = receiver + "." + field + "$_=$_$valueParamName"'),
|
| js('prototype["${namer.setterPrefix}" + accessorName] = '
|
| - 'new Function(args, body)')
|
| + 'new Function(args, body)'),
|
| + js.if_('!reflectable', [
|
| + js('prototype["${namer.setterPrefix}" + accessorName].'
|
| + '$reflectableField = false')])
|
| ]),
|
|
|
| ]),
|
| @@ -1099,7 +1114,9 @@ class CodeEmitterTask extends CompilerTask {
|
|
|
| String reflectionName = getReflectionName(selector, invocationName);
|
| if (reflectionName != null) {
|
| - defineStub('+$reflectionName', js('0'));
|
| + var reflectable =
|
| + js(backend.isAccessibleByReflection(member) ? '1' : '0');
|
| + defineStub('+$reflectionName', reflectable);
|
| }
|
| }
|
|
|
| @@ -1270,7 +1287,9 @@ class CodeEmitterTask extends CompilerTask {
|
| builder.addProperty(name, code);
|
| String reflectionName = getReflectionName(member, name);
|
| if (reflectionName != null) {
|
| - builder.addProperty('+$reflectionName', js('0'));
|
| + var reflectable =
|
| + js(backend.isAccessibleByReflection(member) ? '1' : '0');
|
| + builder.addProperty('+$reflectionName', reflectable);
|
| }
|
| code = backend.generatedBailoutCode[member];
|
| if (code != null) {
|
| @@ -1325,7 +1344,10 @@ class CodeEmitterTask extends CompilerTask {
|
| String getter = '${namer.getterPrefix}$base';
|
| mangledFieldNames[getter] = name;
|
| recordedMangledNames.add(getter);
|
| - return null;
|
| + // TODO(karlklose,ahe): we do not actually need to store information
|
| + // about the name of this setter in the output, but it is needed for
|
| + // marking the function as invokable by reflection.
|
| + return '$name=';
|
| }
|
| if (elementOrSelector is Selector
|
| || elementOrSelector.isFunction()
|
| @@ -1861,6 +1883,9 @@ class CodeEmitterTask extends CompilerTask {
|
| buffer.write(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]);
|
| }
|
| }
|
| + if (backend.isAccessibleByReflection(field)) {
|
| + buffer.write(new String.fromCharCode(REFLECTION_MARKER));
|
| + }
|
| }
|
| });
|
| }
|
| @@ -2300,7 +2325,8 @@ class CodeEmitterTask extends CompilerTask {
|
| emitStaticFunction(buffer, name, code);
|
| String reflectionName = getReflectionName(element, name);
|
| if (reflectionName != null) {
|
| - buffer.write(',$n$n"+$reflectionName":${_}0');
|
| + var reflectable = backend.isAccessibleByReflection(element) ? 1 : 0;
|
| + buffer.write(',$n$n"+$reflectionName":${_}$reflectable');
|
| }
|
| jsAst.Expression bailoutCode = backend.generatedBailoutCode[element];
|
| if (bailoutCode != null) {
|
| @@ -4030,6 +4056,7 @@ class CodeEmitterTask extends CompilerTask {
|
| // TODO(ahe): This code should be integrated in finishClasses.
|
| String getReflectionDataParser() {
|
| String metadataField = '"${namer.metadataField}"';
|
| + String reflectableField = namer.reflectableField;
|
| return '''
|
| (function (reflectionData) {
|
| '''
|
| @@ -4078,7 +4105,9 @@ class CodeEmitterTask extends CompilerTask {
|
| var previousProperty;
|
| if (firstChar === "+") {
|
| mangledGlobalNames[previousProperty] = property.substring(1);
|
| - if (element && element.length) ''' // Breaking long line.
|
| + descriptor[previousProperty].''' // Break long line.
|
| +'''$reflectableField = (descriptor[property] == 1);
|
| + if (element && element.length) ''' // Break long line.
|
| '''init.interfaces[previousProperty] = element;
|
| } else if (firstChar === "@") {
|
| property = property.substring(1);
|
| @@ -4097,6 +4126,8 @@ class CodeEmitterTask extends CompilerTask {
|
| processStatics(init.statics[property] = element[prop]);
|
| } else if (firstChar === "+") {
|
| mangledNames[previousProp] = prop.substring(1);
|
| + element[previousProp].''' // Break long line.
|
| +'''$reflectableField = (element[prop] == 1);
|
| } else if (firstChar === "@" && prop !== "@") {
|
| newDesc[prop.substring(1)][$metadataField] = element[prop];
|
| } else {
|
|
|