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