summaryrefslogtreecommitdiffstats
path: root/js/src/jsfuninlines.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jsfuninlines.h')
-rw-r--r--js/src/jsfuninlines.h100
1 files changed, 100 insertions, 0 deletions
diff --git a/js/src/jsfuninlines.h b/js/src/jsfuninlines.h
new file mode 100644
index 000000000..8286a7d6a
--- /dev/null
+++ b/js/src/jsfuninlines.h
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jsfuninlines_h
+#define jsfuninlines_h
+
+#include "jsfun.h"
+
+#include "vm/EnvironmentObject.h"
+
+namespace js {
+
+inline const char*
+GetFunctionNameBytes(JSContext* cx, JSFunction* fun, JSAutoByteString* bytes)
+{
+ if (JSAtom* name = fun->name())
+ return bytes->encodeLatin1(cx, name);
+ return js_anonymous_str;
+}
+
+static inline JSObject*
+SkipEnvironmentObjects(JSObject* env)
+{
+ if (!env)
+ return nullptr;
+ while (env->is<EnvironmentObject>())
+ env = &env->as<EnvironmentObject>().enclosingEnvironment();
+ return env;
+}
+
+inline bool
+CanReuseFunctionForClone(JSContext* cx, HandleFunction fun)
+{
+ if (!fun->isSingleton())
+ return false;
+ if (fun->isInterpretedLazy()) {
+ LazyScript* lazy = fun->lazyScript();
+ if (lazy->hasBeenCloned())
+ return false;
+ lazy->setHasBeenCloned();
+ } else {
+ JSScript* script = fun->nonLazyScript();
+ if (script->hasBeenCloned())
+ return false;
+ script->setHasBeenCloned();
+ }
+ return true;
+}
+
+inline JSFunction*
+CloneFunctionObjectIfNotSingleton(JSContext* cx, HandleFunction fun, HandleObject parent,
+ HandleObject proto = nullptr,
+ NewObjectKind newKind = GenericObject)
+{
+ /*
+ * For attempts to clone functions at a function definition opcode,
+ * try to avoid the the clone if the function has singleton type. This
+ * was called pessimistically, and we need to preserve the type's
+ * property that if it is singleton there is only a single object
+ * with its type in existence.
+ *
+ * For functions inner to run once lambda, it may be possible that
+ * the lambda runs multiple times and we repeatedly clone it. In these
+ * cases, fall through to CloneFunctionObject, which will deep clone
+ * the function's script.
+ */
+ if (CanReuseFunctionForClone(cx, fun)) {
+ RootedObject obj(cx, SkipEnvironmentObjects(parent));
+ ObjectOpResult succeeded;
+ if (proto && !SetPrototype(cx, fun, proto, succeeded))
+ return nullptr;
+ MOZ_ASSERT(!proto || succeeded);
+ fun->setEnvironment(parent);
+ return fun;
+ }
+
+ // These intermediate variables are needed to avoid link errors on some
+ // platforms. Sigh.
+ gc::AllocKind finalizeKind = gc::AllocKind::FUNCTION;
+ gc::AllocKind extendedFinalizeKind = gc::AllocKind::FUNCTION_EXTENDED;
+ gc::AllocKind kind = fun->isExtended()
+ ? extendedFinalizeKind
+ : finalizeKind;
+
+ if (CanReuseScriptForClone(cx->compartment(), fun, parent))
+ return CloneFunctionReuseScript(cx, fun, parent, kind, newKind, proto);
+
+ RootedScript script(cx, fun->getOrCreateScript(cx));
+ if (!script)
+ return nullptr;
+ RootedScope enclosingScope(cx, script->enclosingScope());
+ return CloneFunctionAndScript(cx, fun, parent, enclosingScope, kind, proto);
+}
+
+} /* namespace js */
+
+#endif /* jsfuninlines_h */