Skip to content

Commit ac122ff

Browse files
committed
Restrict backend misuse
BUG= [email protected] Review URL: https://codereview.chromium.org/1469353004.
1 parent c8cec94 commit ac122ff

File tree

7 files changed

+162
-99
lines changed

7 files changed

+162
-99
lines changed

pkg/compiler/lib/src/compiler.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ abstract class Compiler {
325325
ClassElement symbolImplementationClass;
326326

327327
// Initialized when symbolImplementationClass has been resolved.
328+
// TODO(johnniwinther): Move this to [BackendHelpers].
328329
FunctionElement symbolValidatedConstructor;
329330

330331
// Initialized when mirrorsUsedClass has been resolved.

pkg/compiler/lib/src/js_backend/backend.dart

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,52 @@ class JavaScriptBackend extends Backend {
581581
new Namer(compiler);
582582
}
583583

584+
/// The backend must *always* call this method when enqueuing an
585+
/// element. Calls done by the backend are not seen by global
586+
/// optimizations, so they would make these optimizations unsound.
587+
/// Therefore we need to collect the list of helpers the backend may
588+
/// use.
589+
// TODO(johnniwinther): Replace this with a more precise modelling; type
590+
// inference of these elements is disabled.
591+
Element registerBackendUse(Element element) {
592+
if (element != null) {
593+
bool registerUse = false;
594+
if (element == helpers.streamIteratorConstructor ||
595+
element == helpers.compiler.symbolConstructor ||
596+
element == helpers.compiler.symbolValidatedConstructor ||
597+
element == helpers.syncCompleterConstructor ||
598+
element == coreClasses.symbolClass ||
599+
element == helpers.objectNoSuchMethod) {
600+
// TODO(johnniwinther): These are valid but we could be more precise.
601+
registerUse = true;
602+
} else if (element.implementationLibrary.isPatch ||
603+
element.library == helpers.jsHelperLibrary ||
604+
element.library == helpers.interceptorsLibrary ||
605+
element.library == helpers.isolateHelperLibrary) {
606+
// TODO(johnniwinther): We should be more precise about these.
607+
registerUse = true;
608+
} else if (element == coreClasses.listClass ||
609+
element == helpers.mapLiteralClass ||
610+
element == coreClasses.functionClass ||
611+
element == coreClasses.stringClass) {
612+
// TODO(johnniwinther): Avoid these.
613+
registerUse = true;
614+
}
615+
if (!registerUse) {
616+
assert(invariant(element, false,
617+
message: "Backend use of $element is not allowed."));
618+
return element;
619+
}
620+
helpersUsed.add(element.declaration);
621+
if (element.isClass && element.isPatched) {
622+
// Both declaration and implementation may declare fields, so we
623+
// add both to the list of helpers.
624+
helpersUsed.add(element.implementation);
625+
}
626+
}
627+
return element;
628+
}
629+
584630
bool usedByBackend(Element element) {
585631
if (element.isParameter
586632
|| element.isInitializingFormal
@@ -1479,23 +1525,6 @@ class JavaScriptBackend extends Backend {
14791525
compiler.enabledRuntimeType;
14801526
}
14811527

1482-
/// The backend must *always* call this method when enqueuing an
1483-
/// element. Calls done by the backend are not seen by global
1484-
/// optimizations, so they would make these optimizations unsound.
1485-
/// Therefore we need to collect the list of helpers the backend may
1486-
/// use.
1487-
Element registerBackendUse(Element element) {
1488-
if (element != null) {
1489-
helpersUsed.add(element.declaration);
1490-
if (element.isClass && element.isPatched) {
1491-
// Both declaration and implementation may declare fields, so we
1492-
// add both to the list of helpers.
1493-
helpersUsed.add(element.implementation);
1494-
}
1495-
}
1496-
return element;
1497-
}
1498-
14991528
/// Enqueue [e] in [enqueuer].
15001529
///
15011530
/// This method calls [registerBackendUse].

pkg/compiler/lib/src/js_backend/backend_helpers.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ library dart2js.js_backend.helpers;
66

77
import '../common.dart';
88
import '../common/names.dart' show
9+
Identifiers,
910
Uris;
1011
import '../common/resolution.dart' show
1112
Resolution;
@@ -679,4 +680,18 @@ class BackendHelpers {
679680
Element get convertRtiToRuntimeType {
680681
return findHelper('convertRtiToRuntimeType');
681682
}
683+
684+
ClassElement get stackTraceClass {
685+
return findHelper('_StackTrace');
686+
}
687+
688+
MethodElement _objectNoSuchMethod;
689+
690+
MethodElement get objectNoSuchMethod {
691+
if (_objectNoSuchMethod == null) {
692+
_objectNoSuchMethod =
693+
coreClasses.objectClass.lookupLocalMember(Identifiers.noSuchMethod_);
694+
}
695+
return _objectNoSuchMethod;
696+
}
682697
}

pkg/compiler/lib/src/js_backend/backend_impact.dart

Lines changed: 89 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ class BackendImpacts {
6868
helpers.getRuntimeTypeInfo,
6969
helpers.computeSignature,
7070
helpers.getRuntimeTypeArguments],
71-
instantiatedClasses: [
72-
coreClasses.listClass]);
71+
otherImpacts: [
72+
listValues]);
7373
}
7474
return _computeSignature;
7575
}
@@ -187,16 +187,84 @@ class BackendImpacts {
187187
return _throwNoSuchMethod;
188188
}
189189

190+
BackendImpact _stringValues;
191+
192+
BackendImpact get stringValues {
193+
if (_stringValues == null) {
194+
_stringValues = new BackendImpact(
195+
instantiatedClasses: [
196+
helpers.jsStringClass]);
197+
}
198+
return _stringValues;
199+
}
200+
201+
BackendImpact _numValues;
202+
203+
BackendImpact get numValues {
204+
if (_numValues == null) {
205+
_numValues = new BackendImpact(
206+
instantiatedClasses: [
207+
helpers.jsIntClass,
208+
helpers.jsPositiveIntClass,
209+
helpers.jsUInt32Class,
210+
helpers.jsUInt31Class,
211+
helpers.jsNumberClass,
212+
helpers.jsDoubleClass]);
213+
}
214+
return _numValues;
215+
}
216+
217+
BackendImpact get intValues => numValues;
218+
219+
BackendImpact get doubleValues => numValues;
220+
221+
BackendImpact _boolValues;
222+
223+
BackendImpact get boolValues {
224+
if (_boolValues == null) {
225+
_boolValues = new BackendImpact(
226+
instantiatedClasses: [
227+
helpers.jsBoolClass]);
228+
}
229+
return _boolValues;
230+
}
231+
232+
BackendImpact _nullValue;
233+
234+
BackendImpact get nullValue {
235+
if (_nullValue == null) {
236+
_nullValue = new BackendImpact(
237+
instantiatedClasses: [
238+
helpers.jsNullClass]);
239+
}
240+
return _nullValue;
241+
}
242+
243+
BackendImpact _listValues;
244+
245+
BackendImpact get listValues {
246+
if (_listValues == null) {
247+
_listValues = new BackendImpact(
248+
instantiatedClasses: [
249+
helpers.jsArrayClass,
250+
helpers.jsMutableArrayClass,
251+
helpers.jsFixedArrayClass,
252+
helpers.jsExtendableArrayClass,
253+
helpers.jsUnmodifiableArrayClass]);
254+
}
255+
return _listValues;
256+
}
257+
190258
BackendImpact _throwRuntimeError;
191259

192260
BackendImpact get throwRuntimeError {
193261
if (_throwRuntimeError == null) {
194262
_throwRuntimeError = new BackendImpact(
195263
staticUses: [
196264
helpers.throwRuntimeError],
197-
// Also register the types of the arguments passed to this method.
198-
instantiatedClasses: [
199-
coreClasses.stringClass]);
265+
otherImpacts: [
266+
// Also register the types of the arguments passed to this method.
267+
stringValues]);
200268
}
201269
return _throwRuntimeError;
202270
}
@@ -208,8 +276,7 @@ class BackendImpacts {
208276
_superNoSuchMethod = new BackendImpact(
209277
staticUses: [
210278
helpers.createInvocationMirror,
211-
coreClasses.objectClass.lookupLocalMember(
212-
Identifiers.noSuchMethod_)],
279+
helpers.objectNoSuchMethod],
213280
otherImpacts: [
214281
_needsInt(
215282
'Needed to encode the invocation kind of super.noSuchMethod.'),
@@ -277,23 +344,19 @@ class BackendImpacts {
277344
/// Helper for registering that `int` is needed.
278345
BackendImpact _needsInt(String reason) {
279346
// TODO(johnniwinther): Register [reason] for use in dump-info.
280-
return new BackendImpact(
281-
instantiatedClasses: [coreClasses.intClass]);
347+
return intValues;
282348
}
283349

284350
/// Helper for registering that `List` is needed.
285351
BackendImpact _needsList(String reason) {
286352
// TODO(johnniwinther): Register [reason] for use in dump-info.
287-
return new BackendImpact(
288-
instantiatedClasses: [coreClasses.listClass]);
353+
return listValues;
289354
}
290355

291356
/// Helper for registering that `String` is needed.
292357
BackendImpact _needsString(String reason) {
293358
// TODO(johnniwinther): Register [reason] for use in dump-info.
294-
return new BackendImpact(
295-
instantiatedClasses: [
296-
coreClasses.stringClass]);
359+
return stringValues;
297360
}
298361

299362
BackendImpact _assertWithoutMessage;
@@ -352,62 +415,15 @@ class BackendImpacts {
352415
return _stringJuxtaposition;
353416
}
354417

355-
// TODO(johnniwinther): Point to to the JavaScript classes instead of the Dart
356-
// classes in these impacts.
357-
BackendImpact _nullLiteral;
418+
BackendImpact get nullLiteral => nullValue;
358419

359-
BackendImpact get nullLiteral {
360-
if (_nullLiteral == null) {
361-
_nullLiteral = new BackendImpact(
362-
instantiatedClasses: [
363-
coreClasses.nullClass]);
364-
}
365-
return _nullLiteral;
366-
}
420+
BackendImpact get boolLiteral => boolValues;
367421

368-
BackendImpact _boolLiteral;
422+
BackendImpact get intLiteral => intValues;
369423

370-
BackendImpact get boolLiteral {
371-
if (_boolLiteral == null) {
372-
_boolLiteral = new BackendImpact(
373-
instantiatedClasses: [
374-
coreClasses.boolClass]);
375-
}
376-
return _boolLiteral;
377-
}
424+
BackendImpact get doubleLiteral => doubleValues;
378425

379-
BackendImpact _intLiteral;
380-
381-
BackendImpact get intLiteral {
382-
if (_intLiteral == null) {
383-
_intLiteral = new BackendImpact(
384-
instantiatedClasses: [
385-
coreClasses.intClass]);
386-
}
387-
return _intLiteral;
388-
}
389-
390-
BackendImpact _doubleLiteral;
391-
392-
BackendImpact get doubleLiteral {
393-
if (_doubleLiteral == null) {
394-
_doubleLiteral = new BackendImpact(
395-
instantiatedClasses: [
396-
coreClasses.doubleClass]);
397-
}
398-
return _doubleLiteral;
399-
}
400-
401-
BackendImpact _stringLiteral;
402-
403-
BackendImpact get stringLiteral {
404-
if (_stringLiteral == null) {
405-
_stringLiteral = new BackendImpact(
406-
instantiatedClasses: [
407-
coreClasses.stringClass]);
408-
}
409-
return _stringLiteral;
410-
}
426+
BackendImpact get stringLiteral => stringValues;
411427

412428
BackendImpact _catchStatement;
413429

@@ -468,7 +484,7 @@ class BackendImpacts {
468484
if (_stackTraceInCatch == null) {
469485
_stackTraceInCatch = new BackendImpact(
470486
instantiatedClasses: [
471-
coreClasses.stackTraceClass],
487+
helpers.stackTraceClass],
472488
staticUses: [
473489
helpers.traceFromException]);
474490
}
@@ -498,9 +514,8 @@ class BackendImpacts {
498514
helpers.getRuntimeTypeInfo,
499515
helpers.runtimeTypeToString,
500516
helpers.createRuntimeType],
501-
instantiatedClasses: [
502-
coreClasses.listClass],
503517
otherImpacts: [
518+
listValues,
504519
getRuntimeTypeArgument,
505520
_needsInt('Needed for accessing a type variable literal on this.')
506521
]);
@@ -513,8 +528,8 @@ class BackendImpacts {
513528
BackendImpact get typeCheck {
514529
if (_typeCheck == null) {
515530
_typeCheck = new BackendImpact(
516-
instantiatedClasses: [
517-
coreClasses.boolClass]);
531+
otherImpacts: [
532+
boolValues]);
518533
}
519534
return _typeCheck;
520535
}
@@ -551,9 +566,8 @@ class BackendImpacts {
551566
// TODO(johnniwinther): Investigate why this is needed.
552567
helpers.setRuntimeTypeInfo,
553568
helpers.getRuntimeTypeInfo],
554-
instantiatedClasses: [
555-
coreClasses.listClass],
556569
otherImpacts: [
570+
listValues,
557571
getRuntimeTypeArgument]);
558572
}
559573
return _genericTypeCheck;
@@ -564,8 +578,8 @@ class BackendImpacts {
564578
BackendImpact get genericIsCheck {
565579
if (_genericIsCheck == null) {
566580
_genericIsCheck = new BackendImpact(
567-
instantiatedClasses: [
568-
coreClasses.listClass]);
581+
otherImpacts: [
582+
intValues]);
569583
}
570584
return _genericIsCheck;
571585
}

tests/compiler/dart2js/mock_libraries.dart

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,6 @@ const Map<String, String> DEFAULT_CORE_LIBRARY = const <String, String>{
6464
}''',
6565
'LinkedHashMap': r'''
6666
class LinkedHashMap<K, V> implements Map<K, V> {
67-
factory LinkedHashMap._empty() => null;
68-
factory LinkedHashMap._literal(elements) => null;
69-
static _makeEmpty() => null;
70-
static _makeLiteral(elements) => null;
7167
}''',
7268
'List': r'''
7369
class List<E> extends Iterable<E> {
@@ -113,6 +109,14 @@ import 'dart:_js_helper';
113109
import 'dart:_interceptors';
114110
import 'dart:_isolate_helper';
115111
import 'dart:async';
112+
113+
@patch
114+
class LinkedHashMap<K, V> {
115+
factory LinkedHashMap._empty() => null;
116+
factory LinkedHashMap._literal(elements) => null;
117+
static _makeEmpty() => null;
118+
static _makeLiteral(elements) => null;
119+
}
116120
''';
117121

118122
const Map<String, String> DEFAULT_JS_HELPER_LIBRARY = const <String, String>{

0 commit comments

Comments
 (0)