SelfHosting.h (10964B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef vm_SelfHosting_h_ 8 #define vm_SelfHosting_h_ 9 10 #include "NamespaceImports.h" 11 12 #include "js/CallNonGenericMethod.h" 13 #include "js/RootingAPI.h" 14 #include "js/TypeDecls.h" 15 16 // [SMDOC] Self-hosted JS 17 // 18 // Self-hosted JS allows implementing a part of the JS engine using JavaScript. 19 // 20 // This allows implementing new feature easily, and also enables JIT 21 // compilation to achieve better performance, for example with higher order 22 // functions. Self-hosted functions can be inlined in, and optimized with, the 23 // JS caller functions. 24 // 25 // Self-hosted JS code is compiled into a stencil during the initialization of 26 // the engine, and each function is instantiated into each global on demand. 27 // 28 // Self-hosted JS has several differences between regular JavaScript code, 29 // for performance optimization, security, and some other reasons. 30 // 31 // # Always strict mode 32 // 33 // Unlike regular JavaScript, self-hosted JS code is always in strict mode. 34 // 35 // # Prohibited syntax 36 // 37 // * Regular expression `/foo/` cannot be used 38 // * `obj.method(...)` and `obj[method](...)` style call cannot be used. 39 // See `callFunction` below 40 // * Object literal cannot contain duplicate property names 41 // * `yield*` cannot be used 42 // 43 // # No lazy parsing 44 // 45 // Self-hosted JS does not use lazy/syntax parsing: bytecode is generated 46 // eagerly for each function. However, we do instantiate the BaseScript lazily 47 // from the stencil for JSFunctions created for self-hosted built-ins. See 48 // `SelfHostedLazyScript` and `JSRuntime::selfHostedLazyScript`. 49 // 50 // # Extended function 51 // 52 // Functions with "$"-prefix in their name are allocated as extended function. 53 // See "SetCanonicalName" below. 54 // 55 // # Intrinsic helper functions 56 // 57 // Self-hosted JS has access to special functions that can interact with 58 // native code or internal representation of JS values and objects. 59 // 60 // See `intrinsic_functions` array in SelfHosting.cpp. 61 // 62 // # Stack Frame 63 // 64 // Stack frame inside self-hosted JS is hidden from Error.prototype.stack by 65 // default, to hide the internal from user code. 66 // 67 // During debugging self-hosted JS code, `MOZ_SHOW_ALL_JS_FRAMES` environment 68 // variable can be used to expose those frames 69 // 70 // # Debugger interaction 71 // 72 // Self-hosted JS is hidden from debugger, and no source notes or breakpoint 73 // is generated. 74 // 75 // Most function calls inside self-hosted JS are hidden from Debugger's 76 // `onNativeCall` hook, except for the following (see below for each): 77 // * `callContentFunction` 78 // * `constructContentFunction` 79 // * `allowContentIter` 80 // * `allowContentIterWith` 81 // * `allowContentIterWithNext` 82 // 83 // # XDR cache 84 // 85 // Compiling self-hosted JS code takes some time. 86 // To improve the startup performance, the bytecode for self-hosted JS code 87 // can be saved as XDR, and used by other instance. This is used to speed up 88 // JS shell tests and Firefox content process startup. 89 // 90 // See `JSRuntime::initSelfHostingStencil` function. 91 // 92 // # Special functions 93 // 94 // Self-hosted JS code has special functions, to emit special bytecode 95 // sequence, or directly operate on internals: 96 // 97 // callFunction(callee, thisV, arg0, ...) 98 // Call `callee` function with `thisV` as "this" value, passing 99 // arg0, ..., as arguments. 100 // This is used when "this" value is not `undefined. 101 // 102 // `obj.method(...)` syntax is forbidden in self-hosted JS, to avoid 103 // accidentally exposing the internal, or allowing user code to modify the 104 // behavior. 105 // 106 // If the `callee` can be user-provided, `callContentFunction` must be 107 // used instead. 108 // 109 // callContentFunction(callee, thisV, arg0, ...) 110 // Same as `callFunction`, but this must be used when calling possibly 111 // user-provided functions, even if "this" value is `undefined`. 112 // 113 // This exposes function calls to debuggers, using `JSOp::CallContent` 114 // opcode. 115 // 116 // constructContentFunction(callee, newTarget, arg0, ...) 117 // Construct `callee` function using `newTarget` as `new.target`. 118 // This must be used when constructing possibly user-provided functions. 119 // 120 // This exposes constructs to debuggers, using `JSOp::NewContent` opcode. 121 // 122 // allowContentIter(iterable) 123 // Iteration such as for-of and spread on user-provided value is 124 // prohibited inside self-hosted JS by default. 125 // 126 // `allowContentIter` marks iteration allowed for given possibly 127 // user-provided iterable. 128 // 129 // This exposes implicit function calls around iteration to debuggers, 130 // using `JSOp::CallContentIter` opcode. 131 // 132 // Used in the following contexts: 133 // 134 // for (var item of allowContentIter(iterable)) { ... } 135 // [...allowContentIter(iterable)] 136 // 137 // allowContentIterWith(iterable, iteratorFunc) 138 // Special form of `allowContentIter`, where `iterable[Symbol.iterator]` is 139 // already retrieved. 140 // 141 // This directly uses `iteratorFunc` instead of accessing 142 // `iterable[Symbol.iterator]` again inside for-of bytecode. 143 // 144 // for (var item of allowContentIterWith(iterable, iteratorFunc)) { ... } 145 // 146 // allowContentIterWith(iterator, nextFunc) 147 // Special form of `allowContentIter`, where `iterable[Symbol.iterator]()` 148 // is already called and the iterator's `next` property retrieved. 149 // 150 // This form doesn't call `iterable[Symbol.iterator]` and directly uses 151 // `nextFunc` instead of retrieving it inside for-of bytecode. 152 // 153 // for (var item of allowContentIterWithNext(iterator, nextFunc)) { ... } 154 // 155 // DefineDataProperty(obj, key, value) 156 // Initialize `obj`'s `key` property with `value`, like 157 // `Object.defineProperty(obj, key, {value})`, using `JSOp::InitElem` 158 // opcode. This is almost always better than `obj[key] = value` because it 159 // ignores setters and other properties on the prototype chain. 160 // 161 // hasOwn(key, obj) 162 // Return `true` if `obj` has an own `key` property, using `JSOp::HasOwn` 163 // opcode. 164 // 165 // getPropertySuper(obj, key, receiver) 166 // Return `obj.[[Get]](key, receiver)`, using `JSOp::GetElemSuper` opcode. 167 // 168 // ToNumeric(v) 169 // Convert `v` to number, using `JSOp::ToNumeric` opcode 170 // 171 // ToString(v) 172 // Convert `v` to string, `JSOp::ToString` opcode 173 // 174 // GetBuiltinConstructor(name) 175 // Return built-in constructor for `name`, e.g. `"Array"`, using 176 // `JSOp::BuiltinObject` opcode. 177 // 178 // GetBuiltinPrototype(name) 179 // Return built-in prototype for `name`, e.g. `"RegExp"`, using 180 // `JSOp::BuiltinObject` opcode. 181 // 182 // GetBuiltinSymbol(name) 183 // Return built-in symbol `Symbol[name]`, using `JSOp::Symbol` opcode. 184 // 185 // SetIsInlinableLargeFunction(fun) 186 // Mark the large function `fun` inlineable. 187 // `fun` must be the last function declaration before this call. 188 // 189 // SetCanonicalName(fun) 190 // Set canonical name for the function `fun`. 191 // `fun` must be the last function declaration before this call, and also 192 // its function name must be prefixed with "$", to make it extended 193 // function and store the original function name in the extended slot. 194 // 195 // UnsafeGetReservedSlot(obj, slot) 196 // UnsafeGetObjectFromReservedSlot(obj, slot) 197 // UnsafeGetInt32FromReservedSlot(obj, slot) 198 // UnsafeGetStringFromReservedSlot(obj, slot) 199 // UnsafeGetBooleanFromReservedSlot(obj, slot) 200 // Get `obj`'s reserved slot specified by integer value `slot`. 201 // They are intrinsic helper functions, and also optimized during JIT 202 // compilation. 203 // 204 // UnsafeSetReservedSlot(obj, slot, value) 205 // Set `obj`'s reserved slot specified by integer value `slot` to `value`. 206 // This is an intrinsic helper function, and also optimized during JIT 207 // compilation. 208 // 209 // resumeGenerator(gen, value, kind) 210 // Resume generator `gen`, using `kind`, which is one of "next", "throw", 211 // or "return", pasing `value` as parameter, using `JSOp::Resume` opcode. 212 // 213 // forceInterpreter() 214 // Force interpreter execution for this function, using 215 // `JSOp::ForceInterpreter` opcode. 216 // This must be the first statement inside the function. 217 218 namespace JS { 219 class JS_PUBLIC_API CompileOptions; 220 } 221 222 namespace js { 223 224 class AnyInvokeArgs; 225 class PropertyName; 226 class ScriptSourceObject; 227 228 ScriptSourceObject* SelfHostingScriptSourceObject(JSContext* cx); 229 230 /* 231 * Check whether the given JSFunction or Value is a self-hosted function whose 232 * self-hosted name is the given name. 233 */ 234 bool IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name); 235 bool IsSelfHostedFunctionWithName(const Value& v, JSAtom* name); 236 237 /* 238 * Returns the name of the cloned function's binding in the self-hosted global. 239 * 240 * This returns a non-null value only when this is a top level function 241 * declaration in the self-hosted global. 242 */ 243 PropertyName* GetClonedSelfHostedFunctionName(const JSFunction* fun); 244 void SetClonedSelfHostedFunctionName(JSFunction* fun, PropertyName* name); 245 246 constexpr char ExtendedUnclonedSelfHostedFunctionNamePrefix = '$'; 247 248 /* 249 * Uncloned self-hosted functions with `$` prefix are allocated as 250 * extended function, to store the original name in `_SetCanonicalName`. 251 */ 252 bool IsExtendedUnclonedSelfHostedFunctionName(JSAtom* name); 253 254 void SetUnclonedSelfHostedCanonicalName(JSFunction* fun, JSAtom* name); 255 256 bool IsCallSelfHostedNonGenericMethod(NativeImpl impl); 257 258 enum class IncompatibleContext { Regular, RegExpExec }; 259 260 bool ReportIncompatibleSelfHostedMethod( 261 JSContext* cx, Handle<Value> thisValue, 262 IncompatibleContext incompatibleContext); 263 264 /* Get the compile options used when compiling self hosted code. */ 265 void FillSelfHostingCompileOptions(JS::CompileOptions& options); 266 267 const JSFunctionSpec* FindIntrinsicSpec(PropertyName* name); 268 269 #ifdef DEBUG 270 /* 271 * Calls a self-hosted function by name. 272 * 273 * This function is only available in debug mode, because it always atomizes 274 * its |name| parameter. Use the alternative function below in non-debug code. 275 */ 276 bool CallSelfHostedFunction(JSContext* cx, char const* name, HandleValue thisv, 277 const AnyInvokeArgs& args, MutableHandleValue rval); 278 #endif 279 280 /* 281 * Calls a self-hosted function by name. 282 */ 283 bool CallSelfHostedFunction(JSContext* cx, Handle<PropertyName*> name, 284 HandleValue thisv, const AnyInvokeArgs& args, 285 MutableHandleValue rval); 286 287 bool intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, JS::Value* vp); 288 289 bool intrinsic_NewStringIterator(JSContext* cx, unsigned argc, JS::Value* vp); 290 291 bool intrinsic_NewRegExpStringIterator(JSContext* cx, unsigned argc, 292 JS::Value* vp); 293 } /* namespace js */ 294 295 #endif /* vm_SelfHosting_h_ */