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