RawFunction js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript script, jsbytecode *pc) { JS_ASSERT(cx->typeInferenceEnabled()); JS_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite); JS_ASSERT(!fun->nonLazyScript()->enclosingStaticScope()); JS_ASSERT(types::UseNewTypeForClone(fun)); typedef CallsiteCloneKey Key; typedef CallsiteCloneTable Table; Table &table = cx->compartment->callsiteClones; if (!table.initialized() && !table.init()) return NULL; Key key; SkipRoot skipKey(cx, &key); /* Stop the analysis complaining about unrooted key. */ key.script = script; key.offset = pc - script->code; key.original = fun; Table::AddPtr p = table.lookupForAdd(key); SkipRoot skipHash(cx, &p); /* Prevent the hash from being poisoned. */ if (p) return p->value; RootedObject parent(cx, fun->environment()); RootedFunction clone(cx, CloneFunctionObject(cx, fun, parent)); if (!clone) return NULL; /* * Store a link back to the original for function.caller and avoid cloning * clones. */ clone->nonLazyScript()->shouldCloneAtCallsite = false; clone->nonLazyScript()->isCallsiteClone = true; clone->nonLazyScript()->setOriginalFunctionObject(fun); /* Recalculate the hash if script or fun have been moved. */ if (key.script != script && key.original != fun) { key.script = script; key.original = fun; Table::AddPtr p = table.lookupForAdd(key); JS_ASSERT(!p); } if (!table.relookupOrAdd(p, key, clone.get())) return NULL; return clone; }
RawFunction js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript script, jsbytecode *pc) { JS_ASSERT(cx->typeInferenceEnabled()); JS_ASSERT(fun->isCloneAtCallsite()); JS_ASSERT(types::UseNewTypeForClone(fun)); JS_ASSERT(!fun->nonLazyScript()->enclosingStaticScope()); typedef CallsiteCloneKey Key; typedef CallsiteCloneTable Table; Table &table = cx->compartment->callsiteClones; if (!table.initialized() && !table.init()) return NULL; Key key; key.script = script; key.offset = pc - script->code; key.original = fun; Table::AddPtr p = table.lookupForAdd(key); SkipRoot skipHash(cx, &p); /* Prevent the hash from being poisoned. */ if (p) return p->value; RootedObject parent(cx, fun->environment()); RootedFunction clone(cx, CloneFunctionObject(cx, fun, parent, JSFunction::ExtendedFinalizeKind)); if (!clone) return NULL; // Store a link back to the original for function.caller. clone->setExtendedSlot(0, ObjectValue(*fun)); // Recalculate the hash if script or fun have been moved. if (key.script != script && key.original != fun) { key.script = script; key.original = fun; Table::AddPtr p = table.lookupForAdd(key); JS_ASSERT(!p); } if (!table.relookupOrAdd(p, key, clone.get())) return NULL; return clone; }