diff options
Diffstat (limited to 'js/src/vm/SelfHosting.h')
-rw-r--r-- | js/src/vm/SelfHosting.h | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/js/src/vm/SelfHosting.h b/js/src/vm/SelfHosting.h new file mode 100644 index 0000000000..e81cbe97c7 --- /dev/null +++ b/js/src/vm/SelfHosting.h @@ -0,0 +1,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_ */ |