Backed out 3 changesets (bug 969786) for m-oth permabustage on a CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Wed, 26 Feb 2014 17:05:33 -0800
changeset 171194 782acfe6edfdd423376d514179764fccbc8c3803
parent 171193 e0ef930a64cbd2e5e1836d275da2f7da56dd1149
child 171219 75e7fb569d74a41e863d6e1c69b2199aa79dbcf5
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
bugs969786
milestone30.0a1
backs outa79a64806e6c3de5a4be9124e77a84ce309ef7e2
198decf16acf8ed23b2825bb8eba26a943fc9168
7d0b03e1376516a1e7cade6afc45c697c13fb87b
Backed out 3 changesets (bug 969786) for m-oth permabustage on a CLOSED TREE Backed out changeset a79a64806e6c (bug 969786) Backed out changeset 198decf16acf (bug 969786) Backed out changeset 7d0b03e13765 (bug 969786)
js/src/builtin/Eval.cpp
js/src/jit-test/tests/debug/Source-introductionScript-01.js
js/src/jit-test/tests/debug/Source-introductionScript-02.js
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsfun.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsworkers.cpp
js/src/jsworkers.h
js/src/vm/Debugger.cpp
toolkit/devtools/server/tests/mochitest/chrome.ini
toolkit/devtools/server/tests/mochitest/test_Debugger.Source.prototype.introductionScript.html
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -315,17 +315,17 @@ EvalKernel(JSContext *cx, const CallArgs
 
         CompileOptions options(cx);
         options.setFileAndLine(filename, 1)
                .setCompileAndGo(true)
                .setForEval(true)
                .setNoScriptRval(false)
                .setPrincipals(principals)
                .setOriginPrincipals(originPrincipals)
-               .setIntroductionInfo(introducerFilename, "eval", lineno, script, pcOffset);
+               .setIntroductionInfo(introducerFilename, "eval", lineno, pcOffset);
         JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
                                                      scopeobj, callerScript, options,
                                                      chars.get(), length, flatStr, staticLevel);
         if (!compiled)
             return false;
 
         MarkFunctionsWithinEvalScript(compiled);
 
@@ -387,17 +387,17 @@ js::DirectEvalStringFromIon(JSContext *c
 
         CompileOptions options(cx);
         options.setFileAndLine(filename, 1)
                .setCompileAndGo(true)
                .setForEval(true)
                .setNoScriptRval(false)
                .setPrincipals(principals)
                .setOriginPrincipals(originPrincipals)
-               .setIntroductionInfo(introducerFilename, "eval", lineno, script, pcOffset);
+               .setIntroductionInfo(introducerFilename, "eval", lineno, pcOffset);
         JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
                                                      scopeobj, callerScript, options,
                                                      chars.get(), length, flatStr, staticLevel);
         if (!compiled)
             return false;
 
         MarkFunctionsWithinEvalScript(compiled);
 
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Source-introductionScript-01.js
+++ /dev/null
@@ -1,118 +0,0 @@
-// Dynamically generated sources should have their introduction script and
-// offset set correctly.
-
-var g = newGlobal();
-var dbg = new Debugger;
-var gDO = dbg.addDebuggee(g);
-var log;
-
-// Direct eval, while the frame is live.
-dbg.onDebuggerStatement = function (frame) {
-  log += 'd';
-  var source = frame.script.source;
-  var introducer = frame.older;
-  assertEq(source.introductionScript, introducer.script);
-  assertEq(source.introductionOffset, introducer.offset);
-};
-log = '';
-g.eval('\n\neval("\\n\\ndebugger;");');
-assertEq(log, 'd');
-
-// Direct eval, after the frame has been popped.
-var introducer, introduced;
-dbg.onDebuggerStatement = function (frame) {
-  log += 'de1';
-  introducer = frame.script;
-  dbg.onDebuggerStatement = function (frame) {
-    log += 'de2';
-    introduced = frame.script.source;
-  };
-};
-log = '';
-g.evaluate('debugger; eval("\\n\\ndebugger;");', { lineNumber: 1812 });
-assertEq(log, 'de1de2');
-assertEq(introduced.introductionScript, introducer);
-assertEq(introducer.getOffsetLine(introduced.introductionOffset), 1812);
-
-// Indirect eval, while the frame is live.
-dbg.onDebuggerStatement = function (frame) {
-  log += 'd';
-  var source = frame.script.source;
-  var introducer = frame.older;
-  assertEq(source.introductionScript, introducer.script);
-  assertEq(source.introductionOffset, introducer.offset);
-};
-log = '';
-g.eval('\n\n(0,eval)("\\n\\ndebugger;");');
-assertEq(log, 'd');
-
-// Indirect eval, after the frame has been popped.
-var introducer, introduced;
-dbg.onDebuggerStatement = function (frame) {
-  log += 'de1';
-  introducer = frame.script;
-  dbg.onDebuggerStatement = function (frame) {
-    log += 'de2';
-    introduced = frame.script.source;
-  };
-};
-log = '';
-g.evaluate('debugger; (0,eval)("\\n\\ndebugger;");', { lineNumber: 1066 });
-assertEq(log, 'de1de2');
-assertEq(introduced.introductionScript, introducer);
-assertEq(introducer.getOffsetLine(introduced.introductionOffset), 1066);
-
-// Function constructor.
-dbg.onDebuggerStatement = function (frame) {
-  log += 'o';
-  var outerScript = frame.script;
-  var outerOffset = frame.offset;
-  dbg.onDebuggerStatement = function (frame) {
-    log += 'i';
-    var source = frame.script.source;
-    assertEq(source.introductionScript, outerScript);
-    assertEq(outerScript.getOffsetLine(source.introductionOffset),
-             outerScript.getOffsetLine(outerOffset));
-  };
-};
-log = '';
-g.eval('\n\n\ndebugger; Function("debugger;")()');
-assertEq(log, 'oi');
-
-// Function constructor, after the the introduction call's frame has been
-// popped.
-var introducer;
-dbg.onDebuggerStatement = function (frame) {
-  log += 'F2';
-  introducer = frame.script;
-};
-log = '';
-var fDO = gDO.evalInGlobal('debugger; Function("origami;")', { lineNumber: 1685 }).return;
-var source = fDO.script.source;
-assertEq(log, 'F2');
-assertEq(source.introductionScript, introducer);
-assertEq(introducer.getOffsetLine(source.introductionOffset), 1685);
-
-// If the introduction script is in a different global from the script it
-// introduced, we don't record it.
-dbg.onDebuggerStatement = function (frame) {
-  log += 'x';
-  var source = frame.script.source;
-  assertEq(source.introductionScript, undefined);
-  assertEq(source.introductionOffset, undefined);
-};
-log = '';
-g.eval('debugger;'); // introduction script is this top-level script
-assertEq(log, 'x');
-
-// If the code is introduced by a function that doesn't provide
-// introduction information, that shouldn't be a problem.
-dbg.onDebuggerStatement = function (frame) {
-  log += 'x';
-  var source = frame.script.source;
-  assertEq(source.introductionScript, undefined);
-  assertEq(source.introductionOffset, undefined);
-};
-log = '';
-g.eval('evaluate("debugger;", { lineNumber: 1729 });');
-assertEq(log, 'x');
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Source-introductionScript-02.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// Calls to 'eval', etc. by JS primitives get attributed to the point of
-// the primitive's call.
-
-var g = newGlobal();
-var dbg = new Debugger;
-var gDO = dbg.addDebuggee(g);
-var log = '';
-
-function outerHandler(frame) {
-  log += 'o';
-  var outerScript = frame.script;
-
-  dbg.onDebuggerStatement = function (frame) {
-    log += 'i';
-    var source = frame.script.source;
-    var introScript = source.introductionScript;
-    assertEq(introScript, outerScript);
-    assertEq(introScript.getOffsetLine(source.introductionOffset), 1234);
-  };
-};
-
-log = '';
-dbg.onDebuggerStatement = outerHandler;
-g.evaluate('debugger; ["debugger;"].map(eval)', { lineNumber: 1234 });
-assertEq(log, 'oi');
-
-log = '';
-dbg.onDebuggerStatement = outerHandler;
-g.evaluate('debugger; "debugger;".replace(/.*/, eval);',
-           { lineNumber: 1234 });
-assertEq(log, 'oi');
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4321,18 +4321,17 @@ JS::ReadOnlyCompileOptions::originPrinci
 {
     return NormalizeOriginPrincipals(principals_, originPrincipals_);
 }
 
 JS::OwningCompileOptions::OwningCompileOptions(JSContext *cx)
     : ReadOnlyCompileOptions(),
       runtime(GetRuntime(cx)),
       elementRoot(cx),
-      elementAttributeNameRoot(cx),
-      introductionScriptRoot(cx)
+      elementAttributeNameRoot(cx)
 {
 }
 
 JS::OwningCompileOptions::~OwningCompileOptions()
 {
     if (principals_)
         JS_DropPrincipals(runtime, principals_);
     if (originPrincipals_)
@@ -4348,17 +4347,16 @@ bool
 JS::OwningCompileOptions::copy(JSContext *cx, const ReadOnlyCompileOptions &rhs)
 {
     copyPODOptions(rhs);
 
     setPrincipals(rhs.principals());
     setOriginPrincipals(rhs.originPrincipals());
     setElement(rhs.element());
     setElementAttributeName(rhs.elementAttributeName());
-    setIntroductionScript(rhs.introductionScript());
 
     return (setFileAndLine(cx, rhs.filename(), rhs.lineno) &&
             setSourceMapURL(cx, rhs.sourceMapURL()) &&
             setIntroducerFilename(cx, rhs.introducerFilename()));
 }
 
 bool
 JS::OwningCompileOptions::setFile(JSContext *cx, const char *f)
@@ -4425,33 +4423,21 @@ bool
 JS::OwningCompileOptions::wrap(JSContext *cx, JSCompartment *compartment)
 {
     if (!compartment->wrap(cx, &elementRoot))
         return false;
     if (elementAttributeNameRoot) {
         if (!compartment->wrap(cx, elementAttributeNameRoot.address()))
             return false;
     }
-
-    // There is no equivalent of cross-compartment wrappers for scripts. If
-    // the introduction script would be in a different compartment from the
-    // compiled code, we would be creating a cross-compartment script
-    // reference, which would be bogus. In that case, just don't bother to
-    // retain the introduction script.
-    if (introductionScriptRoot) {
-        if (introductionScriptRoot->compartment() != compartment)
-            introductionScriptRoot = nullptr;
-    }
-
     return true;
 }
 
 JS::CompileOptions::CompileOptions(JSContext *cx, JSVersion version)
-    : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx),
-      introductionScriptRoot(cx)
+    : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx)
 {
     this->version = (version != JSVERSION_UNKNOWN) ? version : cx->findVersion();
 
     compileAndGo = false;
     noScriptRval = cx->options().noScriptRval();
     strictOption = cx->options().strictMode();
     extraWarningsOption = cx->options().extraWarnings();
     werrorOption = cx->options().werror();
@@ -4462,27 +4448,16 @@ bool
 JS::CompileOptions::wrap(JSContext *cx, JSCompartment *compartment)
 {
     if (!compartment->wrap(cx, &elementRoot))
         return false;
     if (elementAttributeNameRoot) {
         if (!compartment->wrap(cx, elementAttributeNameRoot.address()))
             return false;
     }
-
-    // There is no equivalent of cross-compartment wrappers for scripts. If
-    // the introduction script would be in a different compartment from the
-    // compiled code, we would be creating a cross-compartment script
-    // reference, which would be bogus. In that case, just don't bother to
-    // retain the introduction script.
-    if (introductionScriptRoot) {
-        if (introductionScriptRoot->compartment() != compartment)
-            introductionScriptRoot = nullptr;
-    }
-
     return true;
 }
 
 JSScript *
 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
             const jschar *chars, size_t length)
 {
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3506,17 +3506,16 @@ class JS_FRIEND_API(ReadOnlyCompileOptio
     // depends on the derived type.
     JSPrincipals *principals() const { return principals_; }
     JSPrincipals *originPrincipals() const;
     const char *filename() const { return filename_; }
     const char *introducerFilename() const { return introducerFilename_; }
     const jschar *sourceMapURL() const { return sourceMapURL_; }
     virtual JSObject *element() const = 0;
     virtual JSString *elementAttributeName() const = 0;
-    virtual JSScript *introductionScript() const = 0;
 
     // POD options.
     JSVersion version;
     bool versionSet;
     bool utf8;
     unsigned lineno;
     unsigned column;
     bool compileAndGo;
@@ -3564,29 +3563,27 @@ class JS_FRIEND_API(ReadOnlyCompileOptio
  * comes to refer to the object that owns this, then the whole cycle, and
  * anything else it entrains, will never be freed.
  */
 class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions
 {
     JSRuntime *runtime;
     PersistentRootedObject elementRoot;
     PersistentRootedString elementAttributeNameRoot;
-    PersistentRootedScript introductionScriptRoot;
 
   public:
     // A minimal constructor, for use with OwningCompileOptions::copy. This
     // leaves |this.version| set to JSVERSION_UNKNOWN; the instance
     // shouldn't be used until we've set that to something real (as |copy|
     // will).
     explicit OwningCompileOptions(JSContext *cx);
     ~OwningCompileOptions();
 
     JSObject *element() const MOZ_OVERRIDE { return elementRoot; }
     JSString *elementAttributeName() const MOZ_OVERRIDE { return elementAttributeNameRoot; }
-    JSScript *introductionScript() const MOZ_OVERRIDE { return introductionScriptRoot; }
 
     // Set this to a copy of |rhs|. Return false on OOM.
     bool copy(JSContext *cx, const ReadOnlyCompileOptions &rhs);
 
     /* These setters make copies of their string arguments, and are fallible. */
     bool setFile(JSContext *cx, const char *f);
     bool setFileAndLine(JSContext *cx, const char *f, unsigned l);
     bool setSourceMapURL(JSContext *cx, const jschar *s);
@@ -3597,20 +3594,16 @@ class JS_FRIEND_API(OwningCompileOptions
     OwningCompileOptions &setElement(JSObject *e) {
         elementRoot = e;
         return *this;
     }
     OwningCompileOptions &setElementAttributeName(JSString *p) {
         elementAttributeNameRoot = p;
         return *this;
     }
-    OwningCompileOptions &setIntroductionScript(JSScript *s) {
-        introductionScriptRoot = s;
-        return *this;
-    }
     OwningCompileOptions &setPrincipals(JSPrincipals *p) {
         if (p) JS_HoldPrincipals(p);
         if (principals_) JS_DropPrincipals(runtime, principals_);
         principals_ = p;
         return *this;
     }
     OwningCompileOptions &setOriginPrincipals(JSPrincipals *p) {
         if (p) JS_HoldPrincipals(p);
@@ -3628,23 +3621,22 @@ class JS_FRIEND_API(OwningCompileOptions
     OwningCompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; }
     OwningCompileOptions &setForEval(bool eval) { forEval = eval; return *this; }
     OwningCompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
     OwningCompileOptions &setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; }
     OwningCompileOptions &setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; }
     OwningCompileOptions &setSourcePolicy(SourcePolicy sp) { sourcePolicy = sp; return *this; }
     OwningCompileOptions &setIntroductionType(const char *t) { introductionType = t; return *this; }
     bool setIntroductionInfo(JSContext *cx, const char *introducerFn, const char *intro,
-                             unsigned line, JSScript *script, uint32_t offset)
+                             unsigned line, uint32_t offset)
     {
         if (!setIntroducerFilename(cx, introducerFn))
             return false;
         introductionType = intro;
         introductionLineno = line;
-        introductionScriptRoot = script;
         introductionOffset = offset;
         hasIntroductionInfo = true;
         return true;
     }
 
     virtual bool wrap(JSContext *cx, JSCompartment *compartment) MOZ_OVERRIDE;
 };
 
@@ -3654,54 +3646,46 @@ class JS_FRIEND_API(OwningCompileOptions
  * filename; source map URL) that are owned by something else. If you
  * create an instance of this type, it's up to you to guarantee that
  * everything you store in it will outlive it.
  */
 class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOptions
 {
     RootedObject elementRoot;
     RootedString elementAttributeNameRoot;
-    RootedScript introductionScriptRoot;
 
   public:
     explicit CompileOptions(JSContext *cx, JSVersion version = JSVERSION_UNKNOWN);
     CompileOptions(js::ContextFriendFields *cx, const ReadOnlyCompileOptions &rhs)
-      : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx),
-        introductionScriptRoot(cx)
+      : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx)
     {
         copyPODOptions(rhs);
 
         principals_ = rhs.principals();
         originPrincipals_ = rhs.originPrincipals();
         filename_ = rhs.filename();
         sourceMapURL_ = rhs.sourceMapURL();
         elementRoot = rhs.element();
         elementAttributeNameRoot = rhs.elementAttributeName();
-        introductionScriptRoot = rhs.introductionScript();
     }
 
     JSObject *element() const MOZ_OVERRIDE { return elementRoot; }
     JSString *elementAttributeName() const MOZ_OVERRIDE { return elementAttributeNameRoot; }
-    JSScript *introductionScript() const MOZ_OVERRIDE { return introductionScriptRoot; }
 
     CompileOptions &setFile(const char *f) { filename_ = f; return *this; }
     CompileOptions &setLine(unsigned l) { lineno = l; return *this; }
     CompileOptions &setFileAndLine(const char *f, unsigned l) {
         filename_ = f; lineno = l; return *this;
     }
     CompileOptions &setSourceMapURL(const jschar *s) { sourceMapURL_ = s;       return *this; }
     CompileOptions &setElement(JSObject *e)          { elementRoot = e;         return *this; }
     CompileOptions &setElementAttributeName(JSString *p) {
         elementAttributeNameRoot = p;
         return *this;
     }
-    CompileOptions &setIntroductionScript(JSScript *s) {
-        introductionScriptRoot = s;
-        return *this;
-    }
     CompileOptions &setPrincipals(JSPrincipals *p) {
         principals_ = p;
         return *this;
     }
     CompileOptions &setOriginPrincipals(JSPrincipals *p) {
         originPrincipals_ = p;
         return *this;
     }
@@ -3715,22 +3699,21 @@ class MOZ_STACK_CLASS JS_FRIEND_API(Comp
     CompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; }
     CompileOptions &setForEval(bool eval) { forEval = eval; return *this; }
     CompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
     CompileOptions &setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; }
     CompileOptions &setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; }
     CompileOptions &setSourcePolicy(SourcePolicy sp) { sourcePolicy = sp; return *this; }
     CompileOptions &setIntroductionType(const char *t) { introductionType = t; return *this; }
     CompileOptions &setIntroductionInfo(const char *introducerFn, const char *intro,
-                                        unsigned line, JSScript *script, uint32_t offset)
+                                        unsigned line, uint32_t offset)
     {
         introducerFilename_ = introducerFn;
         introductionType = intro;
         introductionLineno = line;
-        introductionScriptRoot = script;
         introductionOffset = offset;
         hasIntroductionInfo = true;
         return *this;
     }
 
     virtual bool wrap(JSContext *cx, JSCompartment *compartment) MOZ_OVERRIDE;
 };
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1527,17 +1527,17 @@ FunctionConstructor(JSContext *cx, unsig
         introducerFilename = script->scriptSource()->introducerFilename();
 
     CompileOptions options(cx);
     options.setPrincipals(principals)
            .setOriginPrincipals(originPrincipals)
            .setFileAndLine(filename, 1)
            .setNoScriptRval(false)
            .setCompileAndGo(true)
-           .setIntroductionInfo(introducerFilename, introductionType, lineno, script, pcOffset);
+           .setIntroductionInfo(introducerFilename, introductionType, lineno, pcOffset);
 
     unsigned n = args.length() ? args.length() - 1 : 0;
     if (n > 0) {
         /*
          * Collect the function-argument arguments into one string, separated
          * by commas, then make a tokenstream from that string, and scan it to
          * get the arguments.  We need to throw the full scanner at the
          * problem, because the argument string can legitimately contain
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1265,41 +1265,16 @@ const Value &
 ScriptSourceObject::elementAttributeName() const
 {
     const Value &prop = getReservedSlot(ELEMENT_PROPERTY_SLOT);
     JS_ASSERT(prop.isUndefined() || prop.isString());
     return prop;
 }
 
 void
-ScriptSourceObject::initIntroductionScript(JSScript *script)
-{
-    JS_ASSERT(!getReservedSlot(INTRODUCTION_SCRIPT_SLOT).toPrivate());
-
-    // There is no equivalent of cross-compartment wrappers for scripts. If
-    // the introduction script would be in a different compartment from the
-    // compiled code, we would be creating a cross-compartment script
-    // reference, which would be bogus. In that case, just don't bother to
-    // retain the introduction script.
-    if (script && script->compartment() == compartment())
-        setReservedSlot(INTRODUCTION_SCRIPT_SLOT, PrivateValue(script));
-}
-
-void
-ScriptSourceObject::trace(JSTracer *trc, JSObject *obj)
-{
-    ScriptSourceObject *sso = static_cast<ScriptSourceObject *>(obj);
-
-    if (JSScript *script = sso->introductionScript()) {
-        MarkScriptUnbarriered(trc, &script, "ScriptSourceObject introductionScript");
-        sso->setReservedSlot(INTRODUCTION_SCRIPT_SLOT, PrivateValue(script));
-    }
-}
-
-void
 ScriptSourceObject::finalize(FreeOp *fop, JSObject *obj)
 {
     // ScriptSource::setSource automatically takes care of the refcount
     obj->as<ScriptSourceObject>().setSource(nullptr);
 }
 
 const Class ScriptSourceObject::class_ = {
     "ScriptSource",
@@ -1307,21 +1282,17 @@ const Class ScriptSourceObject::class_ =
     JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_IS_ANONYMOUS,
     JS_PropertyStub,        /* addProperty */
     JS_DeletePropertyStub,  /* delProperty */
     JS_PropertyStub,        /* getProperty */
     JS_StrictPropertyStub,  /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
-    finalize,
-    nullptr,                /* call        */
-    nullptr,                /* hasInstance */
-    nullptr,                /* construct   */
-    trace
+    ScriptSourceObject::finalize
 };
 
 ScriptSourceObject *
 ScriptSourceObject::create(ExclusiveContext *cx, ScriptSource *source,
                            const ReadOnlyCompileOptions &options)
 {
     RootedObject object(cx, NewObjectWithGivenProto(cx, &class_, nullptr, cx->global()));
     if (!object)
@@ -1331,19 +1302,16 @@ ScriptSourceObject::create(ExclusiveCont
     source->incref();
     sourceObject->initSlot(SOURCE_SLOT, PrivateValue(source));
     sourceObject->initSlot(ELEMENT_SLOT, ObjectOrNullValue(options.element()));
     if (options.elementAttributeName())
         sourceObject->initSlot(ELEMENT_PROPERTY_SLOT, StringValue(options.elementAttributeName()));
     else
         sourceObject->initSlot(ELEMENT_PROPERTY_SLOT, UndefinedValue());
 
-    sourceObject->initSlot(INTRODUCTION_SCRIPT_SLOT, PrivateValue(nullptr));
-    sourceObject->initIntroductionScript(options.introductionScript());
-
     return sourceObject;
 }
 
 static const unsigned char emptySource[] = "";
 
 /* Adjust the amount of memory this script source uses for source data,
    reallocating if needed. */
 bool
@@ -1821,17 +1789,17 @@ ScriptSource::initFromOptions(ExclusiveC
     JS_ASSERT(!filename_);
     JS_ASSERT(!introducerFilename_);
 
     originPrincipals_ = options.originPrincipals();
     if (originPrincipals_)
         JS_HoldPrincipals(originPrincipals_);
 
     introductionType_ = options.introductionType;
-    setIntroductionOffset(options.introductionOffset);
+    introductionOffset_ = options.introductionOffset;
 
     if (options.hasIntroductionInfo) {
         JS_ASSERT(options.introductionType != nullptr);
         const char *filename = options.filename() ? options.filename() : "<unknown>";
         char *formatted = FormatIntroducedFilename(cx, filename, options.introductionLineno,
                                                    options.introductionType);
         if (!formatted)
             return false;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -552,43 +552,35 @@ class ScriptSourceHolder
     }
 };
 
 class ScriptSourceObject : public JSObject
 {
   public:
     static const Class class_;
 
-    static void trace(JSTracer *trc, JSObject *obj);
     static void finalize(FreeOp *fop, JSObject *obj);
     static ScriptSourceObject *create(ExclusiveContext *cx, ScriptSource *source,
                                       const ReadOnlyCompileOptions &options);
 
     ScriptSource *source() {
         return static_cast<ScriptSource *>(getReservedSlot(SOURCE_SLOT).toPrivate());
     }
 
     void setSource(ScriptSource *source);
 
     JSObject *element() const;
     void initElement(HandleObject element);
     const Value &elementAttributeName() const;
 
-    JSScript *introductionScript() const {
-        void *untyped = getReservedSlot(INTRODUCTION_SCRIPT_SLOT).toPrivate();
-        return static_cast<JSScript *>(untyped);
-    }
-    void initIntroductionScript(JSScript *script);
-
   private:
     static const uint32_t SOURCE_SLOT = 0;
     static const uint32_t ELEMENT_SLOT = 1;
     static const uint32_t ELEMENT_PROPERTY_SLOT = 2;
-    static const uint32_t INTRODUCTION_SCRIPT_SLOT = 3;
-    static const uint32_t RESERVED_SLOTS = 4;
+    static const uint32_t RESERVED_SLOTS = 3;
 };
 
 enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator };
 
 static inline unsigned
 GeneratorKindAsBits(GeneratorKind generatorKind) {
     return static_cast<unsigned>(generatorKind);
 }
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -172,34 +172,31 @@ static const JSClass workerGlobalClass =
     JS_ConvertStub,   nullptr
 };
 
 ParseTask::ParseTask(ExclusiveContext *cx, JSObject *exclusiveContextGlobal, JSContext *initCx,
                      const jschar *chars, size_t length, JSObject *scopeChain,
                      JS::OffThreadCompileCallback callback, void *callbackData)
   : cx(cx), options(initCx), chars(chars), length(length),
     alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), scopeChain(initCx, scopeChain),
-    exclusiveContextGlobal(initCx, exclusiveContextGlobal), optionsElement(initCx),
-    optionsIntroductionScript(initCx), callback(callback), callbackData(callbackData),
-    script(nullptr), errors(cx), overRecursed(false)
+    exclusiveContextGlobal(initCx, exclusiveContextGlobal), optionsElement(initCx), callback(callback),
+    callbackData(callbackData), script(nullptr), errors(cx), overRecursed(false)
 {
 }
 
 bool
 ParseTask::init(JSContext *cx, const ReadOnlyCompileOptions &options)
 {
     if (!this->options.copy(cx, options))
         return false;
 
     // Save those compilation options that the ScriptSourceObject can't
     // point at while it's in the compilation's temporary compartment.
     optionsElement = this->options.element();
     this->options.setElement(nullptr);
-    optionsIntroductionScript = this->options.introductionScript();
-    this->options.setIntroductionScript(nullptr);
 
     return true;
 }
 
 void
 ParseTask::activate(JSRuntime *rt)
 {
     rt->setUsedByExclusiveThread(exclusiveContextGlobal->zone());
@@ -209,17 +206,16 @@ ParseTask::activate(JSRuntime *rt)
 void
 ParseTask::finish()
 {
     if (script) {
         // Initialize the ScriptSourceObject slots that we couldn't while the SSO
         // was in the temporary compartment.
         ScriptSourceObject &sso = script->sourceObject()->as<ScriptSourceObject>();
         sso.initElement(optionsElement);
-        sso.initIntroductionScript(optionsIntroductionScript);
     }
 }
 
 ParseTask::~ParseTask()
 {
     // ParseTask takes over ownership of its input exclusive context.
     js_delete(cx);
 
--- a/js/src/jsworkers.h
+++ b/js/src/jsworkers.h
@@ -400,17 +400,16 @@ struct ParseTask
     PersistentRootedObject exclusiveContextGlobal;
 
     // Saved GC-managed CompileOptions fields that will populate slots in
     // the ScriptSourceObject. We create the ScriptSourceObject in the
     // compilation's temporary compartment, so storing these values there
     // at that point would create cross-compartment references. Instead we
     // hold them here, and install them after merging the compartments.
     PersistentRootedObject optionsElement;
-    PersistentRootedScript optionsIntroductionScript;
 
     // Callback invoked off the main thread when the parse finishes.
     JS::OffThreadCompileCallback callback;
     void *callbackData;
 
     // Holds the final script between the invocation of the callback and the
     // point where FinishOffThreadScript is called, which will destroy the
     // ParseTask.
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -3916,52 +3916,32 @@ static bool
 DebuggerSource_getElementProperty(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get elementAttributeName)", args, obj, sourceObject);
     args.rval().set(sourceObject->elementAttributeName());
     return Debugger::fromChildJSObject(obj)->wrapDebuggeeValue(cx, args.rval());
 }
 
 static bool
-DebuggerSource_getIntroductionScript(JSContext *cx, unsigned argc, Value *vp)
-{
-    THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get introductionScript)", args, obj, sourceObject);
-
-    RootedScript script(cx, sourceObject->introductionScript());
-    if (script) {
-        RootedObject scriptDO(cx, Debugger::fromChildJSObject(obj)->wrapScript(cx, script));
-        if (!scriptDO)
-            return false;
-        args.rval().setObject(*scriptDO);
-    } else {
-        args.rval().setUndefined();
-    }
-    return true;
-}
-
-static bool
 DebuggerSource_getIntroductionOffset(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get introductionOffset)", args, obj, sourceObject);
 
-    // Regardless of what's recorded in the ScriptSourceObject and
-    // ScriptSource, only hand out the introduction offset if we also have
-    // the script within which it applies.
     ScriptSource *ss = sourceObject->source();
-    if (ss->hasIntroductionOffset() && sourceObject->introductionScript())
+    if (ss->hasIntroductionOffset())
         args.rval().setInt32(ss->introductionOffset());
     else
         args.rval().setUndefined();
     return true;
 }
 
 static bool
 DebuggerSource_getIntroductionType(JSContext *cx, unsigned argc, Value *vp)
 {
-    THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get introductionType)", args, obj, sourceObject);
+    THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get introductionOffset)", args, obj, sourceObject);
 
     ScriptSource *ss = sourceObject->source();
     if (ss->hasIntroductionType()) {
         JSString *str = js_NewStringCopyZ<CanGC>(cx, ss->introductionType());
         if (!str)
             return false;
         args.rval().setString(str);
     } else {
@@ -3970,17 +3950,16 @@ DebuggerSource_getIntroductionType(JSCon
     return true;
 }
 
 static const JSPropertySpec DebuggerSource_properties[] = {
     JS_PSG("text", DebuggerSource_getText, 0),
     JS_PSG("url", DebuggerSource_getUrl, 0),
     JS_PSG("element", DebuggerSource_getElement, 0),
     JS_PSG("displayURL", DebuggerSource_getDisplayURL, 0),
-    JS_PSG("introductionScript", DebuggerSource_getIntroductionScript, 0),
     JS_PSG("introductionOffset", DebuggerSource_getIntroductionOffset, 0),
     JS_PSG("introductionType", DebuggerSource_getIntroductionType, 0),
     JS_PSG("elementAttributeName", DebuggerSource_getElementProperty, 0),
     JS_PS_END
 };
 
 static const JSFunctionSpec DebuggerSource_methods[] = {
     JS_FS_END
--- a/toolkit/devtools/server/tests/mochitest/chrome.ini
+++ b/toolkit/devtools/server/tests/mochitest/chrome.ini
@@ -7,17 +7,16 @@ support-files =
   nonchrome_unsafeDereference.html
   inspector_getImageData.html
   large-image.jpg
   small-image.gif
   Debugger.Source.prototype.element.js
   Debugger.Source.prototype.element-2.js
   Debugger.Source.prototype.element.html
 
-[test_Debugger.Source.prototype.introductionScript.html]
 [test_Debugger.Source.prototype.introductionType.html]
 [test_Debugger.Source.prototype.element.html]
 [test_Debugger.Script.prototype.global.html]
 [test_connection-manager.html]
 [test_device.html]
 [test_inspector-changeattrs.html]
 [test_inspector-changevalue.html]
 [test_inspector-hide.html]
deleted file mode 100644
--- a/toolkit/devtools/server/tests/mochitest/test_Debugger.Source.prototype.introductionScript.html
+++ /dev/null
@@ -1,97 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=969786
-
-Debugger.Source.prototype.introductionScript and .introductionOffset should
-behave when 'eval' is called with no scripted frames active at all.
--->
-<head>
-  <meta charset="utf-8">
-  <title>Debugger.Source.prototype.introductionScript with no caller</title>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
-</head>
-<body>
-<pre id="test">
-<script>
-
-Components.utils.import("resource://gre/modules/jsdebugger.jsm");
-addDebuggerToGlobal(this);
-
-window.onload = function () {
-  SimpleTest.waitForExplicitFinish();
-
-  var dbg, iframeDO, doc, script2DO;
-
-  // Create an iframe to debug.
-  var iframe = document.createElement("iframe");
-  iframe.src = "data:text/html,<div>Hi!</div>";
-  iframe.onload = onLoadHandler;
-  document.body.appendChild(iframe);
-
-  function onLoadHandler() {
-    // Now that the iframe's window has been created, we can add
-    // it as a debuggee.
-    dbg = new Debugger;
-    iframeDO = dbg.addDebuggee(iframe.contentWindow);
-
-    doc = iframe.contentWindow.document;
-    var script = doc.createElement('script');
-    script.text = "setTimeout(eval.bind(null, 'debugger;'), 0);";
-    dbg.onDebuggerStatement = timerHandler;
-    doc.body.appendChild(script);
-  }
-
-  function timerHandler(frame) {
-    // The top stack frame's source should have an undefined
-    // introduction script and introduction offset.
-    var source = frame.script.source;
-    ok(source.introductionScript === undefined,
-       "setTimeout eval introductionScript is undefined");
-    ok(source.introductionOffset === undefined,
-       "setTimeout eval introductionOffset is undefined");
-
-    // Check that the above isn't just some quirk of iframes, or the
-    // browser milieu destroying information: an eval script should indeed
-    // have proper introduction information.
-    var script2 = doc.createElement('script');
-    script2.text = "eval('debugger;');";
-    script2DO = iframeDO.makeDebuggeeValue(script2);
-    dbg.onDebuggerStatement = evalHandler;
-    doc.body.appendChild(script2);
-  }
-
-  function evalHandler(frame) {
-    // The top stack frame's source should be introduced by the script that
-    // called eval.
-    var source = frame.script.source;
-    var frame2 = frame.older;
-
-    ok(source.introductionType === 'eval',
-       "top frame's source was introduced by 'eval'");
-    ok(source.introductionScript === frame2.script,
-       "eval frame's introduction script is the older frame's script");
-    ok(source.introductionOffset === frame2.offset,
-       "eval frame's introduction offset is current offset in older frame");
-    ok(source.introductionScript.source.element === script2DO,
-       "eval frame's introducer belongs to script2 element");
-
-    // The frame that called eval, in turn, should have no introduction
-    // information. (In the future, we certainly could point at the call
-    // that inserted the script element into the document; if that happens,
-    // we can update this test.)
-    ok(frame2.script.source.introductionType === undefined,
-       "older frame has no introduction type");
-    ok(frame2.script.source.introductionScript === undefined,
-       "older frame has no introduction script");
-    ok(frame2.script.source.introductionOffset === null,
-       "older frame has no introduction offset");
-
-    SimpleTest.finish();
-  }
-}
-</script>
-</pre>
-</body>
-</html>