// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 7.3.9 GetMethod, // reimplemented for proxy handler trap-getting to produce better error // messages. static bool GetProxyTrap(JSContext* cx, HandleObject handler, HandlePropertyName name, MutableHandleValue func) { // Steps 2, 5. if (!GetProperty(cx, handler, handler, name, func)) return false; // Step 3. if (func.isUndefined()) return true; if (func.isNull()) { func.setUndefined(); return true; } // Step 4. if (!IsCallable(func)) { JSAutoByteString bytes(cx, name); if (!bytes) return false; JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_BAD_TRAP, bytes.ptr()); return false; } return true; }
static JSBool fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValue 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.setObject(*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. */ InlinedSite *inlined; jsbytecode *prevpc = fp->prevpc(&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)) { ++iter; if (iter.done() || !iter.isFunctionFrame()) { JS_ASSERT(vp.isNull()); return true; } vp.set(iter.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; }