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; }