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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
Copied from: https://hg.mozilla.org/releases/mozilla-esr38/rev/f31d643afd41
Security advisory: https://www.mozilla.org/en-US/security/advisories/mfsa2016-01/
Mozilla Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1233925
# HG changeset patch
# User Jan de Mooij <jdemooij@mozilla.com>
# Date 1452110721 -3600
# Node ID f31d643afd4159b5422ae5aebcbbea0a088e018e
# Parent 4444e94a99cb9b00c0351cc8bf5459739cc036a5
Bug 1233925 - Treat functions with rest more like functions with lazy arguments. r=nbp a=ritu
diff --git a/js/src/jit/BacktrackingAllocator.cpp b/js/src/jit/BacktrackingAllocator.cpp
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -201,20 +201,19 @@ BacktrackingAllocator::tryGroupRegisters
// constructor calling convention.
if (IsThisSlotDefinition(reg0->def()) || IsThisSlotDefinition(reg1->def())) {
if (*reg0->def()->output() != *reg1->def()->output())
return true;
}
// Registers which might spill to the frame's argument slots can only be
// grouped with other such registers if the frame might access those
- // arguments through a lazy arguments object.
+ // arguments through a lazy arguments object or rest parameter.
if (IsArgumentSlotDefinition(reg0->def()) || IsArgumentSlotDefinition(reg1->def())) {
- JSScript* script = graph.mir().entryBlock()->info().script();
- if (script && script->argumentsAliasesFormals()) {
+ if (graph.mir().entryBlock()->info().mayReadFrameArgsDirectly()) {
if (*reg0->def()->output() != *reg1->def()->output())
return true;
}
}
VirtualRegisterGroup* group0 = reg0->group(), *group1 = reg1->group();
if (!group0 && group1)
diff --git a/js/src/jit/CompileInfo.h b/js/src/jit/CompileInfo.h
--- a/js/src/jit/CompileInfo.h
+++ b/js/src/jit/CompileInfo.h
@@ -194,16 +194,17 @@ enum AnalysisMode {
class CompileInfo
{
public:
CompileInfo(JSScript* script, JSFunction* fun, jsbytecode* osrPc, bool constructing,
AnalysisMode analysisMode, bool scriptNeedsArgsObj,
InlineScriptTree* inlineScriptTree)
: script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing),
analysisMode_(analysisMode), scriptNeedsArgsObj_(scriptNeedsArgsObj),
+ mayReadFrameArgsDirectly_(script->mayReadFrameArgsDirectly()),
inlineScriptTree_(inlineScriptTree)
{
MOZ_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY);
// The function here can flow in from anywhere so look up the canonical
// function to ensure that we do not try to embed a nursery pointer in
// jit-code. Precisely because it can flow in from anywhere, it's not
// guaranteed to be non-lazy. Hence, don't access its script!
@@ -222,17 +223,17 @@ class CompileInfo
fixedLexicalBegin_ = script->fixedLexicalBegin();
nstack_ = script->nslots() - script->nfixed();
nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_;
}
explicit CompileInfo(unsigned nlocals)
: script_(nullptr), fun_(nullptr), osrPc_(nullptr), osrStaticScope_(nullptr),
constructing_(false), analysisMode_(Analysis_None), scriptNeedsArgsObj_(false),
- inlineScriptTree_(nullptr)
+ mayReadFrameArgsDirectly_(false), inlineScriptTree_(nullptr)
{
nimplicit_ = 0;
nargs_ = 0;
nbodyfixed_ = 0;
nlocals_ = nlocals;
nstack_ = 1; /* For FunctionCompiler::pushPhiInput/popPhiOutput */
nslots_ = nlocals_ + nstack_;
fixedLexicalBegin_ = nlocals;
@@ -539,16 +540,20 @@ class CompileInfo
return false;
if (needsArgsObj() && isObservableArgumentSlot(slot))
return false;
return true;
}
+ bool mayReadFrameArgsDirectly() const {
+ return mayReadFrameArgsDirectly_;
+ }
+
private:
unsigned nimplicit_;
unsigned nargs_;
unsigned nbodyfixed_;
unsigned nlocals_;
unsigned nstack_;
unsigned nslots_;
unsigned fixedLexicalBegin_;
@@ -559,15 +564,17 @@ class CompileInfo
bool constructing_;
AnalysisMode analysisMode_;
// Whether a script needs an arguments object is unstable over compilation
// since the arguments optimization could be marked as failed on the main
// thread, so cache a value here and use it throughout for consistency.
bool scriptNeedsArgsObj_;
+ bool mayReadFrameArgsDirectly_;
+
InlineScriptTree* inlineScriptTree_;
};
} // namespace jit
} // namespace js
#endif /* jit_CompileInfo_h */
diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1002,17 +1002,17 @@ MarkThisAndArguments(JSTracer* trc, JitF
// formal arguments is taken care of by the frame's safepoint/snapshot,
// except when the script's lazy arguments object aliases those formals,
// in which case we mark them as well.
size_t nargs = layout->numActualArgs();
size_t nformals = 0;
if (CalleeTokenIsFunction(layout->calleeToken())) {
JSFunction* fun = CalleeTokenToFunction(layout->calleeToken());
- nformals = fun->nonLazyScript()->argumentsAliasesFormals() ? 0 : fun->nargs();
+ nformals = fun->nonLazyScript()->mayReadFrameArgsDirectly() ? 0 : fun->nargs();
}
Value* argv = layout->argv();
// Trace |this|.
gc::MarkValueRoot(trc, argv, "ion-thisv");
// Trace actual arguments beyond the formals. Note + 1 for thisv.
diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3894,16 +3894,22 @@ JSScript::hasLoops()
JSTryNote* tnlimit = tn + trynotes()->length;
for (; tn < tnlimit; tn++) {
if (tn->kind == JSTRY_FOR_IN || tn->kind == JSTRY_LOOP)
return true;
}
return false;
}
+bool
+JSScript::mayReadFrameArgsDirectly()
+{
+ return argumentsHasVarBinding() || (function_ && function_->hasRest());
+}
+
static inline void
LazyScriptHash(uint32_t lineno, uint32_t column, uint32_t begin, uint32_t end,
HashNumber hashes[3])
{
HashNumber hash = lineno;
hash = RotateLeft(hash, 4) ^ column;
hash = RotateLeft(hash, 4) ^ begin;
hash = RotateLeft(hash, 4) ^ end;
diff --git a/js/src/jsscript.h b/js/src/jsscript.h
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1397,16 +1397,20 @@ class JSScript : public js::gc::TenuredC
}
inline void setFunction(JSFunction* fun);
/*
* De-lazifies the canonical function. Must be called before entering code
* that expects the function to be non-lazy.
*/
inline void ensureNonLazyCanonicalFunction(JSContext* cx);
+ // Returns true if the script may read formal arguments on the stack
+ // directly, via lazy arguments or a rest parameter.
+ bool mayReadFrameArgsDirectly();
+
JSFlatString* sourceData(JSContext* cx);
static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked);
void setSourceObject(JSObject* object);
JSObject* sourceObject() const {
return sourceObject_;
}
|