summaryrefslogtreecommitdiffstats
path: root/js/src/vm/SelfHosting.h
blob: e81cbe97c728cbf47ea5b1a3c9f5d81f42c95bb0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef vm_SelfHosting_h_
#define vm_SelfHosting_h_

#include "NamespaceImports.h"

#include "js/CallNonGenericMethod.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"

// [SMDOC] Self-hosted JS
//
// Self-hosted JS allows implementing a part of the JS engine using JavaScript.
//
// This allows implementing new feature easily, and also enables JIT
// compilation to achieve better performance, for example with higher order
// functions. Self-hosted functions can be inlined in, and optimized with, the
// JS caller functions.
//
// Self-hosted JS code is compiled into a stencil during the initialization of
// the engine, and each function is instantiated into each global on demand.
//
// Self-hosted JS has several differences between regular JavaScript code,
// for performance optimization, security, and some other reasons.
//
// # Always strict mode
//
// Unlike regular JavaScript, self-hosted JS code is always in strict mode.
//
// # Prohibited syntax
//
//   * Regular expression `/foo/` cannot be used
//   * `obj.method(...)` and `obj[method](...)` style call cannot be used.
//      See `callFunction` below
//   * Object literal cannot contain duplicate property names
//   * `yield*` cannot be used
//
// # No lazy parsing
//
// Self-hosted JS does not use lazy/syntax parsing: bytecode is generated
// eagerly for each function. However, we do instantiate the BaseScript lazily
// from the stencil for JSFunctions created for self-hosted built-ins. See
// `SelfHostedLazyScript` and `JSRuntime::selfHostedLazyScript`.
//
// # Extended function
//
// Functions with "$"-prefix in their name are allocated as extended function.
// See "SetCanonicalName" below.
//
// # Intrinsic helper functions
//
// Self-hosted JS has access to special functions that can interact with
// native code or internal representation of JS values and objects.
//
// See `intrinsic_functions` array in SelfHosting.cpp.
//
// # Stack Frame
//
// Stack frame inside self-hosted JS is hidden from Error.prototype.stack by
// default, to hide the internal from user code.
//
// During debugging self-hosted JS code, `MOZ_SHOW_ALL_JS_FRAMES` environment
// variable can be used to expose those frames
//
// # Debugger interaction
//
// Self-hosted JS is hidden from debugger, and no source notes or breakpoint
// is generated.
//
// Most function calls inside self-hosted JS are hidden from Debugger's
// `onNativeCall` hook, except for the following (see below for each):
//   * `callContentFunction`
//   * `constructContentFunction`
//   * `allowContentIter`
//   * `allowContentIterWith`
//   * `allowContentIterWithNext`
//
// # XDR cache
//
// Compiling self-hosted JS code takes some time.
// To improve the startup performance, the bytecode for self-hosted JS code
// can be saved as XDR, and used by other instance. This is used to speed up
// JS shell tests and Firefox content process startup.
//
// See `JSRuntime::initSelfHostingStencil` function.
//
// # Special functions
//
// Self-hosted JS code has special functions, to emit special bytecode
// sequence, or directly operate on internals:
//
//   callFunction(callee, thisV, arg0, ...)
//     Call `callee` function with `thisV` as "this" value, passing
//     arg0, ..., as arguments.
//     This is used when "this" value is not `undefined.
//
//     `obj.method(...)` syntax is forbidden in self-hosted JS, to avoid
//     accidentally exposing the internal, or allowing user code to modify the
//     behavior.
//
//     If the `callee` can be user-provided, `callContentFunction` must be
//     used instead.
//
//   callContentFunction(callee, thisV, arg0, ...)
//     Same as `callFunction`, but this must be used when calling possibly
//     user-provided functions, even if "this" value is `undefined`.
//
//     This exposes function calls to debuggers, using `JSOp::CallContent`
//     opcode.
//
//   constructContentFunction(callee, newTarget, arg0, ...)
//     Construct `callee` function using `newTarget` as `new.target`.
//     This must be used when constructing possibly user-provided functions.
//
//     This exposes constructs to debuggers, using `JSOp::NewContent` opcode.
//
//   allowContentIter(iterable)
//     Iteration such as for-of and spread on user-provided value is
//     prohibited inside self-hosted JS by default.
//
//     `allowContentIter` marks iteration allowed for given possibly
//     user-provided iterable.
//
//     This exposes implicit function calls around iteration to debuggers,
//     using `JSOp::CallContentIter` opcode.
//
//     Used in the following contexts:
//
//       for (var item of allowContentIter(iterable)) { ... }
//       [...allowContentIter(iterable)]
//
//   allowContentIterWith(iterable, iteratorFunc)
//     Special form of `allowContentIter`, where `iterable[Symbol.iterator]` is
//     already retrieved.
//
//     This directly uses `iteratorFunc` instead of accessing
//     `iterable[Symbol.iterator]` again inside for-of bytecode.
//
//     for (var item of allowContentIterWith(iterable, iteratorFunc)) { ... }
//
//   allowContentIterWith(iterator, nextFunc)
//     Special form of `allowContentIter`, where `iterable[Symbol.iterator]()`
//     is already called and the iterator's `next` property retrieved.
//
//     This form doesn't call `iterable[Symbol.iterator]` and directly uses
//     `nextFunc` instead of retrieving it inside for-of bytecode.
//
//     for (var item of allowContentIterWithNext(iterator, nextFunc)) { ... }
//
//   DefineDataProperty(obj, key, value)
//     Initialize `obj`'s `key` property with `value`, like
//    `Object.defineProperty(obj, key, {value})`, using `JSOp::InitElem`
//     opcode. This is almost always better than `obj[key] = value` because it
//     ignores setters and other properties on the prototype chain.
//
//   hasOwn(key, obj)
//     Return `true` if `obj` has an own `key` property, using `JSOp::HasOwn`
//     opcode.
//
//   getPropertySuper(obj, key, receiver)
//     Return `obj.[[Get]](key, receiver)`, using `JSOp::GetElemSuper` opcode.
//
//   ToNumeric(v)
//     Convert `v` to number, using `JSOp::ToNumeric` opcode
//
//   ToString(v)
//     Convert `v` to string, `JSOp::ToString` opcode
//
//   GetBuiltinConstructor(name)
//     Return built-in constructor for `name`, e.g. `"Array"`, using
//     `JSOp::BuiltinObject` opcode.
//
//   GetBuiltinPrototype(name)
//     Return built-in prototype for `name`, e.g. `"RegExp"`, using
//     `JSOp::BuiltinObject` opcode.
//
//   GetBuiltinSymbol(name)
//     Return built-in symbol `Symbol[name]`, using `JSOp::Symbol` opcode.
//
//   SetIsInlinableLargeFunction(fun)
//     Mark the large function `fun` inlineable.
//     `fun` must be the last function declaration before this call.
//
//   SetCanonicalName(fun)
//     Set canonical name for the function `fun`.
//     `fun` must be the last function declaration before this call, and also
//     its function name must be prefixed with "$", to make it extended
//     function and store the original function name in the extended slot.
//
//   UnsafeGetReservedSlot(obj, slot)
//   UnsafeGetObjectFromReservedSlot(obj, slot)
//   UnsafeGetInt32FromReservedSlot(obj, slot)
//   UnsafeGetStringFromReservedSlot(obj, slot)
//   UnsafeGetBooleanFromReservedSlot(obj, slot)
//     Get `obj`'s reserved slot specified by integer value `slot`.
//     They are intrinsic helper functions, and also optimized during JIT
//     compilation.
//
//   UnsafeSetReservedSlot(obj, slot, value)
//     Set `obj`'s reserved slot specified by integer value `slot` to `value`.
//     This is an intrinsic helper function, and also optimized during JIT
//     compilation.
//
//   resumeGenerator(gen, value, kind)
//     Resume generator `gen`, using `kind`, which is one of "next", "throw",
//     or "return", pasing `value` as parameter, using `JSOp::Resume` opcode.
//
//   forceInterpreter()
//     Force interpreter execution for this function, using
//     `JSOp::ForceInterpreter` opcode.
//     This must be the first statement inside the function.

namespace JS {
class JS_PUBLIC_API CompileOptions;
}

namespace js {

class AnyInvokeArgs;
class PropertyName;
class ScriptSourceObject;

ScriptSourceObject* SelfHostingScriptSourceObject(JSContext* cx);

/*
 * Check whether the given JSFunction or Value is a self-hosted function whose
 * self-hosted name is the given name.
 */
bool IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name);
bool IsSelfHostedFunctionWithName(const Value& v, JSAtom* name);

/*
 * Returns the name of the cloned function's binding in the self-hosted global.
 *
 * This returns a non-null value only when this is a top level function
 * declaration in the self-hosted global.
 */
PropertyName* GetClonedSelfHostedFunctionName(const JSFunction* fun);
void SetClonedSelfHostedFunctionName(JSFunction* fun, PropertyName* name);

constexpr char ExtendedUnclonedSelfHostedFunctionNamePrefix = '$';

/*
 * Uncloned self-hosted functions with `$` prefix are allocated as
 * extended function, to store the original name in `_SetCanonicalName`.
 */
bool IsExtendedUnclonedSelfHostedFunctionName(JSAtom* name);

void SetUnclonedSelfHostedCanonicalName(JSFunction* fun, JSAtom* name);

bool IsCallSelfHostedNonGenericMethod(NativeImpl impl);

bool ReportIncompatibleSelfHostedMethod(JSContext* cx, Handle<Value> thisValue);

/* Get the compile options used when compiling self hosted code. */
void FillSelfHostingCompileOptions(JS::CompileOptions& options);

const JSFunctionSpec* FindIntrinsicSpec(PropertyName* name);

#ifdef DEBUG
/*
 * Calls a self-hosted function by name.
 *
 * This function is only available in debug mode, because it always atomizes
 * its |name| parameter. Use the alternative function below in non-debug code.
 */
bool CallSelfHostedFunction(JSContext* cx, char const* name, HandleValue thisv,
                            const AnyInvokeArgs& args, MutableHandleValue rval);
#endif

/*
 * Calls a self-hosted function by name.
 */
bool CallSelfHostedFunction(JSContext* cx, Handle<PropertyName*> name,
                            HandleValue thisv, const AnyInvokeArgs& args,
                            MutableHandleValue rval);

bool intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, JS::Value* vp);

bool intrinsic_NewStringIterator(JSContext* cx, unsigned argc, JS::Value* vp);

bool intrinsic_NewRegExpStringIterator(JSContext* cx, unsigned argc,
                                       JS::Value* vp);

#ifdef ENABLE_RECORD_TUPLE
bool IsTupleUnchecked(JSContext* cx, const CallArgs& args);
bool intrinsic_IsTuple(JSContext* cx, unsigned argc, JS::Value* vp);
#endif

} /* namespace js */

#endif /* vm_SelfHosting_h_ */