1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/ArgumentsObject.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,613 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "vm/ArgumentsObject-inl.h" 1.11 + 1.12 +#include "jsinfer.h" 1.13 + 1.14 +#ifdef JS_ION 1.15 +#include "jit/IonFrames.h" 1.16 +#endif 1.17 +#include "vm/GlobalObject.h" 1.18 +#include "vm/Stack.h" 1.19 + 1.20 +#include "jsobjinlines.h" 1.21 + 1.22 +#include "vm/Stack-inl.h" 1.23 + 1.24 +using namespace js; 1.25 +using namespace js::gc; 1.26 + 1.27 +static void 1.28 +CopyStackFrameArguments(const AbstractFramePtr frame, HeapValue *dst, unsigned totalArgs) 1.29 +{ 1.30 + JS_ASSERT_IF(frame.isInterpreterFrame(), !frame.asInterpreterFrame()->runningInJit()); 1.31 + 1.32 + JS_ASSERT(Max(frame.numActualArgs(), frame.numFormalArgs()) == totalArgs); 1.33 + 1.34 + /* Copy arguments. */ 1.35 + Value *src = frame.argv(); 1.36 + Value *end = src + totalArgs; 1.37 + while (src != end) 1.38 + (dst++)->init(*src++); 1.39 +} 1.40 + 1.41 +/* static */ void 1.42 +ArgumentsObject::MaybeForwardToCallObject(AbstractFramePtr frame, JSObject *obj, 1.43 + ArgumentsData *data) 1.44 +{ 1.45 + JSScript *script = frame.script(); 1.46 + if (frame.fun()->isHeavyweight() && script->argsObjAliasesFormals()) { 1.47 + obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(frame.callObj())); 1.48 + for (AliasedFormalIter fi(script); fi; fi++) 1.49 + data->args[fi.frameIndex()] = JS::MagicValueUint32(fi.scopeSlot()); 1.50 + } 1.51 +} 1.52 + 1.53 +#if defined(JS_ION) 1.54 +/* static */ void 1.55 +ArgumentsObject::MaybeForwardToCallObject(jit::IonJSFrameLayout *frame, HandleObject callObj, 1.56 + JSObject *obj, ArgumentsData *data) 1.57 +{ 1.58 + JSFunction *callee = jit::CalleeTokenToFunction(frame->calleeToken()); 1.59 + JSScript *script = callee->nonLazyScript(); 1.60 + if (callee->isHeavyweight() && script->argsObjAliasesFormals()) { 1.61 + JS_ASSERT(callObj && callObj->is<CallObject>()); 1.62 + obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get())); 1.63 + for (AliasedFormalIter fi(script); fi; fi++) 1.64 + data->args[fi.frameIndex()] = JS::MagicValueUint32(fi.scopeSlot()); 1.65 + } 1.66 +} 1.67 +#endif 1.68 + 1.69 +struct CopyFrameArgs 1.70 +{ 1.71 + AbstractFramePtr frame_; 1.72 + 1.73 + CopyFrameArgs(AbstractFramePtr frame) 1.74 + : frame_(frame) 1.75 + { } 1.76 + 1.77 + void copyArgs(JSContext *, HeapValue *dst, unsigned totalArgs) const { 1.78 + CopyStackFrameArguments(frame_, dst, totalArgs); 1.79 + } 1.80 + 1.81 + /* 1.82 + * If a call object exists and the arguments object aliases formals, the 1.83 + * call object is the canonical location for formals. 1.84 + */ 1.85 + void maybeForwardToCallObject(JSObject *obj, ArgumentsData *data) { 1.86 + ArgumentsObject::MaybeForwardToCallObject(frame_, obj, data); 1.87 + } 1.88 +}; 1.89 + 1.90 +#if defined(JS_ION) 1.91 +struct CopyIonJSFrameArgs 1.92 +{ 1.93 + jit::IonJSFrameLayout *frame_; 1.94 + HandleObject callObj_; 1.95 + 1.96 + CopyIonJSFrameArgs(jit::IonJSFrameLayout *frame, HandleObject callObj) 1.97 + : frame_(frame), callObj_(callObj) 1.98 + { } 1.99 + 1.100 + void copyArgs(JSContext *, HeapValue *dstBase, unsigned totalArgs) const { 1.101 + unsigned numActuals = frame_->numActualArgs(); 1.102 + unsigned numFormals = jit::CalleeTokenToFunction(frame_->calleeToken())->nargs(); 1.103 + JS_ASSERT(numActuals <= totalArgs); 1.104 + JS_ASSERT(numFormals <= totalArgs); 1.105 + JS_ASSERT(Max(numActuals, numFormals) == totalArgs); 1.106 + 1.107 + /* Copy all arguments. */ 1.108 + Value *src = frame_->argv() + 1; /* +1 to skip this. */ 1.109 + Value *end = src + numActuals; 1.110 + HeapValue *dst = dstBase; 1.111 + while (src != end) 1.112 + (dst++)->init(*src++); 1.113 + 1.114 + if (numActuals < numFormals) { 1.115 + HeapValue *dstEnd = dstBase + totalArgs; 1.116 + while (dst != dstEnd) 1.117 + (dst++)->init(UndefinedValue()); 1.118 + } 1.119 + } 1.120 + 1.121 + /* 1.122 + * If a call object exists and the arguments object aliases formals, the 1.123 + * call object is the canonical location for formals. 1.124 + */ 1.125 + void maybeForwardToCallObject(JSObject *obj, ArgumentsData *data) { 1.126 + ArgumentsObject::MaybeForwardToCallObject(frame_, callObj_, obj, data); 1.127 + } 1.128 +}; 1.129 +#endif 1.130 + 1.131 +struct CopyScriptFrameIterArgs 1.132 +{ 1.133 + ScriptFrameIter &iter_; 1.134 + 1.135 + CopyScriptFrameIterArgs(ScriptFrameIter &iter) 1.136 + : iter_(iter) 1.137 + { } 1.138 + 1.139 + void copyArgs(JSContext *cx, HeapValue *dstBase, unsigned totalArgs) const { 1.140 + /* Copy actual arguments. */ 1.141 + iter_.unaliasedForEachActual(cx, CopyToHeap(dstBase)); 1.142 + 1.143 + /* Define formals which are not part of the actuals. */ 1.144 + unsigned numActuals = iter_.numActualArgs(); 1.145 + unsigned numFormals = iter_.callee()->nargs(); 1.146 + JS_ASSERT(numActuals <= totalArgs); 1.147 + JS_ASSERT(numFormals <= totalArgs); 1.148 + JS_ASSERT(Max(numActuals, numFormals) == totalArgs); 1.149 + 1.150 + if (numActuals < numFormals) { 1.151 + HeapValue *dst = dstBase + numActuals, *dstEnd = dstBase + totalArgs; 1.152 + while (dst != dstEnd) 1.153 + (dst++)->init(UndefinedValue()); 1.154 + } 1.155 + } 1.156 + 1.157 + /* 1.158 + * Ion frames are copying every argument onto the stack, other locations are 1.159 + * invalid. 1.160 + */ 1.161 + void maybeForwardToCallObject(JSObject *obj, ArgumentsData *data) { 1.162 + if (!iter_.isJit()) 1.163 + ArgumentsObject::MaybeForwardToCallObject(iter_.abstractFramePtr(), obj, data); 1.164 + } 1.165 +}; 1.166 + 1.167 +template <typename CopyArgs> 1.168 +/* static */ ArgumentsObject * 1.169 +ArgumentsObject::create(JSContext *cx, HandleScript script, HandleFunction callee, unsigned numActuals, 1.170 + CopyArgs ©) 1.171 +{ 1.172 + RootedObject proto(cx, callee->global().getOrCreateObjectPrototype(cx)); 1.173 + if (!proto) 1.174 + return nullptr; 1.175 + 1.176 + bool strict = callee->strict(); 1.177 + const Class *clasp = strict ? &StrictArgumentsObject::class_ : &NormalArgumentsObject::class_; 1.178 + 1.179 + RootedTypeObject type(cx, cx->getNewType(clasp, proto.get())); 1.180 + if (!type) 1.181 + return nullptr; 1.182 + 1.183 + JSObject *metadata = nullptr; 1.184 + if (!NewObjectMetadata(cx, &metadata)) 1.185 + return nullptr; 1.186 + 1.187 + RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(proto), 1.188 + proto->getParent(), metadata, FINALIZE_KIND, 1.189 + BaseShape::INDEXED)); 1.190 + if (!shape) 1.191 + return nullptr; 1.192 + 1.193 + unsigned numFormals = callee->nargs(); 1.194 + unsigned numDeletedWords = NumWordsForBitArrayOfLength(numActuals); 1.195 + unsigned numArgs = Max(numActuals, numFormals); 1.196 + unsigned numBytes = offsetof(ArgumentsData, args) + 1.197 + numDeletedWords * sizeof(size_t) + 1.198 + numArgs * sizeof(Value); 1.199 + 1.200 + ArgumentsData *data = (ArgumentsData *)cx->malloc_(numBytes); 1.201 + if (!data) 1.202 + return nullptr; 1.203 + 1.204 + JSObject *obj = JSObject::create(cx, FINALIZE_KIND, GetInitialHeap(GenericObject, clasp), 1.205 + shape, type); 1.206 + if (!obj) { 1.207 + js_free(data); 1.208 + return nullptr; 1.209 + } 1.210 + 1.211 + data->numArgs = numArgs; 1.212 + data->callee.init(ObjectValue(*callee.get())); 1.213 + data->script = script; 1.214 + 1.215 + /* Copy [0, numArgs) into data->slots. */ 1.216 + HeapValue *dst = data->args, *dstEnd = data->args + numArgs; 1.217 + copy.copyArgs(cx, dst, numArgs); 1.218 + 1.219 + data->deletedBits = reinterpret_cast<size_t *>(dstEnd); 1.220 + ClearAllBitArrayElements(data->deletedBits, numDeletedWords); 1.221 + 1.222 + obj->initFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(numActuals << PACKED_BITS_COUNT)); 1.223 + obj->initFixedSlot(DATA_SLOT, PrivateValue(data)); 1.224 + 1.225 + copy.maybeForwardToCallObject(obj, data); 1.226 + 1.227 + ArgumentsObject &argsobj = obj->as<ArgumentsObject>(); 1.228 + JS_ASSERT(argsobj.initialLength() == numActuals); 1.229 + JS_ASSERT(!argsobj.hasOverriddenLength()); 1.230 + return &argsobj; 1.231 +} 1.232 + 1.233 +ArgumentsObject * 1.234 +ArgumentsObject::createExpected(JSContext *cx, AbstractFramePtr frame) 1.235 +{ 1.236 + JS_ASSERT(frame.script()->needsArgsObj()); 1.237 + RootedScript script(cx, frame.script()); 1.238 + RootedFunction callee(cx, frame.callee()); 1.239 + CopyFrameArgs copy(frame); 1.240 + ArgumentsObject *argsobj = create(cx, script, callee, frame.numActualArgs(), copy); 1.241 + if (!argsobj) 1.242 + return nullptr; 1.243 + 1.244 + frame.initArgsObj(*argsobj); 1.245 + return argsobj; 1.246 +} 1.247 + 1.248 +ArgumentsObject * 1.249 +ArgumentsObject::createUnexpected(JSContext *cx, ScriptFrameIter &iter) 1.250 +{ 1.251 + RootedScript script(cx, iter.script()); 1.252 + RootedFunction callee(cx, iter.callee()); 1.253 + CopyScriptFrameIterArgs copy(iter); 1.254 + return create(cx, script, callee, iter.numActualArgs(), copy); 1.255 +} 1.256 + 1.257 +ArgumentsObject * 1.258 +ArgumentsObject::createUnexpected(JSContext *cx, AbstractFramePtr frame) 1.259 +{ 1.260 + RootedScript script(cx, frame.script()); 1.261 + RootedFunction callee(cx, frame.callee()); 1.262 + CopyFrameArgs copy(frame); 1.263 + return create(cx, script, callee, frame.numActualArgs(), copy); 1.264 +} 1.265 + 1.266 +#if defined(JS_ION) 1.267 +ArgumentsObject * 1.268 +ArgumentsObject::createForIon(JSContext *cx, jit::IonJSFrameLayout *frame, HandleObject scopeChain) 1.269 +{ 1.270 + jit::CalleeToken token = frame->calleeToken(); 1.271 + JS_ASSERT(jit::CalleeTokenIsFunction(token)); 1.272 + RootedScript script(cx, jit::ScriptFromCalleeToken(token)); 1.273 + RootedFunction callee(cx, jit::CalleeTokenToFunction(token)); 1.274 + RootedObject callObj(cx, scopeChain->is<CallObject>() ? scopeChain.get() : nullptr); 1.275 + CopyIonJSFrameArgs copy(frame, callObj); 1.276 + return create(cx, script, callee, frame->numActualArgs(), copy); 1.277 +} 1.278 +#endif 1.279 + 1.280 +static bool 1.281 +args_delProperty(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded) 1.282 +{ 1.283 + ArgumentsObject &argsobj = obj->as<ArgumentsObject>(); 1.284 + if (JSID_IS_INT(id)) { 1.285 + unsigned arg = unsigned(JSID_TO_INT(id)); 1.286 + if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) 1.287 + argsobj.markElementDeleted(arg); 1.288 + } else if (JSID_IS_ATOM(id, cx->names().length)) { 1.289 + argsobj.markLengthOverridden(); 1.290 + } else if (JSID_IS_ATOM(id, cx->names().callee)) { 1.291 + argsobj.as<NormalArgumentsObject>().clearCallee(); 1.292 + } 1.293 + *succeeded = true; 1.294 + return true; 1.295 +} 1.296 + 1.297 +static bool 1.298 +ArgGetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) 1.299 +{ 1.300 + if (!obj->is<NormalArgumentsObject>()) 1.301 + return true; 1.302 + 1.303 + NormalArgumentsObject &argsobj = obj->as<NormalArgumentsObject>(); 1.304 + if (JSID_IS_INT(id)) { 1.305 + /* 1.306 + * arg can exceed the number of arguments if a script changed the 1.307 + * prototype to point to another Arguments object with a bigger argc. 1.308 + */ 1.309 + unsigned arg = unsigned(JSID_TO_INT(id)); 1.310 + if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) 1.311 + vp.set(argsobj.element(arg)); 1.312 + } else if (JSID_IS_ATOM(id, cx->names().length)) { 1.313 + if (!argsobj.hasOverriddenLength()) 1.314 + vp.setInt32(argsobj.initialLength()); 1.315 + } else { 1.316 + JS_ASSERT(JSID_IS_ATOM(id, cx->names().callee)); 1.317 + if (!argsobj.callee().isMagic(JS_OVERWRITTEN_CALLEE)) 1.318 + vp.set(argsobj.callee()); 1.319 + } 1.320 + return true; 1.321 +} 1.322 + 1.323 +static bool 1.324 +ArgSetter(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp) 1.325 +{ 1.326 + if (!obj->is<NormalArgumentsObject>()) 1.327 + return true; 1.328 + 1.329 + unsigned attrs; 1.330 + if (!baseops::GetAttributes(cx, obj, id, &attrs)) 1.331 + return false; 1.332 + JS_ASSERT(!(attrs & JSPROP_READONLY)); 1.333 + attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */ 1.334 + 1.335 + NormalArgumentsObject &argsobj = obj->as<NormalArgumentsObject>(); 1.336 + RootedScript script(cx, argsobj.containingScript()); 1.337 + 1.338 + if (JSID_IS_INT(id)) { 1.339 + unsigned arg = unsigned(JSID_TO_INT(id)); 1.340 + if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) { 1.341 + argsobj.setElement(cx, arg, vp); 1.342 + if (arg < script->functionNonDelazifying()->nargs()) 1.343 + types::TypeScript::SetArgument(cx, script, arg, vp); 1.344 + return true; 1.345 + } 1.346 + } else { 1.347 + JS_ASSERT(JSID_IS_ATOM(id, cx->names().length) || JSID_IS_ATOM(id, cx->names().callee)); 1.348 + } 1.349 + 1.350 + /* 1.351 + * For simplicity we use delete/define to replace the property with one 1.352 + * backed by the default Object getter and setter. Note that we rely on 1.353 + * args_delProperty to clear the corresponding reserved slot so the GC can 1.354 + * collect its value. Note also that we must define the property instead 1.355 + * of setting it in case the user has changed the prototype to an object 1.356 + * that has a setter for this id. 1.357 + */ 1.358 + bool succeeded; 1.359 + return baseops::DeleteGeneric(cx, obj, id, &succeeded) && 1.360 + baseops::DefineGeneric(cx, obj, id, vp, nullptr, nullptr, attrs); 1.361 +} 1.362 + 1.363 +static bool 1.364 +args_resolve(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp) 1.365 +{ 1.366 + objp.set(nullptr); 1.367 + 1.368 + Rooted<NormalArgumentsObject*> argsobj(cx, &obj->as<NormalArgumentsObject>()); 1.369 + 1.370 + unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE; 1.371 + if (JSID_IS_INT(id)) { 1.372 + uint32_t arg = uint32_t(JSID_TO_INT(id)); 1.373 + if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg)) 1.374 + return true; 1.375 + 1.376 + attrs |= JSPROP_ENUMERATE; 1.377 + } else if (JSID_IS_ATOM(id, cx->names().length)) { 1.378 + if (argsobj->hasOverriddenLength()) 1.379 + return true; 1.380 + } else { 1.381 + if (!JSID_IS_ATOM(id, cx->names().callee)) 1.382 + return true; 1.383 + 1.384 + if (argsobj->callee().isMagic(JS_OVERWRITTEN_CALLEE)) 1.385 + return true; 1.386 + } 1.387 + 1.388 + if (!baseops::DefineGeneric(cx, argsobj, id, UndefinedHandleValue, ArgGetter, ArgSetter, attrs)) 1.389 + return false; 1.390 + 1.391 + objp.set(argsobj); 1.392 + return true; 1.393 +} 1.394 + 1.395 +static bool 1.396 +args_enumerate(JSContext *cx, HandleObject obj) 1.397 +{ 1.398 + Rooted<NormalArgumentsObject*> argsobj(cx, &obj->as<NormalArgumentsObject>()); 1.399 + RootedId id(cx); 1.400 + 1.401 + /* 1.402 + * Trigger reflection in args_resolve using a series of js_LookupProperty 1.403 + * calls. 1.404 + */ 1.405 + int argc = int(argsobj->initialLength()); 1.406 + for (int i = -2; i != argc; i++) { 1.407 + id = (i == -2) 1.408 + ? NameToId(cx->names().length) 1.409 + : (i == -1) 1.410 + ? NameToId(cx->names().callee) 1.411 + : INT_TO_JSID(i); 1.412 + 1.413 + RootedObject pobj(cx); 1.414 + RootedShape prop(cx); 1.415 + if (!baseops::LookupProperty<CanGC>(cx, argsobj, id, &pobj, &prop)) 1.416 + return false; 1.417 + } 1.418 + return true; 1.419 +} 1.420 + 1.421 +static bool 1.422 +StrictArgGetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) 1.423 +{ 1.424 + if (!obj->is<StrictArgumentsObject>()) 1.425 + return true; 1.426 + 1.427 + StrictArgumentsObject &argsobj = obj->as<StrictArgumentsObject>(); 1.428 + 1.429 + if (JSID_IS_INT(id)) { 1.430 + /* 1.431 + * arg can exceed the number of arguments if a script changed the 1.432 + * prototype to point to another Arguments object with a bigger argc. 1.433 + */ 1.434 + unsigned arg = unsigned(JSID_TO_INT(id)); 1.435 + if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) 1.436 + vp.set(argsobj.element(arg)); 1.437 + } else { 1.438 + JS_ASSERT(JSID_IS_ATOM(id, cx->names().length)); 1.439 + if (!argsobj.hasOverriddenLength()) 1.440 + vp.setInt32(argsobj.initialLength()); 1.441 + } 1.442 + return true; 1.443 +} 1.444 + 1.445 +static bool 1.446 +StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp) 1.447 +{ 1.448 + if (!obj->is<StrictArgumentsObject>()) 1.449 + return true; 1.450 + 1.451 + unsigned attrs; 1.452 + if (!baseops::GetAttributes(cx, obj, id, &attrs)) 1.453 + return false; 1.454 + JS_ASSERT(!(attrs & JSPROP_READONLY)); 1.455 + attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */ 1.456 + 1.457 + Rooted<StrictArgumentsObject*> argsobj(cx, &obj->as<StrictArgumentsObject>()); 1.458 + 1.459 + if (JSID_IS_INT(id)) { 1.460 + unsigned arg = unsigned(JSID_TO_INT(id)); 1.461 + if (arg < argsobj->initialLength()) { 1.462 + argsobj->setElement(cx, arg, vp); 1.463 + return true; 1.464 + } 1.465 + } else { 1.466 + JS_ASSERT(JSID_IS_ATOM(id, cx->names().length)); 1.467 + } 1.468 + 1.469 + /* 1.470 + * For simplicity we use delete/define to replace the property with one 1.471 + * backed by the default Object getter and setter. Note that we rely on 1.472 + * args_delProperty to clear the corresponding reserved slot so the GC can 1.473 + * collect its value. 1.474 + */ 1.475 + bool succeeded; 1.476 + return baseops::DeleteGeneric(cx, argsobj, id, &succeeded) && 1.477 + baseops::DefineGeneric(cx, argsobj, id, vp, nullptr, nullptr, attrs); 1.478 +} 1.479 + 1.480 +static bool 1.481 +strictargs_resolve(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp) 1.482 +{ 1.483 + objp.set(nullptr); 1.484 + 1.485 + Rooted<StrictArgumentsObject*> argsobj(cx, &obj->as<StrictArgumentsObject>()); 1.486 + 1.487 + unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE; 1.488 + PropertyOp getter = StrictArgGetter; 1.489 + StrictPropertyOp setter = StrictArgSetter; 1.490 + 1.491 + if (JSID_IS_INT(id)) { 1.492 + uint32_t arg = uint32_t(JSID_TO_INT(id)); 1.493 + if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg)) 1.494 + return true; 1.495 + 1.496 + attrs |= JSPROP_ENUMERATE; 1.497 + } else if (JSID_IS_ATOM(id, cx->names().length)) { 1.498 + if (argsobj->hasOverriddenLength()) 1.499 + return true; 1.500 + } else { 1.501 + if (!JSID_IS_ATOM(id, cx->names().callee) && !JSID_IS_ATOM(id, cx->names().caller)) 1.502 + return true; 1.503 + 1.504 + attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED; 1.505 + getter = CastAsPropertyOp(argsobj->global().getThrowTypeError()); 1.506 + setter = CastAsStrictPropertyOp(argsobj->global().getThrowTypeError()); 1.507 + } 1.508 + 1.509 + if (!baseops::DefineGeneric(cx, argsobj, id, UndefinedHandleValue, getter, setter, attrs)) 1.510 + return false; 1.511 + 1.512 + objp.set(argsobj); 1.513 + return true; 1.514 +} 1.515 + 1.516 +static bool 1.517 +strictargs_enumerate(JSContext *cx, HandleObject obj) 1.518 +{ 1.519 + Rooted<StrictArgumentsObject*> argsobj(cx, &obj->as<StrictArgumentsObject>()); 1.520 + 1.521 + /* 1.522 + * Trigger reflection in strictargs_resolve using a series of 1.523 + * js_LookupProperty calls. 1.524 + */ 1.525 + RootedObject pobj(cx); 1.526 + RootedShape prop(cx); 1.527 + RootedId id(cx); 1.528 + 1.529 + // length 1.530 + id = NameToId(cx->names().length); 1.531 + if (!baseops::LookupProperty<CanGC>(cx, argsobj, id, &pobj, &prop)) 1.532 + return false; 1.533 + 1.534 + // callee 1.535 + id = NameToId(cx->names().callee); 1.536 + if (!baseops::LookupProperty<CanGC>(cx, argsobj, id, &pobj, &prop)) 1.537 + return false; 1.538 + 1.539 + // caller 1.540 + id = NameToId(cx->names().caller); 1.541 + if (!baseops::LookupProperty<CanGC>(cx, argsobj, id, &pobj, &prop)) 1.542 + return false; 1.543 + 1.544 + for (uint32_t i = 0, argc = argsobj->initialLength(); i < argc; i++) { 1.545 + id = INT_TO_JSID(i); 1.546 + if (!baseops::LookupProperty<CanGC>(cx, argsobj, id, &pobj, &prop)) 1.547 + return false; 1.548 + } 1.549 + 1.550 + return true; 1.551 +} 1.552 + 1.553 +void 1.554 +ArgumentsObject::finalize(FreeOp *fop, JSObject *obj) 1.555 +{ 1.556 + fop->free_(reinterpret_cast<void *>(obj->as<ArgumentsObject>().data())); 1.557 +} 1.558 + 1.559 +void 1.560 +ArgumentsObject::trace(JSTracer *trc, JSObject *obj) 1.561 +{ 1.562 + ArgumentsObject &argsobj = obj->as<ArgumentsObject>(); 1.563 + ArgumentsData *data = argsobj.data(); 1.564 + MarkValue(trc, &data->callee, js_callee_str); 1.565 + MarkValueRange(trc, data->numArgs, data->args, js_arguments_str); 1.566 + MarkScriptUnbarriered(trc, &data->script, "script"); 1.567 +} 1.568 + 1.569 +/* 1.570 + * The classes below collaborate to lazily reflect and synchronize actual 1.571 + * argument values, argument count, and callee function object stored in a 1.572 + * stack frame with their corresponding property values in the frame's 1.573 + * arguments object. 1.574 + */ 1.575 +const Class NormalArgumentsObject::class_ = { 1.576 + "Arguments", 1.577 + JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS | 1.578 + JSCLASS_HAS_RESERVED_SLOTS(NormalArgumentsObject::RESERVED_SLOTS) | 1.579 + JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | JSCLASS_BACKGROUND_FINALIZE, 1.580 + JS_PropertyStub, /* addProperty */ 1.581 + args_delProperty, 1.582 + JS_PropertyStub, /* getProperty */ 1.583 + JS_StrictPropertyStub, /* setProperty */ 1.584 + args_enumerate, 1.585 + reinterpret_cast<JSResolveOp>(args_resolve), 1.586 + JS_ConvertStub, 1.587 + ArgumentsObject::finalize, 1.588 + nullptr, /* call */ 1.589 + nullptr, /* hasInstance */ 1.590 + nullptr, /* construct */ 1.591 + ArgumentsObject::trace 1.592 +}; 1.593 + 1.594 +/* 1.595 + * Strict mode arguments is significantly less magical than non-strict mode 1.596 + * arguments, so it is represented by a different class while sharing some 1.597 + * functionality. 1.598 + */ 1.599 +const Class StrictArgumentsObject::class_ = { 1.600 + "Arguments", 1.601 + JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS | 1.602 + JSCLASS_HAS_RESERVED_SLOTS(StrictArgumentsObject::RESERVED_SLOTS) | 1.603 + JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | JSCLASS_BACKGROUND_FINALIZE, 1.604 + JS_PropertyStub, /* addProperty */ 1.605 + args_delProperty, 1.606 + JS_PropertyStub, /* getProperty */ 1.607 + JS_StrictPropertyStub, /* setProperty */ 1.608 + strictargs_enumerate, 1.609 + reinterpret_cast<JSResolveOp>(strictargs_resolve), 1.610 + JS_ConvertStub, 1.611 + ArgumentsObject::finalize, 1.612 + nullptr, /* call */ 1.613 + nullptr, /* hasInstance */ 1.614 + nullptr, /* construct */ 1.615 + ArgumentsObject::trace 1.616 +};