bool CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval) { rval.set(MagicValue(JS_IS_CONSTRUCTING)); if (callee->isFunction()) { JSFunction *fun = callee->toFunction(); if (fun->isInterpreted()) rval.set(ObjectValue(*js_CreateThisForFunction(cx, callee, false))); } return true; }
bool MarkInnerAndOuterFunctions(JSContext *cx, JSScript* script_) { Rooted<JSScript*> script(cx, script_); Vector<JSScript *, 16> worklist(cx); if (!worklist.append(script.reference())) return false; while (worklist.length()) { JSScript *outer = worklist.back(); worklist.popBack(); /* * If outer has an extensible scope, its slots may be resized which * will invalidate nesting->varArray/argArray. */ if (outer->funHasExtensibleScope) continue; if (outer->hasObjects()) { ObjectArray *arr = outer->objects(); /* * If this is an eval script, don't treat the saved caller function * stored in the first object slot as an inner function. */ size_t start = outer->savedCallerFun ? 1 : 0; for (size_t i = start; i < arr->length; i++) { JSObject *obj = arr->vector[i]; if (!obj->isFunction()) continue; JSFunction *fun = obj->toFunction(); JS_ASSERT(fun->isInterpreted()); JSScript *inner = fun->script(); if (outer->function() && outer->function()->isHeavyweight()) { outer->isOuterFunction = true; inner->isInnerFunction = true; } if (!inner->hasObjects()) continue; if (!worklist.append(inner)) return false; } } } return true; }
static JSObject * ResolveInterpretedFunctionPrototype(JSContext *cx, HandleObject obj) { #ifdef DEBUG JSFunction *fun = obj->toFunction(); JS_ASSERT(fun->isInterpreted()); JS_ASSERT(!fun->isFunctionPrototype()); #endif /* * Assert that fun is not a compiler-created function object, which * must never leak to script or embedding code and then be mutated. * Also assert that obj is not bound, per the ES5 15.3.4.5 ref above. */ JS_ASSERT(!IsInternalFunctionObject(obj)); JS_ASSERT(!obj->isBoundFunction()); /* * Make the prototype object an instance of Object with the same parent * as the function object itself. */ JSObject *objProto = obj->global().getOrCreateObjectPrototype(cx); if (!objProto) return NULL; RootedObject proto(cx, NewObjectWithGivenProto(cx, &ObjectClass, objProto, NULL)); if (!proto || !proto->setSingletonType(cx)) return NULL; /* * Per ES5 15.3.5.2 a user-defined function's .prototype property is * initially non-configurable, non-enumerable, and writable. Per ES5 13.2 * the prototype's .constructor property is configurable, non-enumerable, * and writable. */ RootedValue protoVal(cx, ObjectValue(*proto)); RootedValue objVal(cx, ObjectValue(*obj)); if (!obj->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom, protoVal, JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT) || !proto->defineProperty(cx, cx->runtime->atomState.constructorAtom, objVal, JS_PropertyStub, JS_StrictPropertyStub, 0)) { return NULL; } return proto; }
bool CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval) { rval.set(MagicValue(JS_IS_CONSTRUCTING)); if (callee->isFunction()) { JSFunction *fun = callee->toFunction(); if (fun->isInterpreted()) { JSScript *script = fun->getOrCreateScript(cx); if (!script || !script->ensureHasTypes(cx)) return false; rval.set(ObjectValue(*CreateThisForFunction(cx, callee, false))); } } return true; }
bool MarkInnerAndOuterFunctions(JSContext *cx, JSScript* script) { Root<JSScript*> root(cx, &script); Vector<JSScript *, 16> worklist(cx); if (!worklist.append(script)) return false; while (worklist.length()) { JSScript *outer = worklist.back(); worklist.popBack(); if (outer->hasObjects()) { ObjectArray *arr = outer->objects(); /* * If this is an eval script, don't treat the saved caller function * stored in the first object slot as an inner function. */ size_t start = outer->savedCallerFun ? 1 : 0; for (size_t i = start; i < arr->length; i++) { JSObject *obj = arr->vector[i]; if (!obj->isFunction()) continue; JSFunction *fun = obj->toFunction(); JS_ASSERT(fun->isInterpreted()); JSScript *inner = fun->script(); if (outer->function() && outer->function()->isHeavyweight()) { outer->isOuterFunction = true; inner->isInnerFunction = true; } if (!inner->hasObjects()) continue; if (!worklist.append(inner)) return false; } } } return true; }
/* * This helper function brings the ContextStack to the top of the thread stack * (so that it can be extended to push a frame and/or arguments) by potentially * pushing a StackSegment. The 'pushedSeg' outparam indicates whether such a * segment was pushed (and hence whether the caller needs to call popSegment). * * Additionally, to minimize calls to ensureSpace, ensureOnTop ensures that * there is space for nvars slots on top of the stack. */ Value * ContextStack::ensureOnTop(JSContext *cx, MaybeReportError report, unsigned nvars, MaybeExtend extend, bool *pushedSeg, JSCompartment *dest) { Value *firstUnused = space().firstUnused(); #ifdef JS_METHODJIT /* * The only calls made by inlined methodjit frames can be to other JIT * frames associated with the same VMFrame. If we try to Invoke(), * Execute() or so forth, any topmost inline frame will need to be * expanded (along with other inline frames in the compartment). * To avoid pathological behavior here, make sure to mark any topmost * function as uninlineable, which will expand inline frames if there are * any and prevent the function from being inlined in the future. */ if (FrameRegs *regs = cx->maybeRegs()) { JSFunction *fun = NULL; if (InlinedSite *site = regs->inlined()) { mjit::JITChunk *chunk = regs->fp()->jit()->chunk(regs->pc); fun = chunk->inlineFrames()[site->inlineIndex].fun; } else { StackFrame *fp = regs->fp(); if (fp->isFunctionFrame()) { JSFunction *f = fp->fun(); if (f->isInterpreted()) fun = f; } } if (fun) { fun->script()->uninlineable = true; types::MarkTypeObjectFlags(cx, fun, types::OBJECT_FLAG_UNINLINEABLE); } } JS_ASSERT_IF(cx->hasfp(), !cx->regs().inlined()); #endif if (onTop() && extend) { if (!space().ensureSpace(cx, report, firstUnused, nvars, dest)) return NULL; return firstUnused; } if (!space().ensureSpace(cx, report, firstUnused, VALUES_PER_STACK_SEGMENT + nvars, dest)) return NULL; FrameRegs *regs; CallArgsList *calls; if (seg_ && extend) { regs = seg_->maybeRegs(); calls = seg_->maybeCalls(); } else { regs = NULL; calls = NULL; } seg_ = new(firstUnused) StackSegment(seg_, space().seg_, regs, calls); space().seg_ = seg_; *pushedSeg = true; return seg_->slotsBegin(); }
static JSBool fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, Value *vp) { JSObject *obj = obj_; while (!obj->isFunction()) { obj = obj->getProto(); if (!obj) return true; } JSFunction *fun = obj->toFunction(); /* * Mark the function's script as uninlineable, to expand any of its * frames on the stack before we go looking for them. This allows the * below walk to only check each explicit frame rather than needing to * check any calls that were inlined. */ if (fun->isInterpreted()) { fun->script()->uninlineable = true; MarkTypeObjectFlags(cx, fun, OBJECT_FLAG_UNINLINEABLE); } /* Set to early to null in case of error */ vp->setNull(); /* Find fun's top-most activation record. */ StackIter iter(cx); for (; !iter.done(); ++iter) { if (!iter.isFunctionFrame() || iter.isEvalFrame()) continue; if (iter.callee() == fun) break; } if (iter.done()) return true; StackFrame *fp = iter.fp(); if (JSID_IS_ATOM(id, cx->runtime->atomState.argumentsAtom)) { if (fun->hasRest()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_FUNCTION_ARGUMENTS_AND_REST); return false; } /* Warn if strict about f.arguments or equivalent unqualified uses. */ if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT, js_GetErrorMessage, NULL, JSMSG_DEPRECATED_USAGE, js_arguments_str)) { return false; } ArgumentsObject *argsobj = ArgumentsObject::createUnexpected(cx, fp); if (!argsobj) return false; *vp = ObjectValue(*argsobj); return true; } #ifdef JS_METHODJIT if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom) && fp && fp->prev()) { /* * If the frame was called from within an inlined frame, mark the * innermost function as uninlineable to expand its frame and allow us * to recover its callee object. */ JSInlinedSite *inlined; jsbytecode *prevpc = fp->prev()->pcQuadratic(cx->stack, fp, &inlined); if (inlined) { mjit::JITChunk *chunk = fp->prev()->jit()->chunk(prevpc); JSFunction *fun = chunk->inlineFrames()[inlined->inlineIndex].fun; fun->script()->uninlineable = true; MarkTypeObjectFlags(cx, fun, OBJECT_FLAG_UNINLINEABLE); } } #endif if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) { StackIter prev(iter); do { ++prev; } while (!prev.done() && prev.isImplicitNativeCall()); if (prev.done() || !prev.isFunctionFrame()) { JS_ASSERT(vp->isNull()); return true; } *vp = prev.calleev(); /* Censor the caller if it is from another compartment. */ JSObject &caller = vp->toObject(); if (caller.compartment() != cx->compartment) { vp->setNull(); } else if (caller.isFunction()) { JSFunction *callerFun = caller.toFunction(); if (callerFun->isInterpreted() && callerFun->inStrictMode()) { JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, JSMSG_CALLER_IS_STRICT); return false; } } return true; } JS_NOT_REACHED("fun_getProperty"); return false; }
bool js::XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript) { /* NB: Keep this in sync with CloneInterpretedFunction. */ JSFunction *fun; JSAtom *atom; uint32_t firstword; /* flag telling whether fun->atom is non-null, plus for fun->u.i.skipmin, fun->u.i.wrapper, and 14 bits reserved for future use */ uint32_t flagsword; /* word for argument count and fun->flags */ JSContext *cx = xdr->cx(); JSScript *script; if (mode == XDR_ENCODE) { fun = (*objp)->toFunction(); if (!fun->isInterpreted()) { JSAutoByteString funNameBytes; if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION, name); } return false; } firstword = !!fun->atom; flagsword = (fun->nargs << 16) | fun->flags; atom = fun->atom; script = fun->script(); } else { RootedObject parent(cx, NULL); fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, parent, NULL); if (!fun) return false; if (!fun->clearParent(cx)) return false; if (!fun->clearType(cx)) return false; atom = NULL; script = NULL; } if (!xdr->codeUint32(&firstword)) return false; if ((firstword & 1U) && !XDRAtom(xdr, &atom)) return false; if (!xdr->codeUint32(&flagsword)) return false; if (!XDRScript(xdr, &script, parentScript)) return false; if (mode == XDR_DECODE) { fun->nargs = flagsword >> 16; JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED); fun->flags = uint16_t(flagsword); fun->atom.init(atom); fun->initScript(script); if (!script->typeSetFunction(cx, fun)) return false; JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs()); js_CallNewScriptHook(cx, fun->script(), fun); *objp = fun; }
bool DefineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *script) { JSObject *globalObj = globalScope.globalObj; /* Define and update global properties. */ for (size_t i = 0; i < globalScope.defs.length(); i++) { GlobalScope::GlobalDef &def = globalScope.defs[i]; /* Names that could be resolved ahead of time can be skipped. */ if (!def.atom) continue; jsid id = ATOM_TO_JSID(def.atom); Value rval; if (def.funbox) { JSFunction *fun = def.funbox->function(); /* * No need to check for redeclarations or anything, global * optimizations only take place if the property is not defined. */ rval.setObject(*fun); types::AddTypePropertyId(cx, globalObj, id, rval); } else { rval.setUndefined(); } /* * Don't update the type information when defining the property for the * global object, per the consistency rules for type properties. If the * property is only undefined before it is ever written, we can check * the global directly during compilation and avoid having to emit type * checks every time it is accessed in the script. */ const Shape *shape = DefineNativeProperty(cx, globalObj, id, rval, JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE | JSPROP_PERMANENT, 0, 0, DNP_SKIP_TYPE); if (!shape) return false; def.knownSlot = shape->slot(); } Vector<JSScript *, 16> worklist(cx); if (!worklist.append(script)) return false; /* * Recursively walk through all scripts we just compiled. For each script, * go through all global uses. Each global use indexes into globalScope->defs. * Use this information to repoint each use to the correct slot in the global * object. */ while (worklist.length()) { JSScript *outer = worklist.back(); worklist.popBack(); if (JSScript::isValidOffset(outer->objectsOffset)) { JSObjectArray *arr = outer->objects(); /* * If this is an eval script, don't treat the saved caller function * stored in the first object slot as an inner function. */ size_t start = outer->savedCallerFun ? 1 : 0; for (size_t i = start; i < arr->length; i++) { JSObject *obj = arr->vector[i]; if (!obj->isFunction()) continue; JSFunction *fun = obj->toFunction(); JS_ASSERT(fun->isInterpreted()); JSScript *inner = fun->script(); if (outer->function() && outer->function()->isHeavyweight()) { outer->isOuterFunction = true; inner->isInnerFunction = true; } if (!JSScript::isValidOffset(inner->globalsOffset) && !JSScript::isValidOffset(inner->objectsOffset)) { continue; } if (!worklist.append(inner)) return false; } } if (!JSScript::isValidOffset(outer->globalsOffset)) continue; GlobalSlotArray *globalUses = outer->globals(); uint32_t nGlobalUses = globalUses->length; for (uint32_t i = 0; i < nGlobalUses; i++) { uint32_t index = globalUses->vector[i].slot; JS_ASSERT(index < globalScope.defs.length()); globalUses->vector[i].slot = globalScope.defs[index].knownSlot; } } return true; }