mirror of
https://github.com/dart-lang/sdk
synced 2024-09-06 00:59:09 +00:00
![Sigmund Cherem](/assets/img/avatar_default.png)
Change-Id: I46be49b2effec3e38a3dc44cd45cfe736f77fa78 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/182680 Commit-Queue: Sigmund Cherem <sigmund@google.com> Reviewed-by: Joshua Litt <joshualitt@google.com> Reviewed-by: Nicholas Shahan <nshahan@google.com> Reviewed-by: Stephen Adams <sra@google.com>
327 lines
8.1 KiB
Dart
327 lines
8.1 KiB
Dart
// Copyright (c) 2015, 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.
|
|
|
|
// Test that optimized JSArray indexers generate the same error as dynamically
|
|
// dispatched calls.
|
|
|
|
import 'package:expect/expect.dart';
|
|
|
|
@pragma('dart2js:noInline')
|
|
@pragma('dart2js:assumeDynamic')
|
|
confuse(x) => x;
|
|
|
|
Error? getError(action(), name, part) {
|
|
try {
|
|
action();
|
|
} on Error catch (e) {
|
|
return e;
|
|
}
|
|
Expect.fail('must throw: $name: $part');
|
|
}
|
|
|
|
indexErrorContainsIndex() {
|
|
makeFault(i) => () => confuse([])[i];
|
|
|
|
var name = 'index error contains index';
|
|
var e1 = getError(makeFault(1234), name, 'small');
|
|
var e2 = getError(makeFault(1234000), name, 'medium');
|
|
var e3 = getError(makeFault(1234000000000), name, 'large');
|
|
|
|
Expect.equals('$e1', '$e2'.replaceAll('000', ''));
|
|
Expect.equals('$e1', '$e3'.replaceAll('000', ''));
|
|
Expect.equals('$e1'.length + 3, '$e2'.length);
|
|
Expect.equals('$e1'.length + 9, '$e3'.length);
|
|
}
|
|
|
|
compare(name, fault1(), fault2(), fault3()) {
|
|
var e1 = getError(fault1, name, 'fault1');
|
|
var e2 = getError(fault2, name, 'fault2');
|
|
var e3 = getError(fault3, name, 'fault3');
|
|
|
|
Expect.equals('$e1', '$e2', '$name: fault1 vs fault2');
|
|
Expect.equals('$e1', '$e3', '$name: fault1 vs fault3');
|
|
}
|
|
|
|
// These tests are a bit tedious and avoid common helpers with higher order
|
|
// functions to keep the type inference for each test independent from the
|
|
// others.
|
|
//
|
|
// The 'constant' tests have a constant index which might permit different
|
|
// optimizations to a variable index. e.g. the compiler might determine HUGE is
|
|
// always out of range since the maximum JavaScript Array length is 2^32.
|
|
//
|
|
// The 'variable' forms take the index as an argument.
|
|
|
|
const int HUGE = 1000000000000;
|
|
|
|
constantIndexEmpty() {
|
|
// Single dynamic receiver indexing might go via one-shot interceptor that
|
|
// might have an accelerated path.
|
|
fault1() => confuse([])[0];
|
|
|
|
fault2() {
|
|
var a = [];
|
|
while (confuse(false)) a.add(1);
|
|
// Easily inferred type and open coded indexer.
|
|
return a[0];
|
|
}
|
|
|
|
fault3() {
|
|
var a = confuse([]);
|
|
// Multiple indexing might go via shared interceptor.
|
|
return [a[0], a[1], a[2]];
|
|
}
|
|
|
|
compare('constant index on empty list', fault1, fault2, fault3);
|
|
}
|
|
|
|
constantIndexHugeEmpty() {
|
|
// Single dynamic receiver indexing might go via one-shot interceptor that
|
|
// might have an accelerated path.
|
|
fault1() => confuse([])[HUGE];
|
|
|
|
fault2() {
|
|
var a = [];
|
|
while (confuse(false)) a.add(1);
|
|
return a[HUGE];
|
|
}
|
|
|
|
fault3() {
|
|
var a = confuse([]);
|
|
return [a[HUGE], a[1], a[2]];
|
|
}
|
|
|
|
compare(
|
|
'constant index on empty list with huge index', fault1, fault2, fault3);
|
|
}
|
|
|
|
constantIndexNonempty() {
|
|
// Single dynamic receiver indexing might go via one-shot interceptor that
|
|
// might have an accelerated path.
|
|
fault1() => confuse([1])[1];
|
|
|
|
fault2() {
|
|
var a = [1];
|
|
while (confuse(false)) a.add(1);
|
|
// Easily inferred type and open coded indexer.
|
|
return a[1];
|
|
}
|
|
|
|
fault3() {
|
|
var a = confuse([1]);
|
|
// Multiple indexing might go via shared interceptor.
|
|
return [a[1], a[2], a[3]];
|
|
}
|
|
|
|
compare('constant index on non-empty list', fault1, fault2, fault3);
|
|
}
|
|
|
|
constantIndexHugeNonempty() {
|
|
// Single dynamic receiver indexing might go via one-shot interceptor that
|
|
// might have an accelerated path.
|
|
fault1() => confuse([1])[HUGE];
|
|
|
|
fault2() {
|
|
var a = [1];
|
|
while (confuse(false)) a.add(1);
|
|
// Easily inferred type and open coded indexer.
|
|
return a[HUGE];
|
|
}
|
|
|
|
fault3() {
|
|
var a = confuse([1]);
|
|
// Multiple indexing might go via shared interceptor.
|
|
return [a[HUGE], a[1], a[2]];
|
|
}
|
|
|
|
compare('constant index on non-empty list with huge index', fault1, fault2,
|
|
fault3);
|
|
}
|
|
|
|
constantIndexSetEmpty() {
|
|
fault1() {
|
|
// Single dynamic receiver indexing might go via one-shot interceptor that
|
|
// might have an accelerated path.
|
|
confuse([])[0] = 0;
|
|
}
|
|
|
|
fault2() {
|
|
var a = [];
|
|
while (confuse(false)) a.add(1);
|
|
// Easily inferred type and open coded indexer.
|
|
a[0] = 0;
|
|
return a;
|
|
}
|
|
|
|
fault3() {
|
|
var a = confuse([]);
|
|
// Multiple indexing might go via shared interceptor.
|
|
a[0] = 0;
|
|
a[1] = 0;
|
|
a[2] = 0;
|
|
return a;
|
|
}
|
|
|
|
compare('coinstant index-set on empty list', fault1, fault2, fault3);
|
|
}
|
|
|
|
constantIndexSetNonempty() {
|
|
fault1() {
|
|
// Single dynamic receiver indexing might go via one-shot interceptor that
|
|
// might have an accelerated path.
|
|
confuse([1])[1] = 0;
|
|
}
|
|
|
|
fault2() {
|
|
var a = [1];
|
|
while (confuse(false)) a.add(1);
|
|
// Easily inferred type and open coded indexer.
|
|
a[1] = 0;
|
|
return a;
|
|
}
|
|
|
|
fault3() {
|
|
var a = confuse([1]);
|
|
// Multiple indexing might go via shared interceptor.
|
|
a[0] = 0;
|
|
a[1] = 0;
|
|
a[2] = 0;
|
|
return a;
|
|
}
|
|
|
|
compare('constant index-set on non-empty list', fault1, fault2, fault3);
|
|
}
|
|
|
|
variableIndexEmpty(index, qualifier) {
|
|
// Single dynamic receiver indexing might go via one-shot interceptor that
|
|
// might have an accelerated path.
|
|
fault1() => confuse([])[index];
|
|
|
|
fault2() {
|
|
var a = [];
|
|
while (confuse(false)) a.add(1);
|
|
// Easily inferred type and open coded indexer.
|
|
return a[index];
|
|
}
|
|
|
|
fault3() {
|
|
var a = confuse([]);
|
|
// Multiple indexing might go via shared interceptor.
|
|
return [a[index], a[1], a[2]];
|
|
}
|
|
|
|
compare('general index on empty list $qualifier', fault1, fault2, fault3);
|
|
}
|
|
|
|
variableIndexNonempty(index, qualifier) {
|
|
// Single dynamic receiver indexing might go via one-shot interceptor that
|
|
// might have an accelerated path.
|
|
fault1() => confuse([1])[index];
|
|
|
|
fault2() {
|
|
var a = [1];
|
|
while (confuse(false)) a.add(1);
|
|
// Easily inferred type and open coded indexer.
|
|
return a[index];
|
|
}
|
|
|
|
fault3() {
|
|
var a = confuse([1]);
|
|
// Multiple indexing might go via shared interceptor.
|
|
return [a[index], a[1], a[2]];
|
|
}
|
|
|
|
compare(
|
|
'variable index on non-empty list $qualifier', fault1, fault2, fault3);
|
|
}
|
|
|
|
variableIndexSetEmpty(index, qualifier) {
|
|
fault1() {
|
|
var a = confuse([]);
|
|
// Single dynamic receiver indexing might go via one-shot interceptor that
|
|
// might have an accelerated path.
|
|
a[index] = 1;
|
|
return a;
|
|
}
|
|
|
|
fault2() {
|
|
var a = [];
|
|
while (confuse(false)) a.add(1);
|
|
// Easily inferred type and open coded indexer.
|
|
a[index] = 1;
|
|
return a;
|
|
}
|
|
|
|
fault3() {
|
|
var a = confuse([]);
|
|
// Multiple indexing might go via shared interceptor.
|
|
a[index] = 1;
|
|
a[2] = 2;
|
|
a[3] = 3;
|
|
return a;
|
|
}
|
|
|
|
compare(
|
|
'variable index-set on empty list $qualifier', fault1, fault2, fault3);
|
|
}
|
|
|
|
variableIndexSetNonempty(index, qualifier) {
|
|
fault1() {
|
|
var a = confuse([1]);
|
|
// Single dynamic receiver indexing might go via one-shot interceptor that
|
|
// might have an accelerated path.
|
|
a[index] = 1;
|
|
return a;
|
|
}
|
|
|
|
fault2() {
|
|
var a = [1];
|
|
while (confuse(false)) a.add(1);
|
|
// Easily inferred type and open coded indexer.
|
|
a[index] = 1;
|
|
return a;
|
|
}
|
|
|
|
fault3() {
|
|
var a = confuse([1]);
|
|
// Multiple indexing might go via shared interceptor.
|
|
a[index] = 1;
|
|
a[2] = 2;
|
|
a[3] = 3;
|
|
return a;
|
|
}
|
|
|
|
compare('variable index-set on non-empty list $qualifier', fault1, fault2,
|
|
fault3);
|
|
}
|
|
|
|
main() {
|
|
indexErrorContainsIndex();
|
|
|
|
constantIndexEmpty();
|
|
constantIndexHugeEmpty();
|
|
constantIndexNonempty();
|
|
constantIndexHugeNonempty();
|
|
constantIndexSetEmpty();
|
|
constantIndexSetNonempty();
|
|
|
|
variableIndexEmpty(0, 'zero index');
|
|
variableIndexEmpty(10, 'small index');
|
|
variableIndexEmpty(-1, 'negative index');
|
|
variableIndexEmpty(HUGE, 'huge index');
|
|
|
|
variableIndexNonempty(10, 'small index');
|
|
variableIndexNonempty(-1, 'negative index');
|
|
variableIndexNonempty(HUGE, 'huge index');
|
|
|
|
variableIndexSetEmpty(0, 'zero index');
|
|
variableIndexSetEmpty(10, 'small index');
|
|
variableIndexSetEmpty(-1, 'negative index');
|
|
variableIndexSetEmpty(HUGE, 'huge index');
|
|
|
|
variableIndexSetNonempty(10, 'small index');
|
|
variableIndexSetNonempty(-1, 'negative index');
|
|
variableIndexSetNonempty(HUGE, 'huge index');
|
|
}
|