-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathJSFunction-inl.h
149 lines (119 loc) · 4.78 KB
/
JSFunction-inl.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* 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 vm_JSFunction_inl_h
#define vm_JSFunction_inl_h
#include "vm/JSFunction.h"
#include "gc/Allocator.h"
#include "gc/GCProbes.h"
#include "js/CharacterEncoding.h"
#include "vm/EnvironmentObject.h"
#include "vm/JSObject-inl.h"
#include "vm/NativeObject-inl.h"
namespace js {
inline const char* GetFunctionNameBytes(JSContext* cx, JSFunction* fun,
UniqueChars* bytes) {
if (JSAtom* name = fun->explicitName()) {
*bytes = StringToNewUTF8CharsZ(cx, *name);
return bytes->get();
}
return js_anonymous_str;
}
inline bool CanReuseFunctionForClone(JSContext* cx, HandleFunction fun) {
if (!fun->isSingleton()) {
return false;
}
if (fun->baseScript()->hasBeenCloned()) {
return false;
}
fun->baseScript()->setHasBeenCloned();
return true;
}
inline JSFunction* CloneFunctionObjectIfNotSingleton(
JSContext* cx, HandleFunction fun, HandleObject enclosingEnv,
HandleObject proto = nullptr) {
/*
* 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)) {
if (proto && !SetPrototypeForClonedFunction(cx, fun, proto)) {
return nullptr;
}
fun->setEnvironment(enclosingEnv);
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->realm(), fun, enclosingEnv)) {
return CloneFunctionReuseScript(cx, fun, enclosingEnv, kind, proto);
}
RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
if (!script) {
return nullptr;
}
RootedScope enclosingScope(cx, script->enclosingScope());
Rooted<ScriptSourceObject*> sourceObject(cx, script->sourceObject());
return CloneFunctionAndScript(cx, fun, enclosingEnv, enclosingScope,
sourceObject, kind, proto);
}
} /* namespace js */
/* static */ inline JS::Result<JSFunction*, JS::OOM&> JSFunction::create(
JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
js::HandleShape shape, js::HandleObjectGroup group) {
MOZ_ASSERT(kind == js::gc::AllocKind::FUNCTION ||
kind == js::gc::AllocKind::FUNCTION_EXTENDED);
debugCheckNewObject(group, shape, kind, heap);
const JSClass* clasp = group->clasp();
MOZ_ASSERT(clasp->isJSFunction());
static constexpr size_t NumDynamicSlots = 0;
MOZ_ASSERT(dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(),
clasp) == NumDynamicSlots);
JSObject* obj = js::AllocateObject(cx, kind, NumDynamicSlots, heap, clasp);
if (!obj) {
return cx->alreadyReportedOOM();
}
NativeObject* nobj = static_cast<NativeObject*>(obj);
nobj->initGroup(group);
nobj->initShape(shape);
nobj->initSlots(nullptr);
nobj->setEmptyElements();
MOZ_ASSERT(!clasp->hasPrivate());
MOZ_ASSERT(shape->slotSpan() == 0);
JSFunction* fun = static_cast<JSFunction*>(nobj);
fun->nargs_ = 0;
// This must be overwritten by some ultimate caller: there's no default
// value to which we could sensibly initialize this.
MOZ_MAKE_MEM_UNDEFINED(&fun->u, sizeof(u));
// Safe: we're initializing for the very first time.
fun->atom_.unsafeSet(nullptr);
if (kind == js::gc::AllocKind::FUNCTION_EXTENDED) {
fun->setFlags(FunctionFlags::EXTENDED);
for (js::GCPtrValue& extendedSlot : fun->toExtended()->extendedSlots) {
extendedSlot.unsafeSet(JS::UndefinedValue());
}
} else {
fun->setFlags(0);
}
MOZ_ASSERT(!clasp->shouldDelayMetadataBuilder(),
"Function has no extra data hanging off it, that wouldn't be "
"allocated at this point, that would require delaying the "
"building of metadata for it");
fun = SetNewObjectMetadata(cx, fun);
js::gc::gcprobes::CreateObject(fun);
return fun;
}
#endif /* vm_JSFunction_inl_h */