js/src/vm/ArgumentsObject.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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.

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

mercurial