diff --git a/js/src/jit-test/tests/debug/Source-elementProperty.js b/js/src/jit-test/tests/debug/Source-elementProperty.js new file mode 100644 index 000000000000..8201fc3025c0 --- /dev/null +++ b/js/src/jit-test/tests/debug/Source-elementProperty.js @@ -0,0 +1,11 @@ +// Source.prototype.elementProperty can be a string or undefined. + +var g = newGlobal('new-compartment'); +var dbg = new Debugger; +var gw = dbg.addDebuggee(g); +g.evaluate("function f(x) { return 2*x; }", {elementProperty: "src"}); +var fw = gw.getOwnPropertyDescriptor('f').value; +assertEq(fw.script.source.elementProperty, "src"); +g.evaluate("function f(x) { return 2*x; }"); +var fw = gw.getOwnPropertyDescriptor('f').value; +assertEq(fw.script.source.elementProperty, undefined); diff --git a/js/src/jit-test/tests/debug/Source-surfaces.js b/js/src/jit-test/tests/debug/Source-surfaces.js index 969c076bea11..5f34770d59e4 100644 --- a/js/src/jit-test/tests/debug/Source-surfaces.js +++ b/js/src/jit-test/tests/debug/Source-surfaces.js @@ -21,3 +21,13 @@ assertThrowsInstanceOf(function () { assertThrowsInstanceOf(function () { Debugger.Source.prototype.element.call(Debugger.Source.prototype) }, TypeError); + +assertThrowsInstanceOf(function () { + Debugger.Source.prototype.elementProperty.call(42) +}, TypeError); +assertThrowsInstanceOf(function () { + Debugger.Source.prototype.elementProperty.call({}) +}, TypeError); +assertThrowsInstanceOf(function () { + Debugger.Source.prototype.elementProperty.call(Debugger.Source.prototype) +}, TypeError); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 137c7b5f4d5c..4d0a7c2338e7 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -970,6 +970,14 @@ ScriptSourceObject::element() const return getReservedSlot(ELEMENT_SLOT).toObjectOrNull(); } +const Value & +ScriptSourceObject::elementProperty() const +{ + const Value &prop = getReservedSlot(ELEMENT_PROPERTY_SLOT); + JS_ASSERT(prop.isUndefined() || prop.isString()); + return prop; +} + void ScriptSourceObject::finalize(FreeOp *fop, JSObject *obj) { @@ -979,7 +987,8 @@ ScriptSourceObject::finalize(FreeOp *fop, JSObject *obj) const Class ScriptSourceObject::class_ = { "ScriptSource", - JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_IS_ANONYMOUS, + JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | + JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_IS_ANONYMOUS, JS_PropertyStub, /* addProperty */ JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ @@ -998,9 +1007,15 @@ ScriptSourceObject::create(ExclusiveContext *cx, ScriptSource *source, if (!object) return nullptr; RootedScriptSource sourceObject(cx, &object->as()); + source->incref(); sourceObject->initSlot(SOURCE_SLOT, PrivateValue(source)); sourceObject->initSlot(ELEMENT_SLOT, ObjectOrNullValue(options.element())); + if (options.elementProperty()) + sourceObject->initSlot(ELEMENT_PROPERTY_SLOT, StringValue(options.elementProperty())); + else + sourceObject->initSlot(ELEMENT_PROPERTY_SLOT, UndefinedValue()); + return sourceObject; } diff --git a/js/src/jsscript.h b/js/src/jsscript.h index dc9215ffa5ec..82f25a291085 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -465,10 +465,13 @@ class ScriptSourceObject : public JSObject void setSource(ScriptSource *source); JSObject *element() const; + const Value &elementProperty() const; 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 RESERVED_SLOTS = 3; }; enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator }; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 36a581a8a9e8..29992017ea7c 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -859,6 +859,7 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp) bool noScriptRval = false; const char *fileName = "@evaluate"; RootedObject element(cx); + RootedString elementProperty(cx); JSAutoByteString fileNameBytes; RootedString sourceURL(cx); RootedString sourceMapURL(cx); @@ -910,6 +911,14 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp) if (v.isObject()) element = &v.toObject(); + if (!JS_GetProperty(cx, opts, "elementProperty", &v)) + return false; + if (!v.isUndefined()) { + elementProperty = ToString(cx, v); + if (!elementProperty) + return false; + } + if (!JS_GetProperty(cx, opts, "sourceURL", &v)) return false; if (!v.isUndefined()) { @@ -1012,6 +1021,7 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp) CompileOptions options(cx); options.setFileAndLine(fileName, lineNumber) .setElement(element) + .setElementProperty(elementProperty) .setSourcePolicy(sourcePolicy) .setCompileAndGo(compileAndGo); @@ -3989,6 +3999,9 @@ static const JSFunctionSpecWithHelp shell_functions[] = { " the source as being attached to the DOM element |o|. If the\n" " property is omitted or |v| is null, don't attribute the source to\n" " any DOM element.\n" +" elementProperty: if present and not undefined, the name of property\n" +" of 'element' that holds this code. This is what Debugger.Source\n" +" .prototype.elementProperty returns.\n" " sourceMapURL: if present with value |v|, convert |v| to a string, and\n" " provide that as the code's source map URL. If omitted, attach no\n" " source map URL to the code (although the code may provide one itself,\n" diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index e54b951f6c0c..cf685aef9867 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -3785,12 +3785,20 @@ DebuggerSource_getElement(JSContext *cx, unsigned argc, Value *vp) return true; } +static bool +DebuggerSource_getElementProperty(JSContext *cx, unsigned argc, Value *vp) +{ + THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get elementProperty)", args, obj, sourceObject); + args.rval().set(sourceObject->elementProperty()); + return Debugger::fromChildJSObject(obj)->wrapDebuggeeValue(cx, args.rval()); +} 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("elementProperty", DebuggerSource_getElementProperty, 0), JS_PS_END };