Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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/. */
7 #ifndef vm_ArgumentsObject_h
8 #define vm_ArgumentsObject_h
10 #include "mozilla/MemoryReporting.h"
12 #include "jsobj.h"
14 #include "gc/Barrier.h"
16 namespace js {
18 class AbstractFramePtr;
19 class ScriptFrameIter;
21 namespace jit {
22 class IonJSFrameLayout;
23 }
25 /*
26 * ArgumentsData stores the initial indexed arguments provided to the
27 * corresponding and that function itself. It is used to store arguments[i]
28 * and arguments.callee -- up until the corresponding property is modified,
29 * when the relevant value is flagged to memorialize the modification.
30 */
31 struct ArgumentsData
32 {
33 /*
34 * numArgs = Max(numFormalArgs, numActualArgs)
35 * The array 'args' has numArgs elements.
36 */
37 unsigned numArgs;
39 /*
40 * arguments.callee, or MagicValue(JS_OVERWRITTEN_CALLEE) if
41 * arguments.callee has been modified.
42 */
43 HeapValue callee;
45 /* The script for the function containing this arguments object. */
46 JSScript *script;
48 /*
49 * Pointer to an array of bits indicating, for every argument in 'slots',
50 * whether the element has been deleted. See isElementDeleted comment.
51 */
52 size_t *deletedBits;
54 /*
55 * This array holds either the current argument value or the magic
56 * forwarding value. The latter means that the function has both a
57 * CallObject and an ArgumentsObject AND the particular formal variable is
58 * aliased by the CallObject. In such cases, the CallObject holds the
59 * canonical value so any element access to the arguments object should load
60 * the value out of the CallObject (which is pointed to by MAYBE_CALL_SLOT).
61 */
62 HeapValue args[1];
64 /* For jit use: */
65 static ptrdiff_t offsetOfArgs() { return offsetof(ArgumentsData, args); }
66 };
68 // Maximum supported value of arguments.length. This bounds the maximum
69 // number of arguments that can be supplied to Function.prototype.apply.
70 // This value also bounds the number of elements parsed in an array
71 // initialiser.
72 static const unsigned ARGS_LENGTH_MAX = 500 * 1000;
74 /*
75 * ArgumentsObject instances represent |arguments| objects created to store
76 * function arguments when a function is called. It's expensive to create such
77 * objects if they're never used, so they're only created when they are
78 * potentially used.
79 *
80 * Arguments objects are complicated because, for non-strict mode code, they
81 * must alias any named arguments which were provided to the function. Gnarly
82 * example:
83 *
84 * function f(a, b, c, d)
85 * {
86 * arguments[0] = "seta";
87 * assertEq(a, "seta");
88 * b = "setb";
89 * assertEq(arguments[1], "setb");
90 * c = "setc";
91 * assertEq(arguments[2], undefined);
92 * arguments[3] = "setd";
93 * assertEq(d, undefined);
94 * }
95 * f("arga", "argb");
96 *
97 * ES5's strict mode behaves more sanely, and named arguments don't alias
98 * elements of an arguments object.
99 *
100 * ArgumentsObject instances use the following reserved slots:
101 *
102 * INITIAL_LENGTH_SLOT
103 * Stores the initial value of arguments.length, plus a bit indicating
104 * whether arguments.length has been modified. Use initialLength() and
105 * hasOverriddenLength() to access these values. If arguments.length has
106 * been modified, then the current value of arguments.length is stored in
107 * another slot associated with a new property.
108 * DATA_SLOT
109 * Stores an ArgumentsData*, described above.
110 */
111 class ArgumentsObject : public JSObject
112 {
113 protected:
114 static const uint32_t INITIAL_LENGTH_SLOT = 0;
115 static const uint32_t DATA_SLOT = 1;
116 static const uint32_t MAYBE_CALL_SLOT = 2;
118 public:
119 static const uint32_t LENGTH_OVERRIDDEN_BIT = 0x1;
120 static const uint32_t PACKED_BITS_COUNT = 1;
122 protected:
123 template <typename CopyArgs>
124 static ArgumentsObject *create(JSContext *cx, HandleScript script, HandleFunction callee,
125 unsigned numActuals, CopyArgs ©);
127 ArgumentsData *data() const {
128 return reinterpret_cast<ArgumentsData *>(getFixedSlot(DATA_SLOT).toPrivate());
129 }
131 public:
132 static const uint32_t RESERVED_SLOTS = 3;
133 static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4_BACKGROUND;
135 /* Create an arguments object for a frame that is expecting them. */
136 static ArgumentsObject *createExpected(JSContext *cx, AbstractFramePtr frame);
138 /*
139 * Purposefully disconnect the returned arguments object from the frame
140 * by always creating a new copy that does not alias formal parameters.
141 * This allows function-local analysis to determine that formals are
142 * not aliased and generally simplifies arguments objects.
143 */
144 static ArgumentsObject *createUnexpected(JSContext *cx, ScriptFrameIter &iter);
145 static ArgumentsObject *createUnexpected(JSContext *cx, AbstractFramePtr frame);
146 #if defined(JS_ION)
147 static ArgumentsObject *createForIon(JSContext *cx, jit::IonJSFrameLayout *frame,
148 HandleObject scopeChain);
149 #endif
151 /*
152 * Return the initial length of the arguments. This may differ from the
153 * current value of arguments.length!
154 */
155 uint32_t initialLength() const {
156 uint32_t argc = uint32_t(getFixedSlot(INITIAL_LENGTH_SLOT).toInt32()) >> PACKED_BITS_COUNT;
157 JS_ASSERT(argc <= ARGS_LENGTH_MAX);
158 return argc;
159 }
161 /* The script for the function containing this arguments object. */
162 JSScript *containingScript() const {
163 return data()->script;
164 }
166 /* True iff arguments.length has been assigned or its attributes changed. */
167 bool hasOverriddenLength() const {
168 const Value &v = getFixedSlot(INITIAL_LENGTH_SLOT);
169 return v.toInt32() & LENGTH_OVERRIDDEN_BIT;
170 }
172 void markLengthOverridden() {
173 uint32_t v = getFixedSlot(INITIAL_LENGTH_SLOT).toInt32() | LENGTH_OVERRIDDEN_BIT;
174 setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
175 }
177 /*
178 * Because the arguments object is a real object, its elements may be
179 * deleted. This is implemented by setting a 'deleted' flag for the arg
180 * which is read by argument object resolve and getter/setter hooks.
181 *
182 * NB: an element, once deleted, stays deleted. Thus:
183 *
184 * function f(x) { delete arguments[0]; arguments[0] = 42; return x }
185 * assertEq(f(1), 1);
186 *
187 * This works because, once a property is deleted from an arguments object,
188 * it gets regular properties with regular getters/setters that don't alias
189 * ArgumentsData::slots.
190 */
191 bool isElementDeleted(uint32_t i) const {
192 JS_ASSERT(i < data()->numArgs);
193 if (i >= initialLength())
194 return false;
195 return IsBitArrayElementSet(data()->deletedBits, initialLength(), i);
196 }
198 bool isAnyElementDeleted() const {
199 return IsAnyBitArrayElementSet(data()->deletedBits, initialLength());
200 }
202 void markElementDeleted(uint32_t i) {
203 SetBitArrayElement(data()->deletedBits, initialLength(), i);
204 }
206 /*
207 * An ArgumentsObject serves two roles:
208 * - a real object, accessed through regular object operations, e.g..,
209 * JSObject::getElement corresponding to 'arguments[i]';
210 * - a VM-internal data structure, storing the value of arguments (formal
211 * and actual) that are accessed directly by the VM when a reading the
212 * value of a formal parameter.
213 * There are two ways to access the ArgumentsData::args corresponding to
214 * these two use cases:
215 * - object access should use elements(i) which will take care of
216 * forwarding when the value is the magic forwarding value;
217 * - VM argument access should use arg(i) which will assert that the
218 * value is not the magic forwarding value (since, if such forwarding was
219 * needed, the frontend should have emitted JSOP_GETALIASEDVAR).
220 */
221 const Value &element(uint32_t i) const;
223 inline void setElement(JSContext *cx, uint32_t i, const Value &v);
225 const Value &arg(unsigned i) const {
226 JS_ASSERT(i < data()->numArgs);
227 const Value &v = data()->args[i];
228 JS_ASSERT(!v.isMagic());
229 return v;
230 }
232 void setArg(unsigned i, const Value &v) {
233 JS_ASSERT(i < data()->numArgs);
234 HeapValue &lhs = data()->args[i];
235 JS_ASSERT(!lhs.isMagic());
236 lhs = v;
237 }
239 /*
240 * Attempt to speedily and efficiently access the i-th element of this
241 * arguments object. Return true if the element was speedily returned.
242 * Return false if the element must be looked up more slowly using
243 * getProperty or some similar method. The second overload copies the
244 * elements [start, start + count) into the locations starting at 'vp'.
245 *
246 * NB: Returning false does not indicate error!
247 */
248 bool maybeGetElement(uint32_t i, MutableHandleValue vp) {
249 if (i >= initialLength() || isElementDeleted(i))
250 return false;
251 vp.set(element(i));
252 return true;
253 }
255 inline bool maybeGetElements(uint32_t start, uint32_t count, js::Value *vp);
257 /*
258 * Measures things hanging off this ArgumentsObject that are counted by the
259 * |miscSize| argument in JSObject::sizeOfExcludingThis().
260 */
261 size_t sizeOfMisc(mozilla::MallocSizeOf mallocSizeOf) const {
262 return mallocSizeOf(data());
263 }
265 static void finalize(FreeOp *fop, JSObject *obj);
266 static void trace(JSTracer *trc, JSObject *obj);
268 /* For jit use: */
269 static size_t getDataSlotOffset() {
270 return getFixedSlotOffset(DATA_SLOT);
271 }
272 static size_t getInitialLengthSlotOffset() {
273 return getFixedSlotOffset(INITIAL_LENGTH_SLOT);
274 }
276 static void MaybeForwardToCallObject(AbstractFramePtr frame, JSObject *obj, ArgumentsData *data);
277 #if defined(JS_ION)
278 static void MaybeForwardToCallObject(jit::IonJSFrameLayout *frame, HandleObject callObj,
279 JSObject *obj, ArgumentsData *data);
280 #endif
281 };
283 class NormalArgumentsObject : public ArgumentsObject
284 {
285 public:
286 static const Class class_;
288 /*
289 * Stores arguments.callee, or MagicValue(JS_ARGS_HOLE) if the callee has
290 * been cleared.
291 */
292 const js::Value &callee() const {
293 return data()->callee;
294 }
296 /* Clear the location storing arguments.callee's initial value. */
297 void clearCallee() {
298 data()->callee.set(zone(), MagicValue(JS_OVERWRITTEN_CALLEE));
299 }
300 };
302 class StrictArgumentsObject : public ArgumentsObject
303 {
304 public:
305 static const Class class_;
306 };
308 } // namespace js
310 template<>
311 inline bool
312 JSObject::is<js::ArgumentsObject>() const
313 {
314 return is<js::NormalArgumentsObject>() || is<js::StrictArgumentsObject>();
315 }
317 #endif /* vm_ArgumentsObject_h */