blob: 7c5e45cdee8574d064bf9af57755ff0a1bdd35f1 [file] [log] [blame]
// 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.
library builtin_operator;
// This is shared by the CPS and Tree IRs.
// Both cps_ir_nodes and tree_ir_nodes import and re-export this file.
import 'effects.dart';
/// An operator supported natively in the CPS and Tree IRs using the
/// `ApplyBuiltinOperator` instructions.
///
/// These operators are pure in the sense that they cannot throw, diverge,
/// have observable side-effects, return new objects, nor depend on any
/// mutable state.
///
/// Most operators place restrictions on the values that may be given as
/// argument; their behaviour is unspecified if those requirements are violated.
///
/// In all cases, the word "null" refers to the Dart null object, corresponding
/// to both JS null and JS undefined.
///
/// Some operators, notably [IsFloor] and [IsInteger], take "repeated"
/// arguments to reflect the number of times the given value is referenced
/// by the generated code. The tree IR needs to know the number of references
/// to safely propagate assignments.
enum BuiltinOperator {
/// The numeric binary operators must take two numbers as argument.
/// The bitwise operators coerce the result to an unsigned integer, but
/// otherwise these all behave like the corresponding JS operator.
NumAdd,
NumSubtract,
NumMultiply,
NumDivide,
NumAnd,
NumOr,
NumXor,
NumShl,
NumLt,
NumLe,
NumGt,
NumGe,
/// NumShr behaves like JS '>>>' but is valid only when the left is in the
/// uint32 range and the right in the range [0, 31].
NumShr,
/// NumRemainder corresponds to JavaScript's `a % b`, and Dart's
/// `a.remainder(b)`, except at zero, since JavaScript `1 % 0` is `NaN`.
/// Dart's modulo (`%`) is the same as remainder only when if both arguments
/// are non-negative.
NumRemainder,
/// Corresponds to `a ~/ b` when b is non-zero and the result fits in a signed
/// 32 bit value.
///
/// This case can be compiled to `(a / b) | 0`.
NumTruncatingDivideToSigned32,
/// Corresponds to JavaScript's negation, which converts 0 to -0.0.
NumNegate,
/// Bit inversions, with coercion to uint32.
///
/// Compiles to `(~x) >>> 0`.
NumBitNot,
/// Concatenates any number of strings.
///
/// Takes any number of arguments, and each argument must be a string.
///
/// Returns the empty string if no arguments are given.
StringConcatenate,
/// Corresponds to `a.charCodeAt(b)`. `a' must be a String. The index `b` must
/// be in range `0 <= b < a.length`.
/// TODO(sra): Consider replacing with a Primitive to allow lowering when 'a'
/// is nullable (i.e. throws).
CharCodeAt,
/// Returns true if the two arguments are the same value, and that value is
/// not NaN, or if one argument is +0 and the other is -0.
///
/// Compiled as a static method call.
Identical,
/// Like [Identical], except at most one argument may be null.
///
/// Compiles to `===`.
StrictEq,
/// Negated version of [StrictEq]. Introduced by [LogicalRewriter] in Tree IR.
StrictNeq,
/// Returns true if the two arguments are both null or are the same string,
/// boolean, or number, and that number is not NaN, or one argument is +0
/// and the other is -0.
///
/// One of the following must hold:
/// - At least one argument is null.
/// - Arguments are both strings, or both booleans, or both numbers.
///
/// Compiles to `==`.
LooseEq,
/// Negated version of [LooseEq]. Introduced by [LogicalRewriter] in Tree IR.
LooseNeq,
/// Returns true if the argument is false, +0. -0, NaN, the empty string,
/// or null.
///
/// Compiles to `!`.
IsFalsy,
/// Returns true if the argument is a number.
///
/// Compiles to `typeof x === 'number'`
IsNumber,
/// Returns true if the argument is not a number.
///
/// Compiles to `typeof x !== 'number'`.
IsNotNumber,
/// Returns true if the argument is an integer, false if it is a double or
/// null, and unspecified if it is anything else.
///
/// The argument must be repeated 2 times.
///
/// Compiles to `Math.floor(x) === x`
IsFloor,
/// Returns true if the argument is an integer.
///
/// The argument must be repeated 3 times.
///
/// Compiles to `typeof x === 'number' && Math.floor(x) === x`
IsInteger,
/// Returns true if the argument is not an integer.
///
/// The argument must be repeated 3 times.
///
/// Compiles to `typeof x !== 'number' || Math.floor(x) !== x`
IsNotInteger,
/// Returns true if `x` is an unsigned 32-bit integer.
///
/// The argument must be repeated 2 times.
///
/// Compiles to `x >>> 0 === x`
IsUnsigned32BitInteger,
/// Returns false if `x` is an unsigned 32-bit integer.
///
/// The argument must be repeated 2 times.
///
/// Compiles to `x >>> 0 !== x`
IsNotUnsigned32BitInteger,
/// Returns true if the argument is a fixed length Array.
///
/// Uses one argument.
///
/// Precondition: Argument is a JavaScript Array.
IsFixedLengthJSArray,
// TODO(sra): Remove this and replace with IsFalsy(IsFixedLengthJSArray(x)).
IsExtendableJSArray,
/// Returns true if the argument is an unmodifiable Array.
///
/// Uses one argument.
///
/// Precondition: Argument is a JavaScript Array.
IsUnmodifiableJSArray,
// TODO(sra): Remove this and replace with IsFalsy(IsUnmodifiableArray(x)).
IsModifiableJSArray,
}
/// A method supported natively in the CPS and Tree IRs using the
/// `ApplyBuiltinMethod` instructions.
///
/// These methods all operate on a distinguished 'object' argument, and
/// take zero or more additional arguments.
///
/// These methods may mutate and depend on the state of the object argument,
/// but may not depend on or mutate any other state. An exception is thrown
/// if the object is null, but otherwise they cannot throw or diverge.
enum BuiltinMethod {
/// Add an item to an array.
///
/// Takes any number of arguments, each argument will be added to the
/// list on the order given (as per the JS `push` method).
///
/// Compiles to `object.push(x1, ..., xN)`.
Push,
/// Remove and return the last item from an array.
///
/// Takes no arguments.
///
/// Compiles to `object.pop()`.
Pop,
/// Sets the length of the array.
///
/// Compiles to `object.length = x1`.
SetLength,
}
/// True for the built-in operators that may be used in a compound assignment.
bool isCompoundableOperator(BuiltinOperator operator) {
switch (operator) {
case BuiltinOperator.NumAdd:
case BuiltinOperator.NumSubtract:
case BuiltinOperator.NumMultiply:
case BuiltinOperator.NumDivide:
case BuiltinOperator.NumRemainder:
case BuiltinOperator.StringConcatenate:
return true;
default:
return false;
}
}
int getEffectsOfBuiltinMethod(BuiltinMethod method) {
switch (method) {
case BuiltinMethod.Push:
return Effects.changesIndexableContent | Effects.changesIndexableLength;
case BuiltinMethod.Pop:
return Effects.dependsOnIndexableContent |
Effects.dependsOnIndexableLength |
Effects.changesIndexableLength;
case BuiltinMethod.SetLength:
return Effects.changesIndexableLength;
}
}