| Index: tests/compiler/dart2js_extra/js_array_index_error_test.dart
|
| diff --git a/tests/compiler/dart2js_extra/js_array_index_error_test.dart b/tests/compiler/dart2js_extra/js_array_index_error_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9cfc87395cb196186832f95b359db3ae9c7e2233
|
| --- /dev/null
|
| +++ b/tests/compiler/dart2js_extra/js_array_index_error_test.dart
|
| @@ -0,0 +1,330 @@
|
| +// 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 enerate the same error as dyncamically
|
| +// dispatched calls.
|
| +
|
| +
|
| +import 'package:expect/expect.dart';
|
| +
|
| +@NoInline() @AssumeDynamic()
|
| +confuse(x) => x;
|
| +
|
| +
|
| +Error getError(action(), name, part) {
|
| + try {
|
| + action();
|
| + } 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');
|
| +}
|
|
|