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 #ifndef jsfuninlines_h
8 #define jsfuninlines_h
9 
10 #include "jsfun.h"
11 
12 #include "vm/ScopeObject.h"
13 
14 namespace js {
15 
16 inline const char*
GetFunctionNameBytes(JSContext * cx,JSFunction * fun,JSAutoByteString * bytes)17 GetFunctionNameBytes(JSContext* cx, JSFunction* fun, JSAutoByteString* bytes)
18 {
19     JSAtom* atom = fun->atom();
20     if (atom)
21         return bytes->encodeLatin1(cx, atom);
22     return js_anonymous_str;
23 }
24 
25 static inline JSObject*
SkipScopeParent(JSObject * parent)26 SkipScopeParent(JSObject* parent)
27 {
28     if (!parent)
29         return nullptr;
30     while (parent->is<ScopeObject>())
31         parent = &parent->as<ScopeObject>().enclosingScope();
32     return parent;
33 }
34 
35 inline bool
CanReuseFunctionForClone(JSContext * cx,HandleFunction fun)36 CanReuseFunctionForClone(JSContext* cx, HandleFunction fun)
37 {
38     if (!fun->isSingleton())
39         return false;
40     if (fun->isInterpretedLazy()) {
41         LazyScript* lazy = fun->lazyScript();
42         if (lazy->hasBeenCloned())
43             return false;
44         lazy->setHasBeenCloned();
45     } else {
46         JSScript* script = fun->nonLazyScript();
47         if (script->hasBeenCloned())
48             return false;
49         script->setHasBeenCloned();
50     }
51     return true;
52 }
53 
54 inline JSFunction*
55 CloneFunctionObjectIfNotSingleton(JSContext* cx, HandleFunction fun, HandleObject parent,
56                                   HandleObject proto = nullptr,
57                                   NewObjectKind newKind = GenericObject)
58 {
59     /*
60      * For attempts to clone functions at a function definition opcode,
61      * try to avoid the the clone if the function has singleton type. This
62      * was called pessimistically, and we need to preserve the type's
63      * property that if it is singleton there is only a single object
64      * with its type in existence.
65      *
66      * For functions inner to run once lambda, it may be possible that
67      * the lambda runs multiple times and we repeatedly clone it. In these
68      * cases, fall through to CloneFunctionObject, which will deep clone
69      * the function's script.
70      */
71     if (CanReuseFunctionForClone(cx, fun)) {
72         RootedObject obj(cx, SkipScopeParent(parent));
73         ObjectOpResult succeeded;
74         if (proto && !SetPrototype(cx, fun, proto, succeeded))
75             return nullptr;
76         MOZ_ASSERT(!proto || succeeded);
77         fun->setEnvironment(parent);
78         return fun;
79     }
80 
81     // These intermediate variables are needed to avoid link errors on some
82     // platforms.  Sigh.
83     gc::AllocKind finalizeKind = gc::AllocKind::FUNCTION;
84     gc::AllocKind extendedFinalizeKind = gc::AllocKind::FUNCTION_EXTENDED;
85     gc::AllocKind kind = fun->isExtended()
86                          ? extendedFinalizeKind
87                          : finalizeKind;
88 
89     if (CanReuseScriptForClone(cx->compartment(), fun, parent))
90         return CloneFunctionReuseScript(cx, fun, parent, kind, newKind, proto);
91 
92     RootedScript script(cx, fun->getOrCreateScript(cx));
93     if (!script)
94         return nullptr;
95     RootedObject staticScope(cx, script->enclosingStaticScope());
96     return CloneFunctionAndScript(cx, fun, parent, staticScope, kind, proto);
97 }
98 
99 } /* namespace js */
100 
101 #endif /* jsfuninlines_h */
102