// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. (function(global, utils, extrasUtils) { "use strict"; %CheckIsBootstrapping(); // ----------------------------------------------------------------------- // Utils var imports = UNDEFINED; var imports_from_experimental = UNDEFINED; var exports_container = %ExportFromRuntime({}); var typed_array_setup = UNDEFINED; // Register context value to be initialized with a typed array in // Genesis::InitializeBuiltinTypedArrays. function SetupTypedArray(f) { f.next = typed_array_setup; typed_array_setup = f; } // Export to other scripts. // In normal natives, this exports functions to other normal natives. // In experimental natives, this exports to other experimental natives and // to normal natives that import using utils.ImportFromExperimental. function Export(f) { f(exports_container); } // Import from other scripts. The actual importing happens in PostNatives and // PostExperimental so that we can import from scripts executed later. However, // that means that the import is not available until the very end. If the // import needs to be available immediate, use ImportNow. // In normal natives, this imports from other normal natives. // In experimental natives, this imports from other experimental natives and // whitelisted exports from normal natives. function Import(f) { f.next = imports; imports = f; } // Import immediately from exports of previous scripts. We need this for // functions called during bootstrapping. Hooking up imports in PostNatives // would be too late. function ImportNow(name) { return exports_container[name]; } // In normal natives, import from experimental natives. // Not callable from experimental natives. function ImportFromExperimental(f) { f.next = imports_from_experimental; imports_from_experimental = f; } function SetFunctionName(f, name, prefix) { if (IS_SYMBOL(name)) { name = "[" + %SymbolDescription(name) + "]"; } if (IS_UNDEFINED(prefix)) { %FunctionSetName(f, name); } else { %FunctionSetName(f, prefix + " " + name); } } function InstallConstants(object, constants) { %CheckIsBootstrapping(); %OptimizeObjectForAddingMultipleProperties(object, constants.length >> 1); var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY; for (var i = 0; i < constants.length; i += 2) { var name = constants[i]; var k = constants[i + 1]; %AddNamedProperty(object, name, k, attributes); } %ToFastProperties(object); } function InstallFunctions(object, attributes, functions) { %CheckIsBootstrapping(); %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1); for (var i = 0; i < functions.length; i += 2) { var key = functions[i]; var f = functions[i + 1]; SetFunctionName(f, key); %FunctionRemovePrototype(f); %AddNamedProperty(object, key, f, attributes); %SetNativeFlag(f); } %ToFastProperties(object); } // Helper function to install a getter-only accessor property. function InstallGetter(object, name, getter, attributes, prefix) { %CheckIsBootstrapping(); if (IS_UNDEFINED(attributes)) attributes = DONT_ENUM; SetFunctionName(getter, name, IS_UNDEFINED(prefix) ? "get" : prefix); %FunctionRemovePrototype(getter); %DefineGetterPropertyUnchecked(object, name, getter, attributes); %SetNativeFlag(getter); } // Helper function to install a getter/setter accessor property. function InstallGetterSetter(object, name, getter, setter, attributes) { %CheckIsBootstrapping(); if (IS_UNDEFINED(attributes)) attributes = DONT_ENUM; SetFunctionName(getter, name, "get"); SetFunctionName(setter, name, "set"); %FunctionRemovePrototype(getter); %FunctionRemovePrototype(setter); %DefineAccessorPropertyUnchecked(object, name, getter, setter, DONT_ENUM); %SetNativeFlag(getter); %SetNativeFlag(setter); } function OverrideFunction(object, name, f, afterInitialBootstrap) { %CheckIsBootstrapping(); %object_define_property(object, name, { value: f, writeable: true, configurable: true, enumerable: false }); SetFunctionName(f, name); if (!afterInitialBootstrap) %FunctionRemovePrototype(f); %SetNativeFlag(f); } // Prevents changes to the prototype of a built-in function. // The "prototype" property of the function object is made non-configurable, // and the prototype object is made non-extensible. The latter prevents // changing the __proto__ property. function SetUpLockedPrototype( constructor, fields, methods) { %CheckIsBootstrapping(); var prototype = constructor.prototype; // Install functions first, because this function is used to initialize // PropertyDescriptor itself. var property_count = (methods.length >> 1) + (fields ? fields.length : 0); if (property_count >= 4) { %OptimizeObjectForAddingMultipleProperties(prototype, property_count); } if (fields) { for (var i = 0; i < fields.length; i++) { %AddNamedProperty(prototype, fields[i], UNDEFINED, DONT_ENUM | DONT_DELETE); } } for (var i = 0; i < methods.length; i += 2) { var key = methods[i]; var f = methods[i + 1]; %AddNamedProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY); %SetNativeFlag(f); } %InternalSetPrototype(prototype, null); %ToFastProperties(prototype); } // ----------------------------------------------------------------------- // To be called by bootstrapper function PostNatives(utils) { %CheckIsBootstrapping(); for ( ; !IS_UNDEFINED(imports); imports = imports.next) { imports(exports_container); } // Whitelist of exports from normal natives to experimental natives and debug. var expose_list = [ "AddBoundMethod", "ArrayToString", "AsyncFunctionNext", "AsyncFunctionThrow", "ErrorToString", "GetIterator", "GetMethod", "IntlParseDate", "IntlParseNumber", "IsNaN", "MakeError", "MakeRangeError", "MakeTypeError", "MapEntries", "MapIterator", "MapIteratorNext", "MaxSimple", "MinSimple", "NumberIsInteger", "PromiseChain", "PromiseDefer", "PromiseAccept", "PromiseCreateRejected", "PromiseCreateResolved", "PromiseThen", "RegExpSubclassExecJS", "RegExpSubclassMatch", "RegExpSubclassReplace", "RegExpSubclassSearch", "RegExpSubclassSplit", "RegExpSubclassTest", "SetIterator", "SetIteratorNext", "SetValues", "SymbolToString", "ToLocaleLowerCaseI18N", "ToLocaleUpperCaseI18N", "ToLowerCaseI18N", "ToPositiveInteger", "ToUpperCaseI18N", // From runtime: "is_concat_spreadable_symbol", "iterator_symbol", "promise_result_symbol", "promise_state_symbol", "object_freeze", "object_is_frozen", "object_is_sealed", "reflect_apply", "reflect_construct", "regexp_flags_symbol", "to_string_tag_symbol", "object_to_string", "species_symbol", "match_symbol", "replace_symbol", "search_symbol", "split_symbol", ]; var filtered_exports = {}; %OptimizeObjectForAddingMultipleProperties( filtered_exports, expose_list.length); for (var key of expose_list) { filtered_exports[key] = exports_container[key]; } %ToFastProperties(filtered_exports); exports_container = filtered_exports; utils.PostNatives = UNDEFINED; utils.ImportFromExperimental = UNDEFINED; } function PostExperimentals(utils) { %CheckIsBootstrapping(); %ExportExperimentalFromRuntime(exports_container); for ( ; !IS_UNDEFINED(imports); imports = imports.next) { imports(exports_container); } for ( ; !IS_UNDEFINED(imports_from_experimental); imports_from_experimental = imports_from_experimental.next) { imports_from_experimental(exports_container); } utils.Export = UNDEFINED; utils.PostDebug = UNDEFINED; utils.PostExperimentals = UNDEFINED; typed_array_setup = UNDEFINED; } function PostDebug(utils) { for ( ; !IS_UNDEFINED(imports); imports = imports.next) { imports(exports_container); } exports_container = UNDEFINED; utils.Export = UNDEFINED; utils.Import = UNDEFINED; utils.ImportNow = UNDEFINED; utils.PostDebug = UNDEFINED; utils.PostExperimentals = UNDEFINED; typed_array_setup = UNDEFINED; } function InitializeBuiltinTypedArrays(utils, rng_state, rempio2result) { var setup_list = typed_array_setup; for ( ; !IS_UNDEFINED(setup_list); setup_list = setup_list.next) { setup_list(rng_state, rempio2result); } } // ----------------------------------------------------------------------- %OptimizeObjectForAddingMultipleProperties(utils, 14); utils.Import = Import; utils.ImportNow = ImportNow; utils.Export = Export; utils.ImportFromExperimental = ImportFromExperimental; utils.SetFunctionName = SetFunctionName; utils.InstallConstants = InstallConstants; utils.InstallFunctions = InstallFunctions; utils.InstallGetter = InstallGetter; utils.InstallGetterSetter = InstallGetterSetter; utils.OverrideFunction = OverrideFunction; utils.SetUpLockedPrototype = SetUpLockedPrototype; utils.PostNatives = PostNatives; utils.PostExperimentals = PostExperimentals; utils.PostDebug = PostDebug; %ToFastProperties(utils); // ----------------------------------------------------------------------- %OptimizeObjectForAddingMultipleProperties(extrasUtils, 5); extrasUtils.logStackTrace = function logStackTrace() { %DebugTrace(); }; extrasUtils.log = function log() { let message = ''; for (const arg of arguments) { message += arg; } %GlobalPrint(message); }; // Extras need the ability to store private state on their objects without // exposing it to the outside world. extrasUtils.createPrivateSymbol = function createPrivateSymbol(name) { return %CreatePrivateSymbol(name); }; // These functions are key for safe meta-programming: // http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming // // Technically they could all be derived from combinations of // Function.prototype.{bind,call,apply} but that introduces lots of layers of // indirection and slowness given how un-optimized bind is. extrasUtils.simpleBind = function simpleBind(func, thisArg) { return function(...args) { return %reflect_apply(func, thisArg, args); }; }; extrasUtils.uncurryThis = function uncurryThis(func) { return function(thisArg, ...args) { return %reflect_apply(func, thisArg, args); }; }; %ToFastProperties(extrasUtils); })