/** * Copyright (c) 2012-2016 André Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.runtime.internal; import static com.github.anba.es6draft.runtime.AbstractOperations.*; import static com.github.anba.es6draft.runtime.LexicalEnvironment.newDeclarativeEnvironment; import static com.github.anba.es6draft.runtime.internal.Errors.*; import static com.github.anba.es6draft.runtime.internal.TailCallInvocation.newTailCallInvocation; import static com.github.anba.es6draft.runtime.modules.ModuleSemantics.GetModuleNamespace; import static com.github.anba.es6draft.runtime.modules.ModuleSemantics.HostResolveImportedModule; import static com.github.anba.es6draft.runtime.types.PropertyDescriptor.AccessorPropertyDescriptor; import static com.github.anba.es6draft.runtime.types.PropertyDescriptor.FromPropertyDescriptor; import static com.github.anba.es6draft.runtime.types.PropertyDescriptor.ToPropertyDescriptor; import static com.github.anba.es6draft.runtime.types.Undefined.UNDEFINED; import static com.github.anba.es6draft.runtime.types.builtins.ArrayObject.ArrayCreate; import static com.github.anba.es6draft.runtime.types.builtins.LegacyConstructorFunction.LegacyFunctionCreate; import static com.github.anba.es6draft.runtime.types.builtins.OrdinaryAsyncFunction.AsyncFunctionCreate; import static com.github.anba.es6draft.runtime.types.builtins.OrdinaryAsyncGenerator.AsyncGeneratorFunctionCreate; import static com.github.anba.es6draft.runtime.types.builtins.OrdinaryConstructorFunction.ConstructorFunctionCreate; import static com.github.anba.es6draft.runtime.types.builtins.OrdinaryConstructorGenerator.ConstructorGeneratorFunctionCreate; import static com.github.anba.es6draft.runtime.types.builtins.OrdinaryFunction.*; import static com.github.anba.es6draft.runtime.types.builtins.OrdinaryGenerator.GeneratorFunctionCreate; import static com.github.anba.es6draft.runtime.types.builtins.OrdinaryObject.ObjectCreate; import java.io.IOException; import java.lang.invoke.CallSite; import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.mozilla.javascript.ConsString; import com.github.anba.es6draft.Executable; import com.github.anba.es6draft.compiler.CompiledObject; import com.github.anba.es6draft.compiler.CompiledScript; import com.github.anba.es6draft.runtime.DeclarativeEnvironmentRecord; import com.github.anba.es6draft.runtime.EnvironmentRecord; import com.github.anba.es6draft.runtime.ExecutionContext; import com.github.anba.es6draft.runtime.FunctionEnvironmentRecord; import com.github.anba.es6draft.runtime.GlobalEnvironmentRecord; import com.github.anba.es6draft.runtime.LexicalEnvironment; import com.github.anba.es6draft.runtime.ModuleEnvironmentRecord; import com.github.anba.es6draft.runtime.ObjectEnvironmentRecord; import com.github.anba.es6draft.runtime.Realm; import com.github.anba.es6draft.runtime.modules.MalformedNameException; import com.github.anba.es6draft.runtime.modules.ModuleExport; import com.github.anba.es6draft.runtime.modules.ModuleRecord; import com.github.anba.es6draft.runtime.modules.ResolutionException; import com.github.anba.es6draft.runtime.modules.SourceTextModuleRecord; import com.github.anba.es6draft.runtime.objects.ArrayIteratorPrototype; import com.github.anba.es6draft.runtime.objects.ArrayPrototype; import com.github.anba.es6draft.runtime.objects.FunctionPrototype; import com.github.anba.es6draft.runtime.objects.async.iteration.AsyncGeneratorAbstractOperations; import com.github.anba.es6draft.runtime.objects.binary.TypedArrayObject; import com.github.anba.es6draft.runtime.objects.binary.TypedArrayPrototypePrototype; import com.github.anba.es6draft.runtime.objects.iteration.GeneratorObject; import com.github.anba.es6draft.runtime.objects.simd.SIMDType; import com.github.anba.es6draft.runtime.types.*; import com.github.anba.es6draft.runtime.types.builtins.*; import com.github.anba.es6draft.runtime.types.builtins.FunctionObject.ConstructorKind; import com.github.anba.es6draft.runtime.types.builtins.FunctionObject.FunctionKind; /** * Runtime support methods */ public final class ScriptRuntime { public static final Object[] EMPTY_ARRAY = new Object[0]; private ScriptRuntime() { } /** * 9.2.2.2 OrdinaryCallBindThis ( F, calleeContext, thisArgument ) * * @param f * the function object * @param thisArgument * the thisArgument * @return the thisValue */ public static ScriptObject functionThisValue(FunctionObject f, Object thisArgument) { Realm calleeRealm = f.getRealm(); if (Type.isUndefinedOrNull(thisArgument)) { return calleeRealm.getGlobalThis(); } return ToObject(calleeRealm.defaultContext(), thisArgument); } /** * 18.2.1.2 EvalDeclarationInstantiation * * @param cx * the execution context * @param envRec * the environment record * @param name * the binding name */ public static void bindingNotPresentOrThrow(ExecutionContext cx, EnvironmentRecord envRec, String name) { if (envRec.hasBinding(name)) { throw newSyntaxError(cx, Messages.Key.VariableRedeclaration, name); } } /** * 15.1.8 Runtime Semantics: GlobalDeclarationInstantiation * * @param cx * the execution context * @param envRec * the environment record * @param name * the binding name */ public static void canDeclareLexicalScopedOrThrow(ExecutionContext cx, GlobalEnvironmentRecord envRec, String name) { /* step 5.a */ if (envRec.hasVarDeclaration(name)) { throw newSyntaxError(cx, Messages.Key.VariableRedeclaration, name); } /* step 5.b */ if (envRec.hasLexicalDeclaration(name)) { throw newSyntaxError(cx, Messages.Key.VariableRedeclaration, name); } /* step 5.c */ if (envRec.hasRestrictedGlobalProperty(name)) { throw newSyntaxError(cx, Messages.Key.VariableRedeclaration, name); } } /** * 15.1.8 Runtime Semantics: GlobalDeclarationInstantiation * * @param cx * the execution context * @param envRec * the environment record * @param name * the binding name */ public static void canDeclareVarScopedOrThrow(ExecutionContext cx, GlobalEnvironmentRecord envRec, String name) { /* step 6.a */ if (envRec.hasLexicalDeclaration(name)) { throw newSyntaxError(cx, Messages.Key.VariableRedeclaration, name); } } /** * 15.1.8 Runtime Semantics: GlobalDeclarationInstantiation * * @param cx * the execution context * @param envRec * the environment record * @param fn * the function name */ public static void canDeclareGlobalFunctionOrThrow(ExecutionContext cx, GlobalEnvironmentRecord envRec, String fn) { /* steps 10.a.iv.1-2 */ boolean fnDefinable = envRec.canDeclareGlobalFunction(fn); if (!fnDefinable) { throw newTypeError(cx, Messages.Key.InvalidDeclaration, fn); } } /** * 15.1.8 Runtime Semantics: GlobalDeclarationInstantiation * * @param cx * the execution context * @param envRec * the environment record * @param vn * the variable name */ public static void canDeclareGlobalVarOrThrow(ExecutionContext cx, GlobalEnvironmentRecord envRec, String vn) { /* steps 12.a.i.1.a-c */ boolean vnDefinable = envRec.canDeclareGlobalVar(vn); if (!vnDefinable) { throw newTypeError(cx, Messages.Key.InvalidDeclaration, vn); } } /** * 18.2.1.2 Runtime Semantics: EvalDeclarationInstantiation( body, varEnv, lexEnv, strict) * * @param cx * the execution context * @param envRec * the environment record * @param name * the variable name * @param catchVar * {@code true} if variable redeclarations are allowed in catch clauses */ public static void canDeclareVarOrThrow(ExecutionContext cx, DeclarativeEnvironmentRecord envRec, String name, boolean catchVar) { /* steps 6.b.ii.2 - 6.b.ii.3 */ if (envRec.hasBinding(name) && !(catchVar && envRec.isCatchEnvironment())) { throw newSyntaxError(cx, Messages.Key.VariableRedeclaration, name); } } /** * 18.2.1.2 Runtime Semantics: EvalDeclarationInstantiation( body, varEnv, lexEnv, strict) * * @param varEnv * the variable environment * @param lexEnv * the lexical environment * @param name * the function name * @param catchVar * {@code true} if variable redeclarations are allowed in catch clauses * @return {@code true} if the name can be declared */ public static boolean canDeclareVarBinding(LexicalEnvironment<?> varEnv, LexicalEnvironment<DeclarativeEnvironmentRecord> lexEnv, String name, boolean catchVar) { for (LexicalEnvironment<?> thisEnv = lexEnv; thisEnv != varEnv; thisEnv = thisEnv.getOuter()) { EnvironmentRecord thisEnvRec = thisEnv.getEnvRec(); if (thisEnvRec instanceof ObjectEnvironmentRecord) { continue; } DeclarativeEnvironmentRecord declEnvRec = (DeclarativeEnvironmentRecord) thisEnvRec; if (declEnvRec.hasBinding(name) && !(catchVar && declEnvRec.isCatchEnvironment())) { return false; } } return true; } /** * 18.2.1.2 Runtime Semantics: EvalDeclarationInstantiation( body, varEnv, lexEnv, strict) * * @param cx * the execution context * @param functionId * the function id */ public static void setLegacyBlockFunction(ExecutionContext cx, int functionId) { Executable executable = cx.getCurrentExecutable(); ((CompiledScript) executable).setLegacyBlockFunction(functionId); } /** * 18.2.1.2 Runtime Semantics: EvalDeclarationInstantiation( body, varEnv, lexEnv, strict) * * @param cx * the execution context * @param functionId * the function id * @return {@code true} if the funciton is legacy block-level scoped */ public static boolean isLegacyBlockFunction(ExecutionContext cx, int functionId) { Executable executable = cx.getCurrentExecutable(); return ((CompiledScript) executable).isLegacyBlockFunction(functionId); } /** * 15.2.1.16.4 ModuleDeclarationInstantiation( ) Concrete Method * * @param module * the module record * @param exportName * the export name * @throws IOException * if there was any I/O error * @throws MalformedNameException * if the module specifier cannot be normalized * @throws ResolutionException * if the export cannot be resolved */ public static void resolveExportOrThrow(SourceTextModuleRecord module, String exportName) throws IOException, MalformedNameException, ResolutionException { /* steps 6.a-b */ ModuleExport resolution = module.resolveExport(exportName, new HashMap<>(), new HashSet<>()); /* step 6.c */ if (resolution == null) { throw new ResolutionException(Messages.Key.ModulesUnresolvedExport, exportName); } if (resolution.isAmbiguous()) { throw new ResolutionException(Messages.Key.ModulesAmbiguousExport, exportName); } } /** * 15.2.1.16.4 ModuleDeclarationInstantiation( ) Concrete Method * * @param module * the module record * @param moduleRequest * the module specifier string * @param importName * the import name * @return the resolved module import * @throws IOException * if there was any I/O error * @throws MalformedNameException * if the module specifier cannot be normalized * @throws ResolutionException * if the export cannot be resolved */ public static ModuleExport resolveImportOrThrow(SourceTextModuleRecord module, String moduleRequest, String importName) throws IOException, MalformedNameException, ResolutionException { /* steps 10.a-b */ ModuleRecord importedModule = HostResolveImportedModule(module, moduleRequest); /* steps 10.d.i-ii */ ModuleExport resolution = importedModule.resolveExport(importName, new HashMap<>(), new HashSet<>()); /* step 10.d.iii */ if (resolution == null) { throw new ResolutionException(Messages.Key.ModulesUnresolvedImport, importName, importedModule.getSourceCodeId().toString()); } if (resolution.isAmbiguous()) { throw new ResolutionException(Messages.Key.ModulesAmbiguousImport, importName, importedModule.getSourceCodeId().toString()); } return resolution; } /** * 15.2.1.16.4 ModuleDeclarationInstantiation( ) Concrete Method * * @param cx * the execution context * @param module * the module record * @param moduleRequest * the module specifier string * @return the module namespace object * @throws IOException * if there was any I/O error * @throws MalformedNameException * if the module specifier cannot be normalized * @throws ResolutionException * if the export cannot be resolved */ public static ScriptObject getModuleNamespace(ExecutionContext cx, SourceTextModuleRecord module, String moduleRequest) throws IOException, MalformedNameException, ResolutionException { /* steps 10.a-b */ ModuleRecord importedModule = HostResolveImportedModule(module, moduleRequest); /* steps 10.c.i-ii */ return GetModuleNamespace(cx, importedModule); } /** * 15.2.1.16.4 ModuleDeclarationInstantiation( ) Concrete Method * * @param cx * the execution context * @param envRec * the module environment record * @param name * the import name * @param resolved * the resolved module export * @throws IOException * if there was any I/O error * @throws MalformedNameException * if the module specifier cannot be normalized * @throws ResolutionException * if the export cannot be resolved */ public static void createImportBinding(ExecutionContext cx, ModuleEnvironmentRecord envRec, String name, ModuleExport resolved) throws IOException, MalformedNameException, ResolutionException { assert !resolved.isAmbiguous(); if (resolved.isNameSpaceExport()) { envRec.createImmutableBinding(name, true); envRec.initializeBinding(name, GetModuleNamespace(cx, resolved.getModule())); } else { envRec.createImportBinding(name, resolved.getModule(), resolved.getBindingName()); } } /* ***************************************************************************************** */ /** * 12.2.4.1 Array Literal * <p> * 12.2.4.1.2 Runtime Semantics: Array Accumulation * <ul> * <li>ElementList : Elision<span><sub>opt</sub></span> AssignmentExpression * <li>ElementList : ElementList , Elision<span><sub>opt</sub></span> AssignmentExpression * </ul> * * @param array * the array object * @param nextIndex * the array index * @param value * the array element value */ public static void defineProperty(ArrayObject array, int nextIndex, Object value) { // Inlined: CreateDataProperty(array, ToString(ToUint32(nextIndex)), value); array.insert(nextIndex, value); } /** * 12.2.4.1 Array Literal * <p> * 12.2.4.1.3 Runtime Semantics: Evaluation * * @param array * the array object * @param length * the array length value */ public static void defineLength(ArrayObject array, int length) { // Set(cx, array, "length", length, false); array.setLengthUnchecked(length); } /** * 12.2.4.1 Array Literal * <p> * 12.2.4.1.2 Runtime Semantics: Array Accumulation * <ul> * <li>SpreadElement : ... AssignmentExpression * </ul> * * @param array * the array object * @param nextIndex * the array index * @param spreadObj * the spread element * @param cx * the execution context * @return the next array index */ public static int ArrayAccumulationSpreadElement(ArrayObject array, int nextIndex, Object spreadObj, ExecutionContext cx) { if (spreadObj instanceof OrdinaryObject) { OrdinaryObject object = (OrdinaryObject) spreadObj; long length = object.getLength(); long newLength = nextIndex + length; if (0 <= length && newLength <= Integer.MAX_VALUE) { if (!(object instanceof TypedArrayObject) && isSpreadable(cx, object, length)) { array.insertFrom(nextIndex, object, length); return (int) newLength; } if (object instanceof TypedArrayObject && isSpreadable(cx, (TypedArrayObject) object)) { array.insertFrom(cx, nextIndex, (TypedArrayObject) object); return (int) newLength; } } } /* steps 1-2 (cf. generated code) */ /* steps 3-4 */ ScriptIterator<?> iterator = GetScriptIterator(cx, spreadObj); /* step 5 */ while (iterator.hasNext()) { defineProperty(array, nextIndex, iterator.next()); nextIndex += 1; } return nextIndex; } private static boolean isSpreadable(ExecutionContext cx, OrdinaryObject object, long length) { if (!(object instanceof ArrayObject || object instanceof ArgumentsObject || object.getClass() == OrdinaryObject.class)) { return false; } if (!object.isDenseArray(length)) { return false; } Property iterProp = findIterator(cx, object); // Test 1: Is object[Symbol.iterator] == %ArrayPrototype%.values? if (iterProp == null || !ArrayPrototype.isBuiltinValues(cx.getRealm(), iterProp.getValue())) { return false; } // Test 2: Is %ArrayIteratorPrototype%.next the built-in next method? Property iterNextProp = cx.getIntrinsic(Intrinsics.ArrayIteratorPrototype).getOwnProperty(cx, "next"); return iterNextProp != null && ArrayIteratorPrototype.isBuiltinNext(cx.getRealm(), iterNextProp.getValue()); } private static boolean isSpreadable(ExecutionContext cx, TypedArrayObject array) { if (array.getBuffer().isDetached()) { return false; } Property iterProp = findIterator(cx, array); // Test 1: Is object[Symbol.iterator] == %ArrayPrototype%.values? if (iterProp == null || !TypedArrayPrototypePrototype.isBuiltinValues(cx.getRealm(), iterProp.getValue())) { return false; } // Test 2: Is %ArrayIteratorPrototype%.next the built-in next method? Property iterNextProp = cx.getIntrinsic(Intrinsics.ArrayIteratorPrototype).getOwnProperty(cx, "next"); return iterNextProp != null && ArrayIteratorPrototype.isBuiltinNext(cx.getRealm(), iterNextProp.getValue()); } private static Property findIterator(ExecutionContext cx, OrdinaryObject object) { final int MAX_PROTO_CHAIN_LENGTH = 5; for (int i = 0; i < MAX_PROTO_CHAIN_LENGTH; ++i) { Property iterProp = object.getOwnProperty(cx, BuiltinSymbol.iterator.get()); if (iterProp != null) { return iterProp; } ScriptObject proto = object.getPrototype(); if (!(proto instanceof OrdinaryObject)) { break; } object = (OrdinaryObject) proto; } return null; } /** * 12.2.5 Object Initializer * <p> * 12.2.5.9 Runtime Semantics: PropertyDefinitionEvaluation * * @param object * the script object * @param propertyName * the property name * @param value * the property value * @param cx * the execution context */ public static void defineProperty(OrdinaryObject object, Object propertyName, Object value, ExecutionContext cx) { CreateDataPropertyOrThrow(cx, object, propertyName, value); } /** * 12.2.5 Object Initializer * <p> * 12.2.5.9 Runtime Semantics: PropertyDefinitionEvaluation * * @param object * the script object * @param propertyName * the property name * @param value * the property value * @param cx * the execution context */ public static void defineProperty(OrdinaryObject object, String propertyName, Object value, ExecutionContext cx) { CreateDataPropertyOrThrow(cx, object, propertyName, value); } /** * 12.2.5 Object Initializer * <p> * 12.2.5.9 Runtime Semantics: PropertyDefinitionEvaluation * * @param object * the script object * @param propertyName * the property name * @param value * the property value * @param cx * the execution context */ public static void defineProperty(OrdinaryObject object, long propertyName, Object value, ExecutionContext cx) { CreateDataPropertyOrThrow(cx, object, propertyName, value); } /** * 12.2.? Generator Comprehensions * <p> * 12.2.?.2 Runtime Semantics: Evaluation * * @param fd * the function runtime info object * @param cx * the execution context * @return the generator object */ public static GeneratorObject EvaluateConstructorGeneratorComprehension(RuntimeInfo.Function fd, ExecutionContext cx) { /* step 1 (omitted) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* steps 3-4 (not applicable) */ /* step 5 */ OrdinaryConstructorGenerator closure = ConstructorGeneratorFunctionCreate(cx, FunctionKind.Arrow, fd, scope); /* step 6 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype); /* step 7 */ MakeConstructor(closure, true, prototype); /* step 8 */ GeneratorObject iterator = (GeneratorObject) closure.call(cx, UNDEFINED); /* step 9 */ return iterator; } /** * 12.2.? Generator Comprehensions * <p> * 12.2.?.2 Runtime Semantics: Evaluation * * @param fd * the function runtime info object * @param cx * the execution context * @return the generator object */ public static GeneratorObject EvaluateGeneratorComprehension(RuntimeInfo.Function fd, ExecutionContext cx) { /* step 1 (omitted) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* steps 3-4 (not applicable) */ /* step 5 */ OrdinaryGenerator closure = GeneratorFunctionCreate(cx, FunctionKind.Arrow, fd, scope); /* step 6 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype); /* step 7 */ closure.infallibleDefineOwnProperty("prototype", new Property(prototype, true, false, false)); /* step 8 */ GeneratorObject iterator = (GeneratorObject) closure.call(cx, UNDEFINED); /* step 9 */ return iterator; } /** * 12.2.? Generator Comprehensions * <p> * Runtime Semantics: Evaluation * * @param fd * the function runtime info object * @param cx * the execution context * @return the generator object */ public static GeneratorObject EvaluateLegacyGeneratorComprehension(RuntimeInfo.Function fd, ExecutionContext cx) { /* step 1 (omitted) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* steps 3-4 (not applicable) */ /* step 5 */ OrdinaryConstructorGenerator closure = ConstructorGeneratorFunctionCreate(cx, FunctionKind.Arrow, fd, scope); /* step 6 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.LegacyGeneratorPrototype); /* step 7 */ MakeConstructor(closure, true, prototype); /* step 8 */ GeneratorObject iterator = (GeneratorObject) closure.call(cx, UNDEFINED); /* step 9 */ return iterator; } /** * 12.2.8 Template Literals * <p> * 12.2.8.2.2 Runtime Semantics: GetTemplateObject ( templateLiteral ) * * @param key * the template literal key * @param handle * the method handle for the template literal data * @param cx * the execution context * @return the template call site object */ public static ArrayObject GetTemplateObject(int key, MethodHandle handle, ExecutionContext cx) { assert cx.getCurrentExecutable() instanceof CompiledObject : cx.getCurrentExecutable(); CompiledObject compiledObject = (CompiledObject) cx.getCurrentExecutable(); ArrayObject template = compiledObject.getTemplateObject(key); if (template == null) { template = GetTemplateObject(handle, cx); compiledObject.setTemplateObject(key, template); } return template; } /** * 12.2.9 Template Literals * <p> * 12.2.9.3 Runtime Semantics: GetTemplateObject ( templateLiteral ) * * @param handle * the method handle for the template literal data * @param cx * the execution context * @return the template call site object */ private static ArrayObject GetTemplateObject(MethodHandle handle, ExecutionContext cx) { /* steps 1, 6 */ String[] strings = evaluateTemplateStrings(handle); assert (strings.length & 1) == 0; /* steps 2-4 */ Map<String, ArrayObject> templateRegistry = cx.getRealm().getTemplateMap(); /* step 5 */ String templateKey = templateStringKey(strings); if (templateRegistry.containsKey(templateKey)) { return templateRegistry.get(templateKey); } /* step 7 */ int count = strings.length >>> 1; /* steps 8-9 */ ArrayObject template = ArrayCreate(cx, count); ArrayObject rawObj = ArrayCreate(cx, count); /* steps 10-11 */ for (int i = 0, n = strings.length; i < n; i += 2) { int index = i >>> 1; int prop = index; String cookedValue = strings[i]; template.defineOwnProperty(cx, prop, new PropertyDescriptor(cookedValue, false, true, false)); String rawValue = strings[i + 1]; rawObj.defineOwnProperty(cx, prop, new PropertyDescriptor(rawValue, false, true, false)); } /* steps 12-14 */ SetIntegrityLevel(cx, rawObj, IntegrityLevel.Frozen); template.defineOwnProperty(cx, "raw", new PropertyDescriptor(rawObj, false, false, false)); SetIntegrityLevel(cx, template, IntegrityLevel.Frozen); /* step 15 */ templateRegistry.put(templateKey, template); /* step 16 */ return template; } private static String templateStringKey(String[] strings) { assert (strings.length & 1) == 0; StringBuilder raw = new StringBuilder(); for (int i = 0, n = strings.length; i < n; i += 2) { // Template string normalization removes any \r character in the source string, so it's // safe to use that character as a delimiter here. String rawValue = strings[i + 1]; raw.append(rawValue).append('\r'); } return raw.toString(); } private static String[] evaluateTemplateStrings(MethodHandle handle) { try { return (String[]) handle.invokeExact(); } catch (Throwable e) { throw ScriptRuntime.<RuntimeException> rethrow(e); } } @SuppressWarnings("unchecked") private static <E extends Throwable> E rethrow(Throwable e) throws E { throw (E) e; } private static Object toPropertyKey(double propertyKey) { long index = (long) propertyKey; if (index == propertyKey) { return index; } return ToString(propertyKey); } public static Object checkAccessElement(Object baseValue, Object propertyName, ExecutionContext cx) { /* steps 1-6 (generated code) */ /* steps 7-8 */ RequireObjectCoercible(cx, baseValue); /* step 9 */ if (Type.isString(propertyName)) { // Convert to flat-string. return Type.stringValue(propertyName).toString(); } if (Type.isNumber(propertyName)) { return toPropertyKey(Type.numberValue(propertyName)); } return ToPropertyKey(cx, propertyName); } public static int checkAccessProperty(Object baseValue, int propertyName, ExecutionContext cx) { /* steps 1-6 (generated code) */ /* steps 7-8 */ RequireObjectCoercible(cx, baseValue); return propertyName; } public static long checkAccessProperty(Object baseValue, long propertyName, ExecutionContext cx) { /* steps 1-6 (generated code) */ /* steps 7-8 */ RequireObjectCoercible(cx, baseValue); return propertyName; } public static double checkAccessProperty(Object baseValue, double propertyName, ExecutionContext cx) { /* steps 1-6 (generated code) */ /* steps 7-8 */ RequireObjectCoercible(cx, baseValue); return propertyName; } public static String checkAccessProperty(Object baseValue, String propertyName, ExecutionContext cx) { /* steps 1-6 (generated code) */ /* steps 7-8 */ RequireObjectCoercible(cx, baseValue); return propertyName; } public static Object checkAccessProperty(Object baseValue, ExecutionContext cx) { /* steps 1-6 (generated code) */ /* steps 7-8 */ return RequireObjectCoercible(cx, baseValue); } public static boolean deleteElement(Object baseValue, Object propertyName, ExecutionContext cx, boolean strict) { return getElement(baseValue, propertyName, cx, strict).delete(cx); } public static boolean deleteProperty(Object baseValue, int propertyName, ExecutionContext cx, boolean strict) { return getProperty(baseValue, propertyName, cx, strict).delete(cx); } public static boolean deleteProperty(Object baseValue, long propertyName, ExecutionContext cx, boolean strict) { return getProperty(baseValue, propertyName, cx, strict).delete(cx); } public static boolean deleteProperty(Object baseValue, double propertyName, ExecutionContext cx, boolean strict) { return getProperty(baseValue, propertyName, cx, strict).delete(cx); } public static boolean deleteProperty(Object baseValue, String propertyName, ExecutionContext cx, boolean strict) { return getProperty(baseValue, propertyName, cx, strict).delete(cx); } /** * 12.3.2 Property Accessors * <p> * 12.3.2.1 Runtime Semantics: Evaluation * <ul> * <li>MemberExpression : MemberExpression . IdentifierName * <li>CallExpression : CallExpression . IdentifierName * </ul> * * @param baseValue * the base value * @param propertyNameString * the property name * @param cx * the execution context * @param strict * the strict mode flag * @return the property reference */ public static Reference<Object, String> getProperty(Object baseValue, int propertyNameString, ExecutionContext cx, boolean strict) { return getProperty(baseValue, (long) propertyNameString, cx, strict); } /** * 12.3.2 Property Accessors * <p> * 12.3.2.1 Runtime Semantics: Evaluation * <ul> * <li>MemberExpression : MemberExpression . IdentifierName * <li>CallExpression : CallExpression . IdentifierName * </ul> * * @param baseValue * the base value * @param propertyNameString * the property name * @param cx * the execution context * @param strict * the strict mode flag * @return the property reference */ public static Reference<Object, String> getProperty(Object baseValue, long propertyNameString, ExecutionContext cx, boolean strict) { /* steps 1-6 (generated code) */ /* steps 7-8 */ RequireObjectCoercible(cx, baseValue); /* steps 9-11 */ return new Reference.PropertyIndexReference(baseValue, propertyNameString, strict); } /** * 12.3.2 Property Accessors * <p> * 12.3.2.1 Runtime Semantics: Evaluation * <ul> * <li>MemberExpression : MemberExpression . IdentifierName * <li>CallExpression : CallExpression . IdentifierName * </ul> * * @param baseValue * the base value * @param propertyNameString * the property name * @param cx * the execution context * @param strict * the strict mode flag * @return the property reference */ public static Reference<Object, String> getProperty(Object baseValue, double propertyNameString, ExecutionContext cx, boolean strict) { long index = (long) propertyNameString; if (index == propertyNameString) { return getProperty(baseValue, index, cx, strict); } return getProperty(baseValue, ToString(propertyNameString), cx, strict); } /** * 12.3.2 Property Accessors * <p> * 12.3.2.1 Runtime Semantics: Evaluation * <ul> * <li>MemberExpression : MemberExpression . IdentifierName * <li>CallExpression : CallExpression . IdentifierName * </ul> * * @param baseValue * the base value * @param propertyNameString * the property name * @param cx * the execution context * @param strict * the strict mode flag * @return the property reference */ public static Reference<Object, String> getProperty(Object baseValue, String propertyNameString, ExecutionContext cx, boolean strict) { /* steps 1-6 (generated code) */ /* steps 7-8 */ RequireObjectCoercible(cx, baseValue); /* steps 9-11 */ return new Reference.PropertyNameReference(baseValue, propertyNameString, strict); } /** * 12.3.2 Property Accessors * <p> * 12.3.2.1 Runtime Semantics: Evaluation * <ul> * <li>MemberExpression : MemberExpression . IdentifierName * <li>CallExpression : CallExpression . IdentifierName * </ul> * * @param baseValue * the base value * @param propertyNameString * the property name * @param cx * the execution context * @return the property value */ public static Object getPropertyValue(Object baseValue, int propertyNameString, ExecutionContext cx) { return getPropertyValue(baseValue, (long) propertyNameString, cx); } /** * 12.3.2 Property Accessors * <p> * 12.3.2.1 Runtime Semantics: Evaluation * <ul> * <li>MemberExpression : MemberExpression . IdentifierName * <li>CallExpression : CallExpression . IdentifierName * </ul> * * @param baseValue * the base value * @param propertyNameString * the property name * @param cx * the execution context * @return the property value */ public static Object getPropertyValue(Object baseValue, long propertyNameString, ExecutionContext cx) { /* steps 1-6 (generated code) */ /* steps 7-8 */ RequireObjectCoercible(cx, baseValue); /* steps 9-11 */ return Reference.PropertyIndexReference.GetValue(cx, baseValue, propertyNameString); } /** * 12.3.2 Property Accessors * <p> * 12.3.2.1 Runtime Semantics: Evaluation * <ul> * <li>MemberExpression : MemberExpression . IdentifierName * <li>CallExpression : CallExpression . IdentifierName * </ul> * * @param baseValue * the base value * @param propertyNameString * the property name * @param cx * the execution context * @return the property value */ public static Object getPropertyValue(Object baseValue, double propertyNameString, ExecutionContext cx) { long index = (long) propertyNameString; if (index == propertyNameString) { return getPropertyValue(baseValue, index, cx); } return getPropertyValue(baseValue, ToString(propertyNameString), cx); } /** * 12.3.2 Property Accessors * <p> * 12.3.2.1 Runtime Semantics: Evaluation * <ul> * <li>MemberExpression : MemberExpression . IdentifierName * <li>CallExpression : CallExpression . IdentifierName * </ul> * * @param baseValue * the base value * @param propertyNameString * the property name * @param cx * the execution context * @return the property value */ public static Object getPropertyValue(Object baseValue, String propertyNameString, ExecutionContext cx) { /* steps 1-6 (generated code) */ /* steps 7-8 */ RequireObjectCoercible(cx, baseValue); /* steps 9-11 */ return Reference.PropertyNameReference.GetValue(cx, baseValue, propertyNameString); } /** * 12.3.2 Property Accessors * <p> * 12.3.2.1 Runtime Semantics: Evaluation * <ul> * <li>MemberExpression : MemberExpression [ Expression ] * <li>CallExpression : CallExpression [ Expression ] * </ul> * * @param baseValue * the base value * @param propertyNameValue * the property name * @param cx * the execution context * @param strict * the strict mode flag * @return the property reference */ public static Reference<Object, ?> getElement(Object baseValue, Object propertyNameValue, ExecutionContext cx, boolean strict) { if (Type.isString(propertyNameValue)) { return getProperty(baseValue, Type.stringValue(propertyNameValue).toString(), cx, strict); } if (Type.isNumber(propertyNameValue)) { return getProperty(baseValue, Type.numberValue(propertyNameValue), cx, strict); } /* steps 1-6 (generated code) */ /* steps 7-8 */ RequireObjectCoercible(cx, baseValue); /* step 9 */ Object propertyKey = ToPropertyKey(cx, propertyNameValue); /* steps 10-11 */ if (propertyKey instanceof String) { return new Reference.PropertyNameReference(baseValue, (String) propertyKey, strict); } return new Reference.PropertySymbolReference(baseValue, (Symbol) propertyKey, strict); } /** * 12.3.2 Property Accessors * <p> * 12.3.2.1 Runtime Semantics: Evaluation * <ul> * <li>MemberExpression : MemberExpression [ Expression ] * <li>CallExpression : CallExpression [ Expression ] * </ul> * * @param baseValue * the base value * @param propertyNameValue * the property name * @param cx * the execution context * @return the property value */ public static Object getElementValue(Object baseValue, Object propertyNameValue, ExecutionContext cx) { if (Type.isString(propertyNameValue)) { return getPropertyValue(baseValue, Type.stringValue(propertyNameValue).toString(), cx); } if (Type.isNumber(propertyNameValue)) { return getPropertyValue(baseValue, Type.numberValue(propertyNameValue), cx); } /* steps 1-6 (generated code) */ /* steps 7-8 */ RequireObjectCoercible(cx, baseValue); /* step 9 */ Object propertyKey = ToPropertyKey(cx, propertyNameValue); /* steps 10-11 */ if (propertyKey instanceof String) { return Reference.PropertyNameReference.GetValue(cx, baseValue, (String) propertyKey); } return Reference.PropertySymbolReference.GetValue(cx, baseValue, (Symbol) propertyKey); } public static void setPropertyValue(Object base, int propertyKey, Object value, ExecutionContext cx, boolean strict) { Reference.PropertyIndexReference.PutValue(cx, base, (long) propertyKey, value, strict); } public static void setPropertyValue(Object base, long propertyKey, Object value, ExecutionContext cx, boolean strict) { Reference.PropertyIndexReference.PutValue(cx, base, propertyKey, value, strict); } public static void setPropertyValue(Object base, double propertyKey, Object value, ExecutionContext cx, boolean strict) { long index = (long) propertyKey; if (index == propertyKey) { setPropertyValue(base, index, value, cx, strict); } else { setPropertyValue(base, ToString(propertyKey), value, cx, strict); } } public static void setPropertyValue(Object base, String propertyKey, Object value, ExecutionContext cx, boolean strict) { Reference.PropertyNameReference.PutValue(cx, base, propertyKey, value, strict); } public static void setPropertyValue(Object base, Symbol propertyKey, Object value, ExecutionContext cx, boolean strict) { Reference.PropertySymbolReference.PutValue(cx, base, propertyKey, value, strict); } public static void setElementValue(Object base, Object propertyKey, Object value, ExecutionContext cx, boolean strict) { if (propertyKey instanceof String) { setPropertyValue(base, (String) propertyKey, value, cx, strict); } else if (propertyKey instanceof Long) { setPropertyValue(base, (Long) propertyKey, value, cx, strict); } else { setPropertyValue(base, (Symbol) propertyKey, value, cx, strict); } } /** * 12.3.3 The new Operator * <p> * 12.3.3.1 Runtime Semantics: Evaluation<br> * 12.3.5.1 Runtime Semantics: Evaluation * <ul> * <li>NewExpression : new NewExpression * <li>MemberExpression : new MemberExpression Arguments * <li>MemberExpression : NewSuper Arguments<span><sub>opt</sub></span> * </ul> * * @param constructor * the constructor function object * @param cx * the execution context * @return the constructor function object * @throws ScriptException * if <var>constructor</var> is not a constructor function */ public static Constructor CheckConstructor(Object constructor, ExecutionContext cx) throws ScriptException { /* steps 4/6/5 */ if (!IsConstructor(constructor)) { throw newTypeError(cx, Messages.Key.NotConstructor); } return (Constructor) constructor; } /** * 12.3.4 Function Calls * <p> * 12.3.4.3 Runtime Semantics: EvaluateDirectCall( func, thisValue, arguments, tailPosition ) * * @param func * the function object * @param cx * the execution context * @return the function object * @throws ScriptException * if <var>func</var> is not a function */ public static Callable CheckCallable(Object func, ExecutionContext cx) throws ScriptException { /* steps 3-4 */ if (!IsCallable(func)) { throw newTypeError(cx, Messages.Key.NotCallable); } return (Callable) func; } /** * 12.3.4 Function Calls * <p> * 12.3.4.1 Runtime Semantics: Evaluation * * @param ref * the reference value * @param f * the function object * @param cx * the execution context * @return {@code true} if <var>f</var> is the built-in eval function */ public static boolean IsBuiltinEval(Object ref, Callable f, ExecutionContext cx) { /* step 4 */ if (ref instanceof Reference) { Reference<?, ?> r = (Reference<?, ?>) ref; if (!r.isPropertyReference()) { assert !r.isUnresolvableReference() && r.getBase() instanceof EnvironmentRecord; return f == cx.getRealm().getBuiltinEval(); } } return false; } /** * 12.3.4 Function Calls * <p> * 12.3.4.1 Runtime Semantics: Evaluation * * @param f * the function object * @param cx * the execution context * @return {@code true} if <var>f</var> is the built-in eval function */ public static boolean IsBuiltinEval(Callable f, ExecutionContext cx) { /* step 4 */ return f == cx.getRealm().getBuiltinEval(); } /** * 12.3.4 Function Calls * * @param cx * the execution context * @return the direct eval fallback hook */ public static Callable directEvalFallbackHook(ExecutionContext cx) { return cx.getRealm().getNonEvalFallback(); } /** * 12.3.4 Function Calls * * @param callee * the function callee * @param cx * the execution context * @param thisValue * the function this-value * @param args * the function call arguments * @return the direct eval fallback arguments */ public static Object[] directEvalFallbackArguments(Callable callee, ExecutionContext cx, Object thisValue, Object[] args) { Object[] fallbackArgs = new Object[3]; fallbackArgs[0] = callee; fallbackArgs[1] = thisValue; fallbackArgs[2] = CreateArrayFromList(cx, Arrays.asList(args)); return fallbackArgs; } /** * 12.3.4 Function Calls * * @param cx * the execution context * @return the direct eval fallback this-argument */ public static Object directEvalFallbackThisArgument(ExecutionContext cx) { return cx.getRealm().getRealmObject(); } /** * 12.3.8 Meta Properties * * @param cx * the execution context * @return the NewTarget constructor object */ public static Object GetNewTargetOrUndefined(ExecutionContext cx) { Constructor newTarget = cx.getNewTarget(); if (newTarget == null) { return UNDEFINED; } return newTarget; } /** * 12.3.5 The super Keyword * * @param cx * the execution context * @return the NewTarget constructor object */ public static Constructor GetNewTarget(ExecutionContext cx) { Constructor newTarget = cx.getNewTarget(); if (newTarget == null) { throw newReferenceError(cx, Messages.Key.MissingNewTarget); } return newTarget; } /** * 12.3.5 The super Keyword * * @param result * the new {@code this} binding value * @param cx * the execution context */ public static void BindThisValue(ScriptObject result, ExecutionContext cx) { EnvironmentRecord thisEnvironment = cx.getThisEnvironment(); assert thisEnvironment instanceof FunctionEnvironmentRecord; ((FunctionEnvironmentRecord) thisEnvironment).bindThisValue(cx, result); } /** * 12.3.5 The super Keyword * <p> * 12.3.5.2 Runtime Semantics: GetSuperConstructor ( ) * * @param cx * the execution context * @return the super reference */ public static Constructor GetSuperConstructor(ExecutionContext cx) { /* step 1 */ EnvironmentRecord envRec = cx.getThisEnvironment(); /* step 2 */ assert envRec instanceof FunctionEnvironmentRecord; FunctionEnvironmentRecord fEnvRec = (FunctionEnvironmentRecord) envRec; /* step 3 */ FunctionObject activeFunction = fEnvRec.getFunctionObject(); /* steps 4-5 */ ScriptObject superConstructor = activeFunction.getPrototypeOf(cx); /* step 6 */ if (!IsConstructor(superConstructor)) { throw newTypeError(cx, Messages.Key.NotConstructor); } /* step 7 */ return (Constructor) superConstructor; } /** * 12.3.5 The super Keyword * <p> * 12.3.5.3 Runtime Semantics: MakeSuperPropertyReference(propertyKey, strict) * * @param propertyKey * the property key * @param cx * the execution context * @param strict * the strict mode flag * @return the super reference */ public static Reference<ScriptObject, ?> MakeSuperPropertyReference(Object propertyKey, ExecutionContext cx, boolean strict) { if (propertyKey instanceof String) { return MakeSuperPropertyReference((String) propertyKey, cx, strict); } else { return MakeSuperPropertyReference((Symbol) propertyKey, cx, strict); } } /** * 12.3.5 The super Keyword * <p> * 12.3.5.3 Runtime Semantics: MakeSuperPropertyReference(propertyKey, strict) * * @param propertyKey * the property key * @param cx * the execution context * @param strict * the strict mode flag * @return the super reference */ public static Reference<ScriptObject, String> MakeSuperPropertyReference(String propertyKey, ExecutionContext cx, boolean strict) { /* steps 1-2 */ FunctionEnvironmentRecord envRec = GetSuperEnvironmentRecord(cx); /* steps 3-4 */ Object actualThis = GetSuperThis(envRec, cx); /* steps 5-7 */ ScriptObject baseValue = GetSuperBase(envRec, cx); /* step 8 */ return new Reference.SuperNameReference(baseValue, propertyKey, strict, actualThis); } /** * 12.3.5 The super Keyword * <p> * 12.3.5.3 Runtime Semantics: MakeSuperPropertyReference(propertyKey, strict) * * @param propertyKey * the property key * @param cx * the execution context * @param strict * the strict mode flag * @return the super reference */ public static Reference<ScriptObject, Symbol> MakeSuperPropertyReference(Symbol propertyKey, ExecutionContext cx, boolean strict) { /* steps 1-2 */ FunctionEnvironmentRecord envRec = GetSuperEnvironmentRecord(cx); /* steps 3-4 */ Object actualThis = GetSuperThis(envRec, cx); /* steps 5-7 */ ScriptObject baseValue = GetSuperBase(envRec, cx); /* step 8 */ return new Reference.SuperSymbolReference(baseValue, propertyKey, strict, actualThis); } public static FunctionEnvironmentRecord GetSuperEnvironmentRecord(ExecutionContext cx) { /* step 1 */ EnvironmentRecord envRec = cx.getThisEnvironment(); /* step 2 */ if (!envRec.hasSuperBinding()) { throw newReferenceError(cx, Messages.Key.MissingSuperBinding); } assert envRec instanceof FunctionEnvironmentRecord : envRec.getClass().toString(); return (FunctionEnvironmentRecord) envRec; } public static Object GetSuperThis(FunctionEnvironmentRecord envRec, ExecutionContext cx) { /* steps 3-4 */ return envRec.getThisBinding(cx); } public static ScriptObject GetSuperBase(FunctionEnvironmentRecord envRec, ExecutionContext cx) { /* step 5 */ ScriptObject baseValue = envRec.getSuperBase(cx); /* steps 6-7 */ // RequireObjectCoercible(cx, baseValue); if (baseValue == null) { throw newTypeError(cx, Messages.Key.UndefinedOrNull); } return baseValue; } /** * 12.3.5 The super Keyword * <p> * 12.3.5.3 Runtime Semantics: MakeSuperPropertyReference(propertyKey, strict) * * @param propertyKey * the property key * @param actualThis * the actual {@code this} value * @param baseValue * the reference base value * @param cx * the execution context * @return the super reference value */ public static Object getSuperProperty(Object propertyKey, Object actualThis, ScriptObject baseValue, ExecutionContext cx) { if (propertyKey instanceof String) { return baseValue.get(cx, (String) propertyKey, actualThis); } else { return baseValue.get(cx, (Symbol) propertyKey, actualThis); } } /** * 12.3.5 The super Keyword * <p> * 12.3.5.3 Runtime Semantics: MakeSuperPropertyReference(propertyKey, strict) * * @param propertyKey * the property key * @param actualThis * the actual {@code this} value * @param baseValue * the reference base value * @param cx * the execution context * @return the super reference value */ public static Object getSuperProperty(String propertyKey, Object actualThis, ScriptObject baseValue, ExecutionContext cx) { return baseValue.get(cx, propertyKey, actualThis); } /** * 12.3.5 The super Keyword * <p> * 12.3.5.3 Runtime Semantics: MakeSuperPropertyReference(propertyKey, strict) * * @param propertyKey * the property key * @param actualThis * the actual {@code this} value * @param baseValue * the reference base value * @param value * the new property value * @param cx * the execution context * @param strict * the strict mode flag */ public static void setSuperProperty(Object propertyKey, Object actualThis, ScriptObject baseValue, Object value, ExecutionContext cx, boolean strict) { boolean succeeded; if (propertyKey instanceof String) { succeeded = baseValue.set(cx, (String) propertyKey, value, actualThis); } else { succeeded = baseValue.set(cx, (Symbol) propertyKey, value, actualThis); } if (!succeeded && strict) { throw newTypeError(cx, Messages.Key.PropertyNotModifiable, propertyKey.toString()); } } /** * 12.3.5 The super Keyword * <p> * 12.3.5.3 Runtime Semantics: MakeSuperPropertyReference(propertyKey, strict) * * @param propertyKey * the property key * @param actualThis * the actual {@code this} value * @param baseValue * the reference base value * @param value * the new property value * @param cx * the execution context * @param strict * the strict mode flag */ public static void setSuperProperty(String propertyKey, Object actualThis, ScriptObject baseValue, Object value, ExecutionContext cx, boolean strict) { boolean succeeded = baseValue.set(cx, (String) propertyKey, value, actualThis); if (!succeeded && strict) { throw newTypeError(cx, Messages.Key.PropertyNotModifiable, propertyKey); } } /** * 12.3.5 The super Keyword * <p> * 12.3.5.3 Runtime Semantics: MakeSuperPropertyReference(propertyKey, strict) * * @param cx * the execution context * @return no value */ public static boolean deleteSuperProperty(ExecutionContext cx) { /* steps 1-2 */ FunctionEnvironmentRecord envRec = GetSuperEnvironmentRecord(cx); /* steps 3-4 */ GetSuperThis(envRec, cx); /* steps 5-7 */ GetSuperBase(envRec, cx); /* step 8 (omitted) */ /* 12.5.4.2, step 5.a */ throw newReferenceError(cx, Messages.Key.SuperDelete); } /** * 12.3.6 Argument Lists * <p> * 12.3.6.1 Runtime Semantics: ArgumentListEvaluation * * @param spreadObj * the spread object * @param cx * the execution context * @return the spread object elements */ public static Object[] SpreadArray(Object spreadObj, ExecutionContext cx) { final int MAX_ARGS = FunctionPrototype.getMaxArguments(); if (spreadObj instanceof OrdinaryObject) { OrdinaryObject object = (OrdinaryObject) spreadObj; long length = object.getLength(); if (0 <= length && length <= MAX_ARGS && isSpreadable(cx, object, length)) { if (length == 0) { return EMPTY_ARRAY; } return object.toArray(length); } } /* steps 1-3 (cf. generated code) */ /* steps 4-5 */ ScriptIterator<?> iterator = GetScriptIterator(cx, spreadObj); /* step 6 */ ArrayList<Object> list = new ArrayList<>(); for (int n = 0; n <= MAX_ARGS; ++n) { if (!iterator.hasNext()) { return list.toArray(new Object[n]); } list.add(iterator.next()); } throw newRangeError(cx, Messages.Key.FunctionTooManyArguments); } /** * 12.3.6 Argument Lists * <p> * 12.3.6.1 Runtime Semantics: ArgumentListEvaluation * * @param spreadObj * the spread object * @param cx * the execution context * @return the spread object elements */ public static Object[] NativeCallSpreadArray(Object spreadObj, ExecutionContext cx) { final int MAX_ARGS = FunctionPrototype.getMaxArguments(); if (spreadObj instanceof ArrayObject) { ArrayObject array = (ArrayObject) spreadObj; long length = array.getLength(); if (array.isDenseArray() && length <= MAX_ARGS) { if (length == 0) { return EMPTY_ARRAY; } return array.toArray(length); } } throw newInternalError(cx, Messages.Key.InternalError, "Invalid native call"); } /** * 12.3.6 Argument Lists * <p> * 12.3.6.1 Runtime Semantics: ArgumentListEvaluation * * @param array * the array * @param cx * the execution context * @return the flattened array */ public static Object[] toFlatArray(Object[] array, ExecutionContext cx) { final int MAX_ARGS = FunctionPrototype.getMaxArguments(); int newlen = array.length; for (int i = 0, len = array.length; i < len; ++i) { if (array[i] instanceof Object[]) { newlen += ((Object[]) array[i]).length - 1; if (newlen > MAX_ARGS) { throw newRangeError(cx, Messages.Key.FunctionTooManyArguments); } } } Object[] result = new Object[newlen]; for (int i = 0, j = 0, len = array.length; i < len; ++i) { if (array[i] instanceof Object[]) { Object[] a = (Object[]) array[i]; System.arraycopy(a, 0, result, j, a.length); j += a.length; } else { result[j++] = array[i]; } } return result; } /** * 12.5 Unary Operators<br> * 12.5.6 The typeof Operator * * @param val * the value * @param cx * the execution context * @return the typeof descriptor string */ public static String typeof(Object val, ExecutionContext cx) { /* step 1 (generated code) */ /* step 2 */ if (val instanceof Reference) { Reference<?, ?> ref = (Reference<?, ?>) val; if (ref.isUnresolvableReference()) { return "undefined"; } val = ref.getValue(cx); } return typeof(val); } /** * 12.5 Unary Operators<br> * 12.5.6 The typeof Operator * * @param ref * the reference * @param cx * the execution context * @return the typeof descriptor string */ public static String typeof(Reference<?, ?> ref, ExecutionContext cx) { if (ref.isUnresolvableReference()) { return "undefined"; } return typeof(ref.getValue(cx)); } /** * 12.5 Unary Operators<br> * 12.5.6 The typeof Operator * * @param val * the value * @return the typeof descriptor string */ public static String typeof(Object val) { /* steps 1-2 (generated code) */ /* steps 3-4 */ switch (Type.of(val)) { case Undefined: return "undefined"; case Null: return "object"; case Boolean: return "boolean"; case Number: return "number"; case String: return "string"; case Symbol: return "symbol"; case SIMD: return Type.simdValue(val).getType().typeof(); case Object: if (IsCallable(val)) { return "function"; } return "object"; default: throw new AssertionError(); } } /** * 12.5 Unary Operators<br> * 12.5.6 The typeof Operator * * @param val * the value * @return {@code true} on success */ public static boolean isNonCallableObjectOrNull(Object val) { return Type.isNull(val) || (Type.isObject(val) && !IsCallable(val)); } /** * 12.5 Unary Operators<br> * 12.5.6 The typeof Operator * * @param val * the value * @param type * the SIMD type * @return {@code true} on success */ public static boolean isSIMDType(Object val, SIMDType type) { return Type.isSIMD(val) && Type.simdValue(val).getType() == type; } /** * 12.7 Additive Operators<br> * 12.7.3 The Addition operator ( + ) * * @param lval * the left-hand side operand * @param rval * the right-hand side operand * @param cx * the execution context * @return the operation result */ public static Object add(Object lval, Object rval, ExecutionContext cx) { /* steps 1-6 (generated code) */ /* steps 7-8 */ Object lprim = ToPrimitive(cx, lval); /* steps 9-10 */ Object rprim = ToPrimitive(cx, rval); /* step 11 */ if (Type.isString(lprim) || Type.isString(rprim)) { CharSequence lstr = ToString(cx, lprim); CharSequence rstr = ToString(cx, rprim); return add(lstr, rstr, cx); } /* steps 12-16 */ return ToNumber(cx, lprim) + ToNumber(cx, rprim); } /** * 12.7 Additive Operators<br> * 12.7.3 The Addition operator ( + ) * * @param lstr * the left-hand side operand * @param rstr * the right-hand side operand * @param cx * the execution context * @return the concatenated string */ public static CharSequence add(CharSequence lstr, CharSequence rstr, ExecutionContext cx) { int llen = lstr.length(), rlen = rstr.length(); if (llen == 0) { return rstr; } if (rlen == 0) { return lstr; } int newlen = llen + rlen; if (newlen < 0) { throw newInternalError(cx, Messages.Key.OutOfMemory); } if (newlen <= 10) { // return new StringBuilder(newlen).append(lstr).append(rstr).toString(); return inlineString(lstr, rstr, llen, rlen); } return new ConsString(lstr, rstr); } private static String inlineString(CharSequence lstr, CharSequence rstr, int llen, int rlen) { char[] ca = new char[llen + rlen]; lstr.toString().getChars(0, llen, ca, 0); rstr.toString().getChars(0, rlen, ca, llen); return new String(ca); } /** * 12.7 Additive Operators<br> * 12.7.3 The Addition operator ( + ) * * @param value * the argument value * @param cx * the execution context * @return the result of ToString(ToPrimitive(value)) */ public static CharSequence toStr(Object value, ExecutionContext cx) { return ToString(cx, ToPrimitive(cx, value)); } /** * 12.9 Relational Operators<br> * 12.9.3 Runtime Semantics: Evaluation * * @param lval * the left-hand side operand * @param rval * the right-hand side operand * @param cx * the execution context * @return the operation result */ public static boolean in(Object lval, Object rval, ExecutionContext cx) { /* steps 1-6 (generated code) */ /* step 7 */ if (!Type.isObject(rval)) { throw newTypeError(cx, Messages.Key.InNotObject); } /* step 8 */ return HasProperty(cx, Type.objectValue(rval), ToPropertyKey(cx, lval)); } /** * 12.9 Relational Operators<br> * 12.9.4 Runtime Semantics: InstanceofOperator(O, C) * * @param obj * the object * @param constructor * the constructor function * @param cx * the execution context * @return the operation result */ public static boolean InstanceofOperator(Object obj, Object constructor, ExecutionContext cx) { /* step 1 */ if (!Type.isObject(constructor)) { throw newTypeError(cx, Messages.Key.InstanceofNotObject); } /* steps 2-3 */ Callable instOfHandler = GetMethod(cx, Type.objectValue(constructor), BuiltinSymbol.hasInstance.get()); /* step 4 */ if (instOfHandler != null) { return ToBoolean(instOfHandler.call(cx, constructor, obj)); } /* step 5 */ if (!IsCallable(constructor)) { throw newTypeError(cx, Messages.Key.InstanceofNotCallable); } /* step 6 */ return OrdinaryHasInstance(cx, constructor, obj); } /** * 12.10 Equality Operators * * @param lval * the first string * @param rval * the second string * @return the operation result */ public static boolean compare(CharSequence lval, CharSequence rval) { return lval.length() == rval.length() && lval.toString().equals(rval.toString()); } /** * 12.14.5.3 Runtime Semantics: IteratorDestructuringAssignmentEvaluation * <p> * 13.2.3.5 Runtime Semantics: IteratorBindingInitialization * * @param iterator * the iterator * @param cx * the execution context * @return the array with the remaining elements from <var>iterator</var> */ public static ArrayObject createRestArray(Iterator<?> iterator, ExecutionContext cx) { ArrayObject result = ArrayCreate(cx, 0); for (int n = 0; iterator.hasNext(); ++n) { Object nextValue = iterator.next(); CreateDataProperty(cx, result, n, nextValue); } return result; } /** * 12.14.5.3 Runtime Semantics: IteratorDestructuringAssignmentEvaluation * <p> * 13.2.3.5 Runtime Semantics: IteratorBindingInitialization * * @param iterator * the iterator */ public static void iteratorNextAndIgnore(Iterator<?> iterator) { if (iterator.hasNext()) { iterator.next(); } } /** * 12.14.5.3 Runtime Semantics: IteratorDestructuringAssignmentEvaluation * <p> * 13.2.3.5 Runtime Semantics: IteratorBindingInitialization * * @param iterator * the iterator * @return the next iterator result, or undefined it is already exhausted */ public static Object iteratorNextOrUndefined(Iterator<?> iterator) { return iterator.hasNext() ? iterator.next() : UNDEFINED; } /* ***************************************************************************************** */ /** * 13.6.4 The for-in and for-of Statements * <ul> * <li>13.6.4.12 Runtime Semantics: ForIn/OfHeadEvaluation ( TDZnames, expr, iterationKind, labelSet) * </ul> * * @param value * the object to enumerate * @param cx * the execution context * @return the keys enumerator */ public static ScriptIterator<?> enumerate(Object value, ExecutionContext cx) { /* step 7.b */ ScriptObject obj = ToObject(cx, value); /* step 7.c */ if (cx.getRealm().isEnabled(CompatibilityOption.Enumerate)) { return obj.enumerateKeys(cx); } return new EnumeratePropertiesIterator(cx, obj); } /** * EnumerateObjectProperties (O) */ private static final class EnumeratePropertiesIterator extends SimpleIterator<String> implements ScriptIterator<String> { private final HashSet<Object> visitedKeys = new HashSet<>(); private final ExecutionContext cx; private ScriptObject obj; private Iterator<String> keys; EnumeratePropertiesIterator(ExecutionContext cx, ScriptObject obj) { this.cx = cx; this.obj = obj; this.keys = obj.ownEnumerablePropertyKeys(cx); } @Override protected String findNext() { HashSet<Object> visitedKeys = this.visitedKeys; ExecutionContext cx = this.cx; for (ScriptObject obj = this.obj; obj != null;) { for (Iterator<String> keys = this.keys; keys.hasNext();) { String key = keys.next(); ScriptObject.Enumerability e = obj.isEnumerableOwnProperty(cx, key); if (e != ScriptObject.Enumerability.Deleted) { if (visitedKeys.add(key) && e == ScriptObject.Enumerability.Enumerable) { return key; } } } obj = this.obj = obj.getPrototypeOf(cx); if (obj != null) { this.keys = obj.ownEnumerablePropertyKeys(cx); } else { this.keys = null; } } return null; } @Override public void close() throws ScriptException { // No return() action required. } @Override public void close(Throwable cause) throws ScriptException { // No return() action required. } } /** * 13.6.4 The for-in and for-of Statements * <ul> * <li>13.6.4.12 Runtime Semantics: ForIn/OfHeadEvaluation ( TDZnames, expr, iterationKind, labelSet) * </ul> * <p> * 12.14.5.3 Runtime Semantics: IteratorDestructuringAssignmentEvaluation * <p> * 13.2.3.5 Runtime Semantics: IteratorBindingInitialization * * @param value * the object to iterate * @param cx * the execution context * @return the object iterator */ public static ScriptIterator<?> iterate(Object value, ExecutionContext cx) { /* step 8 */ return GetScriptIterator(cx, value); } /** * 13.6.4 The for-in and for-of Statements<br> * Extension: 'for-await' statement * <p> * 13.6.4.12 Runtime Semantics: ForIn/OfHeadEvaluation ( TDZnames, expr, iterationKind, labelSet) * * @param value * the object to enumerate * @param cx * the execution context * @return the async iterator */ public static ScriptObject asyncIterate(Object value, ExecutionContext cx) { return AsyncGeneratorAbstractOperations.GetAsyncIterator(cx, value); } /** * 13.6.4 The for-in and for-of Statements<br> * Extension: 'for-each' statement * <p> * 13.6.4.12 Runtime Semantics: ForIn/OfHeadEvaluation ( TDZnames, expr, iterationKind, labelSet) * * @param value * the object to enumerate * @param cx * the execution context * @return the values enumerator */ public static ScriptIterator<?> enumerateValues(Object value, ExecutionContext cx) { /* step 7.b */ ScriptObject obj = ToObject(cx, value); /* steps 7.b-c */ return new ValuesIterator(cx, obj, enumerate(obj, cx)); } private static final class ValuesIterator extends SimpleIterator<Object> implements ScriptIterator<Object> { private final ExecutionContext cx; private final ScriptObject object; private final ScriptIterator<?> keysIterator; ValuesIterator(ExecutionContext cx, ScriptObject object, ScriptIterator<?> keysIterator) { this.cx = cx; this.object = object; this.keysIterator = keysIterator; } @Override protected Object findNext() throws ScriptException { if (keysIterator.hasNext()) { Object pk = ToPropertyKey(cx, keysIterator.next()); return Get(cx, object, pk); } return null; } @Override public void close() throws ScriptException { keysIterator.close(); } @Override public void close(Throwable cause) throws ScriptException { keysIterator.close(cause); } } /** * 13.14 The try Statement * * @param e * the error cause * @return if either <var>e</var> or its cause is a stack overflow error, that error object * @throws Error * if neither the error nor its cause is a stack overflow error */ public static StackOverflowError stackOverflowError(Error e) throws Error { if (e instanceof StackOverflowError) { return (StackOverflowError) e; } Throwable cause = e.getCause(); if (cause instanceof StackOverflowError) { return (StackOverflowError) cause; } throw e; } /** * 13.14 The try Statement * * @param e * the error cause * @param cx * the execution context * @return the new script exception */ public static ScriptException toInternalError(StackOverflowError e, ExecutionContext cx) { ScriptException exception = newInternalError(cx, Messages.Key.StackOverflow); // use stacktrace from original error exception.setStackTrace(e.getStackTrace()); return exception; } /** * 13.15 The debugger statement */ public static void debugger() { // breakpoint } /* ***************************************************************************************** */ /** * 14.1 Function Definitions * <p> * 14.1.20 Runtime Semantics: InstantiateFunctionObject * * @param scope * the current lexical scope * @param cx * the execution context * @param fd * the function runtime info object * @return the new function instance */ public static OrdinaryConstructorFunction InstantiateFunctionObject(LexicalEnvironment<?> scope, ExecutionContext cx, RuntimeInfo.Function fd) { /* step 1 (not applicable) */ /* step 2 */ String name = fd.functionName(); /* step 3 */ OrdinaryConstructorFunction f = ConstructorFunctionCreate(cx, FunctionKind.Normal, fd, scope); /* step 4 */ MakeConstructor(cx, f); /* step 4 */ SetFunctionName(f, name); /* step 6 */ return f; } /** * 14.1 Function Definitions * <p> * 14.1.20 Runtime Semantics: InstantiateFunctionObject * * @param scope * the current lexical scope * @param cx * the execution context * @param fd * the function runtime info object * @return the new function instance */ public static LegacyConstructorFunction InstantiateLegacyFunctionObject(LexicalEnvironment<?> scope, ExecutionContext cx, RuntimeInfo.Function fd) { /* step 1 (not applicable) */ /* step 2 */ String name = fd.functionName(); /* step 3 */ LegacyConstructorFunction f = LegacyFunctionCreate(cx, fd, scope); /* step 4 */ MakeConstructor(cx, f); /* step 4 */ SetFunctionName(f, name); /* step 6 */ return f; } /** * 14.1 Function Definitions * <p> * 14.1.21 Runtime Semantics: Evaluation * <ul> * <li>FunctionExpression : function ( FormalParameters ) { FunctionBody } * <li>FunctionExpression : function BindingIdentifier ( FormalParameters ) { FunctionBody } * </ul> * * @param fd * the function runtime info object * @param cx * the execution context * @return the new function instance */ public static OrdinaryConstructorFunction EvaluateFunctionExpression(RuntimeInfo.Function fd, ExecutionContext cx) { OrdinaryConstructorFunction closure; if (!fd.is(RuntimeInfo.FunctionFlags.ScopedName)) { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ closure = ConstructorFunctionCreate(cx, FunctionKind.Normal, fd, scope); /* step 4 */ MakeConstructor(cx, closure); } else { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ LexicalEnvironment<DeclarativeEnvironmentRecord> funcEnv = newDeclarativeEnvironment(scope); /* step 4 */ DeclarativeEnvironmentRecord envRec = funcEnv.getEnvRec(); /* step 5 */ String name = fd.functionName(); /* step 6 */ envRec.createImmutableBinding(name, false); /* step 7 */ closure = ConstructorFunctionCreate(cx, FunctionKind.Normal, fd, funcEnv); /* step 8 */ MakeConstructor(cx, closure); /* step 9 */ SetFunctionName(closure, name); /* step 10 */ envRec.initializeBinding(name, closure); } /* step 5/11 */ return closure; } /** * 14.1 Function Definitions * <p> * 14.1.21 Runtime Semantics: Evaluation * <ul> * <li>FunctionExpression : function ( FormalParameters ) { FunctionBody } * <li>FunctionExpression : function BindingIdentifier ( FormalParameters ) { FunctionBody } * </ul> * * @param fd * the function runtime info object * @param cx * the execution context * @return the new function instance */ public static LegacyConstructorFunction EvaluateLegacyFunctionExpression(RuntimeInfo.Function fd, ExecutionContext cx) { LegacyConstructorFunction closure; if (!fd.is(RuntimeInfo.FunctionFlags.ScopedName)) { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ closure = LegacyFunctionCreate(cx, fd, scope); /* step 4 */ MakeConstructor(cx, closure); } else { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ LexicalEnvironment<DeclarativeEnvironmentRecord> funcEnv = newDeclarativeEnvironment(scope); /* step 4 */ DeclarativeEnvironmentRecord envRec = funcEnv.getEnvRec(); /* step 5 */ String name = fd.functionName(); /* step 6 */ envRec.createImmutableBinding(name, false); /* step 7 */ closure = LegacyFunctionCreate(cx, fd, funcEnv); /* step 8 */ MakeConstructor(cx, closure); /* step 9 */ SetFunctionName(closure, name); /* step 10 */ envRec.initializeBinding(name, closure); } /* step 5/11 */ return closure; } /** * 14.2 Arrow Function Definitions * <p> * 14.2.17 Runtime Semantics: Evaluation * <ul> * <li>ArrowFunction : ArrowParameters {@literal =>} ConciseBody * </ul> * * @param fd * the function runtime info object * @param cx * the execution context * @return the new function instance */ public static OrdinaryFunction EvaluateArrowFunction(RuntimeInfo.Function fd, ExecutionContext cx) { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 4 */ OrdinaryFunction closure = FunctionCreate(cx, FunctionKind.Arrow, fd, scope); /* step 5 */ return closure; } /** * 14.3 Method Definitions, 14.5 Class Definitions * <p> * 14.3.8 Runtime Semantics: DefineMethod<br> * 14.5.14 Runtime Semantics: ClassDefinitionEvaluation * * @param constructorParent * the constructor prototype * @param proto * the class prototype * @param fd * the function runtime info object * @param isDerived * {@code true} if evaluating the constructor of a derived class * @param cx * the execution context * @return the new function instance */ public static OrdinaryConstructorFunction EvaluateConstructorMethod(ScriptObject constructorParent, OrdinaryObject proto, RuntimeInfo.Function fd, boolean isDerived, ExecutionContext cx) { // ClassDefinitionEvaluation - steps 11-13 (call DefineMethod) LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); ConstructorKind constructorKind = isDerived ? ConstructorKind.Derived : ConstructorKind.Base; OrdinaryConstructorFunction constructor = ConstructorFunctionCreate(cx, FunctionKind.ClassConstructor, constructorKind, fd, scope, constructorParent); MakeMethod(constructor, proto); // ClassDefinitionEvaluation - step 14 (not applicable, cf. ConstructorFunctionCreate) // ClassDefinitionEvaluation - step 15 MakeConstructor(constructor, false, proto); // ClassDefinitionEvaluation - step 16 MakeClassConstructor(constructor); // ClassDefinitionEvaluation - step 17 proto.defineOwnProperty(cx, "constructor", new PropertyDescriptor(constructor, true, false, true)); return constructor; } /** * 14.3 Method Definitions * <p> * 14.3.9 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>PropertyName ( StrictFormalParameters ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinition(OrdinaryObject object, Object propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { if (propKey instanceof String) { EvaluatePropertyDefinition(object, (String) propKey, enumerable, fd, cx); } else { EvaluatePropertyDefinition(object, (Symbol) propKey, enumerable, fd, cx); } } /** * 14.3 Method Definitions * <p> * 14.3.9 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>PropertyName ( StrictFormalParameters ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinition(OrdinaryObject object, String propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-2 (DefineMethod) */ /* DefineMethod: steps 1-3 (generated code) */ /* DefineMethod: step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* DefineMethod: steps 5-6 */ OrdinaryFunction closure = FunctionCreate(cx, FunctionKind.Method, fd, scope); /* DefineMethod: step 7 */ MakeMethod(closure, object); /* step 3 */ SetFunctionName(closure, propKey); /* step 4 */ PropertyDescriptor desc = new PropertyDescriptor(closure, true, enumerable, true); /* step 5 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * 14.3 Method Definitions * <p> * 14.3.9 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>PropertyName ( StrictFormalParameters ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinition(OrdinaryObject object, Symbol propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-2 (Call DefineMethod) */ /* DefineMethod: steps 1-3 (generated code) */ /* DefineMethod: step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* DefineMethod: steps 5-6 */ OrdinaryFunction closure = FunctionCreate(cx, FunctionKind.Method, fd, scope); /* DefineMethod: step 7 */ MakeMethod(closure, object); /* step 3 */ SetFunctionName(closure, propKey); /* step 4 */ PropertyDescriptor desc = new PropertyDescriptor(closure, true, enumerable, true); /* step 5 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * 14.3 Method Definitions * <p> * 14.3.9 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>get PropertyName ( ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionGetter(OrdinaryObject object, Object propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { if (propKey instanceof String) { EvaluatePropertyDefinitionGetter(object, (String) propKey, enumerable, fd, cx); } else { EvaluatePropertyDefinitionGetter(object, (Symbol) propKey, enumerable, fd, cx); } } /** * 14.3 Method Definitions * <p> * 14.3.9 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>get PropertyName ( ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionGetter(OrdinaryObject object, String propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-3 (generated code) */ /* step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* steps 5-6 */ OrdinaryFunction closure = FunctionCreate(cx, FunctionKind.Method, fd, scope); /* step 7 */ MakeMethod(closure, object); /* steps 8-9 */ SetFunctionName(closure, propKey, "get"); /* step 10 */ PropertyDescriptor desc = AccessorPropertyDescriptor(closure, null, enumerable, true); /* step 11 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * 14.3 Method Definitions * <p> * 14.3.9 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>get PropertyName ( ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionGetter(OrdinaryObject object, Symbol propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-3 (generated code) */ /* step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* steps 5-6 */ OrdinaryFunction closure = FunctionCreate(cx, FunctionKind.Method, fd, scope); /* step 7 */ MakeMethod(closure, object); /* steps 8-9 */ SetFunctionName(closure, propKey, "get"); /* step 10 */ PropertyDescriptor desc = AccessorPropertyDescriptor(closure, null, enumerable, true); /* step 11 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * 14.3 Method Definitions * <p> * 14.3.9 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>set PropertyName ( PropertySetParameterList ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionSetter(OrdinaryObject object, Object propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { if (propKey instanceof String) { EvaluatePropertyDefinitionSetter(object, (String) propKey, enumerable, fd, cx); } else { EvaluatePropertyDefinitionSetter(object, (Symbol) propKey, enumerable, fd, cx); } } /** * 14.3 Method Definitions * <p> * 14.3.9 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>set PropertyName ( PropertySetParameterList ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionSetter(OrdinaryObject object, String propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-3 (generated code) */ /* step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 5 */ OrdinaryFunction closure = FunctionCreate(cx, FunctionKind.Method, fd, scope); /* step 6 */ MakeMethod(closure, object); /* steps 7-8 */ SetFunctionName(closure, propKey, "set"); /* step 9 */ PropertyDescriptor desc = AccessorPropertyDescriptor(null, closure, enumerable, true); /* step 10 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * 14.3 Method Definitions * <p> * 14.3.9 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>set PropertyName ( PropertySetParameterList ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionSetter(OrdinaryObject object, Symbol propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-3 (generated code) */ /* step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 5 */ OrdinaryFunction closure = FunctionCreate(cx, FunctionKind.Method, fd, scope); /* step 6 */ MakeMethod(closure, object); /* steps 7-8 */ SetFunctionName(closure, propKey, "set"); /* step 9 */ PropertyDescriptor desc = AccessorPropertyDescriptor(null, closure, enumerable, true); /* step 10 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * 14.4 Generator Function Definitions * <p> * 14.4.12 Runtime Semantics: InstantiateFunctionObject * * @param scope * the current lexical scope * @param cx * the execution context * @param fd * the function runtime info object * @return the new generator function instance */ public static OrdinaryConstructorGenerator InstantiateConstructorGeneratorObject(LexicalEnvironment<?> scope, ExecutionContext cx, RuntimeInfo.Function fd) { /* step 1 (not applicable) */ /* step 2 */ String name = fd.functionName(); /* step 3 */ OrdinaryConstructorGenerator f = ConstructorGeneratorFunctionCreate(cx, FunctionKind.Normal, fd, scope); /* step 4 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype); /* step 5 */ MakeConstructor(f, true, prototype); /* step 6 */ SetFunctionName(f, name); /* step 7 */ return f; } /** * 14.4 Generator Function Definitions * <p> * 14.4.12 Runtime Semantics: InstantiateFunctionObject * * @param scope * the current lexical scope * @param cx * the execution context * @param fd * the function runtime info object * @return the new generator function instance */ public static OrdinaryGenerator InstantiateGeneratorObject(LexicalEnvironment<?> scope, ExecutionContext cx, RuntimeInfo.Function fd) { /* step 1 (not applicable) */ /* step 2 */ String name = fd.functionName(); /* step 3 */ OrdinaryGenerator f = GeneratorFunctionCreate(cx, FunctionKind.Normal, fd, scope); /* step 4 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype); /* step 5 */ f.infallibleDefineOwnProperty("prototype", new Property(prototype, true, false, false)); /* step 6 */ SetFunctionName(f, name); /* step 7 */ return f; } /** * 14.4 Generator Function Definitions * <p> * 14.4.12 Runtime Semantics: InstantiateFunctionObject * * @param scope * the current lexical scope * @param cx * the execution context * @param fd * the function runtime info object * @return the new generator function instance */ public static OrdinaryConstructorGenerator InstantiateLegacyGeneratorObject(LexicalEnvironment<?> scope, ExecutionContext cx, RuntimeInfo.Function fd) { /* step 1 (not applicable) */ /* step 2 */ String name = fd.functionName(); /* step 3 */ OrdinaryConstructorGenerator f = ConstructorGeneratorFunctionCreate(cx, FunctionKind.Normal, fd, scope); /* step 4 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.LegacyGeneratorPrototype); /* step 5 */ MakeConstructor(f, true, prototype); /* step 6 */ SetFunctionName(f, name); /* step 7 */ return f; } /** * 14.4 Generator Function Definitions * <p> * 14.4.13 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>GeneratorMethod : * PropertyName ( StrictFormalParameters ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionConstructorGenerator(OrdinaryObject object, Object propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { if (propKey instanceof String) { EvaluatePropertyDefinitionConstructorGenerator(object, (String) propKey, enumerable, fd, cx); } else { EvaluatePropertyDefinitionConstructorGenerator(object, (Symbol) propKey, enumerable, fd, cx); } } /** * 14.4 Generator Function Definitions * <p> * 14.4.13 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>GeneratorMethod : * PropertyName ( StrictFormalParameters ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionConstructorGenerator(OrdinaryObject object, String propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-2 (bytecode) */ /* step 3 (not applicable) */ /* step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 5 */ OrdinaryConstructorGenerator closure = ConstructorGeneratorFunctionCreate(cx, FunctionKind.Method, fd, scope); /* step 6 */ MakeMethod(closure, object); /* step 7 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype); /* step 8 */ MakeConstructor(closure, true, prototype); /* step 9 */ SetFunctionName(closure, propKey); /* step 10 */ PropertyDescriptor desc = new PropertyDescriptor(closure, true, enumerable, true); /* step 11 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * 14.4 Generator Function Definitions * <p> * 14.4.13 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>GeneratorMethod : * PropertyName ( StrictFormalParameters ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionConstructorGenerator(OrdinaryObject object, Symbol propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-2 (bytecode) */ /* step 3 (not applicable) */ /* step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 5 */ OrdinaryConstructorGenerator closure = ConstructorGeneratorFunctionCreate(cx, FunctionKind.Method, fd, scope); /* step 6 */ MakeMethod(closure, object); /* step 7 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype); /* step 8 */ MakeConstructor(closure, true, prototype); /* step 9 */ SetFunctionName(closure, propKey); /* step 10 */ PropertyDescriptor desc = new PropertyDescriptor(closure, true, enumerable, true); /* step 11 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * 14.4 Generator Function Definitions * <p> * 14.4.13 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>GeneratorMethod : * PropertyName ( StrictFormalParameters ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionGenerator(OrdinaryObject object, Object propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { if (propKey instanceof String) { EvaluatePropertyDefinitionGenerator(object, (String) propKey, enumerable, fd, cx); } else { EvaluatePropertyDefinitionGenerator(object, (Symbol) propKey, enumerable, fd, cx); } } /** * 14.4 Generator Function Definitions * <p> * 14.4.13 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>GeneratorMethod : * PropertyName ( StrictFormalParameters ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionGenerator(OrdinaryObject object, String propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-2 (bytecode) */ /* step 3 (not applicable) */ /* step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 5 */ OrdinaryGenerator closure = GeneratorFunctionCreate(cx, FunctionKind.Method, fd, scope); /* step 6 */ MakeMethod(closure, object); /* step 7 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype); /* step 8 */ closure.infallibleDefineOwnProperty("prototype", new Property(prototype, true, false, false)); /* step 9 */ SetFunctionName(closure, propKey); /* step 10 */ PropertyDescriptor desc = new PropertyDescriptor(closure, true, enumerable, true); /* step 11 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * 14.4 Generator Function Definitions * <p> * 14.4.13 Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>GeneratorMethod : * PropertyName ( StrictFormalParameters ) { FunctionBody } * </ul> * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionGenerator(OrdinaryObject object, Symbol propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-2 (bytecode) */ /* step 3 (not applicable) */ /* step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 5 */ OrdinaryGenerator closure = GeneratorFunctionCreate(cx, FunctionKind.Method, fd, scope); /* step 6 */ MakeMethod(closure, object); /* step 7 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype); /* step 8 */ closure.infallibleDefineOwnProperty("prototype", new Property(prototype, true, false, false)); /* step 9 */ SetFunctionName(closure, propKey); /* step 10 */ PropertyDescriptor desc = new PropertyDescriptor(closure, true, enumerable, true); /* step 11 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * 14.4 Generator Function Definitions * <p> * 14.4.14 Runtime Semantics: Evaluation * <ul> * <li>GeneratorExpression: function* ( FormalParameters ) { FunctionBody } * <li>GeneratorExpression: function* BindingIdentifier ( FormalParameters ) { FunctionBody } * </ul> * * @param fd * the function runtime info object * @param cx * the execution context * @return the new generator function instance */ public static OrdinaryConstructorGenerator EvaluateConstructorGeneratorExpression(RuntimeInfo.Function fd, ExecutionContext cx) { OrdinaryConstructorGenerator closure; if (!fd.is(RuntimeInfo.FunctionFlags.ScopedName)) { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ closure = ConstructorGeneratorFunctionCreate(cx, FunctionKind.Normal, fd, scope); /* step 4 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype); /* step 5 */ MakeConstructor(closure, true, prototype); } else { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ LexicalEnvironment<DeclarativeEnvironmentRecord> funcEnv = newDeclarativeEnvironment(scope); /* step 4 */ DeclarativeEnvironmentRecord envRec = funcEnv.getEnvRec(); /* step 5 */ String name = fd.functionName(); /* step 6 */ envRec.createImmutableBinding(name, false); /* step 7 */ closure = ConstructorGeneratorFunctionCreate(cx, FunctionKind.Normal, fd, funcEnv); /* step 8 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype); /* step 9 */ MakeConstructor(closure, true, prototype); /* step 10 */ SetFunctionName(closure, name); /* step 11 */ envRec.initializeBinding(name, closure); } /* step 6/12 */ return closure; } /** * 14.4 Generator Function Definitions * <p> * 14.4.14 Runtime Semantics: Evaluation * <ul> * <li>GeneratorExpression: function* ( FormalParameters ) { FunctionBody } * <li>GeneratorExpression: function* BindingIdentifier ( FormalParameters ) { FunctionBody } * </ul> * * @param fd * the function runtime info object * @param cx * the execution context * @return the new generator function instance */ public static OrdinaryGenerator EvaluateGeneratorExpression(RuntimeInfo.Function fd, ExecutionContext cx) { OrdinaryGenerator closure; if (!fd.is(RuntimeInfo.FunctionFlags.ScopedName)) { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ closure = GeneratorFunctionCreate(cx, FunctionKind.Normal, fd, scope); /* step 4 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype); /* step 5 */ closure.infallibleDefineOwnProperty("prototype", new Property(prototype, true, false, false)); } else { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ LexicalEnvironment<DeclarativeEnvironmentRecord> funcEnv = newDeclarativeEnvironment(scope); /* step 4 */ DeclarativeEnvironmentRecord envRec = funcEnv.getEnvRec(); /* step 5 */ String name = fd.functionName(); /* step 6 */ envRec.createImmutableBinding(name, false); /* step 7 */ closure = GeneratorFunctionCreate(cx, FunctionKind.Normal, fd, funcEnv); /* step 8 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype); /* step 9 */ closure.infallibleDefineOwnProperty("prototype", new Property(prototype, true, false, false)); /* step 10 */ SetFunctionName(closure, name); /* step 11 */ envRec.initializeBinding(name, closure); } /* step 6/12 */ return closure; } /** * 14.4 Generator Function Definitions * <p> * 14.4.14 Runtime Semantics: Evaluation * <ul> * <li>GeneratorExpression: function* ( FormalParameters ) { FunctionBody } * <li>GeneratorExpression: function* BindingIdentifier ( FormalParameters ) { FunctionBody } * </ul> * * @param fd * the function runtime info object * @param cx * the execution context * @return the new generator function instance */ public static OrdinaryConstructorGenerator EvaluateLegacyGeneratorExpression(RuntimeInfo.Function fd, ExecutionContext cx) { OrdinaryConstructorGenerator closure; if (!fd.is(RuntimeInfo.FunctionFlags.ScopedName)) { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ closure = ConstructorGeneratorFunctionCreate(cx, FunctionKind.Normal, fd, scope); /* step 4 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.LegacyGeneratorPrototype); /* step 5 */ MakeConstructor(closure, true, prototype); } else { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 2 */ LexicalEnvironment<DeclarativeEnvironmentRecord> funcEnv = newDeclarativeEnvironment(scope); /* step 4 */ DeclarativeEnvironmentRecord envRec = funcEnv.getEnvRec(); /* step 5 */ String name = fd.functionName(); /* step 6 */ envRec.createImmutableBinding(name, false); /* step 7 */ closure = ConstructorGeneratorFunctionCreate(cx, FunctionKind.Normal, fd, funcEnv); /* step 8 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.LegacyGeneratorPrototype); /* step 9 */ MakeConstructor(closure, true, prototype); /* step 10 */ SetFunctionName(closure, name); /* step 11 */ envRec.initializeBinding(name, closure); } /* step 6/12 */ return closure; } /** * 14.4 Generator Function Definitions * <p> * 14.4.14 Runtime Semantics: Evaluation * <ul> * <li>YieldExpression : yield * AssignmentExpression * </ul> * * @param cx * the execution context * @param iterator * the iterator object * @param e * the script exception * @return the {@code throw} method result value */ public static ScriptObject yieldThrowCompletion(ExecutionContext cx, ScriptObject iterator, ScriptException e) { /* step 6.b */ /* steps 6.b.i-ii */ Callable throwMethod = GetMethod(cx, iterator, "throw"); /* steps 6.b.iii-iv */ if (throwMethod != null) { /* step 6.b.iii */ /* steps 6.b.iii.1-3 */ Object innerThrowResult = throwMethod.call(cx, iterator, e.getValue()); /* step 6.b.iii.4 */ return requireObjectResult(innerThrowResult, "throw", cx); } else { /* step 6.b.iv */ /* steps 6.b.iv.1-3 */ IteratorClose(cx, iterator); /* steps 6.b.iv.4-5 */ throw reportPropertyNotCallable("throw", cx); } } /** * 14.4 Generator Function Definitions * <p> * 14.4.14 Runtime Semantics: Evaluation * <ul> * <li>YieldExpression : yield * AssignmentExpression * </ul> * * @param cx * the execution context * @param iterator * the iterator object * @param e * the return value wrapper * @return the {@code return} method result value or {@code null} */ public static ScriptObject yieldReturnCompletion(ExecutionContext cx, ScriptObject iterator, ReturnValue e) { /* step 6.c */ /* steps 6.c.i-iii */ Callable returnMethod = GetMethod(cx, iterator, "return"); /* step 6.c.iv */ if (returnMethod == null) { return null; } /* steps 6.c.v-vi */ Object innerReturnResult = returnMethod.call(cx, iterator, e.getValue()); /* step 6.c.vii */ return requireObjectResult(innerReturnResult, "return", cx); } public static ScriptObject requireObjectResult(Object resultValue, String methodName, ExecutionContext cx) { if (!Type.isObject(resultValue)) { throw newTypeError(cx, Messages.Key.NotObjectTypeReturned, methodName); } return Type.objectValue(resultValue); } public static ScriptException reportPropertyNotCallable(String methodName, ExecutionContext cx) { throw newTypeError(cx, Messages.Key.PropertyNotCallable, methodName); } public static CallSite runtimeBootstrap(MethodHandles.Lookup caller, String name, MethodType type) { assert "rt:stack".equals(name) || "rt:locals".equals(name); MethodHandle mh = MethodHandles.identity(Object[].class); mh = mh.asCollector(Object[].class, type.parameterCount()); mh = mh.asType(type); return new ConstantCallSite(mh); } /** * Extension: 'function.sent' meta property * * @param cx * the execution context * @return the last yield value */ public static Object functionSent(ExecutionContext cx) { return cx.getCurrentGenerator().getLastYieldValue(); } /** * 14.5 Class Definitions * <p> * 14.5.14 Runtime Semantics: ClassDefinitionEvaluation * * @param cx * the execution context * @return the tuple (prototype, constructorParent) */ public static ScriptObject[] getDefaultClassProto(ExecutionContext cx) { // step 5 ScriptObject protoParent = cx.getIntrinsic(Intrinsics.ObjectPrototype); ScriptObject constructorParent = cx.getIntrinsic(Intrinsics.FunctionPrototype); // step 7 OrdinaryObject proto = ObjectCreate(cx, protoParent); return new ScriptObject[] { constructorParent, proto }; } /** * 14.5 Class Definitions * <p> * 14.5.14 Runtime Semantics: ClassDefinitionEvaluation * * @param cx * the execution context * @return the tuple (prototype, constructorParent) */ public static ScriptObject[] getClassProto(ExecutionContext cx) { // step 6 ScriptObject protoParent = null; ScriptObject constructorParent = cx.getIntrinsic(Intrinsics.FunctionPrototype); // step 7 OrdinaryObject proto = ObjectCreate(cx, protoParent); return new ScriptObject[] { constructorParent, proto }; } /** * 14.5 Class Definitions * <p> * 14.5.14 Runtime Semantics: ClassDefinitionEvaluation * * @param superClass * the super class object * @param cx * the execution context * @return the tuple (prototype, constructorParent) */ public static ScriptObject[] getClassProto(Object superClass, ExecutionContext cx) { ScriptObject protoParent; ScriptObject constructorParent; // step 6 if (Type.isNull(superClass)) { protoParent = null; constructorParent = cx.getIntrinsic(Intrinsics.FunctionPrototype); } else if (!IsConstructor(superClass)) { throw newTypeError(cx, Messages.Key.NotConstructor); } else { Constructor superClassObj = (Constructor) superClass; if (superClassObj instanceof OrdinaryConstructorGenerator) { throw newTypeError(cx, Messages.Key.InvalidSuperClass); } Object p = Get(cx, superClassObj, "prototype"); if (!Type.isObjectOrNull(p)) { throw newTypeError(cx, Messages.Key.NotObjectOrNull); } protoParent = Type.objectValueOrNull(p); constructorParent = superClassObj; } // step 7 OrdinaryObject proto = ObjectCreate(cx, protoParent); return new ScriptObject[] { constructorParent, proto }; } /** * Extension: Async Function Definitions * * @param scope * the current lexical scope * @param cx * the execution context * @param fd * the function runtime info object * @return the new async function instance */ public static OrdinaryAsyncFunction InstantiateAsyncFunctionObject(LexicalEnvironment<?> scope, ExecutionContext cx, RuntimeInfo.Function fd) { /* step 1 (not applicable) */ /* step 2 */ String name = fd.functionName(); /* step 3 */ OrdinaryAsyncFunction f = AsyncFunctionCreate(cx, FunctionKind.Normal, fd, scope); /* step 4 */ SetFunctionName(f, name); /* step 5 */ return f; } /** * Extension: Async Function Definitions * * @param fd * the function runtime info object * @param cx * the execution context * @return the new async function instance */ public static OrdinaryAsyncFunction EvaluateAsyncFunctionExpression(RuntimeInfo.Function fd, ExecutionContext cx) { OrdinaryAsyncFunction closure; if (!fd.is(RuntimeInfo.FunctionFlags.ScopedName)) { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ closure = AsyncFunctionCreate(cx, FunctionKind.Normal, fd, scope); } else { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ LexicalEnvironment<DeclarativeEnvironmentRecord> funcEnv = newDeclarativeEnvironment(scope); /* step 4 */ DeclarativeEnvironmentRecord envRec = funcEnv.getEnvRec(); /* step 5 */ String name = fd.functionName(); /* step 6 */ envRec.createImmutableBinding(name, false); /* step 7 */ closure = AsyncFunctionCreate(cx, FunctionKind.Normal, fd, funcEnv); /* step 8 */ SetFunctionName(closure, name); /* step 9 */ envRec.initializeBinding(name, closure); } /* step 4/10 */ return closure; } /** * Extension: Async Function Definitions * * @param fd * the function runtime info object * @param cx * the execution context * @return the new async function instance */ public static OrdinaryAsyncFunction EvaluateAsyncArrowFunction(RuntimeInfo.Function fd, ExecutionContext cx) { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* steps 3-4/3-5 */ OrdinaryAsyncFunction closure = AsyncFunctionCreate(cx, FunctionKind.Arrow, fd, scope); /* step 5/6 */ return closure; } /** * Extension: Async Function Definitions * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param cx * the execution context * @param fd * the function runtime info object */ public static void EvaluatePropertyDefinitionAsync(OrdinaryObject object, Object propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { if (propKey instanceof String) { EvaluatePropertyDefinitionAsync(object, (String) propKey, enumerable, fd, cx); } else { EvaluatePropertyDefinitionAsync(object, (Symbol) propKey, enumerable, fd, cx); } } /** * Extension: Async Function Definitions * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param cx * the execution context * @param fd * the function runtime info object */ public static void EvaluatePropertyDefinitionAsync(OrdinaryObject object, String propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-2 (bytecode) */ /* step 3 (not applicable) */ /* step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 5 */ OrdinaryAsyncFunction closure = AsyncFunctionCreate(cx, FunctionKind.Method, fd, scope); /* step 6 */ MakeMethod(closure, object); /* step 7 */ SetFunctionName(closure, propKey); /* step 8 */ PropertyDescriptor desc = new PropertyDescriptor(closure, true, enumerable, true); /* step 9 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * Extension: Async Function Definitions * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionAsync(OrdinaryObject object, Symbol propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-2 (bytecode) */ /* step 3 (not applicable) */ /* step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 5 */ OrdinaryAsyncFunction closure = AsyncFunctionCreate(cx, FunctionKind.Method, fd, scope); /* step 6 */ MakeMethod(closure, object); /* step 7 */ SetFunctionName(closure, propKey); /* step 8 */ PropertyDescriptor desc = new PropertyDescriptor(closure, true, enumerable, true); /* step 9 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * Extension: Async Generator Function Definitions * * @param scope * the current lexical scope * @param cx * the execution context * @param fd * the function runtime info object * @return the new async generator instance */ public static OrdinaryAsyncGenerator InstantiateAsyncGeneratorObject(LexicalEnvironment<?> scope, ExecutionContext cx, RuntimeInfo.Function fd) { /* step 1 (not applicable) */ /* step 2 */ String name = fd.functionName(); /* step 3 */ OrdinaryAsyncGenerator f = AsyncGeneratorFunctionCreate(cx, FunctionKind.Normal, fd, scope); /* step 4 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.AsyncGeneratorPrototype); /* step 5 */ f.infallibleDefineOwnProperty("prototype", new Property(prototype, true, false, false)); /* step 6 */ SetFunctionName(f, name); /* step 7 */ return f; } /** * Extension: Async Generator Function Definitions * * @param fd * the function runtime info object * @param cx * the execution context * @return the new async generator instance */ public static OrdinaryAsyncGenerator EvaluateAsyncGeneratorExpression(RuntimeInfo.Function fd, ExecutionContext cx) { OrdinaryAsyncGenerator closure; if (!fd.is(RuntimeInfo.FunctionFlags.ScopedName)) { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ closure = AsyncGeneratorFunctionCreate(cx, FunctionKind.Normal, fd, scope); /* step 4 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.AsyncGeneratorPrototype); /* step 5 */ closure.infallibleDefineOwnProperty("prototype", new Property(prototype, true, false, false)); } else { /* step 1 (not applicable) */ /* step 2 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 3 */ LexicalEnvironment<DeclarativeEnvironmentRecord> funcEnv = newDeclarativeEnvironment(scope); /* step 4 */ DeclarativeEnvironmentRecord envRec = funcEnv.getEnvRec(); /* step 5 */ String name = fd.functionName(); /* step 6 */ envRec.createImmutableBinding(name, false); /* step 7 */ closure = AsyncGeneratorFunctionCreate(cx, FunctionKind.Normal, fd, funcEnv); /* step 8 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.AsyncGeneratorPrototype); /* step 9 */ closure.infallibleDefineOwnProperty("prototype", new Property(prototype, true, false, false)); /* step 10 */ SetFunctionName(closure, name); /* step 11 */ envRec.initializeBinding(name, closure); } /* step 6/12 */ return closure; } /** * Extension: Async Generator Function Definitions * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param cx * the execution context * @param fd * the function runtime info object */ public static void EvaluatePropertyDefinitionAsyncGenerator(OrdinaryObject object, Object propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { if (propKey instanceof String) { EvaluatePropertyDefinitionAsyncGenerator(object, (String) propKey, enumerable, fd, cx); } else { EvaluatePropertyDefinitionAsyncGenerator(object, (Symbol) propKey, enumerable, fd, cx); } } /** * Extension: Async Generator Function Definitions * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param cx * the execution context * @param fd * the function runtime info object */ public static void EvaluatePropertyDefinitionAsyncGenerator(OrdinaryObject object, String propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-2 (bytecode) */ /* step 3 (not applicable) */ /* step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 5 */ OrdinaryAsyncGenerator closure = AsyncGeneratorFunctionCreate(cx, FunctionKind.Method, fd, scope); /* step 6 */ MakeMethod(closure, object); /* step 7 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.AsyncGeneratorPrototype); /* step 8 */ closure.infallibleDefineOwnProperty("prototype", new Property(prototype, true, false, false)); /* step 9 */ SetFunctionName(closure, propKey); /* step 10 */ PropertyDescriptor desc = new PropertyDescriptor(closure, true, enumerable, true); /* step 11 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * Extension: Async Generator Function Definitions * * @param object * the script object * @param propKey * the property key * @param enumerable * the enumerable property attribute * @param fd * the function runtime info object * @param cx * the execution context */ public static void EvaluatePropertyDefinitionAsyncGenerator(OrdinaryObject object, Symbol propKey, boolean enumerable, RuntimeInfo.Function fd, ExecutionContext cx) { /* steps 1-2 (bytecode) */ /* step 3 (not applicable) */ /* step 4 */ LexicalEnvironment<?> scope = cx.getLexicalEnvironment(); /* step 5 */ OrdinaryAsyncGenerator closure = AsyncGeneratorFunctionCreate(cx, FunctionKind.Method, fd, scope); /* step 6 */ MakeMethod(closure, object); /* step 7 */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.AsyncGeneratorPrototype); /* step 8 */ closure.infallibleDefineOwnProperty("prototype", new Property(prototype, true, false, false)); /* step 9 */ SetFunctionName(closure, propKey); /* step 10 */ PropertyDescriptor desc = new PropertyDescriptor(closure, true, enumerable, true); /* step 11 */ DefinePropertyOrThrow(cx, object, propKey, desc); } /** * Extension: Class Decorators * * @param f * the function object * @param decorators * the list of decorator functions * @param cx * the execution context */ public static void EvaluateClassDecorators(OrdinaryConstructorFunction f, ArrayList<Callable> decorators, ExecutionContext cx) { for (Callable decorator : decorators) { decorator.call(cx, UNDEFINED, f); } } /** * Extension: Method Decorators * * @param object * the script object * @param decorators * the list of method decorators * @param cx * the execution context */ public static void EvaluateMethodDecorators(OrdinaryObject object, ArrayList<Object> decorators, ExecutionContext cx) { // TODO: Deserves clean-up when proper evaluation semantics are specified. // decorators = object, list of <1..n callable, property key> for (int i = 0, size = decorators.size(); i < size;) { int count = evaluateMethodDecorators(object, decorators, i, cx); i += count + 1; } } /** * Extension: Class Method Decorators * * @param decorators * the list of method decorators * @param cx * the execution context */ public static void EvaluateClassMethodDecorators(ArrayList<Object> decorators, ExecutionContext cx) { // TODO: Deserves clean-up when proper evaluation semantics are specified. // decorators = list of <object, 1..n callable, property key> for (int i = 0, size = decorators.size(); i < size;) { OrdinaryObject object = (OrdinaryObject) decorators.get(i); int count = evaluateMethodDecorators(object, decorators, i + 1, cx); i += count + 2; } } private static int evaluateMethodDecorators(OrdinaryObject object, ArrayList<Object> decorators, int start, ExecutionContext cx) { int count = 0; for (int i = start, size = decorators.size(); i < size; ++i, ++count) { if (!(decorators.get(i) instanceof Callable)) break; } assert count > 0; Object propKey = decorators.get(start + count); Property property = object.getOwnProperty(cx, propKey); // Current proposal uses `undefined` instead of the initial property descriptor in, and only // in, object literals. We don't support this distinction between decorators for object and // decorators for class methods. Object desc = FromPropertyDescriptor(cx, property); for (int i = start; i < start + count; ++i) { Callable decorator = (Callable) decorators.get(i); Object result = decorator.call(cx, UNDEFINED, object, propKey, desc); if (Type.isObject(result)) { // So, this means a bad decorator can mess up all following decorators? // Example: `({ @(()=>({})) @((o,p,d)=>{ print(JSON.stringify(d)) }) m() {} })` desc = result; } } if (Type.isObject(desc)) { PropertyDescriptor pdesc = ToPropertyDescriptor(cx, desc); DefinePropertyOrThrow(cx, object, propKey, pdesc); } return count; } /** * Extension: Object Spread Initializer * <p> * Runtime Semantics: PropertyDefinitionEvaluation * <ul> * <li>PropertyDefinition : ... AssignmentExpression * </ul> * * @param object * the script object * @param value * the spread value * @param cx * the execution context */ public static void defineSpreadProperty(OrdinaryObject object, Object value, ExecutionContext cx) { CopyDataProperties(cx, object, value, Collections.EMPTY_SET); } /** * Extension: Object Rest Destructuring * <ul> * <li>Runtime Semantics: DestructuringAssignmentEvaluation * <li>Runtime Semantics: BindingInitialization * </ul> * * @param value * the rest property * @param excludedNames * the excluded property names * @param cx * the execution context * @return the rest object */ public static OrdinaryObject createRestObject(Object value, Set<?> excludedNames, ExecutionContext cx) { OrdinaryObject restObj = ObjectCreate(cx, Intrinsics.ObjectPrototype); return CopyDataProperties(cx, restObj, value, excludedNames); } /** * 14.6 Tail Position Calls * <p> * 14.6.1 Runtime Semantics: PrepareForTailCall * * @param args * the function arguments * @param thisValue * the function this-value * @param function * the tail call function * @return the tail call trampoline object */ public static Object PrepareForTailCall(Callable function, Object thisValue, Object[] args) { return newTailCallInvocation(function, thisValue, args); } // Called from generated code public static Object PrepareForTailCall(Callable function, ExecutionContext cx, Object thisValue, Object[] args) { return newTailCallInvocation(function, thisValue, args); } // Called from generated code public static Object PrepareForTailCall(Object function, ExecutionContext cx, Object thisValue, Object[] args) { return newTailCallInvocation(CheckCallable(function, cx), thisValue, args); } /* ***************************************************************************************** */ /** * B.3.1 __proto___ Property Names in Object Initializers * * @param object * the object instance * @param value * the new prototype * @param cx * the execution context */ public static void defineProtoProperty(OrdinaryObject object, Object value, ExecutionContext cx) { if (Type.isObjectOrNull(value)) { object.setPrototypeOf(cx, Type.objectValueOrNull(value)); } } }