1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5(function(global, utils, extrasUtils) {
6
7"use strict";
8
9%CheckIsBootstrapping();
10
11// -----------------------------------------------------------------------
12// Utils
13
14var imports = UNDEFINED;
15var imports_from_experimental = UNDEFINED;
16var exports_container = %ExportFromRuntime({});
17var typed_array_setup = UNDEFINED;
18
19// Register context value to be initialized with a typed array in
20// Genesis::InitializeBuiltinTypedArrays.
21function SetupTypedArray(f) {
22  f.next = typed_array_setup;
23  typed_array_setup = f;
24}
25
26// Export to other scripts.
27// In normal natives, this exports functions to other normal natives.
28// In experimental natives, this exports to other experimental natives and
29// to normal natives that import using utils.ImportFromExperimental.
30function Export(f) {
31  f(exports_container);
32}
33
34
35// Import from other scripts. The actual importing happens in PostNatives and
36// PostExperimental so that we can import from scripts executed later. However,
37// that means that the import is not available until the very end. If the
38// import needs to be available immediate, use ImportNow.
39// In normal natives, this imports from other normal natives.
40// In experimental natives, this imports from other experimental natives and
41// whitelisted exports from normal natives.
42function Import(f) {
43  f.next = imports;
44  imports = f;
45}
46
47
48// Import immediately from exports of previous scripts. We need this for
49// functions called during bootstrapping. Hooking up imports in PostNatives
50// would be too late.
51function ImportNow(name) {
52  return exports_container[name];
53}
54
55
56// In normal natives, import from experimental natives.
57// Not callable from experimental natives.
58function ImportFromExperimental(f) {
59  f.next = imports_from_experimental;
60  imports_from_experimental = f;
61}
62
63
64function SetFunctionName(f, name, prefix) {
65  if (IS_SYMBOL(name)) {
66    name = "[" + %SymbolDescription(name) + "]";
67  }
68  if (IS_UNDEFINED(prefix)) {
69    %FunctionSetName(f, name);
70  } else {
71    %FunctionSetName(f, prefix + " " + name);
72  }
73}
74
75
76function InstallConstants(object, constants) {
77  %CheckIsBootstrapping();
78  %OptimizeObjectForAddingMultipleProperties(object, constants.length >> 1);
79  var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
80  for (var i = 0; i < constants.length; i += 2) {
81    var name = constants[i];
82    var k = constants[i + 1];
83    %AddNamedProperty(object, name, k, attributes);
84  }
85  %ToFastProperties(object);
86}
87
88
89function InstallFunctions(object, attributes, functions) {
90  %CheckIsBootstrapping();
91  %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
92  for (var i = 0; i < functions.length; i += 2) {
93    var key = functions[i];
94    var f = functions[i + 1];
95    SetFunctionName(f, key);
96    %FunctionRemovePrototype(f);
97    %AddNamedProperty(object, key, f, attributes);
98    %SetNativeFlag(f);
99  }
100  %ToFastProperties(object);
101}
102
103
104// Helper function to install a getter-only accessor property.
105function InstallGetter(object, name, getter, attributes, prefix) {
106  %CheckIsBootstrapping();
107  if (IS_UNDEFINED(attributes)) attributes = DONT_ENUM;
108  SetFunctionName(getter, name, IS_UNDEFINED(prefix) ? "get" : prefix);
109  %FunctionRemovePrototype(getter);
110  %DefineGetterPropertyUnchecked(object, name, getter, attributes);
111  %SetNativeFlag(getter);
112}
113
114
115// Helper function to install a getter/setter accessor property.
116function InstallGetterSetter(object, name, getter, setter, attributes) {
117  %CheckIsBootstrapping();
118  if (IS_UNDEFINED(attributes)) attributes = DONT_ENUM;
119  SetFunctionName(getter, name, "get");
120  SetFunctionName(setter, name, "set");
121  %FunctionRemovePrototype(getter);
122  %FunctionRemovePrototype(setter);
123  %DefineAccessorPropertyUnchecked(object, name, getter, setter, attributes);
124  %SetNativeFlag(getter);
125  %SetNativeFlag(setter);
126}
127
128
129function OverrideFunction(object, name, f, afterInitialBootstrap) {
130  %CheckIsBootstrapping();
131  %object_define_property(object, name, { value: f,
132                                          writeable: true,
133                                          configurable: true,
134                                          enumerable: false });
135  SetFunctionName(f, name);
136  if (!afterInitialBootstrap) %FunctionRemovePrototype(f);
137  %SetNativeFlag(f);
138}
139
140
141// Prevents changes to the prototype of a built-in function.
142// The "prototype" property of the function object is made non-configurable,
143// and the prototype object is made non-extensible. The latter prevents
144// changing the __proto__ property.
145function SetUpLockedPrototype(
146    constructor, fields, methods) {
147  %CheckIsBootstrapping();
148  var prototype = constructor.prototype;
149  // Install functions first, because this function is used to initialize
150  // PropertyDescriptor itself.
151  var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
152  if (property_count >= 4) {
153    %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
154  }
155  if (fields) {
156    for (var i = 0; i < fields.length; i++) {
157      %AddNamedProperty(prototype, fields[i],
158                        UNDEFINED, DONT_ENUM | DONT_DELETE);
159    }
160  }
161  for (var i = 0; i < methods.length; i += 2) {
162    var key = methods[i];
163    var f = methods[i + 1];
164    %AddNamedProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
165    %SetNativeFlag(f);
166  }
167  %InternalSetPrototype(prototype, null);
168  %ToFastProperties(prototype);
169}
170
171
172// -----------------------------------------------------------------------
173// To be called by bootstrapper
174
175function PostNatives(utils) {
176  %CheckIsBootstrapping();
177
178  for ( ; !IS_UNDEFINED(imports); imports = imports.next) {
179    imports(exports_container);
180  }
181
182  // Whitelist of exports from normal natives to experimental natives and debug.
183  var expose_list = [
184    "FormatDateToParts",
185    "MapEntries",
186    "MapIterator",
187    "MapIteratorNext",
188    "MaxSimple",
189    "MinSimple",
190    "SetIterator",
191    "SetIteratorNext",
192    "SetValues",
193    "ToLocaleLowerCaseI18N",
194    "ToLocaleUpperCaseI18N",
195    "ToLowerCaseI18N",
196    "ToUpperCaseI18N",
197    // From runtime:
198    "promise_result_symbol",
199    "promise_state_symbol",
200    "reflect_apply",
201    "to_string_tag_symbol",
202  ];
203
204  var filtered_exports = {};
205  %OptimizeObjectForAddingMultipleProperties(
206      filtered_exports, expose_list.length);
207  for (var key of expose_list) {
208    filtered_exports[key] = exports_container[key];
209  }
210  %ToFastProperties(filtered_exports);
211  exports_container = filtered_exports;
212
213  utils.PostNatives = UNDEFINED;
214  utils.ImportFromExperimental = UNDEFINED;
215}
216
217
218function PostExperimentals(utils) {
219  %CheckIsBootstrapping();
220  %ExportExperimentalFromRuntime(exports_container);
221  for ( ; !IS_UNDEFINED(imports); imports = imports.next) {
222    imports(exports_container);
223  }
224  for ( ; !IS_UNDEFINED(imports_from_experimental);
225          imports_from_experimental = imports_from_experimental.next) {
226    imports_from_experimental(exports_container);
227  }
228
229  utils.Export = UNDEFINED;
230  utils.PostDebug = UNDEFINED;
231  utils.PostExperimentals = UNDEFINED;
232  typed_array_setup = UNDEFINED;
233}
234
235
236function PostDebug(utils) {
237  for ( ; !IS_UNDEFINED(imports); imports = imports.next) {
238    imports(exports_container);
239  }
240
241  exports_container = UNDEFINED;
242
243  utils.Export = UNDEFINED;
244  utils.Import = UNDEFINED;
245  utils.ImportNow = UNDEFINED;
246  utils.PostDebug = UNDEFINED;
247  utils.PostExperimentals = UNDEFINED;
248  typed_array_setup = UNDEFINED;
249}
250
251
252function InitializeBuiltinTypedArrays(utils, rng_state, rempio2result) {
253  var setup_list =  typed_array_setup;
254
255  for ( ; !IS_UNDEFINED(setup_list); setup_list = setup_list.next) {
256    setup_list(rng_state, rempio2result);
257  }
258}
259
260
261// -----------------------------------------------------------------------
262
263%OptimizeObjectForAddingMultipleProperties(utils, 14);
264
265utils.Import = Import;
266utils.ImportNow = ImportNow;
267utils.Export = Export;
268utils.ImportFromExperimental = ImportFromExperimental;
269utils.SetFunctionName = SetFunctionName;
270utils.InstallConstants = InstallConstants;
271utils.InstallFunctions = InstallFunctions;
272utils.InstallGetter = InstallGetter;
273utils.InstallGetterSetter = InstallGetterSetter;
274utils.OverrideFunction = OverrideFunction;
275utils.SetUpLockedPrototype = SetUpLockedPrototype;
276utils.PostNatives = PostNatives;
277utils.PostExperimentals = PostExperimentals;
278utils.PostDebug = PostDebug;
279
280%ToFastProperties(utils);
281
282// -----------------------------------------------------------------------
283
284%OptimizeObjectForAddingMultipleProperties(extrasUtils, 5);
285
286extrasUtils.logStackTrace = function logStackTrace() {
287  %DebugTrace();
288};
289
290extrasUtils.log = function log() {
291  let message = '';
292  for (const arg of arguments) {
293    message += arg;
294  }
295
296  %GlobalPrint(message);
297};
298
299// Extras need the ability to store private state on their objects without
300// exposing it to the outside world.
301
302extrasUtils.createPrivateSymbol = function createPrivateSymbol(name) {
303  return %CreatePrivateSymbol(name);
304};
305
306// These functions are key for safe meta-programming:
307// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
308//
309// Technically they could all be derived from combinations of
310// Function.prototype.{bind,call,apply} but that introduces lots of layers of
311// indirection and slowness given how un-optimized bind is.
312
313extrasUtils.simpleBind = function simpleBind(func, thisArg) {
314  return function(...args) {
315    return %reflect_apply(func, thisArg, args);
316  };
317};
318
319extrasUtils.uncurryThis = function uncurryThis(func) {
320  return function(thisArg, ...args) {
321    return %reflect_apply(func, thisArg, args);
322  };
323};
324
325%ToFastProperties(extrasUtils);
326
327})
328