Saturday, January 21, 2023

Saturated Q15 and Q31 arithmetic

Saturated Q15 and Q31 arithmetic

A 32-bit signed value can be treated as having a binary point immediately after its sign bit. This is equivalent to dividing its signed integer value by 231, so that it can now represent numbers from –1 to (1 – 2–31). When a 32-bit value is used to represent a fractional number in this fashion, it is known as a Q31 number.

Saturated additions, subtractions, and doublings can be performed on Q31 numbers using the same instructions as are used for saturated integer arithmetic, since everything is simply scaled down by a factor of 2–31.

If two Q15 numbers are multiplied together as integers, the resulting integer needs to be scaled down by a factor of 2–15 × 2–15 == 2–30. For example, multiplying the Q15 number 0x8000 (representing –1) by itself using an integer multiplication instruction yields the value 0x40000000, which is 230 times the desired result of +1.

This means that the result of the integer multiplication instruction is not quite in Q31 form. To get it into Q31 form, it must be doubled, so that the required scaling factor becomes 2–31. Furthermore, it is possible that the doubling will cause integer overflow, so the result should in fact be doubled with saturation. In particular, the result 0x40000000 from the multiplication of 0x8000 by itself should be doubled with saturation to produce 0x7FFFFFFF (the closest possible Q31 number to the correct mathematical result of –1 × –1 == +1). If it were doubled without saturation, it would instead produce 0x80000000, which is the Q31 representation of –1.

To implement a saturated Q15 × Q15 --> Q31 multiplication, therefore, an integer multiply instruction should be followed by a saturated integer doubling. The latter can be performed by a QADD instruction adding the multiply result to itself.

Friday, January 6, 2023

Global Environment Record

Global Environment Record

A global Environment Record is used to represent the outer most scope that is shared by all of the ECMAScript Script elements that are processed in a common realm. A global Environment Record provides the bindings for built-in globals, properties of the global object(FunctionDeclaration or VariableStatement), and for all top-level declarations(the let and const declarations) that occur within a Script.

A global Environment Record is logically a single record but it is specified as a composite encapsulating of object Environment Record([[ObjectRecord]]) and a declarative Environment Record([[DeclarativeRecord]]).

The object Environment Record has as its base object the global object of the associated Realm Record. This global object is the value returned by the global Environment Record's GetThisBinding concrete method:

 Let envRec be the global Environment Record for which the method was invoked.
 Return envRec.[[GlobalThisValue]]
 zxxu: according to ecma, Regular object Environment Records do not provide a this binding, so global Environment Record has a  [[GlobalThisValue]] field

The object Environment Record contains the bindings for all built-in globals and all bindings introduced by a FunctionDeclaration or VariableStatement contained in global code. The bindings for all other ECMAScript declarations(the let and const declarations) in global code are contained in the declarative Environment Record component.

Properties may exist upon a global object that were directly created rather than being declared using a var or function declaration. so global Environment Record also has a field [[VarNames]] for string names bound by FunctionDeclaration or VariableDeclaration.

Tuesday, January 3, 2023

GetValue abstract operation

GetValue abstract operation GetValue ( V )
  1. ReturnIfAbrupt(V).
  2. If Type(V) is not Reference, return V.
  3. If IsUnresolvableReference(V) is true, throw a ReferenceError exception.
  4. Let base be GetBase(V).
  5. If HasPrimitiveBase(V) is true, Set base to !ToObject(base)
  6. If IsPropertyReference(V) is true, Return ? base.[[Get]](GetReferencedName(V), Receiver = GetThisValue(V)).
  7. Return ? base.GetBindingValue(GetReferencedName(V), IsStrictReference(V))

note If IsSuperReference(V), GetThisValue(V) returns the thisValue component of the reference V; else returns GetBase(V).

abstract operation O.[[Get]](P, Receiver) works as:

  • Let desc be ? O.[[GetOwnProperty]](P).
  • If desc is undefined, Return ?O.[[Prototype]].[[Get]](P, Receiver).
  • If IsDataDescriptor(desc) is true, return desc.[[Value]].
  • Return ? Call(desc.[[Get]], Receiver)// Receiver is only used by AccessorDescriptor

above all

  1. super is parent and super.super is grandpa
  2. desc.[[Get]] can accept base, base.super, base.super.super... as Receiver
  3. refer to new.target for more info regarding the super keyword

ToString.FromNum

ToString.FromNum

abstract operation

  1. If m is NaN, return the String "NaN".
  2. If m is +0 or -0, return the String "0".
  3. If m is less than zero, return the String concatenation of the String "-" and ToString(-m).
  4. If m is infinity, return the String "Infinity".
  5. let n, k, and s be integers such that k >= 1, s in [10^(k-1), 10^k), the Number value for s * 10^(n-k) is m. Note that k is the number of digits in the decimal representation of s, that s is not divisible by 10.
  6. if both k and n are no greater than 21:
    • if k is no greater than n, return the string-concatenation of:
      • the k digits of the decimal representation of s
      • n−k occurrences of the character 0
    • if n is greater than 0, return the string-concatenation of:
      • the code units of the most significant n digits of the decimal representation of s
      • the code unit 0x002E (FULL STOP)
      • the code units of the remaining k - n digits of the decimal representation of s
  7. ...

example 0.12300

k=3, s=123, n=0

example 123.4

n=k1=3, k2=1, s=123.4

example 0.0423

k=3, s=423, n=-1 ==> k1=n=-1,pow(10,k1-1)=0.04

example 42300

k=3, s=423, n=5 ==> pow(10, n-1) = 4

Wednesday, December 28, 2022

Symbol

Symbol

The Symbol Constructor

Symbol ( [ description ] )

  1. If NewTarget is not undefined, throw a TypeError exception.
  2. Note: the Symbol Constructor is not intended to be used with the new operator(not the target for new)
  3. If description is undefined, let descString be undefined; Else, let descString be ? ToString(description).
  4. Return a new unique Symbol value whose [[Description]] value is descString.
  5. Note: the Symbol() function returns a Symbol type instead of a Symbol object

Symbol Prototype Object

abstract operation thisSymbolValue(value)

  1. If Type(value) is Symbol, return value.
  2. If Type(value) is Object and value has a [[SymbolData]] internal slot
  3. then Return value.[[SymbolData]] //a Symbol Object
  4. Throw a TypeError exception.

Example

mySymbol = Symbol( "my symbol" )

// Object() performs a type conversion when called as a function rather than as a constructor.
mySymObj = Object(mySymbol)

console.log(mySymObj.toString()) // Symbol(my symbol)

Tuesday, December 27, 2022

Function.prototype.call

Function.prototype.call ( thisArgument, argumentsList )

Example

function anInstanceOfFunction(data)
{
    this.data = data;
}

thisArgument = {"data" : null};

// all instances of Function(function definitions or dynamical functions by `new Function`) has
// their [[prototype]] chained to the Function constructor's prototype property(Function.prototype)
anInstanceOfFunction.call(thisArgument, "dat");

console.log(thisArgument.data);

Function.prototype.call ( thisArgument, argumentsList )

note Function.prototype itself is a function object(to ensure compatibility with es2015), which returns undefined when called; but the call here is `Function.prototype.` instead of `Function.prototype(`

  1. If IsCallable(F) is false, throw a TypeError exception.//F is anInstanceOfFunction in our example
  2. Pop from the execution context stack//the top execution context has no further use and optimized out
  3. Let calleeContext be PrepareForOrdinaryCall(F, undefined):
            calleeContext = {
                "Function" : F,
                "LexicalEnvironment" : new NewFunctionEnvironment(F),
            }
            calleeContext.VariableEnvironment = calleeContext.LexicalEnvironment
            Push calleeContext onto the execution context stack
            return calleeContext
        
    
  4. calleeContext.LexicalEnvironment.EnvironmentRecord.[[ThisValue]] = thisArgument
  5. Let result be Evaluate F with argumentsList.
  6. Remove(exactly, Pop) calleeContext from the execution context stack
  7. If result.[[Type]] is return, return NormalCompletion(result.[[Value]]).
  8. ReturnIfAbrupt(result).
  9. Return NormalCompletion(undefined).

Function.prototype.bind

Function.prototype.bind( boundThis, ...boundArgs )

Example

const person = {
    getFullName: function () {
        return this.firstName + " " + this.lastName;
    }
}

const thisPerson = {
	firstName   :   "John",
	lastName    :   "Xu",
}

let getFullName = person.getFullName.bind(thisPerson);

console.log( getFullName() )

Function.prototype.bind( boundThis, ...boundArgs )

  1. Let targetFunction be the this value. // for our example, person.getFullName
  2. If IsCallable(targetFunction) is false, throw a TypeError exception.
  3. Let boundArgs be a new List consisting of all of the argument values provided after boundThis(for our example, empty) .
  4. Let F be ?BoundFunctionCreate(targetFunction, boundThis, boundArgs)
            return {
                [[BoundTargetFunction]]: targetFunction,
                [[BoundThis]]: boundThis,
                [[BoundArguments]]: boundArgs,
                [[Prototype]]:targetFunction.[[Prototype]],
            }
        
  5. Perform SetFunctionName(F, name = Get(Target, "name"), prefix = "bound").