85beb0398d
Change-Id: I257139079514cb4cb21be51743f6bdd9fcab35e0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417322 Reviewed-by: Stephen Adams <sra@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com>
122 lines
4.9 KiB
Dart
122 lines
4.9 KiB
Dart
// Copyright (c) 2024, 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.
|
|
|
|
/// Values for the 'array flags' property that is attached to native JSArray and
|
|
/// typed data objects to encode restrictions.
|
|
///
|
|
/// We encode the restrictions as two bits - one for potentially growable
|
|
/// objects that are restricted to be fixed length, and a second for objects
|
|
/// with potentially modifiable contents that are restricted to have
|
|
/// unmodifiable contents. We only use three combinations (00 = growable, 01 =
|
|
/// fixed-length, 11 = unmodifiable), since the core List class does not have a
|
|
/// variant that is an 'append-only' list (would be 10).
|
|
///
|
|
/// We use the same scheme for typed data so that the same check works for
|
|
/// modifiability checks for `a[i] = v` when `a` is a JSarray or Uint8Array.
|
|
///
|
|
/// `const` JSArray values are tagged with an additional bit for future use in
|
|
/// avoiding copying. We could also use the `const` bit for unmodifiable typed
|
|
/// data for which there in no modifable view of the underlying buffer.
|
|
///
|
|
/// Given the absense of append-only lists, we could have used a more
|
|
/// numerically compact scheme (0 = growable, 1 = fixed-length, 2 =
|
|
/// unmodifiable, 3 = const). This compact scheme requires comparison
|
|
///
|
|
/// if (x.flags > 0)
|
|
///
|
|
/// rather than mask-testing
|
|
///
|
|
/// if (x.flags & 1)
|
|
///
|
|
/// The unrestricted flags (0) are usually encoded as a missing property, i.e.,
|
|
/// `undefined`, which is converted to NaN for '>', but converted to the more
|
|
/// comfortable '0' for '&'. We hope that there is less to go potentially go
|
|
/// wrong with JavaScript engine slow paths with the bitmask.
|
|
class ArrayFlags {
|
|
/// Value of array flags that marks a JSArray as being fixed-length. This is
|
|
/// not used on typed data since that is always fixed-length.
|
|
static const int fixedLength = fixedLengthCheck;
|
|
|
|
/// Value of array flags that marks a JSArray or typed-data object as
|
|
/// unmodifiable. Includes the 'fixed-length' bit, since all unmodifiable
|
|
/// lists are also fixed length.
|
|
static const int unmodifiable = fixedLengthCheck | unmodifiableCheck;
|
|
|
|
/// Value of array flags that marks a JSArray as a constant (transitively
|
|
/// unmodifiable).
|
|
static const int constant =
|
|
fixedLengthCheck | unmodifiableCheck | constantCheck;
|
|
|
|
/// Default value of array flags when there is no flags property. This value
|
|
/// is not stored on the flags property.
|
|
static const int none = 0;
|
|
|
|
/// Bit to check for fixed-length JSArray.
|
|
static const int fixedLengthCheck = 1;
|
|
|
|
/// Bit to check for unmodifiable JSArray and typed data.
|
|
static const int unmodifiableCheck = 2;
|
|
|
|
/// Bit to check for constant JSArray.
|
|
static const int constantCheck = 4;
|
|
|
|
/// A List of operation names for HArrayFlagsCheck, encoded in a string of
|
|
/// names separated by semicolons.
|
|
///
|
|
/// The optimizer may replace the string with an index into this
|
|
/// table. Generally this makes the generated code smaller. A name does not
|
|
/// need to be in this table. It makes sense for this table to include only
|
|
/// names that occur in more than one HArrayFlagsCheck, either as written in
|
|
/// js_runtime, or occuring multiple times via inlining.
|
|
static const operationNames = //
|
|
'[]=' // This is the most common operation so it comes first.
|
|
';add'
|
|
';removeWhere'
|
|
';retainWhere'
|
|
';removeRange'
|
|
';setRange'
|
|
';setInt8'
|
|
';setInt16'
|
|
';setInt32'
|
|
';setUint8'
|
|
';setUint16'
|
|
';setUint32'
|
|
';setFloat32'
|
|
';setFloat64' //
|
|
;
|
|
|
|
/// A list of 'verbs' for HArrayFlagsCheck, encoded as a string of phrases
|
|
/// separated by semicolons. The 'verb' fills a span of the error message, for
|
|
/// example, "remove from" in the message
|
|
///
|
|
/// Cannot remove from an unmodifiable list.
|
|
/// ^^^^^^^^^^^
|
|
///
|
|
/// The optimizer may replace the string with an index into this
|
|
/// table. Generally this makes the program smaller. A 'verb' does not need to
|
|
/// be in this table. It makes sense to only have verbs that are used by
|
|
/// several calls to HArrayFlagsCheck, either as written in js_runtime, or
|
|
/// occuring multiple times via inlining.
|
|
static const verbs = //
|
|
'modify' // This is the verb for '[]=' so it comes first.
|
|
';remove from'
|
|
';add to' //
|
|
;
|
|
|
|
/// A view of [operationNames] as a map from the name to the index of the name
|
|
/// in the list.
|
|
static final Map<String, int> operationNameToIndex = _invert(operationNames);
|
|
|
|
/// A view of [verbs] as a map from the verb to the index of the verb in the
|
|
/// list.
|
|
static final Map<String, int> verbToIndex = _invert(verbs);
|
|
|
|
static Map<String, int> _invert(String joinedStrings) {
|
|
return {
|
|
for (final entry in joinedStrings.split(';').asMap().entries)
|
|
entry.value: entry.key,
|
|
};
|
|
}
|
|
}
|