/* static */ ArgumentsObject * ArgumentsObject::create(JSContext *cx, HandleScript script, HandleFunction callee, unsigned numActuals, CopyArgs ©) { RootedObject proto(cx, callee->global().getOrCreateObjectPrototype(cx)); if (!proto) return NULL; bool strict = callee->strict(); Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass; RootedTypeObject type(cx, proto->getNewType(cx, clasp)); if (!type) return NULL; RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(proto), proto->getParent(), FINALIZE_KIND, BaseShape::INDEXED)); if (!shape) return NULL; unsigned numFormals = callee->nargs; unsigned numDeletedWords = NumWordsForBitArrayOfLength(numActuals); unsigned numArgs = Max(numActuals, numFormals); unsigned numBytes = offsetof(ArgumentsData, args) + numDeletedWords * sizeof(size_t) + numArgs * sizeof(Value); ArgumentsData *data = (ArgumentsData *)cx->malloc_(numBytes); if (!data) return NULL; data->numArgs = numArgs; data->callee.init(ObjectValue(*callee.get())); data->script = script; /* Copy [0, numArgs) into data->slots. */ HeapValue *dst = data->args, *dstEnd = data->args + numArgs; copy.copyArgs(cx, dst, numArgs); data->deletedBits = reinterpret_cast<size_t *>(dstEnd); ClearAllBitArrayElements(data->deletedBits, numDeletedWords); JSObject *obj = JSObject::create(cx, FINALIZE_KIND, GetInitialHeap(GenericObject, clasp), shape, type); if (!obj) { js_free(data); return NULL; } obj->initFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(numActuals << PACKED_BITS_COUNT)); obj->initFixedSlot(DATA_SLOT, PrivateValue(data)); copy.maybeForwardToCallObject(obj, data); ArgumentsObject &argsobj = obj->asArguments(); JS_ASSERT(argsobj.initialLength() == numActuals); JS_ASSERT(!argsobj.hasOverriddenLength()); return &argsobj; }
ArgumentsObject * ArgumentsObject::create(JSContext *cx, StackFrame *fp) { JSFunction &callee = fp->callee(); RootedObject proto(cx, callee.global().getOrCreateObjectPrototype(cx)); if (!proto) return NULL; RootedTypeObject type(cx); type = proto->getNewType(cx); if (!type) return NULL; bool strict = callee.inStrictMode(); Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass; RootedShape emptyArgumentsShape(cx); emptyArgumentsShape = EmptyShape::getInitialShape(cx, clasp, proto, proto->getParent(), FINALIZE_KIND, BaseShape::INDEXED); if (!emptyArgumentsShape) return NULL; unsigned numActuals = fp->numActualArgs(); unsigned numFormals = fp->numFormalArgs(); unsigned numDeletedWords = NumWordsForBitArrayOfLength(numActuals); unsigned numArgs = Max(numActuals, numFormals); unsigned numBytes = offsetof(ArgumentsData, args) + numDeletedWords * sizeof(size_t) + numArgs * sizeof(Value); ArgumentsData *data = (ArgumentsData *)cx->malloc_(numBytes); if (!data) return NULL; data->numArgs = numArgs; data->callee.init(ObjectValue(callee)); data->script = fp->script(); /* Copy [0, numArgs) into data->slots. */ HeapValue *dst = data->args, *dstEnd = data->args + numArgs; for (Value *src = fp->formals(), *end = src + numFormals; src != end; ++src, ++dst) dst->init(*src); if (numActuals > numFormals) { for (Value *src = fp->actuals() + numFormals; dst != dstEnd; ++src, ++dst) dst->init(*src); } else if (numActuals < numFormals) { for (; dst != dstEnd; ++dst) dst->init(UndefinedValue()); } data->deletedBits = reinterpret_cast<size_t *>(dstEnd); ClearAllBitArrayElements(data->deletedBits, numDeletedWords); JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyArgumentsShape, type, NULL); if (!obj) return NULL; obj->initFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(numActuals << PACKED_BITS_COUNT)); obj->initFixedSlot(DATA_SLOT, PrivateValue(data)); /* * If it exists and the arguments object aliases formals, the call object * is the canonical location for formals. */ JSScript *script = fp->script(); if (fp->fun()->isHeavyweight() && script->argsObjAliasesFormals()) { obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(fp->callObj())); /* Flag each slot that canonically lives in the callObj. */ if (script->bindingsAccessedDynamically) { for (unsigned i = 0; i < numFormals; ++i) data->args[i] = MagicValue(JS_FORWARD_TO_CALL_OBJECT); } else { for (unsigned i = 0; i < script->numClosedArgs(); ++i) data->args[script->getClosedArg(i)] = MagicValue(JS_FORWARD_TO_CALL_OBJECT); } } ArgumentsObject &argsobj = obj->asArguments(); JS_ASSERT(argsobj.initialLength() == numActuals); JS_ASSERT(!argsobj.hasOverriddenLength()); return &argsobj; }
/* * Construct a call object for the given bindings. If this is a call object * for a function invocation, callee should be the function being called. * Otherwise it must be a call object for eval of strict mode code, and callee * must be null. */ CallObject * CallObject::create(JSContext *cx, JSScript *script, JSObject &enclosing, JSObject *callee) { RootedVarShape shape(cx); shape = script->bindings.callObjectShape(cx); if (shape == NULL) return NULL; gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots() + 1); RootedVarTypeObject type(cx); type = cx->compartment->getEmptyType(cx); if (!type) return NULL; HeapSlot *slots; if (!PreallocateObjectDynamicSlots(cx, shape, &slots)) return NULL; JSObject *obj = JSObject::create(cx, kind, shape, type, slots); if (!obj) return NULL; /* * Update the parent for bindings associated with non-compileAndGo scripts, * whose call objects do not have a consistent global variable and need * to be updated dynamically. */ JSObject &global = enclosing.global(); if (&global != obj->getParent()) { JS_ASSERT(obj->getParent() == NULL); if (!obj->setParent(cx, &global)) return NULL; } #ifdef DEBUG JS_ASSERT(!obj->inDictionaryMode()); for (Shape::Range r = obj->lastProperty(); !r.empty(); r.popFront()) { const Shape &s = r.front(); if (s.hasSlot()) { JS_ASSERT(s.slot() + 1 == obj->slotSpan()); break; } } #endif if (!obj->asScope().setEnclosingScope(cx, enclosing)) return NULL; JS_ASSERT_IF(callee, callee->isFunction()); obj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee)); obj->initFixedSlot(ARGUMENTS_SLOT, MagicValue(JS_UNASSIGNED_ARGUMENTS)); /* * If |bindings| is for a function that has extensible parents, that means * its Call should have its own shape; see BaseShape::extensibleParents. */ if (obj->lastProperty()->extensibleParents() && !obj->generateOwnShape(cx)) return NULL; return &obj->asCall(); }