Bug 1121433 - Remove clone-at-call-site functionality (r=shu,jandem)
authorLuke Wagner <luke@mozilla.com>
Mon, 09 Feb 2015 18:16:12 -0600
changeset 228382 40c95e7f4f4bd7a7d58acb4392e7e3cf73b6c8d8
parent 228381 84877a7e03338c92ddc8d6542db6e38df936f8cf
child 228383 b7e806aa4fe8180f66e70db6d0257af6f39b9351
push id28261
push userryanvm@gmail.com
push dateTue, 10 Feb 2015 21:03:20 +0000
treeherderautoland@ee093ca70666 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu, jandem
bugs1121433
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1121433 - Remove clone-at-call-site functionality (r=shu,jandem)
js/src/builtin/Utilities.js
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineJIT.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/CompileWrappers.cpp
js/src/jit/CompileWrappers.h
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/IonCaches.cpp
js/src/jit/IonCaches.h
js/src/jit/LIR-Common.h
js/src/jit/LOpcodes.h
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/VMFunctions.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsgc.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/vm/Interpreter.cpp
js/src/vm/ObjectGroup.cpp
js/src/vm/SelfHosting.cpp
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -5,17 +5,17 @@
 /*jshint bitwise: true, camelcase: false, curly: false, eqeqeq: true,
          es5: true, forin: true, immed: true, indent: 4, latedef: false,
          newcap: false, noarg: true, noempty: true, nonew: true,
          plusplus: false, quotmark: false, regexp: true, undef: true,
          unused: false, strict: false, trailing: true,
 */
 
 /*global ToObject: false, ToInteger: false, IsCallable: false,
-         ThrowError: false, AssertionFailed: false, SetScriptHints: false,
+         ThrowError: false, AssertionFailed: false,
          MakeConstructible: false, DecompileArg: false,
          RuntimeDefaultLocale: false,
          ParallelDo: false, ParallelSlices: false, NewDenseArray: false,
          UnsafePutElements: false, ShouldForceSequential: false,
          ParallelTestsShouldPass: false,
          Dump: false,
          callFunction: false,
          TO_UINT32: false,
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -9291,19 +9291,16 @@ TryAttachCallStub(JSContext *cx, ICCall_
         // If callee is not an interpreted constructor, we have to throw.
         if (constructing && !fun->isInterpretedConstructor())
             return true;
 
         RootedScript calleeScript(cx, fun->nonLazyScript());
         if (!calleeScript->hasBaselineScript() && !calleeScript->hasIonScript())
             return true;
 
-        if (calleeScript->shouldCloneAtCallsite())
-            return true;
-
         // Check if this stub chain has already generalized scripted calls.
         if (stub->scriptedStubsAreGeneralized()) {
             JitSpew(JitSpew_BaselineIC, "  Chain already has generalized scripted call stub!");
             return true;
         }
 
         if (stub->scriptedStubCount() >= ICCall_Fallback::MAX_SCRIPTED_STUBS) {
             // Create a Call_AnyScripted stub.
@@ -9491,35 +9488,16 @@ TryAttachStringSplit(JSContext *cx, ICCa
     if (!newStub)
         return false;
 
     stub->addNewStub(newStub);
     return true;
 }
 
 static bool
-MaybeCloneFunctionAtCallsite(JSContext *cx, MutableHandleValue callee, HandleScript script,
-                             jsbytecode *pc)
-{
-    RootedFunction fun(cx);
-    if (!IsFunctionObject(callee, fun.address()))
-        return true;
-
-    if (!fun->hasScript() || !fun->nonLazyScript()->shouldCloneAtCallsite())
-        return true;
-
-    fun = CloneFunctionAtCallsite(cx, fun, script, pc);
-    if (!fun)
-        return false;
-
-    callee.setObject(*fun);
-    return true;
-}
-
-static bool
 DoCallFallback(JSContext *cx, BaselineFrame *frame, ICCall_Fallback *stub_, uint32_t argc,
                Value *vp, MutableHandleValue res)
 {
     // This fallback stub may trigger debug mode toggling.
     DebugModeOSRVolatileStub<ICCall_Fallback *> stub(frame, stub_);
 
     // Ensure vp array is rooted - we may GC in here.
     AutoArrayRooter vpRoot(cx, argc + 2, vp);
@@ -9546,19 +9524,16 @@ DoCallFallback(JSContext *cx, BaselineFr
     // Compute construcing and useNewGroup flags.
     bool constructing = (op == JSOP_NEW);
     bool createSingleton = ObjectGroup::useSingletonForNewObject(cx, script, pc);
 
     // Try attaching a call stub.
     if (!TryAttachCallStub(cx, stub, script, pc, op, argc, vp, constructing, false, createSingleton))
         return false;
 
-    if (!MaybeCloneFunctionAtCallsite(cx, &callee, script, pc))
-        return false;
-
     if (op == JSOP_NEW) {
         if (!InvokeConstructor(cx, callee, argc, args, res))
             return false;
     } else if ((op == JSOP_EVAL || op == JSOP_STRICTEVAL) &&
                frame->scopeChain()->global().valueIsEval(callee))
     {
         if (!DirectEval(cx, CallArgsFromVp(argc, vp)))
             return false;
@@ -9618,19 +9593,16 @@ DoSpreadCallFallback(JSContext *cx, Base
 
     // Try attaching a call stub.
     if (op != JSOP_SPREADEVAL && op != JSOP_STRICTSPREADEVAL &&
         !TryAttachCallStub(cx, stub, script, pc, op, 1, vp, constructing, true, false))
     {
         return false;
     }
 
-    if (!MaybeCloneFunctionAtCallsite(cx, &callee, script, pc))
-        return false;
-
     if (!SpreadCallOperation(cx, script, pc, thisv, callee, arr, res))
         return false;
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
 
     // Attach a new TypeMonitor stub for this value.
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -268,32 +268,16 @@ CanEnterBaselineJIT(JSContext *cx, Handl
 
     if (script->hasBaselineScript())
         return Method_Compiled;
 
     // Check script warm-up counter.
     if (script->incWarmUpCounter() <= js_JitOptions.baselineWarmUpThreshold)
         return Method_Skipped;
 
-    if (script->isCallsiteClone()) {
-        // Ensure the original function is compiled too, so that bailouts from
-        // Ion code have a BaselineScript to resume into.
-        RootedScript original(cx, script->donorFunction()->nonLazyScript());
-        MOZ_ASSERT(original != script);
-
-        if (!original->canBaselineCompile())
-            return Method_CantCompile;
-
-        if (!original->hasBaselineScript()) {
-            MethodStatus status = BaselineCompile(cx, original);
-            if (status != Method_Compiled)
-                return status;
-        }
-    }
-
     // Frames can be marked as debuggee frames independently of its underlying
     // script being a debuggee script, e.g., when performing
     // Debugger.Frame.prototype.eval.
     return BaselineCompile(cx, script, osrFrame && osrFrame->isDebuggee());
 }
 
 MethodStatus
 jit::CanEnterBaselineAtBranch(JSContext *cx, InterpreterFrame *fp, bool newType)
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -7648,47 +7648,16 @@ CodeGenerator::visitStoreFixedSlotT(LSto
     Address address(obj, NativeObject::getFixedSlotOffset(slot));
     if (ins->mir()->needsBarrier())
         emitPreBarrier(address);
 
     masm.storeConstantOrRegister(nvalue, address);
 }
 
 void
-CodeGenerator::visitCallsiteCloneCache(LCallsiteCloneCache *ins)
-{
-    const MCallsiteCloneCache *mir = ins->mir();
-    Register callee = ToRegister(ins->callee());
-    Register output = ToRegister(ins->output());
-
-    CallsiteCloneIC cache(callee, mir->block()->info().script(), mir->callPc(), output);
-    cache.setProfilerLeavePC(mir->profilerLeavePc());
-    addCache(ins, allocateCache(cache));
-}
-
-typedef JSObject *(*CallsiteCloneICFn)(JSContext *, size_t, HandleObject);
-const VMFunction CallsiteCloneIC::UpdateInfo =
-    FunctionInfo<CallsiteCloneICFn>(CallsiteCloneIC::update);
-
-void
-CodeGenerator::visitCallsiteCloneIC(OutOfLineUpdateCache *ool, DataPtr<CallsiteCloneIC> &ic)
-{
-    LInstruction *lir = ool->lir();
-    saveLive(lir);
-
-    pushArg(ic->calleeReg());
-    pushArg(Imm32(ool->getCacheIndex()));
-    callVM(CallsiteCloneIC::UpdateInfo, lir);
-    StoreRegisterTo(ic->outputReg()).generate(this);
-    restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered());
-
-    masm.jump(ool->rejoin());
-}
-
-void
 CodeGenerator::visitGetNameCache(LGetNameCache *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register scopeChain = ToRegister(ins->scopeObj());
     TypedOrValueRegister output(GetValueOutput(ins));
     bool isTypeOf = ins->mir()->accessKind() != MGetNameCache::NAME;
 
     NameIC cache(liveRegs, isTypeOf, scopeChain, ins->mir()->name(), output);
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -335,25 +335,23 @@ class CodeGenerator : public CodeGenerat
     void visitGetElementCacheT(LGetElementCacheT *ins);
     void visitSetElementCacheV(LSetElementCacheV *ins);
     void visitSetElementCacheT(LSetElementCacheT *ins);
     void visitBindNameCache(LBindNameCache *ins);
     void visitCallSetProperty(LInstruction *ins);
     void visitSetPropertyCacheV(LSetPropertyCacheV *ins);
     void visitSetPropertyCacheT(LSetPropertyCacheT *ins);
     void visitGetNameCache(LGetNameCache *ins);
-    void visitCallsiteCloneCache(LCallsiteCloneCache *ins);
 
     void visitGetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyIC> &ic);
     void visitSetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyIC> &ic);
     void visitGetElementIC(OutOfLineUpdateCache *ool, DataPtr<GetElementIC> &ic);
     void visitSetElementIC(OutOfLineUpdateCache *ool, DataPtr<SetElementIC> &ic);
     void visitBindNameIC(OutOfLineUpdateCache *ool, DataPtr<BindNameIC> &ic);
     void visitNameIC(OutOfLineUpdateCache *ool, DataPtr<NameIC> &ic);
-    void visitCallsiteCloneIC(OutOfLineUpdateCache *ool, DataPtr<CallsiteCloneIC> &ic);
 
     void visitAssertRangeI(LAssertRangeI *ins);
     void visitAssertRangeD(LAssertRangeD *ins);
     void visitAssertRangeF(LAssertRangeF *ins);
     void visitAssertRangeV(LAssertRangeV *ins);
 
     void visitInterruptCheck(LInterruptCheck *lir);
     void visitAsmJSInterruptCheck(LAsmJSInterruptCheck *lir);
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -244,22 +244,16 @@ CompileCompartment::runtime()
 }
 
 const void *
 CompileCompartment::addressOfEnumerators()
 {
     return &compartment()->enumerators;
 }
 
-const CallsiteCloneTable &
-CompileCompartment::callsiteClones()
-{
-    return compartment()->callsiteClones;
-}
-
 const JitCompartment *
 CompileCompartment::jitCompartment()
 {
     return compartment()->jitCompartment();
 }
 
 bool
 CompileCompartment::hasObjectMetadataCallback()
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -108,18 +108,16 @@ class CompileCompartment
   public:
     static CompileCompartment *get(JSCompartment *comp);
 
     CompileZone *zone();
     CompileRuntime *runtime();
 
     const void *addressOfEnumerators();
 
-    const CallsiteCloneTable &callsiteClones();
-
     const JitCompartment *jitCompartment();
 
     bool hasObjectMetadataCallback();
 
     // Mirror CompartmentOptions.
     void setSingletonsAsValues();
 };
 
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -4676,87 +4676,84 @@ IonBuilder::makeInliningDecision(JSObjec
     // Determine whether inlining is possible at callee site
     InliningDecision decision = canInlineTarget(target, callInfo);
     if (decision != InliningDecision_Inline)
         return decision;
 
     // Heuristics!
     JSScript *targetScript = target->nonLazyScript();
 
-    // Skip heuristics if we have an explicit hint to inline.
-    if (!targetScript->shouldInline()) {
-        // Cap the inlining depth.
-        if (js_JitOptions.isSmallFunction(targetScript)) {
-            if (inliningDepth_ >= optimizationInfo().smallFunctionMaxInlineDepth()) {
-                trackOptimizationOutcome(TrackedOutcome::CantInlineExceededDepth);
-                return DontInline(targetScript, "Vetoed: exceeding allowed inline depth");
-            }
-        } else {
-            if (inliningDepth_ >= optimizationInfo().maxInlineDepth()) {
-                trackOptimizationOutcome(TrackedOutcome::CantInlineExceededDepth);
-                return DontInline(targetScript, "Vetoed: exceeding allowed inline depth");
+    // Cap the inlining depth.
+    if (js_JitOptions.isSmallFunction(targetScript)) {
+        if (inliningDepth_ >= optimizationInfo().smallFunctionMaxInlineDepth()) {
+            trackOptimizationOutcome(TrackedOutcome::CantInlineExceededDepth);
+            return DontInline(targetScript, "Vetoed: exceeding allowed inline depth");
+        }
+    } else {
+        if (inliningDepth_ >= optimizationInfo().maxInlineDepth()) {
+            trackOptimizationOutcome(TrackedOutcome::CantInlineExceededDepth);
+            return DontInline(targetScript, "Vetoed: exceeding allowed inline depth");
+        }
+
+        if (targetScript->hasLoops()) {
+            // Currently, we are not inlining function which have loops because
+            // the cost inherent to inlining the function overcome the cost
+            // calling it. The reason is not yet clear to everybody, and we
+            // hope that we might be able to remove this restriction in the
+            // future.
+            //
+            // In the mean time, if we have opportunities to optimize the
+            // loop better, then we should try it. Such opportunity might be
+            // suggested by:
+            //
+            //  - Constant as argument. Inlining a function called with a
+            //    constant, might help GVN, as well as UCE, and potentially
+            //    improve bound check removal.
+            //
+            //  - Inner function as argument. Inlining a function called
+            //    with an inner function might help scalar replacement at
+            //    removing the scope chain, and thus using registers within
+            //    the loop instead of writting everything back to memory.
+            bool hasOpportunities = false;
+            for (size_t i = 0, e = callInfo.argv().length(); !hasOpportunities && i < e; i++) {
+                MDefinition *arg = callInfo.argv()[i];
+                hasOpportunities = arg->isLambda() || arg->isConstantValue();
             }
 
-            if (targetScript->hasLoops()) {
-                // Currently, we are not inlining function which have loops because
-                // the cost inherent to inlining the function overcome the cost
-                // calling it. The reason is not yet clear to everybody, and we
-                // hope that we might be able to remove this restriction in the
-                // future.
-                //
-                // In the mean time, if we have opportunities to optimize the
-                // loop better, then we should try it. Such opportunity might be
-                // suggested by:
-                //
-                //  - Constant as argument. Inlining a function called with a
-                //    constant, might help GVN, as well as UCE, and potentially
-                //    improve bound check removal.
-                //
-                //  - Inner function as argument. Inlining a function called
-                //    with an inner function might help scalar replacement at
-                //    removing the scope chain, and thus using registers within
-                //    the loop instead of writting everything back to memory.
-                bool hasOpportunities = false;
-                for (size_t i = 0, e = callInfo.argv().length(); !hasOpportunities && i < e; i++) {
-                    MDefinition *arg = callInfo.argv()[i];
-                    hasOpportunities = arg->isLambda() || arg->isConstantValue();
-                }
-
-                if (!hasOpportunities) {
-                    trackOptimizationOutcome(TrackedOutcome::CantInlineBigLoop);
-                    return DontInline(targetScript, "Vetoed: big function that contains a loop");
-                }
+            if (!hasOpportunities) {
+                trackOptimizationOutcome(TrackedOutcome::CantInlineBigLoop);
+                return DontInline(targetScript, "Vetoed: big function that contains a loop");
             }
-
-            // Caller must not be excessively large.
-            if (script()->length() >= optimizationInfo().inliningMaxCallerBytecodeLength()) {
-                trackOptimizationOutcome(TrackedOutcome::CantInlineBigCaller);
-                return DontInline(targetScript, "Vetoed: caller excessively large");
-            }
-        }
-
-        // Callee must not be excessively large.
-        // This heuristic also applies to the callsite as a whole.
-        if (targetScript->length() > optimizationInfo().inlineMaxTotalBytecodeLength()) {
-            trackOptimizationOutcome(TrackedOutcome::CantInlineBigCallee);
-            return DontInline(targetScript, "Vetoed: callee excessively large");
-        }
-
-        // Callee must have been called a few times to have somewhat stable
-        // type information, except for definite properties analysis,
-        // as the caller has not run yet.
-        if (targetScript->getWarmUpCount() < optimizationInfo().inliningWarmUpThreshold() &&
-            !targetScript->baselineScript()->ionCompiledOrInlined() &&
-            info().analysisMode() != Analysis_DefiniteProperties)
-        {
-            trackOptimizationOutcome(TrackedOutcome::CantInlineNotHot);
-            JitSpew(JitSpew_Inlining, "Cannot inline %s:%u: callee is insufficiently hot.",
-                    targetScript->filename(), targetScript->lineno());
-            return InliningDecision_WarmUpCountTooLow;
-        }
+        }
+
+        // Caller must not be excessively large.
+        if (script()->length() >= optimizationInfo().inliningMaxCallerBytecodeLength()) {
+            trackOptimizationOutcome(TrackedOutcome::CantInlineBigCaller);
+            return DontInline(targetScript, "Vetoed: caller excessively large");
+        }
+    }
+
+    // Callee must not be excessively large.
+    // This heuristic also applies to the callsite as a whole.
+    if (targetScript->length() > optimizationInfo().inlineMaxTotalBytecodeLength()) {
+        trackOptimizationOutcome(TrackedOutcome::CantInlineBigCallee);
+        return DontInline(targetScript, "Vetoed: callee excessively large");
+    }
+
+    // Callee must have been called a few times to have somewhat stable
+    // type information, except for definite properties analysis,
+    // as the caller has not run yet.
+    if (targetScript->getWarmUpCount() < optimizationInfo().inliningWarmUpThreshold() &&
+        !targetScript->baselineScript()->ionCompiledOrInlined() &&
+        info().analysisMode() != Analysis_DefiniteProperties)
+    {
+        trackOptimizationOutcome(TrackedOutcome::CantInlineNotHot);
+        JitSpew(JitSpew_Inlining, "Cannot inline %s:%u: callee is insufficiently hot.",
+                targetScript->filename(), targetScript->lineno());
+        return InliningDecision_WarmUpCountTooLow;
     }
 
     // TI calls ObjectStateChange to trigger invalidation of the caller.
     TypeSet::ObjectKey *targetKey = TypeSet::ObjectKey::get(target);
     targetKey->watchStateChangeForInlinedCall(constraints());
 
     return InliningDecision_Inline;
 }
@@ -4967,18 +4964,17 @@ IonBuilder::inlineSingleCall(CallInfo &c
     // which has a different pc than the current call pc.
     trackInlineSuccess();
     if (!inlineScriptedCall(callInfo, target))
         return InliningStatus_Error;
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineCallsite(const ObjectVector &targets, ObjectVector &originals,
-                           CallInfo &callInfo)
+IonBuilder::inlineCallsite(const ObjectVector &targets, CallInfo &callInfo)
 {
     if (targets.empty()) {
         trackOptimizationAttempt(TrackedStrategy::Call_Inline);
         trackOptimizationOutcome(TrackedOutcome::CantInlineNoTarget);
         return InliningStatus_NotInlined;
     }
 
     // Is the function provided by an MGetPropertyCache?
@@ -5028,41 +5024,40 @@ IonBuilder::inlineCallsite(const ObjectV
     BoolVector choiceSet(alloc());
     uint32_t numInlined;
     if (!selectInliningTargets(targets, callInfo, choiceSet, &numInlined))
         return InliningStatus_Error;
     if (numInlined == 0)
         return InliningStatus_NotInlined;
 
     // Perform a polymorphic dispatch.
-    if (!inlineCalls(callInfo, targets, originals, choiceSet, propCache.get()))
+    if (!inlineCalls(callInfo, targets, choiceSet, propCache.get()))
         return InliningStatus_Error;
 
     return InliningStatus_Inlined;
 }
 
 bool
-IonBuilder::inlineGenericFallback(JSFunction *target, CallInfo &callInfo, MBasicBlock *dispatchBlock,
-                                  bool clonedAtCallsite)
+IonBuilder::inlineGenericFallback(JSFunction *target, CallInfo &callInfo, MBasicBlock *dispatchBlock)
 {
     // Generate a new block with all arguments on-stack.
     MBasicBlock *fallbackBlock = newBlock(dispatchBlock, pc);
     if (!fallbackBlock)
         return false;
 
     // Create a new CallInfo to track modified state within this block.
     CallInfo fallbackInfo(alloc(), callInfo.constructing());
     if (!fallbackInfo.init(callInfo))
         return false;
     fallbackInfo.popFormals(fallbackBlock);
 
     // Generate an MCall, which uses stateful |current|.
     if (!setCurrentAndSpecializePhis(fallbackBlock))
         return false;
-    if (!makeCall(target, fallbackInfo, clonedAtCallsite))
+    if (!makeCall(target, fallbackInfo))
         return false;
 
     // Pass return block to caller as |current|.
     return true;
 }
 
 bool
 IonBuilder::inlineObjectGroupFallback(CallInfo &callInfo, MBasicBlock *dispatchBlock,
@@ -5148,51 +5143,45 @@ IonBuilder::inlineObjectGroupFallback(Ca
 
     // Construct an end block with the correct resume point.
     MBasicBlock *preCallBlock = newBlock(getPropBlock, pc, preCallResumePoint);
     if (!preCallBlock)
         return false;
     getPropBlock->end(MGoto::New(alloc(), preCallBlock));
 
     // Now inline the MCallGeneric, using preCallBlock as the dispatch point.
-    if (!inlineGenericFallback(nullptr, fallbackInfo, preCallBlock, false))
+    if (!inlineGenericFallback(nullptr, fallbackInfo, preCallBlock))
         return false;
 
     // inlineGenericFallback() set the return block as |current|.
     preCallBlock->end(MGoto::New(alloc(), current));
     *fallbackTarget = prepBlock;
     return true;
 }
 
 bool
-IonBuilder::inlineCalls(CallInfo &callInfo, const ObjectVector &targets,
-                        ObjectVector &originals, BoolVector &choiceSet,
+IonBuilder::inlineCalls(CallInfo &callInfo, const ObjectVector &targets, BoolVector &choiceSet,
                         MGetPropertyCache *maybeCache)
 {
     // Only handle polymorphic inlining.
     MOZ_ASSERT(IsIonInlinablePC(pc));
     MOZ_ASSERT(choiceSet.length() == targets.length());
     MOZ_ASSERT_IF(!maybeCache, targets.length() >= 2);
     MOZ_ASSERT_IF(maybeCache, targets.length() >= 1);
 
     MBasicBlock *dispatchBlock = current;
     callInfo.setImplicitlyUsedUnchecked();
     callInfo.pushFormals(dispatchBlock);
 
-    // Patch any InlinePropertyTable to only contain functions that are inlineable.
-    //
-    // Note that we trim using originals, as callsite clones are not user
-    // visible. We don't patch the entries inside the table with the cloned
-    // targets, as the entries should only be used for comparison.
-    //
-    // The InlinePropertyTable will also be patched at the end to exclude native functions
-    // that vetoed inlining.
+    // Patch any InlinePropertyTable to only contain functions that are
+    // inlineable. The InlinePropertyTable will also be patched at the end to
+    // exclude native functions that vetoed inlining.
     if (maybeCache) {
         InlinePropertyTable *propTable = maybeCache->propTable();
-        propTable->trimToTargets(originals);
+        propTable->trimToTargets(targets);
         if (propTable->numEntries() == 0)
             maybeCache = nullptr;
     }
 
     // Generate a dispatch based on guard kind.
     MDispatchInstruction *dispatch;
     if (maybeCache) {
         dispatch = MObjectGroupDispatch::New(alloc(), maybeCache->object(), maybeCache->propTable());
@@ -5230,34 +5219,28 @@ IonBuilder::inlineCalls(CallInfo &callIn
 
     // During inlining the 'this' value is assigned a type set which is
     // specialized to the groups which can generate that inlining target.
     // After inlining the original type set is restored.
     TemporaryTypeSet *cacheObjectTypeSet =
         maybeCache ? maybeCache->object()->resultTypeSet() : nullptr;
 
     // Inline each of the inlineable targets.
-    MOZ_ASSERT(targets.length() == originals.length());
     for (uint32_t i = 0; i < targets.length(); i++) {
         // Target must be inlineable.
         if (!choiceSet[i])
             continue;
 
         // Even though we made one round of inline decisions already, we may
         // be amending them below.
         amendOptimizationAttempt(i);
 
-        // When original != target, the target is a callsite clone. The
-        // original should be used for guards, and the target should be the
-        // actual function inlined.
-        JSFunction *original = &originals[i]->as<JSFunction>();
+        // Target must be reachable by the MDispatchInstruction.
         JSFunction *target = &targets[i]->as<JSFunction>();
-
-        // Target must be reachable by the MDispatchInstruction.
-        if (maybeCache && !maybeCache->propTable()->hasFunction(original)) {
+        if (maybeCache && !maybeCache->propTable()->hasFunction(target)) {
             choiceSet[i] = false;
             trackOptimizationOutcome(TrackedOutcome::CantInlineNotInDispatch);
             continue;
         }
 
         MBasicBlock *inlineBlock = newBlock(dispatchBlock, pc);
         if (!inlineBlock)
             return false;
@@ -5284,17 +5267,17 @@ IonBuilder::inlineCalls(CallInfo &callIn
         if (!inlineInfo.init(callInfo))
             return false;
         inlineInfo.popFormals(inlineBlock);
         inlineInfo.setFun(funcDef);
 
         if (maybeCache) {
             MOZ_ASSERT(callInfo.thisArg() == maybeCache->object());
             TemporaryTypeSet *targetThisTypes =
-                maybeCache->propTable()->buildTypeSetForFunction(original);
+                maybeCache->propTable()->buildTypeSetForFunction(target);
             if (!targetThisTypes)
                 return false;
             maybeCache->object()->setResultTypeSet(targetThisTypes);
         }
 
         // Inline the call into the inlineBlock.
         if (!setCurrentAndSpecializePhis(inlineBlock))
             return false;
@@ -5311,37 +5294,32 @@ IonBuilder::inlineCalls(CallInfo &callIn
             continue;
         }
 
         // inlineSingleCall() changed |current| to the inline return block.
         MBasicBlock *inlineReturnBlock = current;
         setCurrent(dispatchBlock);
 
         // Connect the inline path to the returnBlock.
-        //
-        // Note that guarding is on the original function pointer even
-        // if there is a clone, since cloning occurs at the callsite.
-        ObjectGroup *funcGroup = original->isSingleton() ? nullptr : original->group();
-        dispatch->addCase(original, funcGroup, inlineBlock);
+        ObjectGroup *funcGroup = target->isSingleton() ? nullptr : target->group();
+        dispatch->addCase(target, funcGroup, inlineBlock);
 
         MDefinition *retVal = inlineReturnBlock->peek(-1);
         retPhi->addInput(retVal);
         inlineReturnBlock->end(MGoto::New(alloc(), returnBlock));
         if (!returnBlock->addPredecessorWithoutPhis(inlineReturnBlock))
             return false;
     }
 
     // Patch the InlinePropertyTable to not dispatch to vetoed paths.
-    //
-    // Note that like above, we trim using originals instead of targets.
     if (maybeCache) {
         maybeCache->object()->setResultTypeSet(cacheObjectTypeSet);
 
         InlinePropertyTable *propTable = maybeCache->propTable();
-        propTable->trimTo(originals, choiceSet);
+        propTable->trimTo(targets, choiceSet);
 
         // If all paths were vetoed, output only a generic fallback path.
         if (propTable->numEntries() == 0) {
             MOZ_ASSERT(dispatch->numCases() == 0);
             maybeCache = nullptr;
         }
     }
 
@@ -5354,39 +5332,32 @@ IonBuilder::inlineCalls(CallInfo &callIn
             if (!inlineObjectGroupFallback(callInfo, dispatchBlock, (MObjectGroupDispatch *)dispatch,
                                           maybeCache, &fallbackTarget))
             {
                 return false;
             }
             dispatch->addFallback(fallbackTarget);
         } else {
             JSFunction *remaining = nullptr;
-            bool clonedAtCallsite = false;
 
             // If there is only 1 remaining case, we can annotate the fallback call
             // with the target information.
-            if (dispatch->numCases() + 1 == originals.length()) {
-                for (uint32_t i = 0; i < originals.length(); i++) {
+            if (dispatch->numCases() + 1 == targets.length()) {
+                for (uint32_t i = 0; i < targets.length(); i++) {
                     if (choiceSet[i])
                         continue;
 
                     MOZ_ASSERT(!remaining);
-
-                    if (targets[i]->is<JSFunction>()) {
-                        JSFunction *target = &targets[i]->as<JSFunction>();
-                        if (target->isSingleton()) {
-                            remaining = target;
-                            clonedAtCallsite = target != originals[i];
-                        }
-                    }
+                    if (targets[i]->is<JSFunction>() && targets[i]->as<JSFunction>().isSingleton())
+                        remaining = &targets[i]->as<JSFunction>();
                     break;
                 }
             }
 
-            if (!inlineGenericFallback(remaining, callInfo, dispatchBlock, clonedAtCallsite))
+            if (!inlineGenericFallback(remaining, callInfo, dispatchBlock))
                 return false;
             dispatch->addFallback(current);
         }
 
         MBasicBlock *fallbackReturnBlock = current;
 
         // Connect fallback case to return infrastructure.
         MDefinition *retVal = fallbackReturnBlock->peek(-1);
@@ -5602,17 +5573,17 @@ IonBuilder::jsop_funcall(uint32_t argc)
 
     // If |Function.prototype.call| may be overridden, don't optimize callsite.
     TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     JSFunction *native = getSingleCallTarget(calleeTypes);
     if (!native || !native->isNative() || native->native() != &js_fun_call) {
         CallInfo callInfo(alloc(), false);
         if (!callInfo.init(current, argc))
             return false;
-        return makeCall(native, callInfo, false);
+        return makeCall(native, callInfo);
     }
     current->peek(calleeDepth)->setImplicitlyUsedUnchecked();
 
     // Extract call target.
     TemporaryTypeSet *funTypes = current->peek(funcDepth)->resultTypeSet();
     JSFunction *target = getSingleCallTarget(funTypes);
 
     // Shimmy the slots down to remove the native 'call' function.
@@ -5645,31 +5616,31 @@ IonBuilder::jsop_funcall(uint32_t argc)
           case InliningDecision_Inline:
             if (target->isInterpreted())
                 return inlineScriptedCall(callInfo, target);
             break;
         }
     }
 
     // Call without inlining.
-    return makeCall(target, callInfo, false);
+    return makeCall(target, callInfo);
 }
 
 bool
 IonBuilder::jsop_funapply(uint32_t argc)
 {
     int calleeDepth = -((int)argc + 2);
 
     TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     JSFunction *native = getSingleCallTarget(calleeTypes);
     if (argc != 2 || info().analysisMode() == Analysis_ArgumentsUsage) {
         CallInfo callInfo(alloc(), false);
         if (!callInfo.init(current, argc))
             return false;
-        return makeCall(native, callInfo, false);
+        return makeCall(native, callInfo);
     }
 
     // Disable compilation if the second argument to |apply| cannot be guaranteed
     // to be either definitely |arguments| or definitely not |arguments|.
     MDefinition *argument = current->peek(-1);
     if (script()->argumentsHasVarBinding() &&
         argument->mightBeType(MIRType_MagicOptimizedArguments) &&
         argument->type() != MIRType_MagicOptimizedArguments)
@@ -5677,17 +5648,17 @@ IonBuilder::jsop_funapply(uint32_t argc)
         return abort("fun.apply with MaybeArguments");
     }
 
     // Fallback to regular call if arg 2 is not definitely |arguments|.
     if (argument->type() != MIRType_MagicOptimizedArguments) {
         CallInfo callInfo(alloc(), false);
         if (!callInfo.init(current, argc))
             return false;
-        return makeCall(native, callInfo, false);
+        return makeCall(native, callInfo);
     }
 
     if ((!native || !native->isNative() ||
         native->native() != js_fun_apply) &&
         info().analysisMode() != Analysis_DefiniteProperties)
     {
         return abort("fun.apply speculation failed");
     }
@@ -5781,17 +5752,17 @@ IonBuilder::jsop_funapplyarguments(uint3
       case InliningDecision_DontInline:
       case InliningDecision_WarmUpCountTooLow:
         break;
       case InliningDecision_Inline:
         if (target->isInterpreted())
             return inlineScriptedCall(callInfo, target);
     }
 
-    return makeCall(target, callInfo, false);
+    return makeCall(target, callInfo);
 }
 
 bool
 IonBuilder::jsop_call(uint32_t argc, bool constructing)
 {
     startTrackingOptimizations();
 
     // If this call has never executed, try to seed the observed type set
@@ -5806,49 +5777,27 @@ IonBuilder::jsop_call(uint32_t argc, boo
             // See bug 870847.
             observed->addType(TypeSet::DoubleType(), alloc_->lifoAlloc());
         }
     }
 
     int calleeDepth = -((int)argc + 2);
 
     // Acquire known call target if existent.
-    ObjectVector originals(alloc());
+    ObjectVector targets(alloc());
     TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
-    if (calleeTypes && !getPolyCallTargets(calleeTypes, constructing, originals, 4))
-        return false;
-
-    // If any call targets need to be cloned, look for existing clones to use.
-    // Keep track of the originals as we need to case on them for poly inline.
-    bool hasClones = false;
-    ObjectVector targets(alloc());
-    if (!targets.reserve(originals.length()))
-        return false;
-    for (uint32_t i = 0; i < originals.length(); i++) {
-        JSObject *obj = originals[i];
-        if (obj->is<JSFunction>()) {
-            JSFunction *fun = &obj->as<JSFunction>();
-            if (fun->hasScript() && fun->nonLazyScript()->shouldCloneAtCallsite()) {
-                if (JSFunction *clone = ExistingCloneFunctionAtCallsite(compartment->callsiteClones(),
-                                                                        fun, script(), pc))
-                {
-                    obj = clone;
-                    hasClones = true;
-                }
-            }
-        }
-        targets.infallibleAppend(obj);
-    }
+    if (calleeTypes && !getPolyCallTargets(calleeTypes, constructing, targets, 4))
+        return false;
 
     CallInfo callInfo(alloc(), constructing);
     if (!callInfo.init(current, argc))
         return false;
 
     // Try inlining
-    InliningStatus status = inlineCallsite(targets, originals, callInfo);
+    InliningStatus status = inlineCallsite(targets, callInfo);
     if (status == InliningStatus_Inlined)
         return true;
     if (status == InliningStatus_Error)
         return false;
 
     // No inline, just make the call.
     JSFunction *target = nullptr;
     if (targets.length() == 1 && targets[0]->is<JSFunction>())
@@ -5857,37 +5806,17 @@ IonBuilder::jsop_call(uint32_t argc, boo
     if (target && status == InliningStatus_WarmUpCountTooLow) {
         MRecompileCheck *check =
             MRecompileCheck::New(alloc(), target->nonLazyScript(),
                                  optimizationInfo().inliningRecompileThreshold(),
                                  MRecompileCheck::RecompileCheck_Inlining);
         current->add(check);
     }
 
-    return makeCall(target, callInfo, hasClones);
-}
-
-MDefinition *
-IonBuilder::makeCallsiteClone(JSFunction *target, MDefinition *fun)
-{
-    // Bake in the clone eagerly if we have a known target. We have arrived here
-    // because TI told us that the known target is a should-clone-at-callsite
-    // function, which means that target already is the clone. Make sure to ensure
-    // that the old definition remains in resume points.
-    if (target) {
-        fun->setImplicitlyUsedUnchecked();
-        return constant(ObjectValue(*target));
-    }
-
-    // Add a callsite clone IC if we have multiple targets. Note that we
-    // should have checked already that at least some targets are marked as
-    // should-clone-at-callsite.
-    MCallsiteCloneCache *clone = MCallsiteCloneCache::New(alloc(), fun, pc);
-    current->add(clone);
-    return clone;
+    return makeCall(target, callInfo);
 }
 
 bool
 IonBuilder::testShouldDOMCall(TypeSet *inTypes, JSFunction *func, JSJitInfo::OpType opType)
 {
     if (IsInsideNursery(func))
         return false;
 
@@ -5961,17 +5890,17 @@ IonBuilder::testNeedsArgumentCheck(JSFun
         if (!TypeScript::ArgTypes(targetScript, i)->mightBeMIRType(MIRType_Undefined))
             return true;
     }
 
     return false;
 }
 
 MCall *
-IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsite)
+IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo)
 {
     // This function may be called with mutated stack.
     // Querying TI for popped types is invalid.
 
     uint32_t targetArgs = callInfo.argc();
 
     // Collect number of missing arguments provided that the target is
     // scripted. Native functions are passed an explicit 'argc' parameter.
@@ -6025,23 +5954,16 @@ IonBuilder::makeCallHelper(JSFunction *t
         callInfo.thisArg()->setImplicitlyUsedUnchecked();
         callInfo.setThis(create);
     }
 
     // Pass |this| and function.
     MDefinition *thisArg = callInfo.thisArg();
     call->addArg(0, thisArg);
 
-    // Add a callsite clone IC for multiple targets which all should be
-    // callsite cloned, or bake in the clone for a single target.
-    if (cloneAtCallsite) {
-        MDefinition *fun = makeCallsiteClone(target, callInfo.fun());
-        callInfo.setFun(fun);
-    }
-
     if (target && !testNeedsArgumentCheck(target, callInfo))
         call->disableArgCheck();
 
     call->initFunction(callInfo.fun());
 
     current->add(call);
     return call;
 }
@@ -6059,24 +5981,24 @@ DOMCallNeedsBarrier(const JSJitInfo* jit
     if (jitinfo->returnType() == JSVAL_TYPE_OBJECT)
         return true;
 
     // No need for a barrier if we're already expecting the type we'll produce.
     return MIRTypeFromValueType(jitinfo->returnType()) != types->getKnownMIRType();
 }
 
 bool
-IonBuilder::makeCall(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsite)
+IonBuilder::makeCall(JSFunction *target, CallInfo &callInfo)
 {
     // Constructor calls to non-constructors should throw. We don't want to use
     // CallKnown in this case.
     MOZ_ASSERT_IF(callInfo.constructing() && target,
                   target->isInterpretedConstructor() || target->isNativeConstructor());
 
-    MCall *call = makeCallHelper(target, callInfo, cloneAtCallsite);
+    MCall *call = makeCallHelper(target, callInfo);
     if (!call)
         return false;
 
     current->push(call);
     if (call->isEffectful() && !resumeAfter(call))
         return false;
 
     TemporaryTypeSet *types = bytecodeTypes(pc);
@@ -6157,17 +6079,17 @@ IonBuilder::jsop_eval(uint32_t argc)
 
                 current->push(dynamicName);
                 current->push(thisValue);
 
                 CallInfo evalCallInfo(alloc(), /* constructing = */ false);
                 if (!evalCallInfo.init(current, /* argc = */ 0))
                     return false;
 
-                return makeCall(nullptr, evalCallInfo, false);
+                return makeCall(nullptr, evalCallInfo);
             }
         }
 
         MInstruction *filterArguments = MFilterArgumentsOrEval::New(alloc(), string);
         current->add(filterArguments);
 
         MInstruction *ins = MCallDirectEval::New(alloc(), scopeChain, string, thisValue, pc);
         current->add(ins);
@@ -10308,17 +10230,17 @@ IonBuilder::getPropTryCommonGetter(bool 
             if (!inlineScriptedCall(callInfo, commonGetter))
                 return false;
             *emitted = true;
             return true;
         }
     }
 
     JSFunction *tenuredCommonGetter = IsInsideNursery(commonGetter) ? nullptr : commonGetter;
-    if (!makeCall(tenuredCommonGetter, callInfo, false))
+    if (!makeCall(tenuredCommonGetter, callInfo))
         return false;
 
     // If the getter could have been inlined, don't track success. The call to
     // makeInliningDecision above would have tracked a specific reason why we
     // couldn't inline.
     if (!commonGetter->isInterpreted())
         trackOptimizationSuccess();
 
@@ -10783,17 +10705,17 @@ IonBuilder::setPropTryCommonSetter(bool 
             if (!inlineScriptedCall(callInfo, commonSetter))
                 return false;
             *emitted = true;
             return true;
         }
     }
 
     JSFunction *tenuredCommonSetter = IsInsideNursery(commonSetter) ? nullptr : commonSetter;
-    MCall *call = makeCallHelper(tenuredCommonSetter, callInfo, false);
+    MCall *call = makeCallHelper(tenuredCommonSetter, callInfo);
     if (!call)
         return false;
 
     current->push(value);
     if (!resumeAfter(call))
         return false;
 
     // If the setter could have been inlined, don't track success. The call to
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -832,36 +832,33 @@ class IonBuilder
     // Main inlining functions
     InliningStatus inlineNativeCall(CallInfo &callInfo, JSFunction *target);
     InliningStatus inlineNativeGetter(CallInfo &callInfo, JSFunction *target);
     InliningStatus inlineNonFunctionCall(CallInfo &callInfo, JSObject *target);
     bool inlineScriptedCall(CallInfo &callInfo, JSFunction *target);
     InliningStatus inlineSingleCall(CallInfo &callInfo, JSObject *target);
 
     // Call functions
-    InliningStatus inlineCallsite(const ObjectVector &targets, ObjectVector &originals,
-                                  CallInfo &callInfo);
-    bool inlineCalls(CallInfo &callInfo, const ObjectVector &targets, ObjectVector &originals,
-                     BoolVector &choiceSet, MGetPropertyCache *maybeCache);
+    InliningStatus inlineCallsite(const ObjectVector &targets, CallInfo &callInfo);
+    bool inlineCalls(CallInfo &callInfo, const ObjectVector &targets, BoolVector &choiceSet,
+                     MGetPropertyCache *maybeCache);
 
     // Inlining helpers.
-    bool inlineGenericFallback(JSFunction *target, CallInfo &callInfo, MBasicBlock *dispatchBlock,
-                               bool clonedAtCallsite);
+    bool inlineGenericFallback(JSFunction *target, CallInfo &callInfo, MBasicBlock *dispatchBlock);
     bool inlineObjectGroupFallback(CallInfo &callInfo, MBasicBlock *dispatchBlock,
                                    MObjectGroupDispatch *dispatch, MGetPropertyCache *cache,
                                    MBasicBlock **fallbackTarget);
 
     bool atomicsMeetsPreconditions(CallInfo &callInfo, Scalar::Type *arrayElementType);
     void atomicsCheckBounds(CallInfo &callInfo, MInstruction **elements, MDefinition **index);
 
     bool testNeedsArgumentCheck(JSFunction *target, CallInfo &callInfo);
 
-    MDefinition *makeCallsiteClone(JSFunction *target, MDefinition *fun);
-    MCall *makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsite);
-    bool makeCall(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsite);
+    MCall *makeCallHelper(JSFunction *target, CallInfo &callInfo);
+    bool makeCall(JSFunction *target, CallInfo &callInfo);
 
     MDefinition *patchInlinedReturn(CallInfo &callInfo, MBasicBlock *exit, MBasicBlock *bottom);
     MDefinition *patchInlinedReturns(CallInfo &callInfo, MIRGraphReturns &returns,
                                      MBasicBlock *bottom);
     MDefinition *specializeInlinedReturn(MDefinition *rdef, MBasicBlock *exit);
 
     bool objectsHaveCommonPrototype(TemporaryTypeSet *types, PropertyName *name,
                                     bool isGetter, JSObject *foundProto, bool *guardGlobal);
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -4142,50 +4142,8 @@ NameIC::update(JSContext *cx, size_t cac
     }
 
     // Monitor changes to cache entry.
     TypeScript::Monitor(cx, script, pc, vp);
 
     return true;
 }
 
-bool
-CallsiteCloneIC::attach(JSContext *cx, HandleScript outerScript, IonScript *ion,
-                        HandleFunction original, HandleFunction clone)
-{
-    MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
-    RepatchStubAppender attacher(*this);
-
-    // Guard against object identity on the original.
-    attacher.branchNextStub(masm, Assembler::NotEqual, calleeReg(), ImmGCPtr(original));
-
-    // Load the clone.
-    masm.movePtr(ImmGCPtr(clone), outputReg());
-
-    attacher.jumpRejoin(masm);
-
-    return linkAndAttachStub(cx, masm, attacher, ion, "generic");
-}
-
-JSObject *
-CallsiteCloneIC::update(JSContext *cx, size_t cacheIndex, HandleObject callee)
-{
-    // Act as the identity for functions that are not clone-at-callsite, as we
-    // generate this cache as long as some callees are clone-at-callsite.
-    RootedFunction fun(cx, &callee->as<JSFunction>());
-    if (!fun->hasScript() || !fun->nonLazyScript()->shouldCloneAtCallsite())
-        return fun;
-
-    RootedScript outerScript(cx, GetTopJitJSScript(cx));
-    IonScript *ion = outerScript->ionScript();
-    CallsiteCloneIC &cache = ion->getCache(cacheIndex).toCallsiteClone();
-
-    RootedFunction clone(cx, CloneFunctionAtCallsite(cx, fun, cache.callScript(), cache.callPc()));
-    if (!clone)
-        return nullptr;
-
-    if (cache.canAttachStub()) {
-        if (!cache.attach(cx, outerScript, ion, fun, clone))
-            return nullptr;
-    }
-
-    return clone;
-}
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -25,18 +25,17 @@ namespace jit {
 class LInstruction;
 
 #define IONCACHE_KIND_LIST(_)                                   \
     _(GetProperty)                                              \
     _(SetProperty)                                              \
     _(GetElement)                                               \
     _(SetElement)                                               \
     _(BindName)                                                 \
-    _(Name)                                                     \
-    _(CallsiteClone)
+    _(Name)
 
 // Forward declarations of Cache kinds.
 #define FORWARD_DECLARE(kind) class kind##IC;
 IONCACHE_KIND_LIST(FORWARD_DECLARE)
 #undef FORWARD_DECLARE
 
 class IonCacheVisitor
 {
@@ -1042,54 +1041,16 @@ class NameIC : public RepatchIonCache
     bool attachCallGetter(JSContext *cx, HandleScript outerScript, IonScript *ion,
                           HandleObject scopeChain, HandleObject obj, HandleObject holder,
                           HandleShape shape, void *returnAddr);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain, MutableHandleValue vp);
 };
 
-class CallsiteCloneIC : public RepatchIonCache
-{
-  protected:
-    Register callee_;
-    Register output_;
-    JSScript *callScript_;
-    jsbytecode *callPc_;
-
-  public:
-    CallsiteCloneIC(Register callee, JSScript *callScript, jsbytecode *callPc, Register output)
-      : callee_(callee),
-        output_(output),
-        callScript_(callScript),
-        callPc_(callPc)
-    {
-    }
-
-    CACHE_HEADER(CallsiteClone)
-
-    Register calleeReg() const {
-        return callee_;
-    }
-    HandleScript callScript() const {
-        return HandleScript::fromMarkedLocation(&callScript_);
-    }
-    jsbytecode *callPc() const {
-        return callPc_;
-    }
-    Register outputReg() const {
-        return output_;
-    }
-
-    bool attach(JSContext *cx, HandleScript outerScript, IonScript *ion,
-                HandleFunction original, HandleFunction clone);
-
-    static JSObject *update(JSContext *cx, size_t cacheIndex, HandleObject callee);
-};
-
 #undef CACHE_HEADER
 
 // Implement cache casts now that the compiler can see the inheritance.
 #define CACHE_CASTS(ickind)                                             \
     ickind##IC &IonCache::to##ickind()                                  \
     {                                                                   \
         MOZ_ASSERT(is##ickind());                                       \
         return *static_cast<ickind##IC *>(this);                        \
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -5151,32 +5151,16 @@ class LCallGetIntrinsicValue : public LC
   public:
     LIR_HEADER(CallGetIntrinsicValue)
 
     const MCallGetIntrinsicValue *mir() const {
         return mir_->toCallGetIntrinsicValue();
     }
 };
 
-class LCallsiteCloneCache : public LInstructionHelper<1, 1, 0>
-{
-  public:
-    LIR_HEADER(CallsiteCloneCache);
-
-    explicit LCallsiteCloneCache(const LAllocation &callee) {
-        setOperand(0, callee);
-    }
-    const LAllocation *callee() {
-        return getOperand(0);
-    }
-    const MCallsiteCloneCache *mir() const {
-        return mir_->toCallsiteCloneCache();
-    }
-};
-
 // Patchable jump to stubs generated for a GetProperty cache, which loads a
 // boxed value.
 class LGetPropertyCacheV : public LInstructionHelper<BOX_PIECES, 1, 0>
 {
   public:
     LIR_HEADER(GetPropertyCacheV)
 
     explicit LGetPropertyCacheV(const LAllocation &object) {
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -252,17 +252,16 @@
     _(GetPropertyPolymorphicV)      \
     _(GetPropertyPolymorphicT)      \
     _(GetElementCacheV)             \
     _(GetElementCacheT)             \
     _(BindNameCache)                \
     _(CallGetProperty)              \
     _(GetNameCache)                 \
     _(CallGetIntrinsicValue)        \
-    _(CallsiteCloneCache)           \
     _(CallGetElement)               \
     _(CallSetElement)               \
     _(CallInitElementArray)         \
     _(CallSetProperty)              \
     _(CallDeleteProperty)           \
     _(CallDeleteElement)            \
     _(SetPropertyCacheV)            \
     _(SetPropertyCacheT)            \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3057,26 +3057,16 @@ void
 LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue *ins)
 {
     LCallGetIntrinsicValue *lir = new(alloc()) LCallGetIntrinsicValue();
     defineReturn(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
-LIRGenerator::visitCallsiteCloneCache(MCallsiteCloneCache *ins)
-{
-    MOZ_ASSERT(ins->callee()->type() == MIRType_Object);
-
-    LCallsiteCloneCache *lir = new(alloc()) LCallsiteCloneCache(useRegister(ins->callee()));
-    define(lir, ins);
-    assignSafepoint(lir, ins);
-}
-
-void
 LIRGenerator::visitGetPropertyCache(MGetPropertyCache *ins)
 {
     MOZ_ASSERT(ins->object()->type() == MIRType_Object);
     if (ins->type() == MIRType_Value) {
         LGetPropertyCacheV *lir = new(alloc()) LGetPropertyCacheV(useRegister(ins->object()));
         defineBox(lir, ins);
         assignSafepoint(lir, ins);
     } else {
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -222,17 +222,16 @@ class LIRGenerator : public LIRGenerator
     void visitGuardShapePolymorphic(MGuardShapePolymorphic *ins);
     void visitPolyInlineGuard(MPolyInlineGuard *ins);
     void visitAssertRange(MAssertRange *ins);
     void visitCallGetProperty(MCallGetProperty *ins);
     void visitDeleteProperty(MDeleteProperty *ins);
     void visitDeleteElement(MDeleteElement *ins);
     void visitGetNameCache(MGetNameCache *ins);
     void visitCallGetIntrinsicValue(MCallGetIntrinsicValue *ins);
-    void visitCallsiteCloneCache(MCallsiteCloneCache *ins);
     void visitCallGetElement(MCallGetElement *ins);
     void visitCallSetElement(MCallSetElement *ins);
     void visitCallInitElementArray(MCallInitElementArray *ins);
     void visitSetPropertyCache(MSetPropertyCache *ins);
     void visitSetElementCache(MSetElementCache *ins);
     void visitCallSetProperty(MCallSetProperty *ins);
     void visitIteratorStart(MIteratorStart *ins);
     void visitIteratorMore(MIteratorMore *ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -2382,17 +2382,17 @@ IonBuilder::inlineBoundFunction(CallInfo
     if (!callInfo.argv().reserve(argc))
         return InliningStatus_Error;
 
     for (size_t i = 0; i < target->getBoundFunctionArgumentCount(); i++)
         callInfo.argv().infallibleAppend(constant(target->getBoundFunctionArgument(i)));
     for (size_t i = 0; i < nativeCallInfo.argc(); i++)
         callInfo.argv().infallibleAppend(nativeCallInfo.getArg(i));
 
-    if (!makeCall(scriptedTarget, callInfo, false))
+    if (!makeCall(scriptedTarget, callInfo))
         return InliningStatus_Error;
 
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineAtomicsCompareExchange(CallInfo &callInfo)
 {
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -3969,17 +3969,17 @@ MGuardShapePolymorphic::congruentTo(cons
         if (getShape(i) != other->getShape(i))
             return false;
     }
 
     return congruentIfOperandsEqual(ins);
 }
 
 void
-InlinePropertyTable::trimTo(ObjectVector &targets, BoolVector &choiceSet)
+InlinePropertyTable::trimTo(const ObjectVector &targets, const BoolVector &choiceSet)
 {
     for (size_t i = 0; i < targets.length(); i++) {
         // If the target was inlined, don't erase the entry.
         if (choiceSet[i])
             continue;
 
         JSFunction *target = &targets[i]->as<JSFunction>();
 
@@ -3990,17 +3990,17 @@ InlinePropertyTable::trimTo(ObjectVector
                 entries_.erase(&entries_[j]);
             else
                 j++;
         }
     }
 }
 
 void
-InlinePropertyTable::trimToTargets(ObjectVector &targets)
+InlinePropertyTable::trimToTargets(const ObjectVector &targets)
 {
     JitSpew(JitSpew_Inlining, "Got inlineable property cache with %d cases",
             (int)numEntries());
 
     size_t i = 0;
     while (i < numEntries()) {
         bool foundFunc = false;
         for (size_t j = 0; j < targets.length(); j++) {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -9249,20 +9249,20 @@ class InlinePropertyTable : public TempO
         MOZ_ASSERT(i < numEntries());
         return entries_[i]->func;
     }
 
     bool hasFunction(JSFunction *func) const;
     TemporaryTypeSet *buildTypeSetForFunction(JSFunction *func) const;
 
     // Remove targets that vetoed inlining from the InlinePropertyTable.
-    void trimTo(ObjectVector &targets, BoolVector &choiceSet);
+    void trimTo(const ObjectVector &targets, const BoolVector &choiceSet);
 
     // Ensure that the InlinePropertyTable's domain is a subset of |targets|.
-    void trimToTargets(ObjectVector &targets);
+    void trimToTargets(const ObjectVector &targets);
 };
 
 class CacheLocationList : public InlineConcatList<CacheLocationList>
 {
   public:
     CacheLocationList()
       : pc(nullptr),
         script(nullptr)
@@ -10206,48 +10206,16 @@ class MCallGetIntrinsicValue : public MN
     AliasSet getAliasSet() const MOZ_OVERRIDE {
         return AliasSet::None();
     }
     bool possiblyCalls() const MOZ_OVERRIDE {
         return true;
     }
 };
 
-class MCallsiteCloneCache
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    jsbytecode *callPc_;
-
-    MCallsiteCloneCache(MDefinition *callee, jsbytecode *callPc)
-      : MUnaryInstruction(callee),
-        callPc_(callPc)
-    {
-        setResultType(MIRType_Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(CallsiteCloneCache)
-
-    static MCallsiteCloneCache *New(TempAllocator &alloc, MDefinition *callee, jsbytecode *callPc) {
-        return new(alloc) MCallsiteCloneCache(callee, callPc);
-    }
-    MDefinition *callee() const {
-        return getOperand(0);
-    }
-    jsbytecode *callPc() const {
-        return callPc_;
-    }
-
-    // Callsite cloning is idempotent.
-    AliasSet getAliasSet() const MOZ_OVERRIDE {
-        return AliasSet::None();
-    }
-};
-
 class MSetPropertyInstruction : public MBinaryInstruction
 {
     AlwaysTenuredPropertyName name_;
     bool strict_;
     bool needsBarrier_;
 
   protected:
     MSetPropertyInstruction(MDefinition *obj, MDefinition *value, PropertyName *name,
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -198,17 +198,16 @@ namespace jit {
     _(AtomicTypedArrayElementBinop)                                         \
     _(EffectiveAddress)                                                     \
     _(ClampToUint8)                                                         \
     _(LoadFixedSlot)                                                        \
     _(StoreFixedSlot)                                                       \
     _(CallGetProperty)                                                      \
     _(GetNameCache)                                                         \
     _(CallGetIntrinsicValue)                                                \
-    _(CallsiteCloneCache)                                                   \
     _(CallGetElement)                                                       \
     _(CallSetElement)                                                       \
     _(CallSetProperty)                                                      \
     _(CallInitElementArray)                                                 \
     _(DeleteProperty)                                                       \
     _(DeleteElement)                                                        \
     _(SetPropertyCache)                                                     \
     _(IteratorStart)                                                        \
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -52,38 +52,20 @@ VMFunction::addToFunctions()
         initialized = true;
         functions = nullptr;
     }
     this->next = functions;
     functions = this;
 }
 
 bool
-InvokeFunction(JSContext *cx, HandleObject obj0, uint32_t argc, Value *argv, Value *rval)
+InvokeFunction(JSContext *cx, HandleObject obj, uint32_t argc, Value *argv, Value *rval)
 {
     AutoArrayRooter argvRoot(cx, argc + 1, argv);
 
-    RootedObject obj(cx, obj0);
-    if (obj->is<JSFunction>()) {
-        RootedFunction fun(cx, &obj->as<JSFunction>());
-        if (fun->isInterpreted()) {
-            if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
-                return false;
-
-            // Clone function at call site if needed.
-            if (fun->nonLazyScript()->shouldCloneAtCallsite()) {
-                jsbytecode *pc;
-                RootedScript script(cx, cx->currentScript(&pc));
-                fun = CloneFunctionAtCallsite(cx, fun, script, pc);
-                if (!fun)
-                    return false;
-            }
-        }
-    }
-
     // Data in the argument vector is arranged for a JIT -> JIT call.
     Value thisv = argv[0];
     Value *argvWithoutThis = argv + 1;
 
     // For constructing functions, |this| is constructed at caller side and we can just call Invoke.
     // When creating this failed / is impossible at caller site, i.e. MagicValue(JS_IS_CONSTRUCTING),
     // we use InvokeConstructor that creates it at the callee side.
     RootedValue rv(cx);
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -87,92 +87,16 @@ js::TraceCycleDetectionSet(JSTracer *trc
         JSObject *key = e.front();
         trc->setTracingLocation((void *)&e.front());
         MarkObjectRoot(trc, &key, "cycle detector table entry");
         if (key != e.front())
             e.rekeyFront(key);
     }
 }
 
-void
-JSCompartment::sweepCallsiteClones()
-{
-    if (callsiteClones.initialized()) {
-        for (CallsiteCloneTable::Enum e(callsiteClones); !e.empty(); e.popFront()) {
-            CallsiteCloneKey key = e.front().key();
-            if (IsObjectAboutToBeFinalizedFromAnyThread(&key.original) ||
-                IsScriptAboutToBeFinalizedFromAnyThread(&key.script) ||
-                IsObjectAboutToBeFinalizedFromAnyThread(e.front().value().unsafeGet()))
-            {
-                e.removeFront();
-            } else if (key != e.front().key()) {
-                e.rekeyFront(key);
-            }
-        }
-    }
-}
-
-JSFunction *
-js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction *fun,
-                                    JSScript *script, jsbytecode *pc)
-{
-    MOZ_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite());
-    MOZ_ASSERT(!fun->nonLazyScript()->enclosingStaticScope());
-    MOZ_ASSERT(ObjectGroup::useSingletonForClone(fun));
-
-    /*
-     * If we start allocating function objects in the nursery, then the callsite
-     * clone table will need a postbarrier.
-     */
-    MOZ_ASSERT(fun->isTenured());
-
-    if (!table.initialized())
-        return nullptr;
-
-    CallsiteCloneTable::Ptr p = table.readonlyThreadsafeLookup(CallsiteCloneKey(fun, script, script->pcToOffset(pc)));
-    if (p)
-        return p->value();
-
-    return nullptr;
-}
-
-JSFunction *
-js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript script, jsbytecode *pc)
-{
-    if (JSFunction *clone = ExistingCloneFunctionAtCallsite(cx->compartment()->callsiteClones, fun, script, pc))
-        return clone;
-
-    MOZ_ASSERT(fun->isSelfHostedBuiltin(),
-               "only self-hosted builtin functions may be cloned at call sites, and "
-               "Function.prototype.caller relies on this");
-
-    RootedObject parent(cx, fun->environment());
-    JSFunction *clone = CloneFunctionObject(cx, fun, parent);
-    if (!clone)
-        return nullptr;
-
-    /*
-     * Store a link back to the original for function.caller and avoid cloning
-     * clones.
-     */
-    clone->nonLazyScript()->setIsCallsiteClone(fun);
-
-    typedef CallsiteCloneKey Key;
-    typedef CallsiteCloneTable Table;
-
-    Table &table = cx->compartment()->callsiteClones;
-    if (!table.initialized() && !table.init())
-        return nullptr;
-
-    if (!table.putNew(Key(fun, script, script->pcToOffset(pc)), clone))
-        return nullptr;
-
-    return clone;
-}
-
 JSContext *
 js::NewContext(JSRuntime *rt, size_t stackChunkSize)
 {
     JS_AbortIfWrongThread(rt);
 
     JSContext *cx = js_new<JSContext>(rt);
     if (!cx)
         return nullptr;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -24,65 +24,16 @@ struct DtoaState;
 namespace js {
 
 namespace jit {
 class JitContext;
 class CompileCompartment;
 class DebugModeOSRVolatileJitFrameIterator;
 }
 
-struct CallsiteCloneKey {
-    /* The original function that we are cloning. */
-    JSFunction *original;
-
-    /* The script of the call. */
-    JSScript *script;
-
-    /* The offset of the call. */
-    uint32_t offset;
-
-    CallsiteCloneKey(JSFunction *f, JSScript *s, uint32_t o) : original(f), script(s), offset(o) {}
-
-    bool operator==(const CallsiteCloneKey& other) {
-        return original == other.original && script == other.script && offset == other.offset;
-    }
-
-    bool operator!=(const CallsiteCloneKey& other) {
-        return !(*this == other);
-    }
-
-    typedef CallsiteCloneKey Lookup;
-
-    static inline uint32_t hash(CallsiteCloneKey key) {
-        return uint32_t(size_t(key.script->offsetToPC(key.offset)) ^ size_t(key.original));
-    }
-
-    static inline bool match(const CallsiteCloneKey &a, const CallsiteCloneKey &b) {
-        return a.script == b.script && a.offset == b.offset && a.original == b.original;
-    }
-
-    static void rekey(CallsiteCloneKey &k, const CallsiteCloneKey &newKey) {
-        k.original = newKey.original;
-        k.script = newKey.script;
-        k.offset = newKey.offset;
-    }
-};
-
-typedef HashMap<CallsiteCloneKey,
-                ReadBarrieredFunction,
-                CallsiteCloneKey,
-                SystemAllocPolicy> CallsiteCloneTable;
-
-JSFunction *
-ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction *fun,
-                                JSScript *script, jsbytecode *pc);
-
-JSFunction *CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun,
-                                    HandleScript script, jsbytecode *pc);
-
 typedef HashSet<JSObject *> ObjectSet;
 typedef HashSet<Shape *> ShapeSet;
 
 /* Detects cycles when traversing an object graph. */
 class AutoCycleDetector
 {
     JSContext *cx;
     RootedObject obj;
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -667,17 +667,16 @@ void
 JSCompartment::clearTables()
 {
     global_.set(nullptr);
 
     // No scripts should have run in this compartment. This is used when
     // merging a compartment that has been used off thread into another
     // compartment and zone.
     MOZ_ASSERT(crossCompartmentWrappers.empty());
-    MOZ_ASSERT_IF(callsiteClones.initialized(), callsiteClones.empty());
     MOZ_ASSERT(!jitCompartment_);
     MOZ_ASSERT(!debugScopes);
     MOZ_ASSERT(!gcWeakMapList);
     MOZ_ASSERT(enumerators->next() == enumerators);
     MOZ_ASSERT(regExps.empty());
 
     objectGroups.clearTables();
     if (baseShapes.initialized())
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -278,24 +278,16 @@ struct JSCompartment
 
 #ifdef JSGC_HASH_TABLE_CHECKS
     void checkInitialShapesTableAfterMovingGC();
     void checkWrapperMapAfterMovingGC();
     void checkBaseShapeTableAfterMovingGC();
 #endif
 
     /*
-     * Hash table of all manually call site-cloned functions from within
-     * self-hosted code. Cloning according to call site provides extra
-     * sensitivity for type specialization and inlining.
-     */
-    js::CallsiteCloneTable callsiteClones;
-    void sweepCallsiteClones();
-
-    /*
      * Lazily initialized script source object to use for scripts cloned
      * from the self-hosting global.
      */
     js::ReadBarrieredScriptSourceObject selfHostingScriptSource;
 
     // Map from array buffers to views sharing that storage.
     js::InnerViewTable innerViews;
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -257,26 +257,17 @@ CallerGetterImpl(JSContext *cx, CallArgs
     }
 
     ++iter;
     if (iter.done() || !iter.isFunctionFrame()) {
         args.rval().setNull();
         return true;
     }
 
-    // It might seem we need to replace call site clones with the original
-    // functions here.  But we're iterating over *non-builtin* frames, and the
-    // only call site-clonable scripts are for builtin, self-hosted functions
-    // (see assertions in js::CloneFunctionAtCallsite).  So the callee can't be
-    // a call site clone.
-    JSFunction *maybeClone = iter.callee(cx);
-    MOZ_ASSERT(!maybeClone->nonLazyScript()->isCallsiteClone(),
-               "non-builtin functions aren't call site-clonable");
-
-    RootedObject caller(cx, maybeClone);
+    RootedObject caller(cx, iter.callee(cx));
     if (!cx->compartment()->wrap(cx, &caller))
         return false;
 
     // Censor the caller if we don't have full access to it.  If we do, but the
     // caller is a function with strict mode code, throw a TypeError per ES5.
     // If we pass these checks, we can return the computed caller.
     {
         JSObject *callerObj = CheckedUnwrap(caller);
@@ -330,26 +321,17 @@ CallerSetterImpl(JSContext *cx, CallArgs
     NonBuiltinScriptFrameIter iter(cx);
     if (!AdvanceToActiveCallLinear(cx, iter, fun))
         return true;
 
     ++iter;
     if (iter.done() || !iter.isFunctionFrame())
         return true;
 
-    // It might seem we need to replace call site clones with the original
-    // functions here.  But we're iterating over *non-builtin* frames, and the
-    // only call site-clonable scripts are for builtin, self-hosted functions
-    // (see assertions in js::CloneFunctionAtCallsite).  So the callee can't be
-    // a call site clone.
-    JSFunction *maybeClone = iter.callee(cx);
-    MOZ_ASSERT(!maybeClone->nonLazyScript()->isCallsiteClone(),
-               "non-builtin functions aren't call site-clonable");
-
-    RootedObject caller(cx, maybeClone);
+    RootedObject caller(cx, iter.callee(cx));
     if (!cx->compartment()->wrap(cx, &caller)) {
         cx->clearPendingException();
         return true;
     }
 
     // If we don't have full access to the caller, or the caller is not strict,
     // return undefined.  Otherwise throw a TypeError.
     JSObject *callerObj = CheckedUnwrap(caller);
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -319,26 +319,16 @@ class JSFunction : public js::NativeObje
     }
 
     JSScript *nonLazyScript() const {
         MOZ_ASSERT(hasScript());
         MOZ_ASSERT(u.i.s.script_);
         return u.i.s.script_;
     }
 
-    // Returns non-callsited-clone version of this.  Use when return
-    // value can flow to arbitrary JS (see Bug 944975).
-    JSFunction* originalFunction() {
-        if (this->hasScript() && this->nonLazyScript()->isCallsiteClone()) {
-            return this->nonLazyScript()->donorFunction();
-        } else {
-            return this;
-        }
-    }
-
     js::HeapPtrScript &mutableScript() {
         MOZ_ASSERT(isInterpreted());
         return *(js::HeapPtrScript *)&u.i.s.script_;
     }
 
     js::LazyScript *lazyScript() const {
         MOZ_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
         return u.i.s.lazy_;
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2244,17 +2244,16 @@ GCRuntime::sweepZoneAfterCompacting(Zone
 
     for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
         c->sweepInnerViews();
         c->sweepCrossCompartmentWrappers();
         c->sweepBaseShapeTable();
         c->sweepInitialShapeTable();
         c->objectGroups.sweep(fop);
         c->sweepRegExps();
-        c->sweepCallsiteClones();
         c->sweepSavedStacks();
         c->sweepGlobalObject(fop);
         c->sweepSelfHostingScriptSource();
         c->sweepDebugScopes();
         c->sweepJitCompartment(fop);
         c->sweepWeakMaps();
         c->sweepNativeIterators();
     }
@@ -4881,17 +4880,16 @@ SweepRegExpsTask::run()
     for (GCCompartmentGroupIter c(runtime); !c.done(); c.next())
         c->sweepRegExps();
 }
 
 /* virtual */ void
 SweepMiscTask::run()
 {
     for (GCCompartmentGroupIter c(runtime); !c.done(); c.next()) {
-        c->sweepCallsiteClones();
         c->sweepSavedStacks();
         c->sweepSelfHostingScriptSource();
         c->sweepNativeIterators();
     }
 }
 
 void
 GCRuntime::startTask(GCParallelTask &task, gcstats::Phase phase)
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -2384,17 +2384,17 @@ JSScript::Create(ExclusiveContext *cx, H
 
     RootedScript script(cx, js_NewGCScript(cx));
     if (!script)
         return nullptr;
 
     PodZero(script.get());
     new (&script->bindings) Bindings;
 
-    script->enclosingScopeOrOriginalFunction_ = enclosingScope;
+    script->enclosingStaticScope_ = enclosingScope;
     script->savedCallerFun_ = savedCallerFun;
     script->initCompartment(cx);
 
     script->compileAndGo_ = options.compileAndGo;
     script->selfHosted_ = options.selfHostingMode;
     script->noScriptRval_ = options.noScriptRval;
 
     script->version = options.version;
@@ -3120,21 +3120,16 @@ js::CloneScript(JSContext *cx, HandleObj
     dst->funHasExtensibleScope_ = src->funHasExtensibleScope();
     dst->funNeedsDeclEnvObject_ = src->funNeedsDeclEnvObject();
     dst->funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal();
     dst->hasSingletons_ = src->hasSingletons();
     dst->treatAsRunOnce_ = src->treatAsRunOnce();
     dst->isGeneratorExp_ = src->isGeneratorExp();
     dst->setGeneratorKind(src->generatorKind());
 
-    /* Copy over hints. */
-    dst->shouldInline_ = src->shouldInline();
-    dst->shouldCloneAtCallsite_ = src->shouldCloneAtCallsite();
-    dst->isCallsiteClone_ = src->isCallsiteClone();
-
     if (nconsts != 0) {
         HeapValue *vector = Rebase<HeapValue>(dst, src, src->consts()->vector);
         dst->consts()->vector = vector;
         for (unsigned i = 0; i < nconsts; ++i)
             MOZ_ASSERT_IF(vector[i].isMarkable(), vector[i].toString()->isAtom());
     }
     if (nobjects != 0) {
         HeapPtrNativeObject *vector = Rebase<HeapPtrNativeObject>(dst, src, src->objects()->vector);
@@ -3416,18 +3411,18 @@ JSScript::markChildren(JSTracer *trc)
     if (sourceObject()) {
         MOZ_ASSERT(MaybeForwarded(sourceObject())->compartment() == compartment());
         MarkObject(trc, &sourceObject_, "sourceObject");
     }
 
     if (functionNonDelazifying())
         MarkObject(trc, &function_, "function");
 
-    if (enclosingScopeOrOriginalFunction_)
-        MarkObject(trc, &enclosingScopeOrOriginalFunction_, "enclosing");
+    if (enclosingStaticScope_)
+        MarkObject(trc, &enclosingStaticScope_, "enclosingStaticScope");
 
     if (maybeLazyScript())
         MarkLazyScriptUnbarriered(trc, &lazyScript, "lazyScript");
 
     if (IS_GC_MARKING_TRACER(trc)) {
         compartment()->mark();
 
         if (code())
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -827,20 +827,17 @@ class JSScript : public js::gc::TenuredC
 
     // This script's ScriptSourceObject, or a CCW thereof.
     //
     // (When we clone a JSScript into a new compartment, we don't clone its
     // source object. Instead, the clone refers to a wrapper.)
     js::HeapPtrObject sourceObject_;
 
     js::HeapPtrFunction function_;
-
-    // For callsite clones, which cannot have enclosing scopes, the original
-    // function; otherwise the enclosing scope
-    js::HeapPtrObject   enclosingScopeOrOriginalFunction_;
+    js::HeapPtrObject   enclosingStaticScope_;
 
     /* Information attached by Baseline/Ion for sequential mode execution. */
     js::jit::IonScript *ion;
     js::jit::BaselineScript *baseline;
 
     /* Information used to re-lazify a lazily-parsed interpreted function. */
     js::LazyScript *lazyScript;
 
@@ -957,25 +954,16 @@ class JSScript : public js::gc::TenuredC
     bool isCachedEval_:1;
 
     // Set for functions defined at the top level within an 'eval' script.
     bool directlyInsideEval_:1;
 
     // 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper.
     bool usesArgumentsApplyAndThis_:1;
 
-    // PJS FIXME bug 1121433 - clone at call site may be obsolete
-    /* script is attempted to be cloned anew at each callsite. This is
-       temporarily needed for ParallelArray selfhosted code until type
-       information can be made context sensitive. See discussion in
-       bug 826148. */
-    bool shouldCloneAtCallsite_:1;
-    bool isCallsiteClone_:1; /* is a callsite clone; has a link to the original function */
-    bool shouldInline_:1;    /* hint to inline when possible */
-
     // IonMonkey compilation hints.
     bool failedBoundsCheck_:1; /* script has had hoisted bounds checks fail */
     bool failedShapeGuard_:1; /* script has had hoisted shape guard fail */
     bool hadFrequentBailouts_:1;
     bool uninlineable_:1;    /* explicitly marked as uninlineable */
 
     // Idempotent cache has triggered invalidation.
     bool invalidatedIdempotentCache_:1;
@@ -1200,29 +1188,16 @@ class JSScript : public js::gc::TenuredC
     void setActiveEval() { isActiveEval_ = true; }
     void setDirectlyInsideEval() { directlyInsideEval_ = true; }
 
     bool usesArgumentsApplyAndThis() const {
         return usesArgumentsApplyAndThis_;
     }
     void setUsesArgumentsApplyAndThis() { usesArgumentsApplyAndThis_ = true; }
 
-    bool shouldCloneAtCallsite() const {
-        return shouldCloneAtCallsite_;
-    }
-    bool shouldInline() const {
-        return shouldInline_;
-    }
-
-    void setShouldCloneAtCallsite() { shouldCloneAtCallsite_ = true; }
-    void setShouldInline() { shouldInline_ = true; }
-
-    bool isCallsiteClone() const {
-        return isCallsiteClone_;
-    }
     bool isGeneratorExp() const { return isGeneratorExp_; }
 
     bool failedBoundsCheck() const {
         return failedBoundsCheck_;
     }
     bool failedShapeGuard() const {
         return failedShapeGuard_;
     }
@@ -1421,22 +1396,16 @@ class JSScript : public js::gc::TenuredC
     }
     inline void setFunction(JSFunction *fun);
     /*
      * De-lazifies the canonical function. Must be called before entering code
      * that expects the function to be non-lazy.
      */
     inline void ensureNonLazyCanonicalFunction(JSContext *cx);
 
-    /*
-     * Donor provided itself to callsite clone; null if this is non-clone.
-     */
-    JSFunction *donorFunction() const;
-    void setIsCallsiteClone(JSObject *fun);
-
     JSFlatString *sourceData(JSContext *cx);
 
     static bool loadSource(JSContext *cx, js::ScriptSource *ss, bool *worked);
 
     void setSourceObject(JSObject *object);
     JSObject *sourceObject() const {
         return sourceObject_;
     }
@@ -1459,19 +1428,17 @@ class JSScript : public js::gc::TenuredC
 
     void maybeSweepTypes(js::AutoClearTypeInferenceStateOnOOM *oom);
 
     inline js::GlobalObject &global() const;
     js::GlobalObject &uninlinedGlobal() const;
 
     /* See StaticScopeIter comment. */
     JSObject *enclosingStaticScope() const {
-        if (isCallsiteClone())
-            return nullptr;
-        return enclosingScopeOrOriginalFunction_;
+        return enclosingStaticScope_;
     }
 
   private:
     bool makeTypes(JSContext *cx);
 
   public:
     uint32_t getWarmUpCount() const {
         return warmUpCount;
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -140,35 +140,16 @@ JSScript::global() const
 }
 
 inline JSPrincipals *
 JSScript::principals()
 {
     return compartment()->principals;
 }
 
-inline JSFunction *
-JSScript::donorFunction() const
-{
-    if (!isCallsiteClone())
-        return nullptr;
-    return &enclosingScopeOrOriginalFunction_->as<JSFunction>();
-}
-
-inline void
-JSScript::setIsCallsiteClone(JSObject *fun)
-{
-    MOZ_ASSERT(shouldCloneAtCallsite());
-    shouldCloneAtCallsite_ = false;
-    isCallsiteClone_ = true;
-    MOZ_ASSERT(isCallsiteClone());
-    MOZ_ASSERT(fun->is<JSFunction>());
-    enclosingScopeOrOriginalFunction_ = fun;
-}
-
 inline void
 JSScript::setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript)
 {
     if (hasBaselineScript())
         js::jit::BaselineScript::writeBarrierPre(zone(), baseline);
     MOZ_ASSERT(!hasIonScript());
     baseline = baselineScript;
     updateBaselineOrIonRaw(maybecx);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -560,25 +560,22 @@ js::InvokeConstructor(JSContext *cx, Cal
 
     if (!args.calleev().isObject())
         return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT);
 
     JSObject &callee = args.callee();
     if (callee.is<JSFunction>()) {
         RootedFunction fun(cx, &callee.as<JSFunction>());
 
-        if (fun->isNativeConstructor()) {
-            bool ok = CallJSNativeConstructor(cx, fun->native(), args);
-            return ok;
-        }
-
-        if (!fun->isInterpretedConstructor()) {
-            RootedValue orig(cx, ObjectValue(*fun->originalFunction()));
-            return ReportIsNotFunction(cx, orig, args.length() + 1, CONSTRUCT);
-        }
+        if (fun->isNativeConstructor())
+            return CallJSNativeConstructor(cx, fun->native(), args);
+
+        if (!fun->isInterpretedConstructor())
+            return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT);
+
         if (!Invoke(cx, args, CONSTRUCT))
             return false;
 
         MOZ_ASSERT(args.rval().isObject());
         return true;
     }
 
     JSNative construct = callee.constructHook();
@@ -2511,56 +2508,45 @@ CASE(JSOP_FUNAPPLY)
 }
 
 CASE(JSOP_NEW)
 CASE(JSOP_CALL)
 CASE(JSOP_FUNCALL)
 {
     if (REGS.fp()->hasPushedSPSFrame())
         cx->runtime()->spsProfiler.updatePC(script, REGS.pc);
+
     MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
     CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
 
     bool construct = (*REGS.pc == JSOP_NEW);
 
     RootedFunction &fun = rootFunction0;
-    RootedScript &funScript = rootScript0;
     bool isFunction = IsFunctionObject(args.calleev(), fun.address());
 
-    /*
-     * Some builtins are marked as clone-at-callsite to increase precision of
-     * TI and JITs.
-     */
-    if (isFunction && fun->isInterpreted()) {
-        funScript = fun->getOrCreateScript(cx);
-        if (!funScript)
-            goto error;
-        if (funScript->shouldCloneAtCallsite()) {
-            fun = CloneFunctionAtCallsite(cx, fun, script, REGS.pc);
-            if (!fun)
-                goto error;
-            args.setCallee(ObjectValue(*fun));
-        }
-    }
-
     /* Don't bother trying to fast-path calls to scripted non-constructors. */
     if (!isFunction || !fun->isInterpretedConstructor()) {
         if (construct) {
             if (!InvokeConstructor(cx, args))
                 goto error;
         } else {
             if (!Invoke(cx, args))
                 goto error;
         }
         Value *newsp = args.spAfterCall();
         TypeScript::Monitor(cx, script, REGS.pc, newsp[-1]);
         REGS.sp = newsp;
         ADVANCE_AND_DISPATCH(JSOP_CALL_LENGTH);
     }
 
+    RootedScript &funScript = rootScript0;
+    funScript = fun->getOrCreateScript(cx);
+    if (!funScript)
+        goto error;
+
     InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
     bool createSingleton = ObjectGroup::useSingletonForNewObject(cx, script, REGS.pc);
 
     TypeMonitorCall(cx, args, construct);
 
     {
         InvokeState state(cx, args, initial);
         if (createSingleton)
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -92,19 +92,16 @@ ObjectGroup::setAddendum(AddendumKind ki
 }
 
 /* static */ bool
 ObjectGroup::useSingletonForClone(JSFunction *fun)
 {
     if (!fun->isInterpreted())
         return false;
 
-    if (fun->hasScript() && fun->nonLazyScript()->shouldCloneAtCallsite())
-        return true;
-
     if (fun->isArrow())
         return false;
 
     if (fun->isSingleton())
         return false;
 
     /*
      * When a function is being used as a wrapper for another function, it
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -251,64 +251,16 @@ intrinsic_DecompileArg(JSContext *cx, un
     RootedAtom atom(cx, Atomize(cx, str, strlen(str)));
     if (!atom)
         return false;
     args.rval().setString(atom);
     return true;
 }
 
 /*
- * SetScriptHints(fun, flags): Sets various internal hints to the ion
- * compiler for use when compiling |fun| or calls to |fun|.  Flags
- * should be a dictionary object.
- *
- * The function |fun| should be a self-hosted function (in particular,
- * it *must* be a JS function).
- *
- * Possible flags:
- * - |cloneAtCallsite: true| will hint that |fun| should be cloned
- *   each callsite to improve TI resolution.  This is important for
- *   higher-order functions like |Array.map|.
- * - |inline: true| will hint that |fun| be inlined regardless of
- *   JIT heuristics.
- */
-static bool
-intrinsic_SetScriptHints(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() >= 2);
-    MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<JSFunction>());
-    MOZ_ASSERT(args[1].isObject());
-
-    RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
-    RootedScript funScript(cx, fun->getOrCreateScript(cx));
-    if (!funScript)
-        return false;
-    RootedObject flags(cx, &args[1].toObject());
-
-    RootedId id(cx);
-    RootedValue propv(cx);
-
-    id = AtomToId(Atomize(cx, "cloneAtCallsite", strlen("cloneAtCallsite")));
-    if (!GetProperty(cx, flags, flags, id, &propv))
-        return false;
-    if (ToBoolean(propv))
-        funScript->setShouldCloneAtCallsite();
-
-    id = AtomToId(Atomize(cx, "inline", strlen("inline")));
-    if (!GetProperty(cx, flags, flags, id, &propv))
-        return false;
-    if (ToBoolean(propv))
-        funScript->setShouldInline();
-
-    args.rval().setUndefined();
-    return true;
-}
-
-/*
  * NewDenseArray(length): Allocates and returns a new dense array with
  * the given length where all values are initialized to holes.
  */
 bool
 js::intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
@@ -885,17 +837,16 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("ToInteger",               intrinsic_ToInteger,               1,0),
     JS_FN("ToString",                intrinsic_ToString,                1,0),
     JS_FN("ToPropertyKey",           intrinsic_ToPropertyKey,           1,0),
     JS_FN("IsCallable",              intrinsic_IsCallable,              1,0),
     JS_FN("IsConstructor",           intrinsic_IsConstructor,           1,0),
     JS_FN("OwnPropertyKeys",         intrinsic_OwnPropertyKeys,         1,0),
     JS_FN("ThrowError",              intrinsic_ThrowError,              4,0),
     JS_FN("AssertionFailed",         intrinsic_AssertionFailed,         1,0),
-    JS_FN("SetScriptHints",          intrinsic_SetScriptHints,          2,0),
     JS_FN("MakeConstructible",       intrinsic_MakeConstructible,       2,0),
     JS_FN("_IsConstructing",         intrinsic_IsConstructing,          0,0),
     JS_FN("DecompileArg",            intrinsic_DecompileArg,            2,0),
     JS_FN("RuntimeDefaultLocale",    intrinsic_RuntimeDefaultLocale,    0,0),
     JS_FN("SubstringKernel",         intrinsic_SubstringKernel,         3,0),
 
     JS_FN("UnsafePutElements",       intrinsic_UnsafePutElements,       3,0),
     JS_FN("_DefineDataProperty",     intrinsic_DefineDataProperty,      4,0),