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 /*
8 * JS function support.
9 */
10
11 #include "vm/JSFunction-inl.h"
12
13 #include "mozilla/CheckedInt.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/Range.h"
16 #include "mozilla/Utf8.h"
17
18 #include <algorithm>
19 #include <iterator>
20 #include <string.h>
21
22 #include "jsapi.h"
23 #include "jstypes.h"
24
25 #include "builtin/Array.h"
26 #include "builtin/BigInt.h"
27 #include "builtin/Eval.h"
28 #include "builtin/Object.h"
29 #include "builtin/SelfHostingDefines.h"
30 #include "builtin/Symbol.h"
31 #include "frontend/BytecodeCompilation.h"
32 #include "frontend/BytecodeCompiler.h"
33 #include "frontend/TokenStream.h"
34 #include "gc/Marking.h"
35 #include "gc/Policy.h"
36 #include "jit/InlinableNatives.h"
37 #include "jit/Ion.h"
38 #include "js/CallNonGenericMethod.h"
39 #include "js/CompilationAndEvaluation.h"
40 #include "js/CompileOptions.h"
41 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
42 #include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
43 #include "js/PropertySpec.h"
44 #include "js/Proxy.h"
45 #include "js/SourceText.h"
46 #include "js/StableStringChars.h"
47 #include "js/Wrapper.h"
48 #include "util/StringBuffer.h"
49 #include "util/Text.h"
50 #include "vm/AsyncFunction.h"
51 #include "vm/AsyncIteration.h"
52 #include "vm/BooleanObject.h"
53 #include "vm/FunctionFlags.h" // js::FunctionFlags
54 #include "vm/GeneratorAndAsyncKind.h" // js::GeneratorKind, js::FunctionAsyncKind
55 #include "vm/GlobalObject.h"
56 #include "vm/Interpreter.h"
57 #include "vm/JSAtom.h"
58 #include "vm/JSContext.h"
59 #include "vm/JSObject.h"
60 #include "vm/JSScript.h"
61 #include "vm/NumberObject.h"
62 #include "vm/PlainObject.h" // js::PlainObject
63 #include "vm/SelfHosting.h"
64 #include "vm/Shape.h"
65 #include "vm/SharedImmutableStringsCache.h"
66 #include "vm/StringObject.h"
67 #include "vm/WellKnownAtom.h" // js_*_str
68 #include "vm/WrapperObject.h"
69 #include "vm/Xdr.h"
70 #include "wasm/AsmJS.h"
71
72 #include "debugger/DebugAPI-inl.h"
73 #include "vm/FrameIter-inl.h" // js::FrameIter::unaliasedForEachActual
74 #include "vm/Interpreter-inl.h"
75 #include "vm/JSScript-inl.h"
76 #include "vm/Stack-inl.h"
77
78 using namespace js;
79
80 using mozilla::CheckedInt;
81 using mozilla::Maybe;
82 using mozilla::Some;
83 using mozilla::Utf8Unit;
84
85 using JS::AutoStableStringChars;
86 using JS::CompileOptions;
87 using JS::SourceOwnership;
88 using JS::SourceText;
89
fun_enumerate(JSContext * cx,HandleObject obj)90 static bool fun_enumerate(JSContext* cx, HandleObject obj) {
91 MOZ_ASSERT(obj->is<JSFunction>());
92
93 RootedId id(cx);
94 bool found;
95
96 if (!obj->isBoundFunction() && !obj->as<JSFunction>().isArrow()) {
97 id = NameToId(cx->names().prototype);
98 if (!HasOwnProperty(cx, obj, id, &found)) {
99 return false;
100 }
101 }
102
103 if (!obj->as<JSFunction>().hasResolvedLength()) {
104 id = NameToId(cx->names().length);
105 if (!HasOwnProperty(cx, obj, id, &found)) {
106 return false;
107 }
108 }
109
110 if (!obj->as<JSFunction>().hasResolvedName()) {
111 id = NameToId(cx->names().name);
112 if (!HasOwnProperty(cx, obj, id, &found)) {
113 return false;
114 }
115 }
116
117 return true;
118 }
119
IsFunction(HandleValue v)120 bool IsFunction(HandleValue v) {
121 return v.isObject() && v.toObject().is<JSFunction>();
122 }
123
AdvanceToActiveCallLinear(JSContext * cx,NonBuiltinScriptFrameIter & iter,HandleFunction fun)124 static bool AdvanceToActiveCallLinear(JSContext* cx,
125 NonBuiltinScriptFrameIter& iter,
126 HandleFunction fun) {
127 MOZ_ASSERT(!fun->isBuiltin());
128
129 for (; !iter.done(); ++iter) {
130 if (!iter.isFunctionFrame()) {
131 continue;
132 }
133 if (iter.matchCallee(cx, fun)) {
134 return true;
135 }
136 }
137 return false;
138 }
139
ThrowTypeErrorBehavior(JSContext * cx)140 void js::ThrowTypeErrorBehavior(JSContext* cx) {
141 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
142 JSMSG_THROW_TYPE_ERROR);
143 }
144
IsSloppyNormalFunction(JSFunction * fun)145 static bool IsSloppyNormalFunction(JSFunction* fun) {
146 // FunctionDeclaration or FunctionExpression in sloppy mode.
147 if (fun->kind() == FunctionFlags::NormalFunction) {
148 if (fun->isBuiltin() || fun->isBoundFunction()) {
149 return false;
150 }
151
152 if (fun->isGenerator() || fun->isAsync()) {
153 return false;
154 }
155
156 MOZ_ASSERT(fun->isInterpreted());
157 return !fun->strict();
158 }
159
160 // Or asm.js function in sloppy mode.
161 if (fun->kind() == FunctionFlags::AsmJS) {
162 return !IsAsmJSStrictModeModuleOrFunction(fun);
163 }
164
165 return false;
166 }
167
168 // Beware: this function can be invoked on *any* function! That includes
169 // natives, strict mode functions, bound functions, arrow functions,
170 // self-hosted functions and constructors, asm.js functions, functions with
171 // destructuring arguments and/or a rest argument, and probably a few more I
172 // forgot. Turn back and save yourself while you still can. It's too late for
173 // me.
ArgumentsRestrictions(JSContext * cx,HandleFunction fun)174 static bool ArgumentsRestrictions(JSContext* cx, HandleFunction fun) {
175 // Throw unless the function is a sloppy, normal function.
176 // TODO (bug 1057208): ensure semantics are correct for all possible
177 // pairings of callee/caller.
178 if (!IsSloppyNormalFunction(fun)) {
179 ThrowTypeErrorBehavior(cx);
180 return false;
181 }
182
183 return true;
184 }
185
ArgumentsGetterImpl(JSContext * cx,const CallArgs & args)186 bool ArgumentsGetterImpl(JSContext* cx, const CallArgs& args) {
187 MOZ_ASSERT(IsFunction(args.thisv()));
188
189 RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>());
190 if (!ArgumentsRestrictions(cx, fun)) {
191 return false;
192 }
193
194 // Return null if this function wasn't found on the stack.
195 NonBuiltinScriptFrameIter iter(cx);
196 if (!AdvanceToActiveCallLinear(cx, iter, fun)) {
197 args.rval().setNull();
198 return true;
199 }
200
201 Rooted<ArgumentsObject*> argsobj(cx,
202 ArgumentsObject::createUnexpected(cx, iter));
203 if (!argsobj) {
204 return false;
205 }
206
207 #ifndef JS_CODEGEN_NONE
208 // Disabling compiling of this script in IonMonkey. IonMonkey doesn't
209 // guarantee |f.arguments| can be fully recovered, so we try to mitigate
210 // observing this behavior by detecting its use early.
211 JSScript* script = iter.script();
212 jit::ForbidCompilation(cx, script);
213 #endif
214
215 args.rval().setObject(*argsobj);
216 return true;
217 }
218
ArgumentsGetter(JSContext * cx,unsigned argc,Value * vp)219 static bool ArgumentsGetter(JSContext* cx, unsigned argc, Value* vp) {
220 CallArgs args = CallArgsFromVp(argc, vp);
221 return CallNonGenericMethod<IsFunction, ArgumentsGetterImpl>(cx, args);
222 }
223
ArgumentsSetterImpl(JSContext * cx,const CallArgs & args)224 bool ArgumentsSetterImpl(JSContext* cx, const CallArgs& args) {
225 MOZ_ASSERT(IsFunction(args.thisv()));
226
227 RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>());
228 if (!ArgumentsRestrictions(cx, fun)) {
229 return false;
230 }
231
232 // If the function passes the gauntlet, return |undefined|.
233 args.rval().setUndefined();
234 return true;
235 }
236
ArgumentsSetter(JSContext * cx,unsigned argc,Value * vp)237 static bool ArgumentsSetter(JSContext* cx, unsigned argc, Value* vp) {
238 CallArgs args = CallArgsFromVp(argc, vp);
239 return CallNonGenericMethod<IsFunction, ArgumentsSetterImpl>(cx, args);
240 }
241
242 // Beware: this function can be invoked on *any* function! That includes
243 // natives, strict mode functions, bound functions, arrow functions,
244 // self-hosted functions and constructors, asm.js functions, functions with
245 // destructuring arguments and/or a rest argument, and probably a few more I
246 // forgot. Turn back and save yourself while you still can. It's too late for
247 // me.
CallerRestrictions(JSContext * cx,HandleFunction fun)248 static bool CallerRestrictions(JSContext* cx, HandleFunction fun) {
249 // Throw unless the function is a sloppy, normal function.
250 // TODO (bug 1057208): ensure semantics are correct for all possible
251 // pairings of callee/caller.
252 if (!IsSloppyNormalFunction(fun)) {
253 ThrowTypeErrorBehavior(cx);
254 return false;
255 }
256
257 return true;
258 }
259
CallerGetterImpl(JSContext * cx,const CallArgs & args)260 bool CallerGetterImpl(JSContext* cx, const CallArgs& args) {
261 MOZ_ASSERT(IsFunction(args.thisv()));
262
263 // Beware! This function can be invoked on *any* function! It can't
264 // assume it'll never be invoked on natives, strict mode functions, bound
265 // functions, or anything else that ordinarily has immutable .caller
266 // defined with [[ThrowTypeError]].
267 RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>());
268 if (!CallerRestrictions(cx, fun)) {
269 return false;
270 }
271
272 // Also return null if this function wasn't found on the stack.
273 NonBuiltinScriptFrameIter iter(cx);
274 if (!AdvanceToActiveCallLinear(cx, iter, fun)) {
275 args.rval().setNull();
276 return true;
277 }
278
279 ++iter;
280 while (!iter.done() && iter.isEvalFrame()) {
281 ++iter;
282 }
283
284 if (iter.done() || !iter.isFunctionFrame()) {
285 args.rval().setNull();
286 return true;
287 }
288
289 RootedObject caller(cx, iter.callee(cx));
290 if (!cx->compartment()->wrap(cx, &caller)) {
291 return false;
292 }
293
294 // Censor the caller if we don't have full access to it. If we do, but the
295 // caller is a function with strict mode code, throw a TypeError per ES5.
296 // If we pass these checks, we can return the computed caller.
297 {
298 JSObject* callerObj = CheckedUnwrapStatic(caller);
299 if (!callerObj) {
300 args.rval().setNull();
301 return true;
302 }
303
304 if (JS_IsDeadWrapper(callerObj)) {
305 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
306 JSMSG_DEAD_OBJECT);
307 return false;
308 }
309
310 JSFunction* callerFun = &callerObj->as<JSFunction>();
311 MOZ_ASSERT(!callerFun->isBuiltin(),
312 "non-builtin iterator returned a builtin?");
313
314 if (callerFun->strict() || callerFun->isAsync() ||
315 callerFun->isGenerator()) {
316 args.rval().setNull();
317 return true;
318 }
319 }
320
321 args.rval().setObject(*caller);
322 return true;
323 }
324
CallerGetter(JSContext * cx,unsigned argc,Value * vp)325 static bool CallerGetter(JSContext* cx, unsigned argc, Value* vp) {
326 CallArgs args = CallArgsFromVp(argc, vp);
327 return CallNonGenericMethod<IsFunction, CallerGetterImpl>(cx, args);
328 }
329
CallerSetterImpl(JSContext * cx,const CallArgs & args)330 bool CallerSetterImpl(JSContext* cx, const CallArgs& args) {
331 MOZ_ASSERT(IsFunction(args.thisv()));
332
333 // We just have to return |undefined|, but first we call CallerGetterImpl
334 // because we need the same strict-mode and security checks.
335
336 if (!CallerGetterImpl(cx, args)) {
337 return false;
338 }
339
340 args.rval().setUndefined();
341 return true;
342 }
343
CallerSetter(JSContext * cx,unsigned argc,Value * vp)344 static bool CallerSetter(JSContext* cx, unsigned argc, Value* vp) {
345 CallArgs args = CallArgsFromVp(argc, vp);
346 return CallNonGenericMethod<IsFunction, CallerSetterImpl>(cx, args);
347 }
348
349 static const JSPropertySpec function_properties[] = {
350 JS_PSGS("arguments", ArgumentsGetter, ArgumentsSetter, 0),
351 JS_PSGS("caller", CallerGetter, CallerSetter, 0), JS_PS_END};
352
ResolveInterpretedFunctionPrototype(JSContext * cx,HandleFunction fun,HandleId id)353 static bool ResolveInterpretedFunctionPrototype(JSContext* cx,
354 HandleFunction fun,
355 HandleId id) {
356 MOZ_ASSERT(fun->isInterpreted() || fun->isAsmJSNative());
357 MOZ_ASSERT(id == NameToId(cx->names().prototype));
358
359 // Assert that fun is not a compiler-created function object, which
360 // must never leak to script or embedding code and then be mutated.
361 // Also assert that fun is not bound, per the ES5 15.3.4.5 ref above.
362 MOZ_ASSERT(!IsInternalFunctionObject(*fun));
363 MOZ_ASSERT(!fun->isBoundFunction());
364
365 // Make the prototype object an instance of Object with the same parent as
366 // the function object itself, unless the function is an ES6 generator. In
367 // that case, per the 15 July 2013 ES6 draft, section 15.19.3, its parent is
368 // the GeneratorObjectPrototype singleton.
369 bool isGenerator = fun->isGenerator();
370 Rooted<GlobalObject*> global(cx, &fun->global());
371 RootedObject objProto(cx);
372 if (isGenerator && fun->isAsync()) {
373 objProto = GlobalObject::getOrCreateAsyncGeneratorPrototype(cx, global);
374 } else if (isGenerator) {
375 objProto = GlobalObject::getOrCreateGeneratorObjectPrototype(cx, global);
376 } else {
377 objProto = GlobalObject::getOrCreateObjectPrototype(cx, global);
378 }
379 if (!objProto) {
380 return false;
381 }
382
383 RootedPlainObject proto(
384 cx, NewTenuredObjectWithGivenProto<PlainObject>(cx, objProto));
385 if (!proto) {
386 return false;
387 }
388
389 // Per ES5 13.2 the prototype's .constructor property is configurable,
390 // non-enumerable, and writable. However, per the 15 July 2013 ES6 draft,
391 // section 15.19.3, the .prototype of a generator function does not link
392 // back with a .constructor.
393 if (!isGenerator) {
394 RootedValue objVal(cx, ObjectValue(*fun));
395 if (!DefineDataProperty(cx, proto, cx->names().constructor, objVal, 0)) {
396 return false;
397 }
398 }
399
400 // Per ES5 15.3.5.2 a user-defined function's .prototype property is
401 // initially non-configurable, non-enumerable, and writable.
402 RootedValue protoVal(cx, ObjectValue(*proto));
403 return DefineDataProperty(cx, fun, id, protoVal,
404 JSPROP_PERMANENT | JSPROP_RESOLVING);
405 }
406
needsPrototypeProperty()407 bool JSFunction::needsPrototypeProperty() {
408 /*
409 * Built-in functions do not have a .prototype property per ECMA-262,
410 * or (Object.prototype, Function.prototype, etc.) have that property
411 * created eagerly.
412 *
413 * ES5 15.3.4.5: bound functions don't have a prototype property. The
414 * isBuiltin() test covers this case because bound functions are self-hosted
415 * (scripted) built-ins.
416 *
417 * ES6 9.2.8 MakeConstructor defines the .prototype property on constructors.
418 * Generators are not constructors, but they have a .prototype property
419 * anyway, according to errata to ES6. See bug 1191486.
420 *
421 * Thus all of the following don't get a .prototype property:
422 * - Methods (that are not class-constructors or generators)
423 * - Arrow functions
424 * - Function.prototype
425 * - Async functions
426 */
427 return !isBuiltin() && (isConstructor() || isGenerator());
428 }
429
hasNonConfigurablePrototypeDataProperty()430 bool JSFunction::hasNonConfigurablePrototypeDataProperty() {
431 if (!isBuiltin()) {
432 return needsPrototypeProperty();
433 }
434
435 if (isSelfHostedBuiltin()) {
436 // Self-hosted constructors other than bound functions have a
437 // non-configurable .prototype data property.
438 if (!isConstructor() || isBoundFunction()) {
439 return false;
440 }
441 #ifdef DEBUG
442 PropertyName* prototypeName =
443 runtimeFromMainThread()->commonNames->prototype;
444 Maybe<PropertyInfo> prop = lookupPure(prototypeName);
445 MOZ_ASSERT(prop.isSome());
446 MOZ_ASSERT(prop->isDataProperty());
447 MOZ_ASSERT(!prop->configurable());
448 #endif
449 return true;
450 }
451
452 if (!isConstructor()) {
453 // We probably don't have a .prototype property. Avoid the lookup below.
454 return false;
455 }
456
457 PropertyName* prototypeName = runtimeFromMainThread()->commonNames->prototype;
458 Maybe<PropertyInfo> prop = lookupPure(prototypeName);
459 return prop.isSome() && prop->isDataProperty() && !prop->configurable();
460 }
461
fun_mayResolve(const JSAtomState & names,jsid id,JSObject *)462 static bool fun_mayResolve(const JSAtomState& names, jsid id, JSObject*) {
463 if (!id.isAtom()) {
464 return false;
465 }
466
467 JSAtom* atom = id.toAtom();
468 return atom == names.prototype || atom == names.length || atom == names.name;
469 }
470
fun_resolve(JSContext * cx,HandleObject obj,HandleId id,bool * resolvedp)471 static bool fun_resolve(JSContext* cx, HandleObject obj, HandleId id,
472 bool* resolvedp) {
473 if (!id.isAtom()) {
474 return true;
475 }
476
477 RootedFunction fun(cx, &obj->as<JSFunction>());
478
479 if (id.isAtom(cx->names().prototype)) {
480 if (!fun->needsPrototypeProperty()) {
481 return true;
482 }
483
484 if (!ResolveInterpretedFunctionPrototype(cx, fun, id)) {
485 return false;
486 }
487
488 *resolvedp = true;
489 return true;
490 }
491
492 bool isLength = id.isAtom(cx->names().length);
493 if (isLength || id.isAtom(cx->names().name)) {
494 MOZ_ASSERT(!IsInternalFunctionObject(*obj));
495
496 RootedValue v(cx);
497
498 // Since f.length and f.name are configurable, they could be resolved
499 // and then deleted:
500 // function f(x) {}
501 // assertEq(f.length, 1);
502 // delete f.length;
503 // assertEq(f.name, "f");
504 // delete f.name;
505 // Afterwards, asking for f.length or f.name again will cause this
506 // resolve hook to run again. Defining the property again the second
507 // time through would be a bug.
508 // assertEq(f.length, 0); // gets Function.prototype.length!
509 // assertEq(f.name, ""); // gets Function.prototype.name!
510 // We use the RESOLVED_LENGTH and RESOLVED_NAME flags as a hack to prevent
511 // this bug.
512 if (isLength) {
513 if (fun->hasResolvedLength()) {
514 return true;
515 }
516
517 if (!JSFunction::getUnresolvedLength(cx, fun, &v)) {
518 return false;
519 }
520 } else {
521 if (fun->hasResolvedName()) {
522 return true;
523 }
524
525 if (!JSFunction::getUnresolvedName(cx, fun, &v)) {
526 return false;
527 }
528 }
529
530 if (!NativeDefineDataProperty(cx, fun, id, v,
531 JSPROP_READONLY | JSPROP_RESOLVING)) {
532 return false;
533 }
534
535 if (isLength) {
536 fun->setResolvedLength();
537 } else {
538 fun->setResolvedName();
539 }
540
541 *resolvedp = true;
542 return true;
543 }
544
545 return true;
546 }
547
548 template <XDRMode mode>
XDRInterpretedFunction(XDRState<mode> * xdr,HandleScope enclosingScope,HandleScriptSourceObject sourceObject,MutableHandleFunction objp)549 XDRResult js::XDRInterpretedFunction(XDRState<mode>* xdr,
550 HandleScope enclosingScope,
551 HandleScriptSourceObject sourceObject,
552 MutableHandleFunction objp) {
553 enum FirstWordFlag {
554 HasAtom = 1 << 0,
555 IsGenerator = 1 << 1,
556 IsAsync = 1 << 2,
557 IsLazy = 1 << 3,
558 };
559
560 /* NB: Keep this in sync with CloneInnerInterpretedFunction. */
561
562 JSContext* cx = xdr->cx();
563
564 uint8_t xdrFlags = 0; /* bitmask of FirstWordFlag */
565
566 uint16_t nargs = 0;
567 uint16_t flags = 0;
568
569 RootedFunction fun(cx);
570 RootedAtom atom(cx);
571 RootedScript script(cx);
572 Rooted<BaseScript*> lazy(cx);
573
574 if (mode == XDR_ENCODE) {
575 fun = objp;
576 if (!fun->isInterpreted() || fun->isBoundFunction()) {
577 return xdr->fail(JS::TranscodeResult::Failure_NotInterpretedFun);
578 }
579
580 if (fun->isGenerator()) {
581 xdrFlags |= IsGenerator;
582 }
583 if (fun->isAsync()) {
584 xdrFlags |= IsAsync;
585 }
586
587 if (fun->hasBytecode()) {
588 // Encode the script.
589 script = fun->nonLazyScript();
590 } else {
591 // Encode a lazy script.
592 xdrFlags |= IsLazy;
593 lazy = fun->baseScript();
594 }
595
596 if (fun->displayAtom()) {
597 xdrFlags |= HasAtom;
598 }
599
600 nargs = fun->nargs();
601 flags = FunctionFlags::clearMutableflags(fun->flags()).toRaw();
602
603 atom = fun->displayAtom();
604 }
605
606 MOZ_TRY(xdr->codeUint8(&xdrFlags));
607
608 MOZ_TRY(xdr->codeUint16(&nargs));
609 MOZ_TRY(xdr->codeUint16(&flags));
610
611 if (xdrFlags & HasAtom) {
612 MOZ_TRY(XDRAtom(xdr, &atom));
613 }
614
615 if (mode == XDR_DECODE) {
616 GeneratorKind generatorKind = (xdrFlags & IsGenerator)
617 ? GeneratorKind::Generator
618 : GeneratorKind::NotGenerator;
619 FunctionAsyncKind asyncKind = (xdrFlags & IsAsync)
620 ? FunctionAsyncKind::AsyncFunction
621 : FunctionAsyncKind::SyncFunction;
622
623 RootedObject proto(cx);
624 if (!GetFunctionPrototype(cx, generatorKind, asyncKind, &proto)) {
625 return xdr->fail(JS::TranscodeResult::Throw);
626 }
627
628 gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
629 if (flags & FunctionFlags::EXTENDED) {
630 allocKind = gc::AllocKind::FUNCTION_EXTENDED;
631 }
632
633 // Sanity check the flags. We should have cleared the mutable flags already
634 // and we do not support self-hosted-lazy, bound or wasm functions.
635 constexpr uint16_t UnsupportedFlags =
636 FunctionFlags::MUTABLE_FLAGS | FunctionFlags::SELFHOSTLAZY |
637 FunctionFlags::BOUND_FUN | FunctionFlags::WASM_JIT_ENTRY;
638 if ((flags & UnsupportedFlags) != 0) {
639 return xdr->fail(JS::TranscodeResult::Failure_BadDecode);
640 }
641
642 fun = NewFunctionWithProto(cx, nullptr, nargs, FunctionFlags(flags),
643 nullptr, atom, proto, allocKind, TenuredObject);
644 if (!fun) {
645 return xdr->fail(JS::TranscodeResult::Throw);
646 }
647 objp.set(fun);
648 }
649
650 if (xdrFlags & IsLazy) {
651 MOZ_TRY(XDRLazyScript(xdr, enclosingScope, sourceObject, fun, &lazy));
652 } else {
653 MOZ_TRY(XDRScript(xdr, enclosingScope, sourceObject, fun, &script));
654 }
655
656 // Verify marker at end of function to detect buffer trunction.
657 MOZ_TRY(xdr->codeMarker(0x9E35CA1F));
658
659 return Ok();
660 }
661
662 template XDRResult js::XDRInterpretedFunction(XDRState<XDR_ENCODE>*,
663 HandleScope,
664 HandleScriptSourceObject,
665 MutableHandleFunction);
666
667 template XDRResult js::XDRInterpretedFunction(XDRState<XDR_DECODE>*,
668 HandleScope,
669 HandleScriptSourceObject,
670 MutableHandleFunction);
671
672 /* ES6 (04-25-16) 19.2.3.6 Function.prototype [ @@hasInstance ] */
fun_symbolHasInstance(JSContext * cx,unsigned argc,Value * vp)673 static bool fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp) {
674 CallArgs args = CallArgsFromVp(argc, vp);
675
676 if (args.length() < 1) {
677 args.rval().setBoolean(false);
678 return true;
679 }
680
681 /* Step 1. */
682 HandleValue func = args.thisv();
683
684 // Primitives are non-callable and will always return false from
685 // OrdinaryHasInstance.
686 if (!func.isObject()) {
687 args.rval().setBoolean(false);
688 return true;
689 }
690
691 RootedObject obj(cx, &func.toObject());
692
693 /* Step 2. */
694 bool result;
695 if (!OrdinaryHasInstance(cx, obj, args[0], &result)) {
696 return false;
697 }
698
699 args.rval().setBoolean(result);
700 return true;
701 }
702
703 /*
704 * ES6 (4-25-16) 7.3.19 OrdinaryHasInstance
705 */
OrdinaryHasInstance(JSContext * cx,HandleObject objArg,HandleValue v,bool * bp)706 bool JS::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v,
707 bool* bp) {
708 AssertHeapIsIdle();
709 cx->check(objArg, v);
710
711 RootedObject obj(cx, objArg);
712
713 /* Step 1. */
714 if (!obj->isCallable()) {
715 *bp = false;
716 return true;
717 }
718
719 /* Step 2. */
720 if (obj->is<JSFunction>() && obj->isBoundFunction()) {
721 /* Steps 2a-b. */
722 AutoCheckRecursionLimit recursion(cx);
723 if (!recursion.check(cx)) {
724 return false;
725 }
726 obj = obj->as<JSFunction>().getBoundFunctionTarget();
727 return InstanceofOperator(cx, obj, v, bp);
728 }
729
730 /* Step 3. */
731 if (!v.isObject()) {
732 *bp = false;
733 return true;
734 }
735
736 /* Step 4. */
737 RootedValue pval(cx);
738 if (!GetProperty(cx, obj, obj, cx->names().prototype, &pval)) {
739 return false;
740 }
741
742 /* Step 5. */
743 if (pval.isPrimitive()) {
744 /*
745 * Throw a runtime error if instanceof is called on a function that
746 * has a non-object as its .prototype value.
747 */
748 RootedValue val(cx, ObjectValue(*obj));
749 ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, val, nullptr);
750 return false;
751 }
752
753 /* Step 6. */
754 RootedObject pobj(cx, &pval.toObject());
755 bool isPrototype;
756 if (!IsPrototypeOf(cx, pobj, &v.toObject(), &isPrototype)) {
757 return false;
758 }
759 *bp = isPrototype;
760 return true;
761 }
762
trace(JSTracer * trc)763 inline void JSFunction::trace(JSTracer* trc) {
764 if (isExtended()) {
765 TraceRange(trc, std::size(toExtended()->extendedSlots),
766 (GCPtrValue*)toExtended()->extendedSlots, "nativeReserved");
767 }
768
769 TraceNullableEdge(trc, &atom_, "atom");
770
771 if (isInterpreted()) {
772 // Functions can be be marked as interpreted despite having no script
773 // yet at some points when parsing, and can be lazy with no lazy script
774 // for self-hosted code.
775 if (isIncomplete()) {
776 MOZ_ASSERT(u.scripted.s.script_ == nullptr);
777 } else if (hasBaseScript()) {
778 BaseScript* script = u.scripted.s.script_;
779 TraceManuallyBarrieredEdge(trc, &script, "script");
780 // Self-hosted scripts are shared with workers but are never
781 // relocated. Skip unnecessary writes to prevent the possible data race.
782 if (u.scripted.s.script_ != script) {
783 u.scripted.s.script_ = script;
784 }
785 }
786 // NOTE: The u.scripted.s.selfHostedLazy_ does not point to GC things.
787
788 if (u.scripted.env_) {
789 TraceManuallyBarrieredEdge(trc, &u.scripted.env_, "fun_environment");
790 }
791 }
792 }
793
fun_trace(JSTracer * trc,JSObject * obj)794 static void fun_trace(JSTracer* trc, JSObject* obj) {
795 obj->as<JSFunction>().trace(trc);
796 }
797
CreateFunctionConstructor(JSContext * cx,JSProtoKey key)798 static JSObject* CreateFunctionConstructor(JSContext* cx, JSProtoKey key) {
799 Rooted<GlobalObject*> global(cx, cx->global());
800 RootedObject functionProto(
801 cx, &global->getPrototype(JSProto_Function).toObject());
802
803 RootedObject functionCtor(
804 cx, NewFunctionWithProto(
805 cx, Function, 1, FunctionFlags::NATIVE_CTOR, nullptr,
806 HandlePropertyName(cx->names().Function), functionProto,
807 gc::AllocKind::FUNCTION, TenuredObject));
808 if (!functionCtor) {
809 return nullptr;
810 }
811
812 return functionCtor;
813 }
814
FunctionPrototype(JSContext * cx,unsigned argc,Value * vp)815 static bool FunctionPrototype(JSContext* cx, unsigned argc, Value* vp) {
816 CallArgs args = CallArgsFromVp(argc, vp);
817 args.rval().setUndefined();
818 return true;
819 }
820
CreateFunctionPrototype(JSContext * cx,JSProtoKey key)821 static JSObject* CreateFunctionPrototype(JSContext* cx, JSProtoKey key) {
822 Rooted<GlobalObject*> self(cx, cx->global());
823
824 RootedObject objectProto(cx, &self->getPrototype(JSProto_Object).toObject());
825
826 return NewFunctionWithProto(
827 cx, FunctionPrototype, 0, FunctionFlags::NATIVE_FUN, nullptr,
828 HandlePropertyName(cx->names().empty), objectProto,
829 gc::AllocKind::FUNCTION, TenuredObject);
830 }
831
lookup(BaseScript * script) const832 JSString* js::FunctionToStringCache::lookup(BaseScript* script) const {
833 for (size_t i = 0; i < NumEntries; i++) {
834 if (entries_[i].script == script) {
835 return entries_[i].string;
836 }
837 }
838 return nullptr;
839 }
840
put(BaseScript * script,JSString * string)841 void js::FunctionToStringCache::put(BaseScript* script, JSString* string) {
842 for (size_t i = NumEntries - 1; i > 0; i--) {
843 entries_[i] = entries_[i - 1];
844 }
845
846 entries_[0].set(script, string);
847 }
848
FunctionToString(JSContext * cx,HandleFunction fun,bool isToSource)849 JSString* js::FunctionToString(JSContext* cx, HandleFunction fun,
850 bool isToSource) {
851 if (IsAsmJSModule(fun)) {
852 return AsmJSModuleToString(cx, fun, isToSource);
853 }
854 if (IsAsmJSFunction(fun)) {
855 return AsmJSFunctionToString(cx, fun);
856 }
857
858 // Self-hosted built-ins should not expose their source code.
859 bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
860
861 // If we're in toSource mode, put parentheses around lambda functions so
862 // that eval returns lambda, not function statement.
863 bool addParentheses =
864 haveSource && isToSource && (fun->isLambda() && !fun->isArrow());
865
866 if (haveSource) {
867 if (!ScriptSource::loadSource(cx, fun->baseScript()->scriptSource(),
868 &haveSource)) {
869 return nullptr;
870 }
871 }
872
873 // Fast path for the common case, to avoid StringBuffer overhead.
874 if (!addParentheses && haveSource) {
875 FunctionToStringCache& cache = cx->zone()->functionToStringCache();
876 if (JSString* str = cache.lookup(fun->baseScript())) {
877 return str;
878 }
879
880 BaseScript* script = fun->baseScript();
881 size_t start = script->toStringStart();
882 size_t end = script->toStringEnd();
883 JSString* str =
884 (end - start <= ScriptSource::SourceDeflateLimit)
885 ? script->scriptSource()->substring(cx, start, end)
886 : script->scriptSource()->substringDontDeflate(cx, start, end);
887 if (!str) {
888 return nullptr;
889 }
890
891 cache.put(fun->baseScript(), str);
892 return str;
893 }
894
895 JSStringBuilder out(cx);
896 if (addParentheses) {
897 if (!out.append('(')) {
898 return nullptr;
899 }
900 }
901
902 if (haveSource) {
903 if (!fun->baseScript()->appendSourceDataForToString(cx, out)) {
904 return nullptr;
905 }
906 } else if (!isToSource) {
907 // For the toString() output the source representation must match
908 // NativeFunction when no source text is available.
909 //
910 // NativeFunction:
911 // function PropertyName[~Yield,~Await]opt (
912 // FormalParameters[~Yield,~Await] ) { [native code] }
913 //
914 // Additionally, if |fun| is a well-known intrinsic object and is not
915 // identified as an anonymous function, the portion of the returned
916 // string that would be matched by IdentifierName must be the initial
917 // value of the name property of |fun|.
918
919 auto hasGetterOrSetterPrefix = [](JSAtom* name) {
920 auto hasGetterOrSetterPrefix = [](const auto* chars) {
921 return (chars[0] == 'g' || chars[0] == 's') && chars[1] == 'e' &&
922 chars[2] == 't' && chars[3] == ' ';
923 };
924
925 JS::AutoCheckCannotGC nogc;
926 return name->length() >= 4 &&
927 (name->hasLatin1Chars()
928 ? hasGetterOrSetterPrefix(name->latin1Chars(nogc))
929 : hasGetterOrSetterPrefix(name->twoByteChars(nogc)));
930 };
931
932 if (!out.append("function")) {
933 return nullptr;
934 }
935
936 // We don't want to fully parse the function's name here because of
937 // performance reasons, so only append the name if we're confident it
938 // can be matched as the 'PropertyName' grammar production.
939 if (fun->explicitName() && !fun->isBoundFunction() &&
940 (fun->kind() == FunctionFlags::NormalFunction ||
941 fun->kind() == FunctionFlags::ClassConstructor)) {
942 if (!out.append(' ')) {
943 return nullptr;
944 }
945
946 // Built-in getters or setters are classified as normal
947 // functions, strip any leading "get " or "set " if present.
948 JSAtom* name = fun->explicitName();
949 size_t offset = hasGetterOrSetterPrefix(name) ? 4 : 0;
950 if (!out.appendSubstring(name, offset, name->length() - offset)) {
951 return nullptr;
952 }
953 }
954
955 if (!out.append("() {\n [native code]\n}")) {
956 return nullptr;
957 }
958 } else {
959 if (fun->isAsync()) {
960 if (!out.append("async ")) {
961 return nullptr;
962 }
963 }
964
965 if (!fun->isArrow()) {
966 if (!out.append("function")) {
967 return nullptr;
968 }
969
970 if (fun->isGenerator()) {
971 if (!out.append('*')) {
972 return nullptr;
973 }
974 }
975 }
976
977 if (fun->explicitName()) {
978 if (!out.append(' ')) {
979 return nullptr;
980 }
981
982 if (fun->isBoundFunction()) {
983 JSLinearString* boundName = JSFunction::getBoundFunctionName(cx, fun);
984 if (!boundName || !out.append(boundName)) {
985 return nullptr;
986 }
987 } else {
988 if (!out.append(fun->explicitName())) {
989 return nullptr;
990 }
991 }
992 }
993
994 if (!out.append("() {\n [native code]\n}")) {
995 return nullptr;
996 }
997 }
998
999 if (addParentheses) {
1000 if (!out.append(')')) {
1001 return nullptr;
1002 }
1003 }
1004
1005 return out.finishString();
1006 }
1007
fun_toStringHelper(JSContext * cx,HandleObject obj,bool isToSource)1008 JSString* fun_toStringHelper(JSContext* cx, HandleObject obj, bool isToSource) {
1009 if (!obj->is<JSFunction>()) {
1010 if (JSFunToStringOp op = obj->getOpsFunToString()) {
1011 return op(cx, obj, isToSource);
1012 }
1013
1014 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1015 JSMSG_INCOMPATIBLE_PROTO, js_Function_str,
1016 js_toString_str, "object");
1017 return nullptr;
1018 }
1019
1020 return FunctionToString(cx, obj.as<JSFunction>(), isToSource);
1021 }
1022
fun_toString(JSContext * cx,unsigned argc,Value * vp)1023 bool js::fun_toString(JSContext* cx, unsigned argc, Value* vp) {
1024 CallArgs args = CallArgsFromVp(argc, vp);
1025 MOZ_ASSERT(IsFunctionObject(args.calleev()));
1026
1027 RootedObject obj(cx, ToObject(cx, args.thisv()));
1028 if (!obj) {
1029 return false;
1030 }
1031
1032 JSString* str = fun_toStringHelper(cx, obj, /* isToSource = */ false);
1033 if (!str) {
1034 return false;
1035 }
1036
1037 args.rval().setString(str);
1038 return true;
1039 }
1040
fun_toSource(JSContext * cx,unsigned argc,Value * vp)1041 static bool fun_toSource(JSContext* cx, unsigned argc, Value* vp) {
1042 CallArgs args = CallArgsFromVp(argc, vp);
1043 MOZ_ASSERT(IsFunctionObject(args.calleev()));
1044
1045 RootedObject obj(cx, ToObject(cx, args.thisv()));
1046 if (!obj) {
1047 return false;
1048 }
1049
1050 RootedString str(cx);
1051 if (obj->isCallable()) {
1052 str = fun_toStringHelper(cx, obj, /* isToSource = */ true);
1053 } else {
1054 str = ObjectToSource(cx, obj);
1055 }
1056 if (!str) {
1057 return false;
1058 }
1059
1060 args.rval().setString(str);
1061 return true;
1062 }
1063
fun_call(JSContext * cx,unsigned argc,Value * vp)1064 bool js::fun_call(JSContext* cx, unsigned argc, Value* vp) {
1065 CallArgs args = CallArgsFromVp(argc, vp);
1066
1067 HandleValue func = args.thisv();
1068
1069 // We don't need to do this -- Call would do it for us -- but the error
1070 // message is *much* better if we do this here. (Without this,
1071 // JSDVG_SEARCH_STACK tries to decompile |func| as if it were |this| in
1072 // the scripted caller's frame -- so for example
1073 //
1074 // Function.prototype.call.call({});
1075 //
1076 // would identify |{}| as |this| as being the result of evaluating
1077 // |Function.prototype.call| and would conclude, "Function.prototype.call
1078 // is not a function". Grotesque.)
1079 if (!IsCallable(func)) {
1080 ReportIncompatibleMethod(cx, args, &JSFunction::class_);
1081 return false;
1082 }
1083
1084 size_t argCount = args.length();
1085 if (argCount > 0) {
1086 argCount--; // strip off provided |this|
1087 }
1088
1089 InvokeArgs iargs(cx);
1090 if (!iargs.init(cx, argCount)) {
1091 return false;
1092 }
1093
1094 for (size_t i = 0; i < argCount; i++) {
1095 iargs[i].set(args[i + 1]);
1096 }
1097
1098 return Call(cx, func, args.get(0), iargs, args.rval());
1099 }
1100
1101 // ES5 15.3.4.3
fun_apply(JSContext * cx,unsigned argc,Value * vp)1102 bool js::fun_apply(JSContext* cx, unsigned argc, Value* vp) {
1103 CallArgs args = CallArgsFromVp(argc, vp);
1104
1105 // Step 1.
1106 //
1107 // Note that we must check callability here, not at actual call time,
1108 // because extracting argument values from the provided arraylike might
1109 // have side effects or throw an exception.
1110 HandleValue fval = args.thisv();
1111 if (!IsCallable(fval)) {
1112 ReportIncompatibleMethod(cx, args, &JSFunction::class_);
1113 return false;
1114 }
1115
1116 // Step 2.
1117 if (args.length() < 2 || args[1].isNullOrUndefined()) {
1118 return fun_call(cx, (args.length() > 0) ? 1 : 0, vp);
1119 }
1120
1121 // Step 3.
1122 if (!args[1].isObject()) {
1123 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1124 JSMSG_BAD_APPLY_ARGS, js_apply_str);
1125 return false;
1126 }
1127
1128 // Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
1129 // original version of ES5).
1130 RootedObject aobj(cx, &args[1].toObject());
1131 uint64_t length;
1132 if (!GetLengthProperty(cx, aobj, &length)) {
1133 return false;
1134 }
1135
1136 // Step 6.
1137 InvokeArgs args2(cx);
1138 if (!args2.init(cx, length)) {
1139 return false;
1140 }
1141
1142 MOZ_ASSERT(length <= ARGS_LENGTH_MAX);
1143
1144 // Steps 7-8.
1145 if (!GetElements(cx, aobj, length, args2.array())) {
1146 return false;
1147 }
1148
1149 // Step 9.
1150 return Call(cx, fval, args[0], args2, args.rval());
1151 }
1152
1153 static const JSFunctionSpec function_methods[] = {
1154 JS_FN(js_toSource_str, fun_toSource, 0, 0),
1155 JS_FN(js_toString_str, fun_toString, 0, 0),
1156 JS_FN(js_apply_str, fun_apply, 2, 0),
1157 JS_FN(js_call_str, fun_call, 1, 0),
1158 JS_SELF_HOSTED_FN("bind", "FunctionBind", 2, 0),
1159 JS_SYM_FN(hasInstance, fun_symbolHasInstance, 1,
1160 JSPROP_READONLY | JSPROP_PERMANENT),
1161 JS_FS_END};
1162
1163 static const JSClassOps JSFunctionClassOps = {
1164 nullptr, // addProperty
1165 nullptr, // delProperty
1166 fun_enumerate, // enumerate
1167 nullptr, // newEnumerate
1168 fun_resolve, // resolve
1169 fun_mayResolve, // mayResolve
1170 nullptr, // finalize
1171 nullptr, // call
1172 nullptr, // hasInstance
1173 nullptr, // construct
1174 fun_trace, // trace
1175 };
1176
1177 static const ClassSpec JSFunctionClassSpec = {
1178 CreateFunctionConstructor, CreateFunctionPrototype, nullptr, nullptr,
1179 function_methods, function_properties};
1180
1181 const JSClass JSFunction::class_ = {js_Function_str,
1182 JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
1183 &JSFunctionClassOps, &JSFunctionClassSpec};
1184
1185 const JSClass* const js::FunctionClassPtr = &JSFunction::class_;
1186
isDerivedClassConstructor() const1187 bool JSFunction::isDerivedClassConstructor() const {
1188 bool derived = hasBaseScript() && baseScript()->isDerivedClassConstructor();
1189 MOZ_ASSERT_IF(derived, isClassConstructor());
1190 return derived;
1191 }
1192
isSyntheticFunction() const1193 bool JSFunction::isSyntheticFunction() const {
1194 bool synthetic = hasBaseScript() && baseScript()->isSyntheticFunction();
1195 MOZ_ASSERT_IF(synthetic, isMethod());
1196 return synthetic;
1197 }
1198
1199 /* static */
getLength(JSContext * cx,HandleFunction fun,uint16_t * length)1200 bool JSFunction::getLength(JSContext* cx, HandleFunction fun,
1201 uint16_t* length) {
1202 MOZ_ASSERT(!fun->isBoundFunction());
1203
1204 if (fun->isNativeFun()) {
1205 *length = fun->nargs();
1206 return true;
1207 }
1208
1209 JSScript* script = getOrCreateScript(cx, fun);
1210 if (!script) {
1211 return false;
1212 }
1213
1214 *length = script->funLength();
1215 return true;
1216 }
1217
1218 /* static */
getUnresolvedLength(JSContext * cx,HandleFunction fun,MutableHandleValue v)1219 bool JSFunction::getUnresolvedLength(JSContext* cx, HandleFunction fun,
1220 MutableHandleValue v) {
1221 MOZ_ASSERT(!IsInternalFunctionObject(*fun));
1222 MOZ_ASSERT(!fun->hasResolvedLength());
1223
1224 // Bound functions' length can have values up to MAX_SAFE_INTEGER, so
1225 // they're handled differently from other functions.
1226 if (fun->isBoundFunction()) {
1227 constexpr auto lengthSlot = FunctionExtended::BOUND_FUNCTION_LENGTH_SLOT;
1228 MOZ_ASSERT(fun->getExtendedSlot(lengthSlot).isNumber());
1229 v.set(fun->getExtendedSlot(lengthSlot));
1230 return true;
1231 }
1232
1233 uint16_t length;
1234 if (!JSFunction::getLength(cx, fun, &length)) {
1235 return false;
1236 }
1237
1238 v.setInt32(length);
1239 return true;
1240 }
1241
infallibleGetUnresolvedName(JSContext * cx)1242 JSAtom* JSFunction::infallibleGetUnresolvedName(JSContext* cx) {
1243 MOZ_ASSERT(!IsInternalFunctionObject(*this));
1244 MOZ_ASSERT(!hasResolvedName());
1245
1246 if (JSAtom* name = explicitOrInferredName()) {
1247 return name;
1248 }
1249
1250 return cx->names().empty;
1251 }
1252
1253 /* static */
getUnresolvedName(JSContext * cx,HandleFunction fun,MutableHandleValue v)1254 bool JSFunction::getUnresolvedName(JSContext* cx, HandleFunction fun,
1255 MutableHandleValue v) {
1256 if (fun->isBoundFunction()) {
1257 JSLinearString* name = JSFunction::getBoundFunctionName(cx, fun);
1258 if (!name) {
1259 return false;
1260 }
1261
1262 v.setString(name);
1263 return true;
1264 }
1265
1266 v.setString(fun->infallibleGetUnresolvedName(cx));
1267 return true;
1268 }
1269
1270 /* static */
getBoundFunctionName(JSContext * cx,HandleFunction fun)1271 JSLinearString* JSFunction::getBoundFunctionName(JSContext* cx,
1272 HandleFunction fun) {
1273 MOZ_ASSERT(fun->isBoundFunction());
1274 JSAtom* name = fun->explicitName();
1275
1276 // Bound functions are never unnamed.
1277 MOZ_ASSERT(name);
1278
1279 // If the bound function prefix is present, return the name as is.
1280 if (fun->hasBoundFunctionNamePrefix()) {
1281 return name;
1282 }
1283
1284 // Otherwise return "bound " * (number of bound function targets) + name.
1285 size_t boundTargets = 0;
1286 for (JSFunction* boundFn = fun; boundFn->isBoundFunction();) {
1287 boundTargets++;
1288
1289 JSObject* target = boundFn->getBoundFunctionTarget();
1290 if (!target->is<JSFunction>()) {
1291 break;
1292 }
1293 boundFn = &target->as<JSFunction>();
1294 }
1295
1296 // |function /*unnamed*/ (){...}.bind()| is a common case, handle it here.
1297 if (name->empty() && boundTargets == 1) {
1298 return cx->names().boundWithSpace;
1299 }
1300
1301 static constexpr char boundWithSpaceChars[] = "bound ";
1302 static constexpr size_t boundWithSpaceCharsLength =
1303 js_strlen(boundWithSpaceChars);
1304 MOZ_ASSERT(
1305 StringEqualsAscii(cx->names().boundWithSpace, boundWithSpaceChars));
1306
1307 JSStringBuilder sb(cx);
1308 if (name->hasTwoByteChars() && !sb.ensureTwoByteChars()) {
1309 return nullptr;
1310 }
1311
1312 CheckedInt<size_t> len(boundTargets);
1313 len *= boundWithSpaceCharsLength;
1314 len += name->length();
1315 if (!len.isValid()) {
1316 ReportAllocationOverflow(cx);
1317 return nullptr;
1318 }
1319 if (!sb.reserve(len.value())) {
1320 return nullptr;
1321 }
1322
1323 while (boundTargets--) {
1324 sb.infallibleAppend(boundWithSpaceChars, boundWithSpaceCharsLength);
1325 }
1326 sb.infallibleAppendSubstring(name, 0, name->length());
1327
1328 return sb.finishString();
1329 }
1330
BoundFunctionEnvironmentSlotValue(const JSFunction * fun,uint32_t slotIndex)1331 static const js::Value& BoundFunctionEnvironmentSlotValue(const JSFunction* fun,
1332 uint32_t slotIndex) {
1333 MOZ_ASSERT(fun->isBoundFunction());
1334 MOZ_ASSERT(fun->environment()->is<CallObject>());
1335 CallObject* callObject = &fun->environment()->as<CallObject>();
1336 return callObject->getSlot(slotIndex);
1337 }
1338
getBoundFunctionTarget() const1339 JSObject* JSFunction::getBoundFunctionTarget() const {
1340 js::Value targetVal =
1341 BoundFunctionEnvironmentSlotValue(this, BoundFunctionEnvTargetSlot);
1342 MOZ_ASSERT(IsCallable(targetVal));
1343 return &targetVal.toObject();
1344 }
1345
getBoundFunctionThis() const1346 const js::Value& JSFunction::getBoundFunctionThis() const {
1347 return BoundFunctionEnvironmentSlotValue(this, BoundFunctionEnvThisSlot);
1348 }
1349
GetBoundFunctionArguments(const JSFunction * boundFun)1350 static ArrayObject* GetBoundFunctionArguments(const JSFunction* boundFun) {
1351 js::Value argsVal =
1352 BoundFunctionEnvironmentSlotValue(boundFun, BoundFunctionEnvArgsSlot);
1353 return &argsVal.toObject().as<ArrayObject>();
1354 }
1355
getBoundFunctionArgument(unsigned which) const1356 const js::Value& JSFunction::getBoundFunctionArgument(unsigned which) const {
1357 MOZ_ASSERT(which < getBoundFunctionArgumentCount());
1358 return GetBoundFunctionArguments(this)->getDenseElement(which);
1359 }
1360
getBoundFunctionArgumentCount() const1361 size_t JSFunction::getBoundFunctionArgumentCount() const {
1362 return GetBoundFunctionArguments(this)->length();
1363 }
1364
AppendBoundFunctionPrefix(JSContext * cx,JSString * str)1365 static JSAtom* AppendBoundFunctionPrefix(JSContext* cx, JSString* str) {
1366 static constexpr char boundWithSpaceChars[] = "bound ";
1367 MOZ_ASSERT(
1368 StringEqualsAscii(cx->names().boundWithSpace, boundWithSpaceChars));
1369
1370 StringBuffer sb(cx);
1371 if (!sb.append(boundWithSpaceChars) || !sb.append(str)) {
1372 return nullptr;
1373 }
1374 return sb.finishAtom();
1375 }
1376
1377 /* static */
finishBoundFunctionInit(JSContext * cx,HandleFunction bound,HandleObject targetObj,int32_t argCount)1378 bool JSFunction::finishBoundFunctionInit(JSContext* cx, HandleFunction bound,
1379 HandleObject targetObj,
1380 int32_t argCount) {
1381 bound->setIsBoundFunction();
1382 MOZ_ASSERT(bound->getBoundFunctionTarget() == targetObj);
1383
1384 // 9.4.1.3 BoundFunctionCreate, steps 1, 3-5, 8-12 (Already performed).
1385
1386 // 9.4.1.3 BoundFunctionCreate, step 6.
1387 if (targetObj->isConstructor()) {
1388 bound->setIsConstructor();
1389 }
1390
1391 // 9.4.1.3 BoundFunctionCreate, step 2.
1392 RootedObject proto(cx);
1393 if (!GetPrototype(cx, targetObj, &proto)) {
1394 return false;
1395 }
1396
1397 // 9.4.1.3 BoundFunctionCreate, step 7.
1398 if (bound->staticPrototype() != proto) {
1399 if (!SetPrototype(cx, bound, proto)) {
1400 return false;
1401 }
1402 }
1403
1404 double length = 0.0;
1405
1406 // Try to avoid invoking the resolve hook.
1407 if (targetObj->is<JSFunction>() &&
1408 !targetObj->as<JSFunction>().hasResolvedLength()) {
1409 RootedValue targetLength(cx);
1410 if (!JSFunction::getUnresolvedLength(cx, targetObj.as<JSFunction>(),
1411 &targetLength)) {
1412 return false;
1413 }
1414
1415 length = std::max(0.0, targetLength.toNumber() - argCount);
1416 } else {
1417 // 19.2.3.2 Function.prototype.bind, step 5.
1418 bool hasLength;
1419 RootedId idRoot(cx, NameToId(cx->names().length));
1420 if (!HasOwnProperty(cx, targetObj, idRoot, &hasLength)) {
1421 return false;
1422 }
1423
1424 // 19.2.3.2 Function.prototype.bind, step 6.
1425 if (hasLength) {
1426 RootedValue targetLength(cx);
1427 if (!GetProperty(cx, targetObj, targetObj, idRoot, &targetLength)) {
1428 return false;
1429 }
1430
1431 if (targetLength.isNumber()) {
1432 length =
1433 std::max(0.0, JS::ToInteger(targetLength.toNumber()) - argCount);
1434 }
1435 }
1436
1437 // 19.2.3.2 Function.prototype.bind, step 7 (implicit).
1438 }
1439
1440 // 19.2.3.2 Function.prototype.bind, step 8.
1441 bound->setExtendedSlot(FunctionExtended::BOUND_FUNCTION_LENGTH_SLOT,
1442 NumberValue(length));
1443
1444 MOZ_ASSERT(!bound->hasGuessedAtom());
1445
1446 // Try to avoid invoking the resolve hook.
1447 if (targetObj->is<JSFunction>() &&
1448 !targetObj->as<JSFunction>().hasResolvedName()) {
1449 JSFunction* targetFn = &targetObj->as<JSFunction>();
1450
1451 // If the target is a bound function with a prefixed name, we can't
1452 // lazily compute the full name in getBoundFunctionName(), therefore
1453 // we need to append the bound function name prefix here.
1454 if (targetFn->isBoundFunction() && targetFn->hasBoundFunctionNamePrefix()) {
1455 JSAtom* name = AppendBoundFunctionPrefix(cx, targetFn->explicitName());
1456 if (!name) {
1457 return false;
1458 }
1459 bound->setPrefixedBoundFunctionName(name);
1460 } else {
1461 JSAtom* name = targetFn->infallibleGetUnresolvedName(cx);
1462 MOZ_ASSERT(name);
1463
1464 bound->setAtom(name);
1465 }
1466 } else {
1467 // 19.2.3.2 Function.prototype.bind, step 9.
1468 RootedValue targetName(cx);
1469 if (!GetProperty(cx, targetObj, targetObj, cx->names().name, &targetName)) {
1470 return false;
1471 }
1472
1473 // 19.2.3.2 Function.prototype.bind, step 10.
1474 if (!targetName.isString()) {
1475 targetName.setString(cx->names().empty);
1476 }
1477
1478 // If the target itself is a bound function (with a resolved name), we
1479 // can't compute the full name in getBoundFunctionName() based only on
1480 // the number of bound target functions, therefore we need to store
1481 // the complete prefixed name here.
1482 if (targetObj->is<JSFunction>() &&
1483 targetObj->as<JSFunction>().isBoundFunction()) {
1484 JSAtom* name = AppendBoundFunctionPrefix(cx, targetName.toString());
1485 if (!name) {
1486 return false;
1487 }
1488 bound->setPrefixedBoundFunctionName(name);
1489 } else {
1490 JSAtom* name = AtomizeString(cx, targetName.toString());
1491 if (!name) {
1492 return false;
1493 }
1494 bound->setAtom(name);
1495 }
1496 }
1497
1498 return true;
1499 }
1500
1501 /* static */
delazifyLazilyInterpretedFunction(JSContext * cx,HandleFunction fun)1502 bool JSFunction::delazifyLazilyInterpretedFunction(JSContext* cx,
1503 HandleFunction fun) {
1504 MOZ_ASSERT(fun->hasBaseScript());
1505 MOZ_ASSERT(cx->compartment() == fun->compartment());
1506
1507 // The function must be same-compartment but might be cross-realm. Make sure
1508 // the script is created in the function's realm.
1509 AutoRealm ar(cx, fun);
1510
1511 Rooted<BaseScript*> lazy(cx, fun->baseScript());
1512 RootedFunction canonicalFun(cx, lazy->function());
1513
1514 // If this function is non-canonical, then use the canonical function first
1515 // to get the delazified script. This may result in calling this method
1516 // again on the canonical function. This ensures the canonical function is
1517 // always non-lazy if any of the clones are non-lazy.
1518 if (fun != canonicalFun) {
1519 JSScript* script = JSFunction::getOrCreateScript(cx, canonicalFun);
1520 if (!script) {
1521 return false;
1522 }
1523
1524 // Delazifying the canonical function should naturally make us non-lazy
1525 // because we share a BaseScript with the canonical function.
1526 MOZ_ASSERT(fun->hasBytecode());
1527 return true;
1528 }
1529
1530 // Finally, compile the script if it really doesn't exist.
1531 if (!frontend::DelazifyCanonicalScriptedFunction(cx, fun)) {
1532 // The frontend shouldn't fail after linking the function and the
1533 // non-lazy script together.
1534 MOZ_ASSERT(fun->baseScript() == lazy);
1535 MOZ_ASSERT(lazy->isReadyForDelazification());
1536 return false;
1537 }
1538
1539 return true;
1540 }
1541
1542 /* static */
delazifySelfHostedLazyFunction(JSContext * cx,js::HandleFunction fun)1543 bool JSFunction::delazifySelfHostedLazyFunction(JSContext* cx,
1544 js::HandleFunction fun) {
1545 MOZ_ASSERT(cx->compartment() == fun->compartment());
1546
1547 // The function must be same-compartment but might be cross-realm. Make sure
1548 // the script is created in the function's realm.
1549 AutoRealm ar(cx, fun);
1550
1551 /* Lazily cloned self-hosted script. */
1552 MOZ_ASSERT(fun->isSelfHostedBuiltin());
1553 Rooted<PropertyName*> funName(cx, GetClonedSelfHostedFunctionName(fun));
1554 if (!funName) {
1555 return false;
1556 }
1557 return cx->runtime()->cloneSelfHostedFunctionScript(cx, funName, fun);
1558 }
1559
maybeRelazify(JSRuntime * rt)1560 void JSFunction::maybeRelazify(JSRuntime* rt) {
1561 MOZ_ASSERT(!isIncomplete(), "Cannot relazify incomplete functions");
1562
1563 // Don't relazify functions in compartments that are active.
1564 Realm* realm = this->realm();
1565 if (!rt->allowRelazificationForTesting) {
1566 if (realm->compartment()->gcState.hasEnteredRealm) {
1567 return;
1568 }
1569
1570 MOZ_ASSERT(!realm->hasBeenEnteredIgnoringJit());
1571 }
1572
1573 // The caller should have checked we're not in the self-hosting zone (it's
1574 // shared with worker runtimes so relazifying functions in it will race).
1575 MOZ_ASSERT(!realm->isSelfHostingRealm());
1576
1577 // Don't relazify if the realm is being debugged. The debugger side-tables
1578 // such as the set of active breakpoints require bytecode to exist.
1579 if (realm->isDebuggee()) {
1580 return;
1581 }
1582
1583 // Don't relazify if we are collecting coverage so that we do not lose count
1584 // information.
1585 if (coverage::IsLCovEnabled()) {
1586 return;
1587 }
1588
1589 // Check the script's eligibility.
1590 JSScript* script = nonLazyScript();
1591 if (!script->allowRelazify()) {
1592 return;
1593 }
1594 MOZ_ASSERT(script->isRelazifiable());
1595
1596 // There must not be any JIT code attached since the relazification process
1597 // does not know how to discard it. In general, the GC should discard most JIT
1598 // code before attempting relazification.
1599 if (script->hasJitScript()) {
1600 return;
1601 }
1602
1603 if (isSelfHostedBuiltin()) {
1604 gc::PreWriteBarrier(script);
1605 initSelfHostedLazyScript(&rt->selfHostedLazyScript.ref());
1606 } else {
1607 script->relazify(rt);
1608 }
1609 }
1610
clonedSelfHostedGeneratorKind() const1611 js::GeneratorKind JSFunction::clonedSelfHostedGeneratorKind() const {
1612 MOZ_ASSERT(hasSelfHostedLazyScript());
1613
1614 // This is a lazy clone of a self-hosted builtin. It has no BaseScript, and
1615 // `this->flags_` does not contain the generator kind. Consult the
1616 // implementation in the self-hosting realm, which has a BaseScript.
1617 MOZ_RELEASE_ASSERT(isExtended());
1618 PropertyName* name = GetClonedSelfHostedFunctionName(this);
1619 return runtimeFromMainThread()->getSelfHostedFunctionGeneratorKind(name);
1620 }
1621
1622 // ES2018 draft rev 2aea8f3e617b49df06414eb062ab44fad87661d3
1623 // 19.2.1.1.1 CreateDynamicFunction( constructor, newTarget, kind, args )
CreateDynamicFunction(JSContext * cx,const CallArgs & args,GeneratorKind generatorKind,FunctionAsyncKind asyncKind)1624 static bool CreateDynamicFunction(JSContext* cx, const CallArgs& args,
1625 GeneratorKind generatorKind,
1626 FunctionAsyncKind asyncKind) {
1627 using namespace frontend;
1628
1629 // Steps 1-5.
1630 bool isGenerator = generatorKind == GeneratorKind::Generator;
1631 bool isAsync = asyncKind == FunctionAsyncKind::AsyncFunction;
1632
1633 RootedScript maybeScript(cx);
1634 const char* filename;
1635 unsigned lineno;
1636 bool mutedErrors;
1637 uint32_t pcOffset;
1638 DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno,
1639 &pcOffset, &mutedErrors);
1640
1641 const char* introductionType = "Function";
1642 if (isAsync) {
1643 if (isGenerator) {
1644 introductionType = "AsyncGenerator";
1645 } else {
1646 introductionType = "AsyncFunction";
1647 }
1648 } else if (isGenerator) {
1649 introductionType = "GeneratorFunction";
1650 }
1651
1652 const char* introducerFilename = filename;
1653 if (maybeScript && maybeScript->scriptSource()->introducerFilename()) {
1654 introducerFilename = maybeScript->scriptSource()->introducerFilename();
1655 }
1656
1657 CompileOptions options(cx);
1658 options.setMutedErrors(mutedErrors)
1659 .setFileAndLine(filename, 1)
1660 .setNoScriptRval(false)
1661 .setIntroductionInfo(introducerFilename, introductionType, lineno,
1662 pcOffset)
1663 .setdeferDebugMetadata();
1664
1665 JSStringBuilder sb(cx);
1666
1667 if (isAsync) {
1668 if (!sb.append("async ")) {
1669 return false;
1670 }
1671 }
1672 if (!sb.append("function")) {
1673 return false;
1674 }
1675 if (isGenerator) {
1676 if (!sb.append('*')) {
1677 return false;
1678 }
1679 }
1680
1681 if (!sb.append(" anonymous(")) {
1682 return false;
1683 }
1684
1685 if (args.length() > 1) {
1686 RootedString str(cx);
1687
1688 // Steps 10, 14.d.
1689 unsigned n = args.length() - 1;
1690
1691 for (unsigned i = 0; i < n; i++) {
1692 // Steps 14.a-b, 14.d.i-ii.
1693 str = ToString<CanGC>(cx, args[i]);
1694 if (!str) {
1695 return false;
1696 }
1697
1698 // Steps 14.b, 14.d.iii.
1699 if (!sb.append(str)) {
1700 return false;
1701 }
1702
1703 if (i < args.length() - 2) {
1704 // Step 14.d.iii.
1705 if (!sb.append(',')) {
1706 return false;
1707 }
1708 }
1709 }
1710 }
1711
1712 if (!sb.append('\n')) {
1713 return false;
1714 }
1715
1716 // Remember the position of ")".
1717 Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
1718 MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
1719
1720 if (!sb.append(FunctionConstructorMedialSigils)) {
1721 return false;
1722 }
1723
1724 if (args.length() > 0) {
1725 // Steps 13, 14.e, 15.
1726 RootedString body(cx, ToString<CanGC>(cx, args[args.length() - 1]));
1727 if (!body || !sb.append(body)) {
1728 return false;
1729 }
1730 }
1731
1732 if (!sb.append(FunctionConstructorFinalBrace)) {
1733 return false;
1734 }
1735
1736 // The parser only accepts two byte strings.
1737 if (!sb.ensureTwoByteChars()) {
1738 return false;
1739 }
1740
1741 RootedString functionText(cx, sb.finishString());
1742 if (!functionText) {
1743 return false;
1744 }
1745
1746 // Block this call if security callbacks forbid it.
1747 Handle<GlobalObject*> global = cx->global();
1748 if (!GlobalObject::isRuntimeCodeGenEnabled(cx, functionText, global)) {
1749 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1750 JSMSG_CSP_BLOCKED_FUNCTION);
1751 return false;
1752 }
1753
1754 // Steps 7.a-b, 8.a-b, 9.a-b, 16-28.
1755 AutoStableStringChars stableChars(cx);
1756 if (!stableChars.initTwoByte(cx, functionText)) {
1757 return false;
1758 }
1759
1760 mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
1761 SourceOwnership ownership = stableChars.maybeGiveOwnershipToCaller()
1762 ? SourceOwnership::TakeOwnership
1763 : SourceOwnership::Borrowed;
1764 SourceText<char16_t> srcBuf;
1765 if (!srcBuf.init(cx, chars.begin().get(), chars.length(), ownership)) {
1766 return false;
1767 }
1768
1769 FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Expression;
1770
1771 RootedFunction fun(cx);
1772 JSProtoKey protoKey;
1773 if (isAsync) {
1774 if (isGenerator) {
1775 fun = CompileStandaloneAsyncGenerator(cx, options, srcBuf,
1776 parameterListEnd, syntaxKind);
1777 protoKey = JSProto_AsyncGeneratorFunction;
1778 } else {
1779 fun = CompileStandaloneAsyncFunction(cx, options, srcBuf,
1780 parameterListEnd, syntaxKind);
1781 protoKey = JSProto_AsyncFunction;
1782 }
1783 } else {
1784 if (isGenerator) {
1785 fun = CompileStandaloneGenerator(cx, options, srcBuf, parameterListEnd,
1786 syntaxKind);
1787 protoKey = JSProto_GeneratorFunction;
1788 } else {
1789 fun = CompileStandaloneFunction(cx, options, srcBuf, parameterListEnd,
1790 syntaxKind);
1791 protoKey = JSProto_Function;
1792 }
1793 }
1794 if (!fun) {
1795 return false;
1796 }
1797
1798 RootedValue undefValue(cx);
1799 RootedScript funScript(cx, JS_GetFunctionScript(cx, fun));
1800 if (funScript && !UpdateDebugMetadata(cx, funScript, options, undefValue,
1801 nullptr, maybeScript, maybeScript)) {
1802 return false;
1803 }
1804
1805 if (fun->isInterpreted()) {
1806 fun->initEnvironment(&cx->global()->lexicalEnvironment());
1807 }
1808
1809 // Steps 6, 29.
1810 RootedObject proto(cx);
1811 if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey, &proto)) {
1812 return false;
1813 }
1814
1815 // Steps 7.d, 8.d (implicit).
1816 // Call SetPrototype if an explicit prototype was given.
1817 if (proto && !SetPrototype(cx, fun, proto)) {
1818 return false;
1819 }
1820
1821 // Step 38.
1822 args.rval().setObject(*fun);
1823 return true;
1824 }
1825
Function(JSContext * cx,unsigned argc,Value * vp)1826 bool js::Function(JSContext* cx, unsigned argc, Value* vp) {
1827 CallArgs args = CallArgsFromVp(argc, vp);
1828 return CreateDynamicFunction(cx, args, GeneratorKind::NotGenerator,
1829 FunctionAsyncKind::SyncFunction);
1830 }
1831
Generator(JSContext * cx,unsigned argc,Value * vp)1832 bool js::Generator(JSContext* cx, unsigned argc, Value* vp) {
1833 CallArgs args = CallArgsFromVp(argc, vp);
1834 return CreateDynamicFunction(cx, args, GeneratorKind::Generator,
1835 FunctionAsyncKind::SyncFunction);
1836 }
1837
AsyncFunctionConstructor(JSContext * cx,unsigned argc,Value * vp)1838 bool js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp) {
1839 CallArgs args = CallArgsFromVp(argc, vp);
1840 return CreateDynamicFunction(cx, args, GeneratorKind::NotGenerator,
1841 FunctionAsyncKind::AsyncFunction);
1842 }
1843
AsyncGeneratorConstructor(JSContext * cx,unsigned argc,Value * vp)1844 bool js::AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp) {
1845 CallArgs args = CallArgsFromVp(argc, vp);
1846 return CreateDynamicFunction(cx, args, GeneratorKind::Generator,
1847 FunctionAsyncKind::AsyncFunction);
1848 }
1849
isBuiltinFunctionConstructor()1850 bool JSFunction::isBuiltinFunctionConstructor() {
1851 return maybeNative() == Function || maybeNative() == Generator;
1852 }
1853
needsExtraBodyVarEnvironment() const1854 bool JSFunction::needsExtraBodyVarEnvironment() const {
1855 if (isNativeFun()) {
1856 return false;
1857 }
1858
1859 if (!nonLazyScript()->functionHasExtraBodyVarScope()) {
1860 return false;
1861 }
1862
1863 return nonLazyScript()->functionExtraBodyVarScope()->hasEnvironment();
1864 }
1865
needsNamedLambdaEnvironment() const1866 bool JSFunction::needsNamedLambdaEnvironment() const {
1867 if (!isNamedLambda()) {
1868 return false;
1869 }
1870
1871 LexicalScope* scope = nonLazyScript()->maybeNamedLambdaScope();
1872 if (!scope) {
1873 return false;
1874 }
1875
1876 return scope->hasEnvironment();
1877 }
1878
needsCallObject() const1879 bool JSFunction::needsCallObject() const {
1880 if (isNativeFun()) {
1881 return false;
1882 }
1883
1884 MOZ_ASSERT(hasBytecode());
1885
1886 // Note: this should be kept in sync with
1887 // FunctionBox::needsCallObjectRegardlessOfBindings().
1888 MOZ_ASSERT_IF(
1889 baseScript()->funHasExtensibleScope() || isGenerator() || isAsync(),
1890 nonLazyScript()->bodyScope()->hasEnvironment());
1891
1892 return nonLazyScript()->bodyScope()->hasEnvironment();
1893 }
1894
NewScriptedFunction(JSContext * cx,unsigned nargs,FunctionFlags flags,HandleAtom atom,HandleObject proto,gc::AllocKind allocKind,NewObjectKind newKind,HandleObject enclosingEnvArg)1895 JSFunction* js::NewScriptedFunction(
1896 JSContext* cx, unsigned nargs, FunctionFlags flags, HandleAtom atom,
1897 HandleObject proto /* = nullptr */,
1898 gc::AllocKind allocKind /* = AllocKind::FUNCTION */,
1899 NewObjectKind newKind /* = GenericObject */,
1900 HandleObject enclosingEnvArg /* = nullptr */) {
1901 RootedObject enclosingEnv(cx, enclosingEnvArg);
1902 if (!enclosingEnv) {
1903 enclosingEnv = &cx->global()->lexicalEnvironment();
1904 }
1905 return NewFunctionWithProto(cx, nullptr, nargs, flags, enclosingEnv, atom,
1906 proto, allocKind, newKind);
1907 }
1908
1909 #ifdef DEBUG
SkipEnvironmentObjects(JSObject * env)1910 static JSObject* SkipEnvironmentObjects(JSObject* env) {
1911 if (!env) {
1912 return nullptr;
1913 }
1914 while (env->is<EnvironmentObject>()) {
1915 env = &env->as<EnvironmentObject>().enclosingEnvironment();
1916 }
1917 return env;
1918 }
1919
NewFunctionEnvironmentIsWellFormed(JSContext * cx,HandleObject env)1920 static bool NewFunctionEnvironmentIsWellFormed(JSContext* cx,
1921 HandleObject env) {
1922 // Assert that the terminating environment is null, global, or a debug
1923 // scope proxy. All other cases of polluting global scope behavior are
1924 // handled by EnvironmentObjects (viz. non-syntactic DynamicWithObject and
1925 // NonSyntacticVariablesObject).
1926 RootedObject terminatingEnv(cx, SkipEnvironmentObjects(env));
1927 return !terminatingEnv || terminatingEnv == cx->global() ||
1928 terminatingEnv->is<DebugEnvironmentProxy>();
1929 }
1930 #endif
1931
NewFunctionWithProto(JSContext * cx,Native native,unsigned nargs,FunctionFlags flags,HandleObject enclosingEnv,HandleAtom atom,HandleObject proto,gc::AllocKind allocKind,NewObjectKind newKind)1932 JSFunction* js::NewFunctionWithProto(
1933 JSContext* cx, Native native, unsigned nargs, FunctionFlags flags,
1934 HandleObject enclosingEnv, HandleAtom atom, HandleObject proto,
1935 gc::AllocKind allocKind /* = AllocKind::FUNCTION */,
1936 NewObjectKind newKind /* = GenericObject */) {
1937 MOZ_ASSERT(allocKind == gc::AllocKind::FUNCTION ||
1938 allocKind == gc::AllocKind::FUNCTION_EXTENDED);
1939 MOZ_ASSERT_IF(native, !enclosingEnv);
1940 MOZ_ASSERT(NewFunctionEnvironmentIsWellFormed(cx, enclosingEnv));
1941
1942 // NOTE: Keep this in sync with `CreateFunctionFast` in Stencil.cpp
1943
1944 JSFunction* fun =
1945 NewObjectWithClassProto<JSFunction>(cx, proto, allocKind, newKind);
1946 if (!fun) {
1947 return nullptr;
1948 }
1949
1950 if (allocKind == gc::AllocKind::FUNCTION_EXTENDED) {
1951 flags.setIsExtended();
1952 }
1953
1954 // Disallow flags that require special union arms to be initialized.
1955 MOZ_ASSERT(!flags.hasSelfHostedLazyScript());
1956 MOZ_ASSERT(!flags.isWasmWithJitEntry());
1957
1958 /* Initialize all function members. */
1959 fun->setArgCount(uint16_t(nargs));
1960 fun->setFlags(flags);
1961 if (fun->isInterpreted()) {
1962 fun->initScript(nullptr);
1963 fun->initEnvironment(enclosingEnv);
1964 } else {
1965 MOZ_ASSERT(fun->isNativeFun());
1966 fun->initNative(native, nullptr);
1967 }
1968 if (allocKind == gc::AllocKind::FUNCTION_EXTENDED) {
1969 fun->initializeExtended();
1970 }
1971 fun->initAtom(atom);
1972
1973 return fun;
1974 }
1975
GetFunctionPrototype(JSContext * cx,js::GeneratorKind generatorKind,js::FunctionAsyncKind asyncKind,js::MutableHandleObject proto)1976 bool js::GetFunctionPrototype(JSContext* cx, js::GeneratorKind generatorKind,
1977 js::FunctionAsyncKind asyncKind,
1978 js::MutableHandleObject proto) {
1979 // Self-hosted functions have null [[Prototype]]. This allows self-hosting to
1980 // support generators, despite this loop in the builtin object graph:
1981 // - %Generator%.prototype.[[Prototype]] is Iterator.prototype;
1982 // - Iterator.prototype has self-hosted methods (iterator helpers).
1983 if (cx->realm()->isSelfHostingRealm()) {
1984 proto.set(nullptr);
1985 return true;
1986 }
1987
1988 if (generatorKind == js::GeneratorKind::NotGenerator) {
1989 if (asyncKind == js::FunctionAsyncKind::SyncFunction) {
1990 proto.set(nullptr);
1991 return true;
1992 }
1993
1994 proto.set(
1995 GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global()));
1996 } else {
1997 if (asyncKind == js::FunctionAsyncKind::SyncFunction) {
1998 proto.set(GlobalObject::getOrCreateGeneratorFunctionPrototype(
1999 cx, cx->global()));
2000 } else {
2001 proto.set(GlobalObject::getOrCreateAsyncGenerator(cx, cx->global()));
2002 }
2003 }
2004 return !!proto;
2005 }
2006
CanReuseScriptForClone(JS::Realm * realm,HandleFunction fun,HandleObject newEnclosingEnv)2007 bool js::CanReuseScriptForClone(JS::Realm* realm, HandleFunction fun,
2008 HandleObject newEnclosingEnv) {
2009 MOZ_ASSERT(fun->isInterpreted());
2010
2011 if (realm != fun->realm()) {
2012 return false;
2013 }
2014
2015 if (newEnclosingEnv->is<GlobalObject>()) {
2016 return true;
2017 }
2018
2019 // Don't need to clone the script if newEnclosingEnv is a syntactic scope,
2020 // since in that case we have some actual scope objects on our scope chain and
2021 // whatnot; whoever put them there should be responsible for setting our
2022 // script's flags appropriately. We hit this case for JSOp::Lambda, for
2023 // example.
2024 if (IsSyntacticEnvironment(newEnclosingEnv)) {
2025 return true;
2026 }
2027
2028 // We need to clone the script if we're not already marked as having a
2029 // non-syntactic scope. The HasNonSyntacticScope flag is not computed for lazy
2030 // scripts so fallback to checking the scope chain.
2031 BaseScript* script = fun->baseScript();
2032 return script->hasNonSyntacticScope() ||
2033 script->enclosingScope()->hasOnChain(ScopeKind::NonSyntactic);
2034 }
2035
NewFunctionClone(JSContext * cx,HandleFunction fun,NewObjectKind newKind,gc::AllocKind allocKind,HandleObject proto)2036 static inline JSFunction* NewFunctionClone(JSContext* cx, HandleFunction fun,
2037 NewObjectKind newKind,
2038 gc::AllocKind allocKind,
2039 HandleObject proto) {
2040 RootedObject cloneProto(cx, proto);
2041 if (!proto) {
2042 if (!GetFunctionPrototype(cx, fun->generatorKind(), fun->asyncKind(),
2043 &cloneProto)) {
2044 return nullptr;
2045 }
2046 }
2047
2048 RootedFunction clone(cx);
2049 clone =
2050 NewObjectWithClassProto<JSFunction>(cx, cloneProto, allocKind, newKind);
2051 if (!clone) {
2052 return nullptr;
2053 }
2054
2055 constexpr uint16_t NonCloneableFlags = FunctionFlags::EXTENDED |
2056 FunctionFlags::RESOLVED_LENGTH |
2057 FunctionFlags::RESOLVED_NAME;
2058
2059 FunctionFlags flags = fun->flags();
2060 flags.clearFlags(NonCloneableFlags);
2061
2062 if (allocKind == gc::AllocKind::FUNCTION_EXTENDED) {
2063 flags.setIsExtended();
2064 }
2065
2066 clone->setArgCount(fun->nargs());
2067 clone->setFlags(flags);
2068
2069 JSAtom* atom = fun->displayAtom();
2070 if (atom) {
2071 cx->markAtom(atom);
2072 }
2073 clone->initAtom(atom);
2074
2075 if (allocKind == gc::AllocKind::FUNCTION_EXTENDED) {
2076 if (fun->isExtended() && fun->compartment() == cx->compartment()) {
2077 for (unsigned i = 0; i < FunctionExtended::NUM_EXTENDED_SLOTS; i++) {
2078 clone->initExtendedSlot(i, fun->getExtendedSlot(i));
2079 }
2080 } else {
2081 clone->initializeExtended();
2082 }
2083 }
2084
2085 return clone;
2086 }
2087
CloneFunctionReuseScript(JSContext * cx,HandleFunction fun,HandleObject enclosingEnv,gc::AllocKind allocKind,HandleObject proto)2088 JSFunction* js::CloneFunctionReuseScript(JSContext* cx, HandleFunction fun,
2089 HandleObject enclosingEnv,
2090 gc::AllocKind allocKind,
2091 HandleObject proto) {
2092 MOZ_ASSERT(cx->realm() == fun->realm());
2093 MOZ_ASSERT(NewFunctionEnvironmentIsWellFormed(cx, enclosingEnv));
2094 MOZ_ASSERT(fun->isInterpreted());
2095 MOZ_ASSERT(!fun->isBoundFunction());
2096 MOZ_ASSERT(CanReuseScriptForClone(cx->realm(), fun, enclosingEnv));
2097
2098 NewObjectKind newKind = GenericObject;
2099 RootedFunction clone(cx,
2100 NewFunctionClone(cx, fun, newKind, allocKind, proto));
2101 if (!clone) {
2102 return nullptr;
2103 }
2104
2105 if (fun->hasBaseScript()) {
2106 BaseScript* base = fun->baseScript();
2107 clone->initScript(base);
2108 clone->initEnvironment(enclosingEnv);
2109 } else {
2110 MOZ_ASSERT(fun->hasSelfHostedLazyScript());
2111 SelfHostedLazyScript* lazy = fun->selfHostedLazyScript();
2112 clone->initSelfHostedLazyScript(lazy);
2113 clone->initEnvironment(enclosingEnv);
2114 }
2115
2116 return clone;
2117 }
2118
CloneFunctionAndScript(JSContext * cx,HandleFunction fun,HandleObject enclosingEnv,HandleScope newScope,Handle<ScriptSourceObject * > sourceObject,gc::AllocKind allocKind,HandleObject proto)2119 JSFunction* js::CloneFunctionAndScript(JSContext* cx, HandleFunction fun,
2120 HandleObject enclosingEnv,
2121 HandleScope newScope,
2122 Handle<ScriptSourceObject*> sourceObject,
2123 gc::AllocKind allocKind,
2124 HandleObject proto /* = nullptr */) {
2125 MOZ_ASSERT(NewFunctionEnvironmentIsWellFormed(cx, enclosingEnv));
2126 MOZ_ASSERT(fun->isInterpreted());
2127 MOZ_ASSERT(!fun->isBoundFunction());
2128
2129 JSScript::AutoDelazify funScript(cx, fun);
2130 if (!funScript) {
2131 return nullptr;
2132 }
2133
2134 RootedFunction clone(
2135 cx, NewFunctionClone(cx, fun, TenuredObject, allocKind, proto));
2136 if (!clone) {
2137 return nullptr;
2138 }
2139
2140 clone->initScript(nullptr);
2141 clone->initEnvironment(enclosingEnv);
2142
2143 RootedScript script(cx, fun->nonLazyScript());
2144 MOZ_ASSERT(script->realm() == fun->realm());
2145 MOZ_ASSERT(cx->compartment() == clone->compartment(),
2146 "Otherwise we could relazify clone below!");
2147
2148 RootedScript clonedScript(
2149 cx, CloneScriptIntoFunction(cx, newScope, clone, script, sourceObject));
2150 if (!clonedScript) {
2151 return nullptr;
2152 }
2153 DebugAPI::onNewScript(cx, clonedScript);
2154
2155 return clone;
2156 }
2157
CloneAsmJSModuleFunction(JSContext * cx,HandleFunction fun)2158 JSFunction* js::CloneAsmJSModuleFunction(JSContext* cx, HandleFunction fun) {
2159 MOZ_ASSERT(fun->isNativeFun());
2160 MOZ_ASSERT(IsAsmJSModule(fun));
2161 MOZ_ASSERT(fun->isExtended());
2162 MOZ_ASSERT(cx->compartment() == fun->compartment());
2163
2164 JSFunction* clone =
2165 NewFunctionClone(cx, fun, GenericObject, gc::AllocKind::FUNCTION_EXTENDED,
2166 /* proto = */ nullptr);
2167 if (!clone) {
2168 return nullptr;
2169 }
2170
2171 MOZ_ASSERT(fun->native() == InstantiateAsmJS);
2172 MOZ_ASSERT(!fun->hasJitInfo());
2173 clone->initNative(InstantiateAsmJS, nullptr);
2174
2175 return clone;
2176 }
2177
CloneSelfHostingIntrinsic(JSContext * cx,HandleFunction fun)2178 JSFunction* js::CloneSelfHostingIntrinsic(JSContext* cx, HandleFunction fun) {
2179 MOZ_ASSERT(fun->isNativeFun());
2180 MOZ_ASSERT(fun->realm()->isSelfHostingRealm());
2181 MOZ_ASSERT(!fun->isExtended());
2182 MOZ_ASSERT(cx->compartment() != fun->compartment());
2183
2184 JSFunction* clone =
2185 NewFunctionClone(cx, fun, TenuredObject, gc::AllocKind::FUNCTION,
2186 /* proto = */ nullptr);
2187 if (!clone) {
2188 return nullptr;
2189 }
2190
2191 clone->initNative(fun->native(),
2192 fun->hasJitInfo() ? fun->jitInfo() : nullptr);
2193 return clone;
2194 }
2195
SymbolToFunctionName(JSContext * cx,JS::Symbol * symbol,FunctionPrefixKind prefixKind)2196 static JSAtom* SymbolToFunctionName(JSContext* cx, JS::Symbol* symbol,
2197 FunctionPrefixKind prefixKind) {
2198 // Step 4.a.
2199 JSAtom* desc = symbol->description();
2200
2201 // Step 4.b, no prefix fastpath.
2202 if (!desc && prefixKind == FunctionPrefixKind::None) {
2203 return cx->names().empty;
2204 }
2205
2206 // Step 5 (reordered).
2207 StringBuffer sb(cx);
2208 if (prefixKind == FunctionPrefixKind::Get) {
2209 if (!sb.append("get ")) {
2210 return nullptr;
2211 }
2212 } else if (prefixKind == FunctionPrefixKind::Set) {
2213 if (!sb.append("set ")) {
2214 return nullptr;
2215 }
2216 }
2217
2218 // Step 4.b.
2219 if (desc) {
2220 // Note: Private symbols are wedged in, as implementation wise they're
2221 // PrivateNameSymbols with a the source level name as a description
2222 // i.e. obj.#f desugars to obj.[PrivateNameSymbol("#f")], however
2223 // they don't use the symbol naming, but rather property naming.
2224 if (symbol->isPrivateName()) {
2225 if (!sb.append(desc)) {
2226 return nullptr;
2227 }
2228 } else {
2229 // Step 4.c.
2230 if (!sb.append('[') || !sb.append(desc) || !sb.append(']')) {
2231 return nullptr;
2232 }
2233 }
2234 }
2235 return sb.finishAtom();
2236 }
2237
NameToFunctionName(JSContext * cx,HandleValue name,FunctionPrefixKind prefixKind)2238 static JSAtom* NameToFunctionName(JSContext* cx, HandleValue name,
2239 FunctionPrefixKind prefixKind) {
2240 MOZ_ASSERT(name.isString() || name.isNumeric());
2241
2242 if (prefixKind == FunctionPrefixKind::None) {
2243 return ToAtom<CanGC>(cx, name);
2244 }
2245
2246 JSString* nameStr = ToString(cx, name);
2247 if (!nameStr) {
2248 return nullptr;
2249 }
2250
2251 StringBuffer sb(cx);
2252 if (prefixKind == FunctionPrefixKind::Get) {
2253 if (!sb.append("get ")) {
2254 return nullptr;
2255 }
2256 } else {
2257 if (!sb.append("set ")) {
2258 return nullptr;
2259 }
2260 }
2261 if (!sb.append(nameStr)) {
2262 return nullptr;
2263 }
2264 return sb.finishAtom();
2265 }
2266
2267 /*
2268 * Return an atom for use as the name of a builtin method with the given
2269 * property id.
2270 *
2271 * Function names are always strings. If id is the well-known @@iterator
2272 * symbol, this returns "[Symbol.iterator]". If a prefix is supplied the final
2273 * name is |prefix + " " + name|.
2274 *
2275 * Implements steps 3-5 of 9.2.11 SetFunctionName in ES2016.
2276 */
IdToFunctionName(JSContext * cx,HandleId id,FunctionPrefixKind prefixKind)2277 JSAtom* js::IdToFunctionName(
2278 JSContext* cx, HandleId id,
2279 FunctionPrefixKind prefixKind /* = FunctionPrefixKind::None */) {
2280 MOZ_ASSERT(id.isString() || id.isSymbol() || id.isInt());
2281
2282 // No prefix fastpath.
2283 if (id.isAtom() && prefixKind == FunctionPrefixKind::None) {
2284 return id.toAtom();
2285 }
2286
2287 // Step 3 (implicit).
2288
2289 // Step 4.
2290 if (id.isSymbol()) {
2291 return SymbolToFunctionName(cx, id.toSymbol(), prefixKind);
2292 }
2293
2294 // Step 5.
2295 RootedValue idv(cx, IdToValue(id));
2296 return NameToFunctionName(cx, idv, prefixKind);
2297 }
2298
SetFunctionName(JSContext * cx,HandleFunction fun,HandleValue name,FunctionPrefixKind prefixKind)2299 bool js::SetFunctionName(JSContext* cx, HandleFunction fun, HandleValue name,
2300 FunctionPrefixKind prefixKind) {
2301 MOZ_ASSERT(name.isString() || name.isSymbol() || name.isNumeric());
2302
2303 // `fun` is a newly created function, so it can't already have an inferred
2304 // name.
2305 MOZ_ASSERT(!fun->hasInferredName());
2306
2307 // Anonymous functions should neither have an own 'name' property nor a
2308 // resolved name at this point.
2309 MOZ_ASSERT(!fun->containsPure(cx->names().name));
2310 MOZ_ASSERT(!fun->hasResolvedName());
2311
2312 JSAtom* funName = name.isSymbol()
2313 ? SymbolToFunctionName(cx, name.toSymbol(), prefixKind)
2314 : NameToFunctionName(cx, name, prefixKind);
2315 if (!funName) {
2316 return false;
2317 }
2318
2319 fun->setInferredName(funName);
2320
2321 return true;
2322 }
2323
DefineFunction(JSContext * cx,HandleObject obj,HandleId id,Native native,unsigned nargs,unsigned flags,gc::AllocKind allocKind)2324 JSFunction* js::DefineFunction(
2325 JSContext* cx, HandleObject obj, HandleId id, Native native, unsigned nargs,
2326 unsigned flags, gc::AllocKind allocKind /* = AllocKind::FUNCTION */) {
2327 RootedAtom atom(cx, IdToFunctionName(cx, id));
2328 if (!atom) {
2329 return nullptr;
2330 }
2331
2332 MOZ_ASSERT(native);
2333
2334 RootedFunction fun(cx);
2335 if (flags & JSFUN_CONSTRUCTOR) {
2336 fun = NewNativeConstructor(cx, native, nargs, atom, allocKind);
2337 } else {
2338 fun = NewNativeFunction(cx, native, nargs, atom, allocKind);
2339 }
2340
2341 if (!fun) {
2342 return nullptr;
2343 }
2344
2345 RootedValue funVal(cx, ObjectValue(*fun));
2346 if (!DefineDataProperty(cx, obj, id, funVal, flags & ~JSFUN_FLAGS_MASK)) {
2347 return nullptr;
2348 }
2349
2350 return fun;
2351 }
2352
ReportIncompatibleMethod(JSContext * cx,const CallArgs & args,const JSClass * clasp)2353 void js::ReportIncompatibleMethod(JSContext* cx, const CallArgs& args,
2354 const JSClass* clasp) {
2355 RootedValue thisv(cx, args.thisv());
2356
2357 #ifdef DEBUG
2358 switch (thisv.type()) {
2359 case ValueType::Object:
2360 MOZ_ASSERT(thisv.toObject().getClass() != clasp ||
2361 !thisv.toObject().is<NativeObject>() ||
2362 !thisv.toObject().staticPrototype() ||
2363 thisv.toObject().staticPrototype()->getClass() != clasp);
2364 break;
2365 case ValueType::String:
2366 MOZ_ASSERT(clasp != &StringObject::class_);
2367 break;
2368 case ValueType::Double:
2369 case ValueType::Int32:
2370 MOZ_ASSERT(clasp != &NumberObject::class_);
2371 break;
2372 case ValueType::Boolean:
2373 MOZ_ASSERT(clasp != &BooleanObject::class_);
2374 break;
2375 case ValueType::Symbol:
2376 MOZ_ASSERT(clasp != &SymbolObject::class_);
2377 break;
2378 case ValueType::BigInt:
2379 MOZ_ASSERT(clasp != &BigIntObject::class_);
2380 break;
2381 case ValueType::Undefined:
2382 case ValueType::Null:
2383 break;
2384 case ValueType::Magic:
2385 case ValueType::PrivateGCThing:
2386 MOZ_CRASH("unexpected type");
2387 }
2388 #endif
2389
2390 if (JSFunction* fun = ReportIfNotFunction(cx, args.calleev())) {
2391 UniqueChars funNameBytes;
2392 if (const char* funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
2393 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
2394 JSMSG_INCOMPATIBLE_PROTO, clasp->name, funName,
2395 InformalValueTypeName(thisv));
2396 }
2397 }
2398 }
2399
ReportIncompatible(JSContext * cx,const CallArgs & args)2400 void js::ReportIncompatible(JSContext* cx, const CallArgs& args) {
2401 if (JSFunction* fun = ReportIfNotFunction(cx, args.calleev())) {
2402 UniqueChars funNameBytes;
2403 if (const char* funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
2404 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
2405 JSMSG_INCOMPATIBLE_METHOD, funName, "method",
2406 InformalValueTypeName(args.thisv()));
2407 }
2408 }
2409 }
2410
2411 namespace JS {
2412 namespace detail {
2413
CheckIsValidConstructible(const Value & calleev)2414 JS_PUBLIC_API void CheckIsValidConstructible(const Value& calleev) {
2415 MOZ_ASSERT(calleev.toObject().isConstructor());
2416 }
2417
2418 } // namespace detail
2419 } // namespace JS
2420