static JSObject * ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *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; JSObject *proto = 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. */ if (!obj->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom, ObjectValue(*proto), JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT) || !proto->defineProperty(cx, cx->runtime->atomState.constructorAtom, ObjectValue(*obj), JS_PropertyStub, JS_StrictPropertyStub, 0)) { return NULL; } return proto; }
void JS_FASTCALL stubs::DefFun(VMFrame &f, JSFunction *fun_) { /* * A top-level function defined in Global or Eval code (see ECMA-262 * Ed. 3), or else a SpiderMonkey extension: a named function statement in * a compound statement (not at the top statement level of global code, or * at the top level of a function body). */ JSContext *cx = f.cx; StackFrame *fp = f.fp(); RootedFunction fun(f.cx, fun_); /* * If static link is not current scope, clone fun's object to link to the * current scope via parent. We do this to enable sharing of compiled * functions among multiple equivalent scopes, amortizing the cost of * compilation over a number of executions. Examples include XUL scripts * and event handlers shared among Firefox or other Mozilla app chrome * windows, and user-defined JS functions precompiled and then shared among * requests in server-side JS. */ HandleObject scopeChain = f.fp()->scopeChain(); if (fun->environment() != scopeChain) { fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain); if (!fun) THROW(); } else { JS_ASSERT(f.script()->compileAndGo); JS_ASSERT(f.fp()->isGlobalFrame() || f.fp()->isEvalInFunction()); } /* * ECMA requires functions defined when entering Eval code to be * impermanent. */ unsigned attrs = fp->isEvalFrame() ? JSPROP_ENUMERATE : JSPROP_ENUMERATE | JSPROP_PERMANENT; /* * We define the function as a property of the variable object and not the * current scope chain even for the case of function expression statements * and functions defined by eval inside let or with blocks. */ JSObject *parent = &fp->varObj(); /* ES5 10.5 (NB: with subsequent errata). */ PropertyName *name = fun->atom->asPropertyName(); JSProperty *prop = NULL; JSObject *pobj; if (!parent->lookupProperty(cx, name, &pobj, &prop)) THROW(); Value rval = ObjectValue(*fun); do { /* Steps 5d, 5f. */ if (!prop || pobj != parent) { if (!parent->defineProperty(cx, name, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs)) { THROW(); } break; } /* Step 5e. */ JS_ASSERT(parent->isNative()); Shape *shape = reinterpret_cast<Shape *>(prop); if (parent->isGlobal()) { if (shape->configurable()) { if (!parent->defineProperty(cx, name, rval, JS_PropertyStub, JS_StrictPropertyStub, attrs)) { THROW(); } break; } if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) { JSAutoByteString bytes; if (js_AtomToPrintableString(cx, name, &bytes)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_REDEFINE_PROP, bytes.ptr()); } THROW(); } } /* * Non-global properties, and global properties which we aren't simply * redefining, must be set. First, this preserves their attributes. * Second, this will produce warnings and/or errors as necessary if the * specified Call object property is not writable (const). */ /* Step 5f. */ if (!parent->setProperty(cx, name, &rval, strict)) THROW(); } while (false); }