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