Closed Bug 506128 Opened 15 years ago Closed 6 years ago

run jshydra to find js functions that have no callers

Categories

(Developer Infrastructure :: Source Code Analysis, defect, P3)

defect

Tracking

(Not tracked)

RESOLVED INCOMPLETE

People

(Reporter: dietrich, Unassigned)

References

(Blocks 1 open bug)

Details

(Whiteboard: [ts][i/o])

Attachments

(4 files, 8 obsolete files)

No description provided.
Whiteboard: [ts]
-> Rewriting + Analysis
Component: General → Rewriting and Analysis
Product: Firefox → Core
QA Contact: general → rewriting-and-analysis
Assignee: nobody → ddahl
ddahl_: jcranmer: so I want to find functions that are never called, i am not sure how to start. [2:09pm] jcranmer: in order to do that, you need two pieces of information: [2:09pm] jcranmer: 1. all JS functions [2:09pm] jcranmer: 2. all function calls [2:10pm] jcranmer: if you look at dxr, that has code that will find the top-level JS functions [2:10pm] ddahl_: oh cool [2:10pm] ddahl_: i assume dxr is in hg.moz [2:11pm] jcranmer: scripts/dxr.js [2:11pm] ddahl_: oh [2:11pm] jcranmer: in jshydra [2:11pm] ddahl_: sweet [2:12pm] jcranmer: the other piece of the pie is finding the function calls [2:13pm] jcranmer: the syntax of which I forget, which is a good introduction to figuring out how to find information [2:14pm] jcranmer: if you include dumpast.js [2:14pm] jcranmer: there is a function dump_ast which will dump the AST to stdout [2:15pm] jcranmer: I get you the names of all the JS operations, but the TOK stuff isn't imported yet into jshydra (it's not in a nice table format.. :-/) [2:15pm] jcranmer: so, for the first line of dxr, you get this AST: [2:15pm] jcranmer: + op: JSOP_NOP; type: 2; 3:0 [2:15pm] jcranmer: + op: JSOP_CALL; type: 27; 3:0 [2:15pm] jcranmer: + op: JSOP_NAME; type: 29; atom: include; flags: 112; 3:0 [2:15pm] jcranmer: + op: JSOP_STRING; type: 31; atom: ../utils/cleanast.js; flags: 0; 3:8 [2:15pm] bsmedberg is now known as bsmedberg-away. [2:16pm] jcranmer: so any time you find a JSOP_CALL, look at its first child [2:16pm] jcranmer: if it's a JSOP_NAME node, that's the name of the function you've called [2:16pm] ddahl_: jcranmer: i keep getting JS Exception: TypeError: ast is null - when i point the dxr script at anything in browser/base/ [2:16pm] jcranmer: the cleanast isn't perfected yet [2:16pm] jcranmer: oh, are you using the actual JS files? [2:17pm] jcranmer: or the preprocessed ones? [2:17pm] ddahl_: actual - [2:17pm] ddahl_: aha [2:17pm] ddahl_: so i need to point it at the files in the objdir? [2:18pm] jcranmer: if you do make jsexport with the myrules.mk I sent you [2:18pm] jcranmer: you should get a nice jsfiles/ directory in the dist/ directory
Attached file jcranmer's myrules.mk
from jcranmer: Attached are the three files you should need to be able to convert various JS and XML files to jshydra-processable inputs. It's still preliminary, as it doesn't parse comm-central yet (can't find Preprocessor.py or other config files), and I don't have the file mappings from some of the chrome files back to the original source files. Finally, the XML parser agglomerates an entire element tag (e.g., <dialog>) to the line of the `>', which is suboptimal. I'm also sure that there is some XBL code I'm conveniently ignoring due to my lack of namespace-aware parsing.
Attached file ChromeHacker.py
Attached file NicePreprocessor.py
Raw dump of irc to be sorted through for wikimo docs [5:05pm] humph: ddahl_: unless jcranmer has updated things since I last tried running with the jsexport stuff, a top-level build doesn't pick that stuff up on its own. You have to manually do it post-build. [5:06pm] ddahl_: hmm [5:06pm] humph: jcranmer: still true? [5:06pm] ddahl_: humph: i saw that the myrules.mk is included in client.mk via a third .mk [5:06pm] humph: oh yeah, that goes in [5:07pm] humph: but I mean actually doing jsexport won't happen [5:07pm] humph: i.e., [5:07pm] ddahl_: but it is not run until you mnuslly do so? [5:07pm] humph: right [5:07pm] ddahl_: so i need to do a make -f config/myrules.mk [5:07pm] ddahl_: ? [5:07pm] humph: no [5:07pm] humph: jcranmer: ping [5:07pm] • humph tries to recall [5:07pm] ddahl_: i will be glad to document all of this [5:07pm] humph: we need to fix it so it works, I think [5:07pm] ddahl_: on wikimo [5:08pm] humph: sure [5:08pm] humph: let me log into a box that has this setup and check [5:08pm] ddahl_: cool [5:10pm] humph: just |make jsexport| [5:10pm] humph: after your build runs, if you have an empty jsfiles [5:10pm] ddahl_: ok - so keep myrules.mk in config/ [5:10pm] humph: yes [5:10pm] humph: you need that [5:10pm] ddahl_: groovy [5:10pm] humph: we just need a bit more to get it to happen top-level [5:10pm] sid0 is now known as sid0|afk. [5:10pm] sid0|afk is now known as sid0. [5:11pm] dietrich left the chat room. (Ping timeout) [5:11pm] ddahl_: in what directory do i issue make jsexport? [5:12pm] humph: try the root of your objdir [5:12pm] ddahl_: i get " no rule to make target" [5:12pm] jcranmer: it may be a result of the tier system [5:12pm] humph: yeah [5:12pm] jcranmer: if you go into something like browser, it works fine [5:13pm] cjones is now known as cjones-dinner. [5:13pm] ddahl_: isn't working for me [5:13pm] ddahl_: i have added the 2 python mods to mozilla/config as well as myrules.mk [5:14pm] ddahl_: then i ran a clobber build [5:14pm] humph: where is myrules.mk? [5:14pm] humph: src or objdir? [5:14pm] ddahl_: myrules.mk in config [5:14pm] ddahl_: src [5:14pm] humph: objdir/config? [5:14pm] ddahl_: oh [5:14pm] jcranmer: it needs to be objdir [5:14pm] humph: that's where it should go [5:14pm] jcranmer: it's part of the mozilla build system [5:15pm] jcranmer: you probably also have to modify JSTOOLDIR in myrules.mk [5:15pm] humph: yeah [5:15pm] jcranmer: unless you just happen to have dropped it in /src/mozilla-tools/dxr [5:15pm] bent left the chat room. (Input/output error) [5:15pm] ddahl_: aha [5:15pm] • humph loves myrules.mk [5:16pm] ddahl_: so it looks like it all worked but the final attempt in js/src failed [5:16pm] jcranmer: JSTOOLDIR is the location of the python files [5:16pm] humph: you'll need to do it there too [5:16pm] jcranmer: or symlink them all together [5:16pm] ddahl_: hmm which dir is JSTOOLDIR [5:17pm] jcranmer: where the python files no [5:17pm] jcranmer: er, are [5:17pm] humph: I thought the build sys in js/ picked up what you do in myrules.mk [5:17pm] jcranmer: specifically ChromeHacker and NicePreprocessor [5:17pm] ddahl_: they were placed in src/mozilla/config [5:17pm] jcranmer: then point the JSTOOLDIR there [5:18pm] ddahl_: is that an env var i need to set? [5:18pm] ddahl_: i am a make noob [5:18pm] humph: no [5:18pm] jcranmer: there's a line that says [5:19pm] jcranmer: JSTOOLDIR := /src/mozilla-tools/dxr [5:19pm] humph: it's in the myrules.mk: [5:19pm] humph: # JS exporting rules and setup [5:19pm] humph: JSEXPORT := $(DIST)/jsfiles [5:19pm] humph: JSTOOLDIR := /var/www/html/dxr-dev/xref-scripts [5:19pm] humph: or whatever [5:19pm] jcranmer: change that JSTOOLDIR line to point to the location of your tool [5:19pm] ddahl_: oh ok [5:19pm] jcranmer: absolute paths work best [5:19pm] ddahl_: cool [5:22pm] ddahl_: do i need to rebuild after changing this? [5:22pm] • humph bets yes, but doesn't know [5:22pm] ddahl_: ok [5:22pm] humph: try without! [5:23pm] ddahl_: i did [5:23pm] ddahl_: didn't work [5:23pm] humph: yeah, figures
I have followed the instructions I received over irc, and now i get this: make: *** No rule to make target `jsexport'. Stop. I have copied myrules.mk, NicePreprocessor.py and ChromeHacker.py into mozilla/config/ I edited myrules.mk by changing the line that read: JSTOOLDIR := /src/mozilla-tools/dxr to read: JSTOOLDIR := /home/ddahl/code/moz/mozilla-central/mozilla/config I also copied the contents of myrules.mk and appended them to mozilla/js/src/rules.mk I did have this partially working, but since adding the jsexport rules to js/src/rules.mk I cannot get make jsexport to run. I am running 'make jsexport' in the obj dir. I am reverting the js/src/rules.mk changes now and doing a clobber build.
clobber build also failed to allow me to issue make jsexport. WTF?
Here's how I do this, assuming src tree in src/ and objdir in objdir/: * fix up myrules.mk so it points to the right JSTOOLDIR, and use an absolute path * make objdir/config and copy myrules.mk there * make objdir/js/src/config and copy myrules.mk there (separate build system, so you need it here too) * full build * make -C objdir/ jsexport (this extra bit shouldn't be necessary, but 'whatever' for now) This gives me dist/jsfiles with all the cleaned-up js. I just ran this on box that's pretty out of date and it almost made it through the whole tree, dying with this error: make[2]: Entering directory `/home/dave/dxr/mozilla-central/objdir-opt/browser/themes' make: Entering an unknown directory make: *** gnomestripe: No such file or directory. Stop. I don't know what this is without spending a few mins on it, but I suspect it's unrelated. Try this method and see how far it gets you.
OK! it all works. No failures, as far as I can tell. I have the following in objdir/jsfiles/: chrome/ components/ crashreporter/ modules/ Perhaps what is needed is a script to replicate these tasks easily? Or add an ac_add_option to build this whenever a developer wants?
(In reply to comment #10) > Or add an > ac_add_option to build this whenever a developer wants? I think you just volunteered
I just wanted to note that it would be very cool to get jshydra usable inside of xpcshell-tests, or, any way that I could write test-driven jshydra scripts.
(In reply to comment #12) > I just wanted to note that it would be very cool to get jshydra usable inside > of xpcshell-tests, or, any way that I could write test-driven jshydra scripts. this would be great. please file a separate bug for this.
Attached file WIP - findFunctions.js - broken:( (obsolete) —
Just saving work
Attached file WIP - ast_printer (obsolete) —
Playing with the ast - figuring things out.
(In reply to comment #14) > Created an attachment (id=392022) [details] > WIP - findFunctions.js - broken:( > > Just saving work FWIW, I think you're trying a bit too hard here. This script does the work of finding all the easy function calls and declarations: // Find all functions and calls, in the simple case include("../utils/cleanast.js"); include("../utils/dumpast.js"); function process_js(ast, f) { let toplevel = clean_ast(ast); for each (let v in toplevel.functions) { _print("FUNCTION " + v.name); } visit(ast, function (node) { if (node.op == JSOP_CALL && node.kids[0].op == JSOP_NAME) _print("FUNCTION CALL " + node.kids[0].atom); }); } Knowing the state of JS, I expect that this code would only achieve about 50-60% accuracy in terms of definitions and function calls (it would utterly fail to account for such constructs as function() {}() and non-global functions).
Without near 100% accuracy, this approach may be a waste of time, correct?
(In reply to comment #17) > Without near 100% accuracy, this approach may be a waste of time, correct? I expect that one can achieve very high accuracy with a more complex version of the above, but I have not yet found the time to look at anything more than a few files of Mozilla JS (specifically, a few front-end files in c-c).
(In reply to comment #17) > Without near 100% accuracy, this approach may be a waste of time, correct? At whatever level of accuracy, if we find dead code, we win. And as jcranmer said, his snippet is just a start. Please feel free to take it further :)
I agree with Dietrich, and for encouragement would point you at Taras' blog about how he does it for c++ - http://blog.mozilla.com/tglek/2008/09/26/living-dead-code/ Notice the number of times he has to do dirty tricks or make assumptions. It's as much a game as a science, and that makes it more fun ;) Keep going!
Looks like I know who to ask for reviews on this one. I wasn't giving up - I just thought that JSHydra was incapable of high accuracy - for now - if it is my crappy attempt that is inaccurate, that is another issue altogether.
So, some of things I won't find are anonymous functions and inner functions. Are there any other things that are not accounted for that I should be aware of?
OK, this is the procedure I plan on implementing (a python script that instruments XUL/XML parsing and JSHydra processes) to find the dead code for any "context": Identify the context like the places' Library window or the Browser itself. 1. Parse the XUL file for all JS script paths and any inline JS - also may have to parse inline js in XML/XBL files to cover all UI elements. * use Python's elementtree to handle XUL/xml parsing 2. store the inline js and js script paths in a json object. 3. iterate through the list of script paths and "loose/inline JS", create one massive JS file 4. run JSHydra against this massive file with a script that finds the defined functions and the called functions. 5. file bugs when we discover code that should go away:)
Are you using pynarcissus? Make sure it doesn't have bugs mrbkap and I know about in its ?: parsing. /be
I pasted the link in to remind me to look at pynarcissus. It seems to fail on "let" - or perhaps it was some white space. Very cool, but, I am not using it for this bug.
Anything based on narcissus (js/src/narcissus in cvs.mozilla.org/mozilla and now hg.mozilla.org) is not going to support let. How is SpiderMonkey's JS parser treating you jshydra guys? Let me know, thanks. /be
(In reply to comment #24) > Identify the context like the places' Library window or the Browser itself. Context falls into three categories (AIUI): 1. JS modules -- no context. 2. XBL files -- I don't know here, but I think it extends to whatever file it's used in. 3. XUL files -- this will be the master file plus all of the overlays and included JS files. This probably brings in XML files as well. > 1. Parse the XUL file for all JS script paths and any inline JS - also may have > to parse inline js in XML/XBL files to cover all UI elements. The ChromeHacker.py file above should be able to take out all of the interesting JS from the XUL/XBL/HTML files, barring people using attributes as JS (but that falls under the same class as "eval" in my book). What it doesn't yet do is do reverse file mapping or find agglomerations of the scope contexts. (In reply to comment #26) > I pasted the link in to remind me to look at pynarcissus. It seems to fail on > "let" - or perhaps it was some white space. Very cool, but, I am not using it > for this bug. I was once asked when working on jshydra why I wasn't investigating using a less harsh API like narcissus; after announcing an early milestone, I had someone else tell me that they had attempted another API (I think it was narcissus) and found it too buggy to be useful. I figure that relying on the JS engine that the interesting code will be using will work a lot better than another engine which is rarely mentioned :-) (In reply to comment #27) > How is SpiderMonkey's JS parser treating you jshydra guys? Let me know, thanks. The problem I'm grappling with right now is getting error reporting. My biggest peeve is the lack of AST documentation, but I now have a nice tool that dumps JS ASTs for me, so it's not so bad.
(In reply to comment #28) > (In reply to comment #27) > > How is SpiderMonkey's JS parser treating you jshydra guys? Let me know, thanks. > > The problem I'm grappling with right now is getting error reporting. My biggest > peeve is the lack of AST documentation, If you see bugs in the jsparse.h big-comment docs (I know you found some in the past) please file and patch. > but I now have a nice tool that dumps JS ASTs for me, so it's not so bad. How about feeding back via a patch in a new bug? We want DEBUG AST dumping. Also, we want a JsonML AST codec for Narcissus and future versions of the language. I'd be grateful for anything you can contribute, even if not finished/polished. /be
Nice python class that builds the context via JSHydra preprocessed jsexport files and some xml.etree parsing
This was fun to generate, still to add a sweeper that kills the &amp; chars
Just wanted to post this hiccup I am running into. I started adding my own additions to JSHydra - scripts, Python context processing, and docs to this hg repo: http://bitbucket.org/daviddahl/jshydra-ddahl/src/ I ran my context.py script - docs are in jshydra-ddahl/post-build/INSTRUCTIONS - to create a context js file for browser.xul, just as a test. Here is what I get when I run my findFuncs.js: ddahl@onyx:~/code/moz/jshydra-ddahl$ ./jshydra scripts/findFuncs.js post-build/sample_browser_xul_context.js Unexpected type: 77 (arity 1) Unexpected type: 71 (arity 6) Unexpected type: 71 (arity 6) scripts/../utils/cleanast.js:234: JS Exception: Assertion failed :0: #0: Error("Assertion failed") scripts/../utils/cleanast.js:234: #1: assert(false) scripts/../utils/cleanast.js:228: #2: make_function([object JSHydraNode]) scripts/../utils/cleanast.js:194: #3: make_object([object Object]) scripts/../utils/cleanast.js:166: #4: make_variables([object JSHydraNode]) scripts/../utils/cleanast.js:29: #5: clean_ast([object JSHydraNode]) scripts/findFuncs.js:9: #6: process_js([object JSHydraNode],"post-build/sample_browser_xul_context.js","") Here is dxr: ddahl@onyx:~/code/moz/jshydra-ddahl$ ./jshydra scripts/dxr.js post-build/sample_browser_xul_context.js Unexpected type: 77 (arity 1) Unexpected type: 71 (arity 6) Unexpected type: 71 (arity 6) scripts/../utils/cleanast.js:234: JS Exception: Assertion failed :0: #0: Error("Assertion failed") scripts/../utils/cleanast.js:234: #1: assert(false) scripts/../utils/cleanast.js:228: #2: make_function([object JSHydraNode]) scripts/../utils/cleanast.js:194: #3: make_object([object Object]) scripts/../utils/cleanast.js:166: #4: make_variables([object JSHydraNode]) scripts/../utils/cleanast.js:29: #5: clean_ast([object JSHydraNode]) scripts/dxr.js:11: #6: process_js([object JSHydraNode],"post-build/sample_browser_xul_context.js","") If I just run ast.js it seems to work OK. I'm still hacking on it, but would like some input - and wanted you guys to know I made my repo at bitbucket.
(In reply to comment #29) > If you see bugs in the jsparse.h big-comment docs (I know you found some in the > past) please file and patch. * Mutters about a few of the JSToken stuff being added apparently without corresponding documentation in jsparse.h I'll go through this some time, but I'll be sure to file a bug about it. > How about feeding back via a patch in a new bug? We want DEBUG AST dumping. > Also, we want a JsonML AST codec for Narcissus and future versions of the > language. I'd be grateful for anything you can contribute, even if not > finished/polished. For clarity, I was referring to <http://www.tjhsst.edu/~jcranmer/webjshydra/>, which needs some more polish on my end. Producing a nice tree of a real AST according to the specification is also on my list of goals for the mid-term. (In reply to comment #32) > Just wanted to post this hiccup I am running into. I started adding my own > additions to JSHydra - scripts, Python context processing, and docs to this hg > repo: > > http://bitbucket.org/daviddahl/jshydra-ddahl/src/ I'm working on similar processing myself, but it's not quite ready for primetime. I think it should be releasable within a week or two. > ddahl@onyx:~/code/moz/jshydra-ddahl$ ./jshydra scripts/findFuncs.js > post-build/sample_browser_xul_context.js > Unexpected type: 77 (arity 1) > Unexpected type: 71 (arity 6) > Unexpected type: 71 (arity 6) That would be a TOK_DBLCOLON and a TOK_YIELD. The former is part of E4X, which I don't yet support. The latter is a case of someone deciding not to mention it in the jsparse.h comment. From a user perspective, this just means that some portions of the AST will not be communicated to the JS scripts. It's the GC or segfault problems which means you have a serious problem. > scripts/../utils/cleanast.js:234: JS Exception: Assertion failed > :0: #0: Error("Assertion failed") > scripts/../utils/cleanast.js:234: #1: assert(false) > scripts/../utils/cleanast.js:228: #2: make_function([object JSHydraNode]) That I traced to an issue with failing to account for lambda functions, which is supported as of about 9 hours ago.
ddahl|sheriff|away: how's the jshydra work * cbartley_afk is now known as cbartley * You are now known as ddahl <ddahl> dietrich: i'll b back at it on wednesday <ddahl> i need to identify the js that is "in scope" on startup <ddahl> do you guys have anything like that? * You are now known as ddahl|away <dietrich> ddahl|away: nothing like that <dietrich> that i know of <dietrich> there are many scopes <dietrich> startup category listeners <dietrich> certain notification observer components, like nsBrowserGlue <dietrich> then the js pulled in via browser.xul <dietrich> modules pulled into any of those scopes that i just listed <dietrich> js components instantiated via any js in any of the scopes i just listed, including the modules
I am able to parse the sample_browser_xul_context.js now, Cool! I just added a Python class to my repo to get the context of any JS Module, it is in context.py -> JSContext. I was able to generate the context for nsBrowserGlue.js, which is in post-build/nsBrowserGlue_context.js http://bitbucket.org/daviddahl/jshydra-ddahl/src/tip/post-build/nsBrowserGlue_context.js It's ast cannot be created: % ./jshydra scripts/findFuncs.js post-build/nsBrowserGlue_context.js scripts/../utils/cleanast.js:17: JS Exception: TypeError: ast is null scripts/../utils/cleanast.js:17: #0: clean_ast(null) scripts/findFuncs.js:9: #1: process_js(null,"post-build/nsBrowserGlue_context.js","") A cursory examination did not reveal the problem (to me)
Looks like I have a preliminary dead code report, but it is wildly inaccurate as of right now. ################################################################# ################ JSHydra *Possible* Dead Code Summary Report ####### ################ JSContext: post-build/sample_browser_xul_context.js 1073 Defined Functions 503 Functions Called 105 Functions Called But NOT Defined in this context* 423 Functions named 'undefined' - (anonymous) I need to do some more post processing where I lookup the lines of code where the anonymous functions are defined and weeding out js functions that are "built in" like "setTimeout", etc. I am attaching the full report.
very preliminary dead code report from browser.xul context. Ran into some JSHydra issues when running this against nsBrowserGlue.js. Starting to create all js "startup contexts"
The code for all of this has been updated at bitbucket: http://bitbucket.org/daviddahl/jshydra-ddahl/src/
I just updated jshydra re-built it and get this: ddahl-t500 1~/code/moz/jshydra-ddahl/post-build % jshydra ../scripts/deadCode.js sample_browser_xul_context.js Unexpected type: 77 (arity 1) Unexpected type: 71 (arity 6) Unexpected type: 71 (arity 6) ../scripts/../utils/cleanast.js:17: JS Exception: ReferenceError: TOK_LC is not defined ../scripts/../utils/cleanast.js:17: #0: clean_ast([object JSHydraNode]) ../scripts/../scripts/deadCode.js:10: #1: process_js([object JSHydraNode],"sample_browser_xul_context.js") ... sadface
Attached file Current Browser.xul JS context (obsolete) —
The current JS context of browser.xul
I asked jcranmer about getting the parent node to better "name" some "undefined" or anonymous functions.
Narrowing down the list of possible dead code. I am going through this list: http://pastebin.mozilla.org/669042 Of course the very first function listed is passed into setTimeout and probably executed as a callback. Again, these edge (and not so edge-cases) need to be thought of and coded for: http://mxr.mozilla.org/mozilla-central/search?string=pageShowEventHandlers
Looks like most of the functions in the pastebin are in fact used inside of commands in xbl/xul or inside of setTimeout. JSHydra needs to identify functions inside setTimeout. I will rebuild the nsBrowserGlue js context and see if there is any dead code there. This seems it was worth it to test drive JSHydra and to put together some scripts to id dead code, I don't think there is much in browser.xul's context:(
Of course, I should not sounds so pessimistic, as with a small tweak or two I can probably create a list of unanmed functions in browser.js that do, in fact, need names.: 245 Functions named 'undefined' - (anonymous) ################################################################## ################ JSHydra *Possible* Dead Code Summary Report ##### ################ JSContext: post-build/browser_xul_context.js 523 Defined Functions 260 Functions Called 138 Functions Called But NOT Defined in this context* 245 Functions named 'undefined' - (anonymous) 68 Functions defined but not called. 216 Functions checked for property name vs. function name
Attached file deadCode.js
Adding the current deadCode.js script, ( and killing off all old attachments ) which is hosted at bitbucket: http://bitbucket.org/daviddahl/jshydra-ddahl/
Attachment #392022 - Attachment is obsolete: true
Attachment #392023 - Attachment is obsolete: true
Attachment #392631 - Attachment is obsolete: true
Attachment #392632 - Attachment is obsolete: true
Attachment #394394 - Attachment is obsolete: true
Attachment #396588 - Attachment is obsolete: true
Attachment #396589 - Attachment is obsolete: true
Attachment #396601 - Attachment is obsolete: true
Priority: -- → P3
Whiteboard: [ts] → [ts][i/o]
Blocks: 447581
Assignee: ddahl → nobody
Product: Core → Firefox Build System
jshydra is no longer a thing.
Status: NEW → RESOLVED
Closed: 6 years ago
Resolution: --- → INCOMPLETE
Product: Firefox Build System → Developer Infrastructure
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: