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