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, DONT_ENUM);
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    "AddBoundMethod",
185    "ArrayToString",
186    "AsyncFunctionNext",
187    "AsyncFunctionThrow",
188    "ErrorToString",
189    "GetIterator",
190    "GetMethod",
191    "IntlParseDate",
192    "IntlParseNumber",
193    "IsNaN",
194    "MakeError",
195    "MakeRangeError",
196    "MakeTypeError",
197    "MapEntries",
198    "MapIterator",
199    "MapIteratorNext",
200    "MaxSimple",
201    "MinSimple",
202    "NumberIsInteger",
203    "PromiseChain",
204    "PromiseDefer",
205    "PromiseAccept",
206    "PromiseCreateRejected",
207    "PromiseCreateResolved",
208    "PromiseThen",
209    "RegExpSubclassExecJS",
210    "RegExpSubclassMatch",
211    "RegExpSubclassReplace",
212    "RegExpSubclassSearch",
213    "RegExpSubclassSplit",
214    "RegExpSubclassTest",
215    "SetIterator",
216    "SetIteratorNext",
217    "SetValues",
218    "SymbolToString",
219    "ToLocaleLowerCaseI18N",
220    "ToLocaleUpperCaseI18N",
221    "ToLowerCaseI18N",
222    "ToPositiveInteger",
223    "ToUpperCaseI18N",
224    // From runtime:
225    "is_concat_spreadable_symbol",
226    "iterator_symbol",
227    "promise_result_symbol",
228    "promise_state_symbol",
229    "object_freeze",
230    "object_is_frozen",
231    "object_is_sealed",
232    "reflect_apply",
233    "reflect_construct",
234    "regexp_flags_symbol",
235    "to_string_tag_symbol",
236    "object_to_string",
237    "species_symbol",
238    "match_symbol",
239    "replace_symbol",
240    "search_symbol",
241    "split_symbol",
242  ];
243
244  var filtered_exports = {};
245  %OptimizeObjectForAddingMultipleProperties(
246      filtered_exports, expose_list.length);
247  for (var key of expose_list) {
248    filtered_exports[key] = exports_container[key];
249  }
250  %ToFastProperties(filtered_exports);
251  exports_container = filtered_exports;
252
253  utils.PostNatives = UNDEFINED;
254  utils.ImportFromExperimental = UNDEFINED;
255}
256
257
258function PostExperimentals(utils) {
259  %CheckIsBootstrapping();
260  %ExportExperimentalFromRuntime(exports_container);
261  for ( ; !IS_UNDEFINED(imports); imports = imports.next) {
262    imports(exports_container);
263  }
264  for ( ; !IS_UNDEFINED(imports_from_experimental);
265          imports_from_experimental = imports_from_experimental.next) {
266    imports_from_experimental(exports_container);
267  }
268
269  utils.Export = UNDEFINED;
270  utils.PostDebug = UNDEFINED;
271  utils.PostExperimentals = UNDEFINED;
272  typed_array_setup = UNDEFINED;
273}
274
275
276function PostDebug(utils) {
277  for ( ; !IS_UNDEFINED(imports); imports = imports.next) {
278    imports(exports_container);
279  }
280
281  exports_container = UNDEFINED;
282
283  utils.Export = UNDEFINED;
284  utils.Import = UNDEFINED;
285  utils.ImportNow = UNDEFINED;
286  utils.PostDebug = UNDEFINED;
287  utils.PostExperimentals = UNDEFINED;
288  typed_array_setup = UNDEFINED;
289}
290
291
292function InitializeBuiltinTypedArrays(utils, rng_state, rempio2result) {
293  var setup_list =  typed_array_setup;
294
295  for ( ; !IS_UNDEFINED(setup_list); setup_list = setup_list.next) {
296    setup_list(rng_state, rempio2result);
297  }
298}
299
300
301// -----------------------------------------------------------------------
302
303%OptimizeObjectForAddingMultipleProperties(utils, 14);
304
305utils.Import = Import;
306utils.ImportNow = ImportNow;
307utils.Export = Export;
308utils.ImportFromExperimental = ImportFromExperimental;
309utils.SetFunctionName = SetFunctionName;
310utils.InstallConstants = InstallConstants;
311utils.InstallFunctions = InstallFunctions;
312utils.InstallGetter = InstallGetter;
313utils.InstallGetterSetter = InstallGetterSetter;
314utils.OverrideFunction = OverrideFunction;
315utils.SetUpLockedPrototype = SetUpLockedPrototype;
316utils.PostNatives = PostNatives;
317utils.PostExperimentals = PostExperimentals;
318utils.PostDebug = PostDebug;
319
320%ToFastProperties(utils);
321
322// -----------------------------------------------------------------------
323
324%OptimizeObjectForAddingMultipleProperties(extrasUtils, 5);
325
326extrasUtils.logStackTrace = function logStackTrace() {
327  %DebugTrace();
328};
329
330extrasUtils.log = function log() {
331  let message = '';
332  for (const arg of arguments) {
333    message += arg;
334  }
335
336  %GlobalPrint(message);
337};
338
339// Extras need the ability to store private state on their objects without
340// exposing it to the outside world.
341
342extrasUtils.createPrivateSymbol = function createPrivateSymbol(name) {
343  return %CreatePrivateSymbol(name);
344};
345
346// These functions are key for safe meta-programming:
347// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
348//
349// Technically they could all be derived from combinations of
350// Function.prototype.{bind,call,apply} but that introduces lots of layers of
351// indirection and slowness given how un-optimized bind is.
352
353extrasUtils.simpleBind = function simpleBind(func, thisArg) {
354  return function(...args) {
355    return %reflect_apply(func, thisArg, args);
356  };
357};
358
359extrasUtils.uncurryThis = function uncurryThis(func) {
360  return function(thisArg, ...args) {
361    return %reflect_apply(func, thisArg, args);
362  };
363};
364
365%ToFastProperties(extrasUtils);
366
367})
368