| // 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; |
| } |
| } |