Re-assigning a function declaration in javascript - javascript

Right now I am debugging some weird errors which occur in my GWT (version 2.5.1) application since Firefox 46. The javascript code generated by GWT contains multiple instances of this pattern:
function nullMethod() {
}
var v;
function f() {
f = nullMethod;
v = { name : 'Joe' };
console.log("called");
}
// this is called from multiple places
console.log((f(), v).name);
console.log((f(), v).name);
console.log((f(), v).name);
Seems that this somehow implements the singleton pattern. But for some reason this does not prevent that the initial declared method is invoked again. The string 'called' is printed to the console multiple times.
But if I try to reproduce this with a little test everything works as expected. The observations from above was made by adding console outputs to the generated code (>5MB).
Now the really weird stuff. If I add "console.log(f.toString())" as the first statement of the function, it prints the intial function on the first invocation. All further invocations print the nullMethod.
Can somebody explain what could be the cause? IE11 works fine. Chrome has the same issue as Firefox 46. I just didn't find old Chrome versions to verify since when this behaviour was introduced. Is it valid to overwrite a function declared this way?
jsbin.com gives a warning on the function re-assignment line:
Line 6: 'f' is a function.

The method f in this case is a Java static initializer. Running it more than once will cause problems in the emulated Java, which expects that this can only run a single time when the class is first referenced or loaded (ignoring classloader issues, since GWT doesnt emulate classloaders).
However, sufficiently old copies of GWT wrap up blocks of code in a try/catch block (iirc this was related to IE6 issues), and at the time, JS scope rules had some ambiguity around them which made this code work consistently, since all browsers supported this. This was known as a "sloppy mode self-defining function".
As part of ES2015, it has been decided that the try block has a different scope than the outer "function-hosted" one (i.e. when you declare something as a function foo() {...}, it exists in a high-level scope). See a ton of discussion on this at https://github.com/tc39/ecma262/issues/162.
This change means that some formerly sane programs no longer work correctly - for a time, this included Google Inbox as well as others.
Updating to a newer version of GWT, or using a custom Linker that no longer wraps each block of top-level JS in old GWT should resolve this. If you still must support whatever ancient browser that requires this behavior (with enough code archeology, I'm sure we could find out why GWT initially did it, but I haven't done this yet), you are going to have to find a compromise that works in both ancient and bleeding edge browsers.

Related

Is there a way to access/modify the "Execution Context" of a Node module/function

I understand the scoping rules of Node/JavaScript, and from, for example, Understanding Execution Context and Execution Stack in Javascript, I think I understand the principle of how Execution Contexts work: the question is can you actually get access to them?
From an answer to the 2015 question How can I get the execution context of a javascript function inside V8 engine (involving (ab)using (new Error()).stack), and the answer to the 2018 question How can we get the execution context of a function?, I suspect the answer is "no" but just in case things have changed: is it possible to access/modify the Execution Context of a Node module/function?
(I'm very aware this screams either XY Problem or a desire to abuse Node/JavaScript: hopefully the Background section below will provide more context, and – if there's a different way of achieving what I want – that will work as well.)
In a nutshell, I want to achieve something like:
sharedVar = 1 ;
anotherModule.someFunction() ;
console.log( sharedVar ) ; // Where 'sharedVar' has changed value
Having a function in a different module being able to change variables in its caller's scope at will seems the definition of "A Dangerous Thing™", so – if it's possible at all – I expect it would need to be more like:
sharedVar = 1 ;
anotherModule.hereIsMyExecutionContext( SOMETHING ) ;
anotherModule.someFunction() ;
console.log( sharedVar ) ; // Where 'sharedVar' has changed value
and anotherModule would be something like:
let otherExecutionContext ;
function hereIsMyExecutionContext( anExecutionContext ) {
otherExecutionContext = anExecutionContext ;
}
function someFunction() {
//do something else
otherExecutionContext.sharedVar = 42 ;
}
and the question becomes what (if anything) can I replace SOMETHING with?
Notes / Things That Don't Work (for me)
You shouldn't be trying to do this! I realize what I'm trying to achieve isn't "clean" code. The use-case is very specific, where brevity (particularly in the code whose value I want changing) is paramount. It is not "production" code where the danger of forgotten, unexpected side-effects matters.
Returning a new value from the function. In my real use-case, there would be several variables that I would like someFunction() to be able to alter. Having to do { var1, var2, ... varN } = anotherModule.someFunction() would be both inconvenient and distracting (while the function might change some of these variables' values, it is not the main purpose of the function).
Have the variables members of anotherModule. While using anotherModule.sharedVar would be the clean, encapsulated way of doing things, I'd really prefer not to have to use the module name every time: not only is it more typing, but it distracts from what the code that would be using these variables is really doing.
Use the global scope. If I wasn't using "use strict";, it would be possible to have sharedVar on the global object and freely accessible by both bits of code. As I am using strict-mode (and don't want to change that), I'd need to use global.sharedVar which has the same "cumbersomeness" as attaching it to anotherModule.
Use import. It looks like using import { sharedVar } from anotherModule allows "live" sharing of the variables I want between the two modules. However, by using import, the module using the shared variable has to be an ES Module (not a CommonJS Module), and cannot be loaded dynamically using require() (as I also need it to be). Loading it dynamically the ESM way (using import() as a function returning a promise) appears to work, but repeated loadings come from a cache. According to this answer to How to reimport module with ES6 import, there isn't a "clean" way of clearing that cache (cf. delete require.cache[] that works with CommonJS modules). If there is a clean way of invalidating a cached ESM loaded through import(), please feel free to add an answer to that question (and a comment here, please), although the current Node JS docs on ESMs don't mention one, so I'm not hopeful :-(
Background
In early December, a random question on SO alerted me to the Advent of Code website, where a different programming problem is revealed everyday, and I decided to have a go using Node. The first couple of problems I tackled using standalone JS files, at which point I realized that there was a lot of common code being copy-pasted between each file. In parallel with solving the puzzles, I decided to create a "framework" program to coordinate them, and to provide as much of the common code as possible. One goal in creating the framework was that the individual "solution" files should be as "lean" as possible: they should contain the absolute minimum code over that needed to solve the problem.
One of the features of the framework relevant to this question is that it reloads (currently using require()) the selected solution file each time, so that I can work on the solution without re-running the framework... this is why switching to import and ES Modules has drawbacks, as I cannot (cleanly) invalidate the cached solution module.
The other relevant feature is that the framework provides aoc.print(...) and aoc.trace(...) functions. These format and print their arguments: the first all the time; the second conditionally, depending on whether the solution is being run normally or in "trace" mode. The latter is little more than:
function trace( ... ) {
if( traceMode ) {
print( ... )
}
}
Each problem has two sets of inputs: an "example" input, for which expected answers are provided, and the "real" input (which tends to be larger and more involved). The framework would typically run the example input with tracing enabled (so I could check the "inner workings") and run the "real" input with tracing disabled (because it would produce too much output). For most problems, this was fine: the time "wasted" preparing the parameters for the call, and then making the call to aoc.trace() only to find there was nothing to do, was negligible. However, for one solution in particular (involving 10 million iterations), the difference was significant: nearly 30s when making the ignored trace; under a second if they calls were commented-out, or I "short-circuited" the trace-mode decision by using the following construct:
TRACE && aoc.print( ... )
where TRACE is set to true/false as appropriate. My "problem" is that TRACE doesn't track the trace mode in the framework: I have to set it manually. I could, of course, use aoc.traceMode && aoc.print( ... ), but as discussed above, this is more to type than I'd like and makes the solution's code more "cluttered" than I'd ideally want (I freely admit these are somewhat trivial reasons...)
One of the features of the framework relevant to this question is that it reloads the selected solution file each time
This is key. You should load not leave the loading, parsing and execution to require, where you cannot control it. Instead, load the file as text, do nefarious things to the code, then evaluate it.
The evaluation can be done with eval, new Function, the vm module, or by messing with the module system.
The nefarious things I was referring to would most easily be prefixing the code by some "implicit imports", whether you do that by require, import or just const TRACE = true;. But you can also do any other kind of preprocessing, such as macro replacements, where you might simply remove lines that contain trace(…);.
Looks like you're heading the wrong way. The Execution Context isn't meant to be accessible by the user code.
An option is to make a class and pass its instances around different modules for your purpose. JS objects exist in the heap and can be accessed anywhere as long as you have its reference, so you can control it at will.

how do I go into eval('debugger') mode when already stopped at 'regular' debugger statement?

I recently started to swap out all my debugger statements with eval('debugger') statements. The reason is that with the plain version, not all "factually/theoretically" visible variables are "practically" visible. This happens because of optimization (see earlier SO question).
With this trick, the problem is like "90% solved" - there are some drawbacks. Apart from longer source code, those are:
When third party libraries are involved, it is not feasible, maybe not even possible to have the debugger -> eval('debugger') transformation done there also.
When I would rather set a break point in the debugger itself, instead of changing the code, that cannot be done - or can it?
When I'm already stopped at a "normal" debugger statement (in third party code, or where I forgot one), there is no way to switch to the desired mode - certainly typing eval('debugger') on the console doesn't help. If I want the functionality, I have to change the debugger statement, and run the code again, which might be a whole lot of work
When I stopped at an eval('debugger') statement, but then use the debugger 'step over/into/out' functionality, I 'lost my special status'.
How can I work around this? Is there a way to tell v8 to interpret all debugger statements by eval('debugger')? Is there a trick with which you can 'go into the other mode' - as if the eval('debugger') statement would magically appear as the next statement after the debugger statement where you're stopped? Do command line options to the chrome executable help? Maybe there is a way in firefox?
I learned about the eval('debugger') trick in an answer to a recent SO question of my own
ANNOUNCEMENT
What I'm going to do next is write a little transpiler for usage within node webserver. The transpiler will insert eval('') statements all over the place (by default once at the beginning/body of every function, and more or fewer of them if so specified in the query string.) Then I can set a breakpoint where the eval statement is, do "step into" and then I got what I want. Then I'm going to answer my own question.
Unless of course, someone will beat me to it. That would be most delightful, as I do have other things to do.
V8 developer here.
Is there a way to tell v8 to interpret all debugger statements by eval('debugger')?
There is currently no way to treat debugger statements or breakpoints as eval("debugger"), but it might be feasible to add a flag that does this. You can file a "feature request" bug at crbug.com/v8/new and ask for a flag that forcibly context-allocates all variables for debugging purposes.
(Side note 1: It's the eval part that has an effect here. Instead of eval('debugger') you could write eval(""); debugger; or debugger; other_code(); eval("");, so long as you have eval somewhere in the function.)
(Side note 2: the tension here is that on the one hand, it's Good™ when the behavior of a program when it is being debugged is the same as when it is not being debugged -- otherwise there might be issues that only show up when debugging, or un-debuggable failures in production mode. On the other hand, sometimes certain deviations are explicitly necessary in order to make debugging possible. I'm not sure on which side of the line this one falls. Context-allocating all variables will reduce performance and increase memory consumption, so if/when such a mode becomes available, you will probably have to (or want to) switch back and forth during your development work; which in particular means that this couldn't simply be the default when DevTools are open.)
Is there a trick with which you can 'go into the other mode' - as if the eval('debugger') statement would magically appear as the next statement after the debugger statement where you're stopped?
No, and there can't be. It's not a "mode" or "special status", it's a decision that has to be made when first parsing/compiling the outer function (the one that contained the variable you want to see within an inner function). Once that time has passed, it's too late to change anything (non-context-allocated variables are just gone), and the only option is to reload.
[EDIT in response to comments:
To clarify what I mean by "not a mode, but a decision": from the scope chain's point of view, the situation is essentially the same as:
var inner;
function outer() {
var foo = "foo";
var bar = "bar";
inner = function() {
console.log(bar);
debugger;
}
// "inner();" here is moved below
}
outer();
inner();
at the point when inner() is called, foo is either still there like bar (if it's context-allocated because at compile time of outer V8 determined that inner will need it), or gone (if V8 determined that it's local to outer and nobody else will need it). If inner contains eval, then it might need all outer-scope variables.
--end of EDIT]
This happens because of optimization
Well... because of an optimization, namely being smart about whether to allocate variables on the stack or in the "context object". This is completely unrelated to what is typically referred to as "optimization of a function", i.e. running them through the optimizing compiler. That's why the %NeverOptimizeFunction hack discussed in the other issue had no effect -- it's an unrelated mechanism.

Invalid Calling Object, and Compatibility

In Internet Explorer 10, I have the following:
/*
* Alias document.getElementById(), to reduce typing, improve
* readability and speed up access to the function.
*/
var getElmById = document.getElementById;
function . . . (ctlID) {
var ctrl = getElmById(ctlID); // <————<<< error raised here
. . .
}
This has been working fine, but suddenly is giving me
SCRIPT65535: Invalid calling object
I have determined that if I check the box, Tools > Compatibility View Settings > [_] Display intranet sites in Compatibility View, the aliased function runs just fine, but if I clear that box, I get the error.
What is the reason? What is the specific issue that IE is responding to? Has aliasing functions like that been eliminated? Has there been some change to the way the 'document' object behaves?
I just posted this as an answer, but I don't see it. Trying again...
This topic has an outstanding answer:
JavaScript function aliasing doesn't seem to work
"getElementById()" is supposed to be called as a method and not as a function, i.e. with a context to be applied upon (the document, or to put it in Javascript terms, the "this" value), obtained by parsing the left-side of the expression ("document.").
In the past, the context was necessarily accessed as a free variable from the function, so maybe they decided to clean out their code. Since some other major browsers do not support this kind of aliasing, I guess they'd figure most people wouldn't mind.

Possible to enumerate or access module-level function declarations in NodeJs?

In Node.js, if I load a module which contains code in module-scope like:
this["foo"] = function() { console.log("foo"); }
...then I appear to get a globally available function that I can call just by saying foo() from any code using the module. It can be seen as one of the printed items with Object.getOwnPropertyNames(this).
However, if I put the following in module scope instead:
function foo() { console.log("foo"); }
...then it produces a function which can similarly be called within that module as foo(), but is invisible outside of it (e.g. does not show up as one of the items with Object.getOwnPropertyNames(this)).
I gather this is a change in runtime behavior from what's done in browsers. A browser seems to poke everything into global scope by default (and for years people have had to consciously avoid this by wrapping things up in anonymous functions/etc.)
My question is whether NodeJs has some secret way of interacting with these declarations outside of the module in which they are declared BESIDES using exports.(...) = (...). Can they be enumerated somehow, or are they garbage collected as soon as they are declared if they're not called by a module export? If I knew what the name of such a function was going to be in advance of loading a module...could I tell Node.js to "capture it" when it was defined?
I'm not expecting any such capabilities to be well-documented...but perhaps there's a debugger feature or other system call. One of the best pointers would be to the specific code in the Node.js project where this kind of declaration is handled, to see if there are any loopholes.
Note: In researching a little into V8 I saw that a "function definition" doesn't get added to the context. It's put into an "activation object" of the "execution context", and cannot be programmatically accessed. If you want some "light reading" I found:
http://coachwei.sys-con.com/node/676031/mobile
http://perfectionkills.com/understanding-delete/
if you fill in exports.foo = foo; at the end of your file it will be available in other files in node, assuming that you do var myFile = require('myFile.js') with the file name and you call the function via myFile.foo(); You can even rename the function for outside use in exports and set whatever you want to call the package when you use require.
BTW you can enumerate these functions just like you do on any JSON object (ie for k in ...)
This is impossible in node without more advanced reflection tools like the debugger.
The only way to do this would be to use __parent__ which was removed due to security issues and other things (hard to optimize, not standard to begin with) . When you run the script those variables become closed under the module. You can not access them elsewhere without explicitly exporting them.
This is not a bug, it's by design. It's just how node works. see this closely related question.
If this sort of reflection was available without tools like the debugger it would have been extremely hard to optimize the source code (at least the way v8 works) , meaning the answer to your question is no. Sorry.

While debugging javascript, is there a way to alert current call stack?

For simple javascript debugging I'll use alerts to show variable values and the like. Is there a way to get the current call stack in javascript to be able to display it in an alert?
Thanks.
Quick and dirty in Gecko-based browsers:
new Error().stack
You can also manually trawl some of the stack using Function.prototype.caller:
var thisFunction = arguments.callee;
var caller = thisFunction.caller;
var callerCaller = caller.caller;
// ...and eventually, assuming no recursion:
var bottomCaller = ...;
assert(bottomCaller.caller === null);
One (possibly large) caveat of the .caller trick is that it doesn't handle recursion -- .caller looks from the top of the stack downward to find the first instance of the function in the stack and then returns its immediate caller, so without being careful you can loop infinitely looking up callers.
Another caveat to caller is that, going forward, if any of your code uses ECMAScript 5's strict mode, the caller property of strict mode functions (or of functions which have themselves been called from strict mode functions) is a so-called "poison pill" which throws a TypeError when accessed. The caller property of "bound" functions (those created by ES5's Function.prototype.bind method) is also a poison pill. These restrictions break the generic stack-walking algorithm, although one could imagine use-specific ways to work around this (entry and exit annotating functions, perhaps).
Do note that stack-walking like this isn't a great idea in production code (as a quick hack for debugging it's fine, tho); at the moment walking up the stack as in the latter example is somewhat expensive in Mozilla's JS engine, and it'll probably throw you out of machine code and back into interpreted code. Also, the stack-walk is O(n2), which might matter if you tend to have complex, deep stacks.
You can use console.trace()
It doesn't display an alert() but print the stacktrace on the debugger console.
Use debugger like Firebug for this if you are in Firefox. Chrome and Opera have build-in debugger. And there are Developers Tools for Internet Explorer.
The best way to debug Javascript is to use Firebug, which includes a full Javascript debugger.
If you're debugging in IE, you can use Visual Web Developer Express (or any other edition of Visual Studio).
If you're debugging IE8, you can use its built-in developer tools, which include a debugger.
It is possible to get the call stack in Javascript; see here.
Have you looked at firebug - and a breakpoint. If it's just for debugging, then this might suffice.
Also - you can have a look Here
This will give you all call stack
working good for me.
var y = 'arguments.callee.caller';
while (eval(y) != undefined) {
stak += eval(y + '.toString()');
y = y + '.caller';
}
alert(stak);
For nodejs debugging, in Visual Studio Code, as of v.1.14.2, it's View->Debug (Ctrl+Shift+D)

Categories