1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "debugger/Source.h"
8
9 #include "mozilla/Assertions.h" // for AssertionConditionType, MOZ_ASSERT
10 #include "mozilla/Maybe.h" // for Some, Maybe, Nothing
11 #include "mozilla/Variant.h" // for AsVariant, Variant
12
13 #include <stdint.h> // for uint32_t
14 #include <string.h> // for memcpy
15 #include <utility> // for move
16
17 #include "jsapi.h" // for JS_ReportErrorNumberASCII, JS_CopyStringCharsZ
18
19 #include "debugger/Debugger.h" // for DebuggerSourceReferent, Debugger
20 #include "debugger/Script.h" // for DebuggerScript
21 #include "gc/Tracer.h" // for TraceManuallyBarrieredCrossCompartmentEdge
22 #include "js/CompilationAndEvaluation.h" // for Compile
23 #include "js/experimental/TypedData.h" // for JS_NewUint8Array
24 #include "js/friend/ErrorMessages.h" // for GetErrorMessage, JSMSG_*
25 #include "js/SourceText.h" // for JS::SourceOwnership
26 #include "vm/BytecodeUtil.h" // for JSDVG_SEARCH_STACK
27 #include "vm/JSContext.h" // for JSContext (ptr only)
28 #include "vm/JSObject.h" // for JSObject, RequireObject
29 #include "vm/JSScript.h" // for ScriptSource, ScriptSourceObject
30 #include "vm/StringType.h" // for NewStringCopyZ, JSString (ptr only)
31 #include "vm/TypedArrayObject.h" // for TypedArrayObject, JSObject::is
32 #include "wasm/WasmCode.h" // for Metadata
33 #include "wasm/WasmDebug.h" // for DebugState
34 #include "wasm/WasmInstance.h" // for Instance
35 #include "wasm/WasmJS.h" // for WasmInstanceObject
36 #include "wasm/WasmTypes.h" // for Bytes, RootedWasmInstanceObject
37
38 #include "debugger/Debugger-inl.h" // for Debugger::fromJSObject
39 #include "vm/JSObject-inl.h" // for InitClass
40 #include "vm/NativeObject-inl.h" // for NewTenuredObjectWithGivenProto
41
42 namespace js {
43 class GlobalObject;
44 }
45
46 using namespace js;
47
48 using mozilla::AsVariant;
49 using mozilla::Maybe;
50 using mozilla::Nothing;
51 using mozilla::Some;
52
53 const JSClassOps DebuggerSource::classOps_ = {
54 nullptr, // addProperty
55 nullptr, // delProperty
56 nullptr, // enumerate
57 nullptr, // newEnumerate
58 nullptr, // resolve
59 nullptr, // mayResolve
60 nullptr, // finalize
61 nullptr, // call
62 nullptr, // hasInstance
63 nullptr, // construct
64 CallTraceMethod<DebuggerSource>, // trace
65 };
66
67 const JSClass DebuggerSource::class_ = {
68 "Source", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
69 &classOps_};
70
71 /* static */
initClass(JSContext * cx,Handle<GlobalObject * > global,HandleObject debugCtor)72 NativeObject* DebuggerSource::initClass(JSContext* cx,
73 Handle<GlobalObject*> global,
74 HandleObject debugCtor) {
75 return InitClass(cx, debugCtor, nullptr, &class_, construct, 0, properties_,
76 methods_, nullptr, nullptr);
77 }
78
79 /* static */
create(JSContext * cx,HandleObject proto,Handle<DebuggerSourceReferent> referent,HandleNativeObject debugger)80 DebuggerSource* DebuggerSource::create(JSContext* cx, HandleObject proto,
81 Handle<DebuggerSourceReferent> referent,
82 HandleNativeObject debugger) {
83 Rooted<DebuggerSource*> sourceObj(
84 cx, NewTenuredObjectWithGivenProto<DebuggerSource>(cx, proto));
85 if (!sourceObj) {
86 return nullptr;
87 }
88 sourceObj->setReservedSlot(OWNER_SLOT, ObjectValue(*debugger));
89 referent.get().match(
90 [&](auto sourceHandle) { sourceObj->setPrivateGCThing(sourceHandle); });
91
92 return sourceObj;
93 }
94
owner() const95 Debugger* DebuggerSource::owner() const {
96 MOZ_ASSERT(isInstance());
97 JSObject* dbgobj = &getReservedSlot(OWNER_SLOT).toObject();
98 return Debugger::fromJSObject(dbgobj);
99 }
100
101 // For internal use only.
getReferentRawObject() const102 NativeObject* DebuggerSource::getReferentRawObject() const {
103 return static_cast<NativeObject*>(getPrivate());
104 }
105
getReferent() const106 DebuggerSourceReferent DebuggerSource::getReferent() const {
107 if (NativeObject* referent = getReferentRawObject()) {
108 if (referent->is<ScriptSourceObject>()) {
109 return AsVariant(&referent->as<ScriptSourceObject>());
110 }
111 return AsVariant(&referent->as<WasmInstanceObject>());
112 }
113 return AsVariant(static_cast<ScriptSourceObject*>(nullptr));
114 }
115
trace(JSTracer * trc)116 void DebuggerSource::trace(JSTracer* trc) {
117 // There is a barrier on private pointers, so the Unbarriered marking
118 // is okay.
119 if (JSObject* referent = getReferentRawObject()) {
120 TraceManuallyBarrieredCrossCompartmentEdge(
121 trc, static_cast<JSObject*>(this), &referent,
122 "Debugger.Source referent");
123 setPrivateUnbarriered(referent);
124 }
125 }
126
127 /* static */
construct(JSContext * cx,unsigned argc,Value * vp)128 bool DebuggerSource::construct(JSContext* cx, unsigned argc, Value* vp) {
129 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
130 "Debugger.Source");
131 return false;
132 }
133
134 /* static */
check(JSContext * cx,HandleValue thisv)135 DebuggerSource* DebuggerSource::check(JSContext* cx, HandleValue thisv) {
136 JSObject* thisobj = RequireObject(cx, thisv);
137 if (!thisobj) {
138 return nullptr;
139 }
140 if (!thisobj->is<DebuggerSource>()) {
141 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
142 JSMSG_INCOMPATIBLE_PROTO, "Debugger.Source",
143 "method", thisobj->getClass()->name);
144 return nullptr;
145 }
146
147 DebuggerSource* thisSourceObj = &thisobj->as<DebuggerSource>();
148
149 if (!thisSourceObj->isInstance()) {
150 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
151 JSMSG_INCOMPATIBLE_PROTO, "Debugger.Source",
152 "method", "prototype object");
153 return nullptr;
154 }
155
156 return thisSourceObj;
157 }
158
159 struct MOZ_STACK_CLASS DebuggerSource::CallData {
160 JSContext* cx;
161 const CallArgs& args;
162
163 HandleDebuggerSource obj;
164 Rooted<DebuggerSourceReferent> referent;
165
CallDataDebuggerSource::CallData166 CallData(JSContext* cx, const CallArgs& args, HandleDebuggerSource obj)
167 : cx(cx), args(args), obj(obj), referent(cx, obj->getReferent()) {}
168
169 bool getText();
170 bool getBinary();
171 bool getURL();
172 bool getStartLine();
173 bool getId();
174 bool getDisplayURL();
175 bool getElement();
176 bool getElementProperty();
177 bool getIntroductionScript();
178 bool getIntroductionOffset();
179 bool getIntroductionType();
180 bool setSourceMapURL();
181 bool getSourceMapURL();
182 bool reparse();
183
184 using Method = bool (CallData::*)();
185
186 template <Method MyMethod>
187 static bool ToNative(JSContext* cx, unsigned argc, Value* vp);
188 };
189
190 template <DebuggerSource::CallData::Method MyMethod>
191 /* static */
ToNative(JSContext * cx,unsigned argc,Value * vp)192 bool DebuggerSource::CallData::ToNative(JSContext* cx, unsigned argc,
193 Value* vp) {
194 CallArgs args = CallArgsFromVp(argc, vp);
195
196 RootedDebuggerSource obj(cx, DebuggerSource::check(cx, args.thisv()));
197 if (!obj) {
198 return false;
199 }
200
201 CallData data(cx, args, obj);
202 return (data.*MyMethod)();
203 }
204
205 class DebuggerSourceGetTextMatcher {
206 JSContext* cx_;
207
208 public:
DebuggerSourceGetTextMatcher(JSContext * cx)209 explicit DebuggerSourceGetTextMatcher(JSContext* cx) : cx_(cx) {}
210
211 using ReturnType = JSString*;
212
match(HandleScriptSourceObject sourceObject)213 ReturnType match(HandleScriptSourceObject sourceObject) {
214 ScriptSource* ss = sourceObject->source();
215 bool hasSourceText;
216 if (!ScriptSource::loadSource(cx_, ss, &hasSourceText)) {
217 return nullptr;
218 }
219 if (!hasSourceText) {
220 return NewStringCopyZ<CanGC>(cx_, "[no source]");
221 }
222
223 if (ss->isFunctionBody()) {
224 return ss->functionBodyString(cx_);
225 }
226
227 return ss->substring(cx_, 0, ss->length());
228 }
229
match(Handle<WasmInstanceObject * > instanceObj)230 ReturnType match(Handle<WasmInstanceObject*> instanceObj) {
231 wasm::Instance& instance = instanceObj->instance();
232 const char* msg;
233 if (!instance.debugEnabled()) {
234 msg = "Restart with developer tools open to view WebAssembly source.";
235 } else {
236 msg = "[debugger missing wasm binary-to-text conversion]";
237 }
238 return NewStringCopyZ<CanGC>(cx_, msg);
239 }
240 };
241
getText()242 bool DebuggerSource::CallData::getText() {
243 Value textv = obj->getReservedSlot(TEXT_SLOT);
244 if (!textv.isUndefined()) {
245 MOZ_ASSERT(textv.isString());
246 args.rval().set(textv);
247 return true;
248 }
249
250 DebuggerSourceGetTextMatcher matcher(cx);
251 JSString* str = referent.match(matcher);
252 if (!str) {
253 return false;
254 }
255
256 args.rval().setString(str);
257 obj->setReservedSlot(TEXT_SLOT, args.rval());
258 return true;
259 }
260
getBinary()261 bool DebuggerSource::CallData::getBinary() {
262 if (!referent.is<WasmInstanceObject*>()) {
263 ReportValueError(cx, JSMSG_DEBUG_BAD_REFERENT, JSDVG_SEARCH_STACK,
264 args.thisv(), nullptr, "a wasm source");
265 return false;
266 }
267
268 RootedWasmInstanceObject instanceObj(cx, referent.as<WasmInstanceObject*>());
269 wasm::Instance& instance = instanceObj->instance();
270
271 if (!instance.debugEnabled()) {
272 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
273 JSMSG_DEBUG_NO_BINARY_SOURCE);
274 return false;
275 }
276
277 const wasm::Bytes& bytecode = instance.debug().bytecode();
278 RootedObject arr(cx, JS_NewUint8Array(cx, bytecode.length()));
279 if (!arr) {
280 return false;
281 }
282
283 memcpy(arr->as<TypedArrayObject>().dataPointerUnshared(), bytecode.begin(),
284 bytecode.length());
285
286 args.rval().setObject(*arr);
287 return true;
288 }
289
290 class DebuggerSourceGetURLMatcher {
291 JSContext* cx_;
292
293 public:
DebuggerSourceGetURLMatcher(JSContext * cx)294 explicit DebuggerSourceGetURLMatcher(JSContext* cx) : cx_(cx) {}
295
296 using ReturnType = Maybe<JSString*>;
297
match(HandleScriptSourceObject sourceObject)298 ReturnType match(HandleScriptSourceObject sourceObject) {
299 ScriptSource* ss = sourceObject->source();
300 MOZ_ASSERT(ss);
301 if (ss->filename()) {
302 JSString* str = NewStringCopyZ<CanGC>(cx_, ss->filename());
303 return Some(str);
304 }
305 return Nothing();
306 }
match(Handle<WasmInstanceObject * > instanceObj)307 ReturnType match(Handle<WasmInstanceObject*> instanceObj) {
308 return Some(instanceObj->instance().createDisplayURL(cx_));
309 }
310 };
311
getURL()312 bool DebuggerSource::CallData::getURL() {
313 DebuggerSourceGetURLMatcher matcher(cx);
314 Maybe<JSString*> str = referent.match(matcher);
315 if (str.isSome()) {
316 if (!*str) {
317 return false;
318 }
319 args.rval().setString(*str);
320 } else {
321 args.rval().setNull();
322 }
323 return true;
324 }
325
326 class DebuggerSourceGetStartLineMatcher {
327 public:
328 using ReturnType = uint32_t;
329
match(HandleScriptSourceObject sourceObject)330 ReturnType match(HandleScriptSourceObject sourceObject) {
331 ScriptSource* ss = sourceObject->source();
332 return ss->startLine();
333 }
match(Handle<WasmInstanceObject * > instanceObj)334 ReturnType match(Handle<WasmInstanceObject*> instanceObj) { return 0; }
335 };
336
getStartLine()337 bool DebuggerSource::CallData::getStartLine() {
338 DebuggerSourceGetStartLineMatcher matcher;
339 uint32_t line = referent.match(matcher);
340 args.rval().setNumber(line);
341 return true;
342 }
343
344 class DebuggerSourceGetIdMatcher {
345 public:
346 using ReturnType = uint32_t;
347
match(HandleScriptSourceObject sourceObject)348 ReturnType match(HandleScriptSourceObject sourceObject) {
349 ScriptSource* ss = sourceObject->source();
350 return ss->id();
351 }
match(Handle<WasmInstanceObject * > instanceObj)352 ReturnType match(Handle<WasmInstanceObject*> instanceObj) { return 0; }
353 };
354
getId()355 bool DebuggerSource::CallData::getId() {
356 DebuggerSourceGetIdMatcher matcher;
357 uint32_t id = referent.match(matcher);
358 args.rval().setNumber(id);
359 return true;
360 }
361
362 struct DebuggerSourceGetDisplayURLMatcher {
363 using ReturnType = const char16_t*;
matchDebuggerSourceGetDisplayURLMatcher364 ReturnType match(HandleScriptSourceObject sourceObject) {
365 ScriptSource* ss = sourceObject->source();
366 MOZ_ASSERT(ss);
367 return ss->hasDisplayURL() ? ss->displayURL() : nullptr;
368 }
matchDebuggerSourceGetDisplayURLMatcher369 ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
370 return wasmInstance->instance().metadata().displayURL();
371 }
372 };
373
getDisplayURL()374 bool DebuggerSource::CallData::getDisplayURL() {
375 DebuggerSourceGetDisplayURLMatcher matcher;
376 if (const char16_t* displayURL = referent.match(matcher)) {
377 JSString* str = JS_NewUCStringCopyZ(cx, displayURL);
378 if (!str) {
379 return false;
380 }
381 args.rval().setString(str);
382 } else {
383 args.rval().setNull();
384 }
385 return true;
386 }
387
388 struct DebuggerSourceGetElementMatcher {
389 JSContext* mCx = nullptr;
DebuggerSourceGetElementMatcherDebuggerSourceGetElementMatcher390 explicit DebuggerSourceGetElementMatcher(JSContext* cx_) : mCx(cx_) {}
391 using ReturnType = JSObject*;
matchDebuggerSourceGetElementMatcher392 ReturnType match(HandleScriptSourceObject sourceObject) {
393 return sourceObject->unwrappedElement(mCx);
394 }
matchDebuggerSourceGetElementMatcher395 ReturnType match(Handle<WasmInstanceObject*> wasmInstance) { return nullptr; }
396 };
397
getElement()398 bool DebuggerSource::CallData::getElement() {
399 DebuggerSourceGetElementMatcher matcher(cx);
400 RootedValue elementValue(cx);
401 if (JSObject* element = referent.match(matcher)) {
402 elementValue.setObject(*element);
403 if (!obj->owner()->wrapDebuggeeValue(cx, &elementValue)) {
404 return false;
405 }
406 }
407 args.rval().set(elementValue);
408 return true;
409 }
410
411 struct DebuggerSourceGetElementPropertyMatcher {
412 using ReturnType = Value;
matchDebuggerSourceGetElementPropertyMatcher413 ReturnType match(HandleScriptSourceObject sourceObject) {
414 return sourceObject->unwrappedElementAttributeName();
415 }
matchDebuggerSourceGetElementPropertyMatcher416 ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
417 return UndefinedValue();
418 }
419 };
420
getElementProperty()421 bool DebuggerSource::CallData::getElementProperty() {
422 DebuggerSourceGetElementPropertyMatcher matcher;
423 args.rval().set(referent.match(matcher));
424 return obj->owner()->wrapDebuggeeValue(cx, args.rval());
425 }
426
427 class DebuggerSourceGetIntroductionScriptMatcher {
428 JSContext* cx_;
429 Debugger* dbg_;
430 MutableHandleValue rval_;
431
432 public:
DebuggerSourceGetIntroductionScriptMatcher(JSContext * cx,Debugger * dbg,MutableHandleValue rval)433 DebuggerSourceGetIntroductionScriptMatcher(JSContext* cx, Debugger* dbg,
434 MutableHandleValue rval)
435 : cx_(cx), dbg_(dbg), rval_(rval) {}
436
437 using ReturnType = bool;
438
match(HandleScriptSourceObject sourceObject)439 ReturnType match(HandleScriptSourceObject sourceObject) {
440 Rooted<BaseScript*> script(cx_,
441 sourceObject->unwrappedIntroductionScript());
442 if (script) {
443 RootedObject scriptDO(cx_, dbg_->wrapScript(cx_, script));
444 if (!scriptDO) {
445 return false;
446 }
447 rval_.setObject(*scriptDO);
448 } else {
449 rval_.setUndefined();
450 }
451 return true;
452 }
453
match(Handle<WasmInstanceObject * > wasmInstance)454 ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
455 RootedObject ds(cx_, dbg_->wrapWasmScript(cx_, wasmInstance));
456 if (!ds) {
457 return false;
458 }
459 rval_.setObject(*ds);
460 return true;
461 }
462 };
463
getIntroductionScript()464 bool DebuggerSource::CallData::getIntroductionScript() {
465 Debugger* dbg = obj->owner();
466 DebuggerSourceGetIntroductionScriptMatcher matcher(cx, dbg, args.rval());
467 return referent.match(matcher);
468 }
469
470 struct DebuggerGetIntroductionOffsetMatcher {
471 using ReturnType = Value;
matchDebuggerGetIntroductionOffsetMatcher472 ReturnType match(HandleScriptSourceObject sourceObject) {
473 // Regardless of what's recorded in the ScriptSourceObject and
474 // ScriptSource, only hand out the introduction offset if we also have
475 // the script within which it applies.
476 ScriptSource* ss = sourceObject->source();
477 if (ss->hasIntroductionOffset() &&
478 sourceObject->unwrappedIntroductionScript()) {
479 return Int32Value(ss->introductionOffset());
480 }
481 return UndefinedValue();
482 }
matchDebuggerGetIntroductionOffsetMatcher483 ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
484 return UndefinedValue();
485 }
486 };
487
getIntroductionOffset()488 bool DebuggerSource::CallData::getIntroductionOffset() {
489 DebuggerGetIntroductionOffsetMatcher matcher;
490 args.rval().set(referent.match(matcher));
491 return true;
492 }
493
494 struct DebuggerSourceGetIntroductionTypeMatcher {
495 using ReturnType = const char*;
matchDebuggerSourceGetIntroductionTypeMatcher496 ReturnType match(HandleScriptSourceObject sourceObject) {
497 ScriptSource* ss = sourceObject->source();
498 MOZ_ASSERT(ss);
499 return ss->hasIntroductionType() ? ss->introductionType() : nullptr;
500 }
matchDebuggerSourceGetIntroductionTypeMatcher501 ReturnType match(Handle<WasmInstanceObject*> wasmInstance) { return "wasm"; }
502 };
503
getIntroductionType()504 bool DebuggerSource::CallData::getIntroductionType() {
505 DebuggerSourceGetIntroductionTypeMatcher matcher;
506 if (const char* introductionType = referent.match(matcher)) {
507 JSString* str = NewStringCopyZ<CanGC>(cx, introductionType);
508 if (!str) {
509 return false;
510 }
511 args.rval().setString(str);
512 } else {
513 args.rval().setUndefined();
514 }
515
516 return true;
517 }
518
EnsureSourceObject(JSContext * cx,HandleDebuggerSource obj)519 ScriptSourceObject* EnsureSourceObject(JSContext* cx,
520 HandleDebuggerSource obj) {
521 if (!obj->getReferent().is<ScriptSourceObject*>()) {
522 RootedValue v(cx, ObjectValue(*obj));
523 ReportValueError(cx, JSMSG_DEBUG_BAD_REFERENT, JSDVG_SEARCH_STACK, v,
524 nullptr, "a JS source");
525 return nullptr;
526 }
527 return obj->getReferent().as<ScriptSourceObject*>();
528 }
529
setSourceMapURL()530 bool DebuggerSource::CallData::setSourceMapURL() {
531 RootedScriptSourceObject sourceObject(cx, EnsureSourceObject(cx, obj));
532 if (!sourceObject) {
533 return false;
534 }
535 ScriptSource* ss = sourceObject->source();
536 MOZ_ASSERT(ss);
537
538 if (!args.requireAtLeast(cx, "set sourceMapURL", 1)) {
539 return false;
540 }
541
542 JSString* str = ToString<CanGC>(cx, args[0]);
543 if (!str) {
544 return false;
545 }
546
547 UniqueTwoByteChars chars = JS_CopyStringCharsZ(cx, str);
548 if (!chars) {
549 return false;
550 }
551
552 if (!ss->setSourceMapURL(cx, std::move(chars))) {
553 return false;
554 }
555
556 args.rval().setUndefined();
557 return true;
558 }
559
560 class DebuggerSourceGetSourceMapURLMatcher {
561 JSContext* cx_;
562 MutableHandleString result_;
563
564 public:
DebuggerSourceGetSourceMapURLMatcher(JSContext * cx,MutableHandleString result)565 explicit DebuggerSourceGetSourceMapURLMatcher(JSContext* cx,
566 MutableHandleString result)
567 : cx_(cx), result_(result) {}
568
569 using ReturnType = bool;
match(HandleScriptSourceObject sourceObject)570 ReturnType match(HandleScriptSourceObject sourceObject) {
571 ScriptSource* ss = sourceObject->source();
572 MOZ_ASSERT(ss);
573 if (!ss->hasSourceMapURL()) {
574 result_.set(nullptr);
575 return true;
576 }
577 JSString* str = JS_NewUCStringCopyZ(cx_, ss->sourceMapURL());
578 if (!str) {
579 return false;
580 }
581 result_.set(str);
582 return true;
583 }
match(Handle<WasmInstanceObject * > instanceObj)584 ReturnType match(Handle<WasmInstanceObject*> instanceObj) {
585 wasm::Instance& instance = instanceObj->instance();
586 if (!instance.debugEnabled()) {
587 result_.set(nullptr);
588 return true;
589 }
590
591 RootedString str(cx_);
592 if (!instance.debug().getSourceMappingURL(cx_, &str)) {
593 return false;
594 }
595
596 result_.set(str);
597 return true;
598 }
599 };
600
getSourceMapURL()601 bool DebuggerSource::CallData::getSourceMapURL() {
602 RootedString result(cx);
603 DebuggerSourceGetSourceMapURLMatcher matcher(cx, &result);
604 if (!referent.match(matcher)) {
605 return false;
606 }
607 if (result) {
608 args.rval().setString(result);
609 } else {
610 args.rval().setNull();
611 }
612 return true;
613 }
614
615 template <typename Unit>
ReparseSource(JSContext * cx,HandleScriptSourceObject sso)616 static JSScript* ReparseSource(JSContext* cx, HandleScriptSourceObject sso) {
617 AutoRealm ar(cx, sso);
618 ScriptSource* ss = sso->source();
619
620 JS::CompileOptions options(cx);
621 options.hideScriptFromDebugger = true;
622 options.setFileAndLine(ss->filename(), ss->startLine());
623
624 UncompressedSourceCache::AutoHoldEntry holder;
625
626 ScriptSource::PinnedUnits<Unit> units(cx, ss, holder, 0, ss->length());
627 if (!units.get()) {
628 return nullptr;
629 }
630
631 JS::SourceText<Unit> srcBuf;
632 if (!srcBuf.init(cx, units.get(), ss->length(),
633 JS::SourceOwnership::Borrowed)) {
634 return nullptr;
635 }
636
637 return JS::Compile(cx, options, srcBuf);
638 }
639
reparse()640 bool DebuggerSource::CallData::reparse() {
641 RootedScriptSourceObject sourceObject(cx, EnsureSourceObject(cx, obj));
642 if (!sourceObject) {
643 return false;
644 }
645
646 if (!sourceObject->source()->hasSourceText()) {
647 JS_ReportErrorASCII(cx, "Source object missing text");
648 return false;
649 }
650
651 RootedScript script(cx);
652 if (sourceObject->source()->hasSourceType<mozilla::Utf8Unit>()) {
653 script = ReparseSource<mozilla::Utf8Unit>(cx, sourceObject);
654 } else {
655 script = ReparseSource<char16_t>(cx, sourceObject);
656 }
657
658 if (!script) {
659 return false;
660 }
661
662 Debugger* dbg = obj->owner();
663 RootedObject scriptDO(cx, dbg->wrapScript(cx, script));
664 if (!scriptDO) {
665 return false;
666 }
667
668 args.rval().setObject(*scriptDO);
669 return true;
670 }
671
672 const JSPropertySpec DebuggerSource::properties_[] = {
673 JS_DEBUG_PSG("text", getText),
674 JS_DEBUG_PSG("binary", getBinary),
675 JS_DEBUG_PSG("url", getURL),
676 JS_DEBUG_PSG("startLine", getStartLine),
677 JS_DEBUG_PSG("id", getId),
678 JS_DEBUG_PSG("element", getElement),
679 JS_DEBUG_PSG("displayURL", getDisplayURL),
680 JS_DEBUG_PSG("introductionScript", getIntroductionScript),
681 JS_DEBUG_PSG("introductionOffset", getIntroductionOffset),
682 JS_DEBUG_PSG("introductionType", getIntroductionType),
683 JS_DEBUG_PSG("elementAttributeName", getElementProperty),
684 JS_DEBUG_PSGS("sourceMapURL", getSourceMapURL, setSourceMapURL),
685 JS_PS_END};
686
687 const JSFunctionSpec DebuggerSource::methods_[] = {
688 JS_DEBUG_FN("reparse", reparse, 0), JS_FS_END};
689