JScript eval redux, and some spec diving

I was discussing the difference between executing in local and global scopes the other day.  A reader points out something that I forgot to mention – there are two sneaky ways to manipulate the global namespace from an eval in JavaScript.

First, the Function constructor constructs a named function in the global scope. This had slipped my mind when I was writing the entry.

The second trick was very much on my mind but I did not mention as it would be yet another digression.  That is the fact that assigning a value to an undeclared variable creates a new variable in global scope.

This was on my mind because a couple weeks ago my friend CJ was debugging an irksome incompatibility between Gecko and IE. It turned out to hinge on the fact that in IE, fetching the value of an undefined variable is illegal, but setting it is legal.  According to CJ, in Gecko both are legal.

I wouldn’t know, never having actually used any browser other than IE since IE3 was
in development. (UPDATE: There is some dispute over this claim; like I said, I don’t know. Never tried it.)

If you look at the ECMAScript Revision 3 specification (E3) in some depth it becomes
clear that IE and Gecko are both in compliance with the spec, and yet incompatible
with each other.

“How’s that?” I hear you ask. The logic is a little tortuous!

Creating a new global variable when setting an undeclared variable must be legal according to E3 section 10.1.4, line 5, which states that an identifier undeclared in all scopes on the scope chain results in a “null reference”, and section 8.7.2, line 6 which states that an assignment to a null reference creates a new variable in the global scope.   IE does this, and I assume that Gecko does as well.

But setting the value of an undeclared variable must throw an error according to E3 section 8.7.1, line 3, which states that fetching the value of a null reference creates a ReferenceError exception. IE does this. If Gecko creates a variable in some scope rather than throwing a ReferenceError exception then clearly they have produced a situation in which a program running in Gecko has different semantics than when running in the browser used by the other 90% of the world.

Such situations are, as CJ, very painful for developers — mitigating this pain is why my colleagues and I went to the massive trouble and expense of defining the specification in the first place!  However, if that is the case then Gecko is not actually in violation of the specification thanks to E3 section 16, which states:

“An implementation may provide additional types, values, objects, properties, and functions beyond those described in this specification. This may cause constructs (such as looking up a variable in the global scope) to have implementation-defined behaviour instead of throwing an error (such as ReferenceError).”  [Emphasis added]

The E3 authors explicitly added the parenthetical clauses to make Gecko-like behaviour legal, though discouraged.  However, the clause is necessary — without this clause it becomes very difficult to define certain browser-object-model/script-engine interactions in a manner which does not (a) make both IE and Navigator technically noncompliant with the spec, (b) drag lots of extra-language browser semantics into the language specification and (c) make it difficult to extend the language in the future.

We earnestly wished to avoid all these situations, so the rule became “any error situation may legally have non-error semantics.” This is in marked contrast to, say, the ANSI C specification which rigidly defines what error messages a compliant implementation must produce under various circumstances.


As I noted above, this article produced immediate pushback from readers who said that CJ’s claim was wrong, that Gecko does the expected thing in this scenario, and suggested that he submit a reproducer of the defect.

Brendan Eich, the original designer of JavaScript and later CEO of Mozilla who stepped down after supporting anti-equality measures in California, said that I was “misreading” the specification, and that it was not intended to imply that any property can be referenced without error.

I have no idea what Brendan meant by this; the specification seems very clear to me; it specifically calls out that lookups in global scope need not throw.

All in all, the second half of this episode of FAIC seems to have been a waste of time and effort for all concerned.

Running Me Ragged

A reader of the previous episode asked me

Why are there two types of multidimensional arrays? What is the difference between the arr(x)(y) and arr(x,y)notations?

Good question. There are two kinds of multidimensional arrays, called “rectangular” and “ragged“. (Or “jagged”; either is common.)

A rectangular array is, well, rectangular. In VBScript you say

Dim MyArray(3,2)

and you get an array with indices:

(0,0) (0,1) (0,2)
(1,0) (1,1) (1,2)
(2,0) (2,1) (2,2)
(3,0) (3,1) (3,2)

which makes a nice rectangle. A three-dimensional array makes a rectangular prism, and so on up into the higher dimensions.

Now, as I mentioned earlier, JavaScript does not have multidimensional arrays. A clever trick to simulate multidimensional arrays in JavaScript is to make an array of arrays:

var x = new Array(
  new Array(1, 2, 3),
  new Array(4, 5),
  new Array(6, 7, 8, 9));

Dereferencing the outer array gives you the inner array, which can then be dereferenced
itself:

print(x[2][0]); // 6

But you notice something about the indices if we write them out as before:

[0][0]  [0][1]  [0][2]
[1][0]  [1][1]
[2][0]  [2][1]  [2][2]   [2][3]

The indices make a ragged pattern, not a straight rectangular pattern.

You can have ragged higher dimensional arrays as well, though allocating all the sub-arrays gets to be a royal pain, and I recommend against it.

There are often times when you want ragged arrays even in a language that supports rectangular multi-dimensional arrays, so VBScript supports both. If you say

MyArray(2,3)

then you are talking to a rectangular two-dimensional array. If you say

MyArray(2)(3)

then you are talking to a one dimensional array that contains another one dimensional array.

 

 

“For Each” vs. “for in”

While we’re on the subject of semantic differences between seemingly similar syntaxes, let me just take this opportunity to quickly answer a frequently asked question: why doesn’t for-in enumerate a collection?

A VB programmer is used to this printing out every item in a collection:

For Each Item In MyCollection
  Print Item
Next 

VB programmers introduced to JavaScript always make this mistake:

for (var item in myCollection)
  print(item);

and they are always surprised when this prints out a bunch of unexpected strings, or perhaps nothing at all.

The difference is quite simple.  In VBScript For Each enumerates the members of a collection. In JavaScript, for-in enumerates the properties of an object. In JavaScript if you have

var foo = new Object();
foo.bar = 123;
foo.baz = 456; 

then you can enumerate the properties:

for (var prop in foo)
  print (prop + " : " + foo[prop]) 

JavaScript needs such a control flow structure because it has expando objects and sparse arrays. You might not know all the properties of an object or members of an associative array. It’s not like VBScript where objects have fixed members and arrays are indexed by dense integer tuples. VBScript doesn’t need this ability, so it doesn’t have it.

Incidentally, in order to implement the for-in loop we needed to extend the functionality exposed by a dispatch object. Hence IDispatchEx which gives the caller the ability to enumerate dispids and go from dispid back to name.

In JScript to enumerate members of a collection, use the Enumerator object:

for (var enumerator = new Enumerator(myCollection) ; 
  !enumerator.atEnd(); 
  enumerator.moveNext())
{
  var item = enumerator.item();
  // ... 

The reaction I get from people who have not seen object-oriented enumerators before is usually “yuck!” This is an unfortunate reaction, as enumerator objects are extremely powerful. Unlike lexical For Each loops, enumerators are first-class objects. You can take out multiple enumerators on a collection, store them, pass them around, recycle them, all kinds of good stuff.

The semantics of the for in loop in JScript.NET are kind of a hodgepodge of both styles, with several interesting extensions. First off, if you pass an enumerator object itself to the JScript.NET for in loop, we enumerate it. If the argument is an object (or a primitive convertible to an object) then we enumerate its properties as JScript Classic does. If it is a CLR array, we enumerate its first dimension indices. If it is a collection, we fetch an enumerator and enumerate that. Otherwise, you’ve passed a non-enumerable object and we throw an exception.


There were a number of good responses to this article:

I like that you showed a common mistake of VBScript developers moving to JavaScript; what about VBScript developers moving to VB proper? What mistakes to they commonly make?

The advice I gave to the reader was to read Paul Vick’s blog, www.panopticoncentral.net I’m pleased that Paul is still blogging all these years later!

Here’s a clever trick for doing enumeration by passing in a function. We make a helper function, and then call it with the function to execute on each item:

function enumerate( coll, f )
{
  for( var en = new Enumerator(coll); 
    !en.atEnd(); 
    en.moveNext() )
  {
    f( coll.Item() );
  }
}
... 
enumerate(collection, function(item) { ... });

Though that is slick I am generally not that big a fan of mixing functional and imperative programming in cases where there’s an existing language construct that does the job.

I do sometimes need the ability to iterate property names in VBScript because it is often unclear what the properties of an object are; not all objects are well-documented.

The problem is that a lot of OLE Automation objects do not expose a mechanism for doing so; it can be tricky to go from an instance of an object to its type information.

Why are VBScript and JavaScript different in this regard?

VBScript and JavaScript were invented by different people at different companies at different times to solve different problems, so it should not be surprising that the languages are in many ways different.

Can we expect any enhancements to VBScript in this area?

We stopped adding new features to VBScript in 2001, so, I would not expect anything, no.

 

JScript and VBScript Arrays

Earlier I alluded to the fact that JavaScript arrays are objects but VBScript arrays are not. What’s up with that?

It’s kind of strange.

Consider the properties of a JavaScript array. A JavaScript array is

  • one dimensional.
  • associative; that is, indexed by strings. Numeric indices are actually converted to strings internally.
  • sparse: arr[1] = 123; arr[1000000] = 456; gives you a two-member array, not a million-member array.
  • an object with properties and methods.

Whereas a VBScript array is

  • multi-dimensional.
  • indexed by integer tuples.
  • dense.
  • not an object.

It is hard to come up with two things that could be more different and yet both called “array”!

As you might expect, JScript and VBScript arrays have completely different implementations behind the scenes. A JScript array is basically just a simple extension of the existing JScript expando object infrastructure, which is implemented as a (rather complicated) hash table. A VBScript array is implemented using the SAFEARRAY data structure, which is pretty much just a structure wrapped around a standard “chunk of memory” C-style array.

Since all the COM objects in the world expect VBScript-style arrays and not JScript-style arrays, making JScript interoperate with COM is not always easy. I wrote an object called VBArray into the JScript runtime to translate VBScript-style arrays into JScript arrays, but it is pretty kludgy. And though I wrote some code to go the other way — to turn JScript arrays into VBScript arrays — there were just too many thorny issues involving object identity and preservation of information for us to actually turn it on. There weren’t exactly a whole lot of users demanding the feature either, so that part of the feature got cut. (If I recall correctly, my colleague Peter Torr wrote some COM code to do that before he came to work at Microsoft. He might still have it lying around.)

Things got even weirder when I wrote the code to interoperate between CLR arrays and JScript.NET arrays, but that’s another story.


As I port this article over in 2019, I note that Peter is still at Microsoft, designing great developer experiences. Back in the early days — 1997 or thereabouts I think — I was answering JavaScript questions on USENET and Peter kept giving answers that were better than mine. I emailed him and asked if he’d be interested in working on the design of the language itself; that may have been the single email that I sent that got the biggest return on investment for Microsoft. 🙂

There were a number of good reader follow-up questions to this post. A selection:

The VBArray object is useful when we have an existing array in hand, but can we have a tool usable from JScript that produces a new one?

I always meant to add that to the runtime but never got around to it, sorry! I did add better support in JScript.NET, but that’s not super useful, I know.

How can I marshal a JScript array object to C#?

We designed the JScript array object interfaces and implementations long, long before C# was even thought of; there’s no obvious way to do so that I know of. Nowadays with dynamic in C# there might be a way to do it, but I’ve never tried.

Is there a way in VBScript to simulate for-in in JavaScript? That is, iterate over the keys, rather than the values, of a collection?

Nope, sorry.

 

Why does VBScript have Execute, ExecuteGlobal and Eval?

JavaScript has an extremely powerful (and almost always misused, but that’s another story) feature: eval takes a string at runtime and treats that string as though it were part of the compile-time text of the program. I added that feature to VBScript version 5, but I did it with three methods: Execute ExecuteGlobaland Eval

Why three, when JavaScript makes do with one? Let’s start by examining in detail what the JavaScript eval function does.

The JavaScript eval function takes a string, treats the string as JScript code, compiles the string, executes the resulting code, and returns the value of the last expression evaluated while running the code.

In JavaScript (and many other C-like languages) there is a fairly weak distinction between a statement and an expression. For example, this is perfectly legal JavaScript:

function foo()
{
  1;
  2;
  3 + 4;
}

This doesn’t do much; it doesn’t even return a value! But that’s not the compiler’s
problem. The behaviour of the statement 3+4; for instance is to add three to four and discard the result.

Also note that semicolons are semi-optional; more on that in a later post.

When you say eval("3+4") in JavaScript you get seven — the compiler adds the semicolon on, executes the statement 3+4; and returns the result of the last expression computed.

Now consider how JavaScript evaluates expressions that reference variables. The implementation of evalis smart enough to follow JScript’s rules for inner scopes shadowing outer scopes:

var x = 20;
function foo()
{
  var x = 10;
  print(eval("x"));
  // 10 -- eval uses local
}

This seems reasonable. But what if you evaluate a declaration?

var x = 20;
function foo()
{
  eval("var x = 10");
}
foo();
print(x);
// 20 -- declaration was local to foo.

Maybe it’s silly to want to add a declaration using eval. But hold on: as we already discussed, named functions are basically just variables with functions as values. Suppose you wanted to add a function dynamically:

function foo()
{
  eval("function bar(){ return 123; }");
  print(bar()); // 123
}
foo();
print(bar()); // fails

Why does the latter fail? Because the eval is done in the activation of the function foo, so function bar is local to foo. When the activation of foo goes away, so does local bar

The long and short of it is that if you want to affect the global name space, you have to do it explicitly. For example:

var bar;
function foo()
{
  eval("function barlocal(){ return 123; } bar = barlocal;");
}
foo();
print(bar());
// succeeds, bar is a global function.

(And of course, bar now refers to a closure. If foo took any arguments, they would be captured by barlocal.)

Now suppose you were tasked with implementing eval in VBScript, as I was. A few salient facts might spring to mind:

  • VBScript doesn’t have first class functions, so this trick with assigning a local function into global scope won’t work. (VBScript has a very weak form of first class functions that I’ll discuss later.)
  • But contrariwise, it would be a real pain in the rear if the VBScript’s eval equivalent couldn’t access local variables, and worked only at global scope.
  • VBScript does not have this weird property that expressions are statements. In fact, you can’t determine whether you’re looking at an expression or a statement lexically thanks to the assignment and equality operators being the same. Suppose you see X=Y — does that mean “set variable X to the value of Y” or does that mean “compare X to Y, leave both the same, and produce True or False“? Obviously we want to be able to do both, but how do we tell the difference?

There are three things that we need to do:

  • evaluate expressions
  • execute statements using local scope
  • execute statements using global scope.

My philosophy is when you have three things to do, implement three methods. Hence, we have Eval, which takes an expression and returns its value, Execute, which takes a group of statements and executes them in local scope, and ExecuteGlobal which executes them in global scope.

“I understand why you need to distinguish between Eval and Execute,” I hear you say, “but why have both Execute and ExecuteGlobal? Why not just add an optional IsGlobal flag to Execute?

Good question. First of all, in my opinion it is bad coding style to implement public methods which have very different behaviour based on the value of a flag.  You do two things, have two methods.

Second, Boolean flags are a bad idea because sometimes you want to extend the method even more. VBScript has this problem in the runtime — a lot of the methods take an argument which is either 0 for “case insensitive” or 1 for “case sensitive” or a valid LCID, for “case sensitive in this locale”. What a mess! (Worse, 1 is a valid locale identifier: Arabic-with-neutral-sublanguage.)

In the case at hand, I suppose an enumerated type would be superior to a Boolean and extensible to boot, but still, it makes my skin crawl to see one public method that does two things based on a flag where two methods will do.


Commentary from 2019:

This article produced some interesting reader responses:


You do have a ExecuteGlobal of sorts in JavaScript using the new Function(…) notation. When you define a function in this way, it uses in the global scope rather than the containing scope. Add to that the JavaScript “feature” where variables declared without var are added to the global scope, and you get the effect of a ExecuteGlobal.

Good point; use it like this:

var x = 20;
function foo()
{
  var x = 30;
  var bar = new Function("x = 10");
  bar();
}
print(x); // 20

It seems that eval cannot distinguish between block statements and object literals! Compare eval("value={1:2,3:4}") to value=eval("{1:2,3:4}");

Great example! eval takes a statement; An object literal is not a legal statement, and so automatic semi insertion will not insert a semi.

Arrrrr! Cap’n Eric be learnin’ about threadin’ the harrrrd way

Avast ye scurvy dogs, it be National Talk Like A Pirate Day!

A scurvy bilge rat commented on the preceding discussion about putting apartment threaded objects in Session scope:

Back in the era of the NT4 Option Pack I wrote a lot of code that involved stashing Scripting.Dictionary objects in both session and application scope. […] I forget now which version of the runtime changed the threading model they were registered with and broke everything for me.

Shiver me timbers! That be my fault. Sorry about that.

When you create an ActiveX object, the COM runtime code checks the registry to see if the object is marked as participating in the Apartment, Free or Both threading models.  We’ll go into the difference between Free and Both at another time.

(UPDATE: I don’t believe I ever did.)

Now, when I was a young swabbie seven years ago I was given the task of implementing the Scripting.Dictionary object, and I didn’t yet understand all the stuff I just told you maties about threading.  In one build that was released to the public I accidentally marked the dictionary as Both, even though it is a Single Threaded Apartment object. So when lubbers would put a dictionary into Session scope, it would be called by multiple threads at multiple times, in violation of the apartment contract.  As long as there were only readers, it was generally OK, but as soon as there were readers and writers, it would usually crash and die.

And of course when we corrected the mistake, all those pages went from sometimes-crashing-but-fast to not-crashing-but-slow. That was my first majorly customer-impacting mistake, and probably the worst I ever personally made.

(UPDATE: Surely I have made worse since, but it really was very bad. Our code review protocols were not strong in those days. More on that below.)

Speaking of mistakes, there was another interesting performance mistake in early releases of the Scripting.Dictionary object. It uses a very simple hash table for rapid lookup, but of course hash tables require that the hash function distribute hashes broadly given a narrow distribution of keys.  I screwed up the hash algorithm, and one of the consequences was that hashing on a string consisting of five digits was likely to go to a very small number of hash buckets.

We discovered all this the day that msn.com decided to store every zip code in the United States in a Scripting.Dictionary object in Session scope!  Perf of msn.com went way south, way fast.

The combination of the two mistakes above led the ASP team to write their own string table object, that really was Both threaded and blindingly fast. Arr!


There was a lot of good reader response to this article, and a number of commenters went with the silly pirate theme:

So yer the bilge rat who caused that! I meant to ask you about it, arrr. To this day I be not using dictionary object because of a bad experience with it building some scurvy shopping carts.

When I boarded Microsoft a few years back for some Commerce Server demos, I asked a mate there about that bug (and if it still existed). He was most scurvy in his reply. Yarrr.

By the way, why was On Error Goto 0 not documented in earlier versions VBScript? Some lubber VB developer suggested that I try it, and I was very surprised back then that it worked. Were there any other undocumented scurvy features like that? What about easter eggs? Aarr.

Arr, you have to keep in mind that the VBScript documentation “team” at the time was one guy. Actually, not even one guy — Fred spent some time documenting other stuff as well I believe. Now, don’t get me wrong — Fred was a great guy, a lot of fun to work with, and very competent. But there simply was not enough time, budget and manpower to do a really proper job on the script engine documentation. A few things fell through the cracks now and then.

Documentation is extremely expensive. Writing it the first time is not so bad. Translating every page into 26 languages, that gets real expensive real fast.

Arrr! Havin’ spilled the beans, swabby, you best be protectin’ ye precious cannon balls from enemy swords. Many a tall ship crashed on the rocks of the Scripting.Dictionary. Aye, she was a most gnarly beast, for sure.

So, how did a green eared bilge monkey (I mean that in the nicest piratey way) like you come to possess the Scripting.Dictionary beast with nary a review by a superior officer? The captain must surely have been afire that day with many unruly mates on the plank, no?

Well, bygones begone, mate! Let’s heave a pint with a merry yo ho to brave Lippert’s mighty confession this day!

Arr, we certainly had code reviews, but the script team in the early days was pretty cowboyish.

The dictionary object shared its registration code with an object that really was Both threaded, and that fact led to the defect. In that situation even experienced code reviewers fall into the trap of “this code has been reviewed before, we can skip reviewing it this time.” As time went on we became more and more hard core about reviewing every line of every change.

ARR! So ye be the scurvy squad what made yon Dictionary object walk th’ plank! If I was a younger man, I’d a’ strung ya up and keelhauled ye afterwards!

Seriously, though — as much of a mistake that was, it’s good to see that you’re willing to owe up to it. It’s probably not proof against making an even bigger and more far-reaching mistake, but it also says a lot about the caliber of person you are.

Have you yourself ever used any third-party components to replace the Dictionary object, that are also thread-safe? And if so, which one(s)?

As I mentioned in the original article, the ASP team wrote their own “lookup table component”, which you used to be able to download from their site. I have no idea where it is now though.

 

Hard Core Denotational Semantics

Some of the readers of the Lambda blog were discussing my earlier throwaway line about Waldemar Horwat:

The august Waldemar Horwat — who was at one time the lead Javascript developer at AOL-Time-Warner-Netscape — once told me that he considered Javascript to be just another syntax for Common Lisp. I’m pretty sure he was being serious.

One user commented:

Mozilla’s CVS tree still contains the original implementation of Javascript… written in Common Lisp.

I can’t look at the Mozilla sources for legal reasons, so I can’t say for sure.  However, if you look at the drafts of the ECMAScript 4 specification that Waldemar was writing when he worked at Netscape, you’ll see that he uses this denotational semantics metalanguage to describe the operation of the ECMAScript language.  (This stands in marked contrast to the vague operational semantics used for the same purpose in the ECMAScript 1, 2 and 3 specifications.)

I vaguely recall that Waldemar had built a reference implementation of ECMAScript 4 in his metalanguage, and an implementation of the metalanguage in Common Lisp.  (Like I said, that guy is hard core.)  I hypothesize that this is the thing that the Lambda reader was talking about.  If someone could confirm or deny my hypothesis for me, I’d be interested to know.  It is unfortunate that I’m unable to look at this stuff, as I’m sure it would be fascinating.


UPDATE: This article makes a distinction between denotational semantics and operational semantics, and I could have taken the opportunity when it was originally published to discuss the difference in more detail.

Briefly: both are techniques for describing the semantics of a programming language. Denotational semantics is a more formal, mathematical approach where we associate programming language elements with mathematical objects, and then combinations of programming elements must be compositions of those objects.

Operational semantics is a more “algorithmic” approach where you describe what operations a virtual machine that implements the language would take. The original ECMAScript specifications were written as operational semantics. The ECMAScript 4 spec famously never shipped, and E5 went back to operational semantics.

The C# specification was deliberately written to mostly use neither technique; there are a few places where an operational approach is used, but the goal was to not have any “higher math” in the C# spec. It’s written in more or less plain English, and does not even carefully define important words such as “type”.

 

Why is it a bad idea to put script objects in Session scope?

Often a web site will have a series of related pages requested one after the other by the same user. As a convenience for the site developers, the ASP object model provides a Session object to store server-side state for a current user. It also has a global Application object which stores state for an entire virtual root.

Every so often some ASP coder out there tries to put a JScript or VBScript object into the Session or Applicationobject. Things usually start going horribly wrong shortly thereafter — either terrible performance ensues or things just break outright.

Well, like Groucho says, if it hurts when you do that, don’t do that! Understanding
why this is a bad idea will take us yet deeper into the land of threading models.

I mentioned earlier that when you have an apartment threaded object, you need to be in the right apartment (thread) if you want to talk to its occupants (object instances). But what if you are not? What if you are running some code in thread Alpha that really needs to call a method on an object running in thread Beta? Fortunately, COM provides a mechanism called cross-thread marshaling to achieve this.

The behind-the-scenes details are not particularly important to our discussion; suffice to say that windows messages are involved. The important thing to know is that when you marshal a call across threads the calling thread pauses until the called thread responds. That seems reasonable — after all, when you call an ordinary function you sort of “pause” until the function returns.

But threads are usually busy doing something.  If the called thread is not responding to messages because it is busy doing work of its own then the calling thread waits, and waits, and waits…

To continue with our previous apartment threading analogy, it is rather like each apartment has a mailbox. If you’re in apartment Beta and you need someone in apartment Alpha to do something for you, you write up a request and hand it to the mailman who in turn sticks it in Alpha’s mailslot. Alpha’s occupants might be busy doing work and ignoring their mail, or they may have a huge stack of mail to get through, or they might get right on it. You, over in apartment Beta, can’t do anything but wait for the mailman to deliver their reply.

And of course, even if the callee thread is completely responsive and ready to service your request, obviously calling across threads is orders of magnitude more expensive than calling in-thread. An in-thread call requires some arguments to be put on the stack and maybe stash a few values in registers. A cross-thread call gets the operating system involved in a comparatively deep and complex way.

Now you have enough information to figure out why putting script objects in Session scope is a bad idea as far as performance is concerned.

Each ASP page is running on its own thread from the thread pool. The thread that reads the object from session state will likely not be the thread that put the object there, but the script object is apartment threaded. That means that essentially any page that accesses that session object must wait its turn for all other pages using that session object to finish up, because the marshaling code blocks the calling thread until the callee is available.  You end up with a whole lot of blocking threads, and blocking threads are not fast.

Application scope is even worse — if you put a script object in Application scope then every page in the entire vroot that accesses the Application object must wait its turn for the original thread to be free. You’ve effectively single-threaded your web server.

But it gets worse. Remember, when the page is done being served up, the engine is torn down. The compiled state remains, but the runtime state is thrown away. So suppose you have a JScript object sitting in the Session object, and the page that put it there was destroyed a few microseconds ago and the engine put back into the engine pool. Now on another page in the same session you try to fetch the JScript object and call a method on it. Where’s the runtime state associated with that object? It’s gone, dude.

When the script engine is torn down after the original page is served, the teardown code detects that there are existing objects that are owned by external callers. The script engine can’t destroy these objects, otherwise the caller would crash when the caller tried to destroy them later. That’s a fundamental rule of COM — you can’t destroy an object to which someone holds a reference.

But we know that the object is going to be useless, so what we do is tell the object “the engine you require for life is going away. Throw away everything you own and become a zombie.”

These zombie objects look like script objects, but when you actually try to do something to them — call a method, fetch a property, whatever — they don’t actually do anything. They can’t — all the infrastructure they need to live is gone, but they can’t die. Basically they wander the night in ghostly torment until they are freed by whatever code is holding the reference.

So not only are those script objects sitting in Sessionstate wrecking your performance, they’re not even useful for anything once the original page goes away.

Incidentally, Windows Script Components each have their own engine which stays alive as long as they do, so WSC’s are not affected by the zombie issue. They are still apartment threaded though.

But wait, it gets worse.

JScript arrays are objects, so everything said above applies to them. VBScript arrays are not objects (more on the differences between these two kinds of arrays later) but even still, you shouldn’t put them in Session scope either. Though they do not suffer from the threading problems or the lifetime problems mentioned above, arrays are stored into and passed out of Session scope using our old friend copy-in-copy-out semantics. That means that every single time you index into an array in Session scope, a copy of the array is made first. If that array is big, that’s a big performance problem.

Why do we do copy-in-copy-out? Because arrays are not marshaled! We return to the fundamental problem: what if two pages tried to read and write the array in the Session object at the same time? The memory could be corrupted. We really don’t have any good way to synchronize access to the array, so instead we simply make a complete copy of it every time someone tries to read or write it. This is extremely expensive, but it keeps the server heap from being corrupted. A corrupted web server heap can ruin your whole day.

My advice is to not even go there. Don’t put information into Session​ scope unless you absolutely have to.  If you must, put in strings. There are lots of ways to store arrays or objects as strings and reconstitute them as needed.

How does Active Server Pages use the script engines?

It’s always struck me as a little bit odd that Active Server Pages, a web server, encourages developers to use VBScript and JScript to write server-side scripts.  I mean, the whole point of a web server is that it produces complex strings (web pages are just strings of HTML after all) as blindingly fast as possible, on demand.  “Blindingly fast” and “script language” do not really go together, compared to, say, C.

My opinions — and you’d better believe I have plenty of strong ones! — on performance characteristics of the script engines will certainly come back in future posts.  But for now I want to talk a little bit about what features we added to the script engines to make them work as well as they do for ASP.

One of the ways you make a server fast is by caching everything you possibly can cache.  For example, suppose you need to do a job on a separate thread.  You’d probably create a thread, do some work on the thread, and throw it away when you’re done.  OK, now suppose you need to do a million jobs but never more than, say, three at a time. Creating and destroying those million threads is potentially going to be a not-insignificant amount of the total processor time spent.  You’d be better off creating three threads and re-using them as necessary.

This strategy is called “thread pooling”, and ASP certainly uses it. ASP caches a lot more than that though.  It also pools script engines and caches compiled state.  Let me explain with an example.

Suppose a request comes in for this page, time.asp:

<% Response.write Now() %>

Suppose further that this is the first-ever request for this page since the server was started.

The thing above isn’t a legal script, so ASP parses out the non-script blocks and stores them in the Response object.  It then generates a real script that looks something like

Response.WriteBlock 0
Response.Write Now()
Response.WriteBlock 1

ASP also has a pool of created-but-not-initialized script engines sitting around.  I said in my last post that when the script engines are not initialized they can be called on any thread, so it does not matter that these engines were not created on whatever thread happened to be pulled out of the thread pool.

ASP initializes the engine on the current thread and passes in the script code above.  The script engine compiles the script, runs it, and the ASP object model sends the resulting string off to the client.

The script engine then gets uninitialized, but does not throw away its compiled state.  The compiled state – the proprietary bytecode form of the language – is maintained in memory because the second time someone asks for that page, ASP do not want to have to go through all the time and expense of translating the page to script and compiling the script to bytecode.

The thread and the now-uninitialized engine go back to their respective pools.

Now suppose a second request comes in for time.asp.  This time ASP pulls a thread out of the thread pool, notices that it has an engine with the compiled state just sitting there, attaches the engine to the thread, and runs the script again.  No time is spent creating the thread, creating the script engine, translating the page to code or compiling the script to bytecode.

Suppose further that in the few milliseconds that ASP is running this script, a third request comes in for this page.  Then what happens?  There are two obvious possibilities:

  • Wait for the current engine to finish, and start it right back up again when it is done.
  • Fetch a new engine from the engine pool and start over – translate the page to script, compile, run.

The trouble is, both of those are potentially slow.  The first in particular could be extremely slow. We needed a third option.

In my previous post I discussed the trouble you can get into with multithreading.  The problem I described happens because two threads tried to both read and write a particular variable.  If the variable was read-only, then obviously there would not have been a problem.  You can read a read-only variable from as many threads as you want!

But once the script engine compiles a script into bytecode, that bytecode is read-only.  It’s never going to change again.  This means that two script engines on two different threads can share bytecode!

You can call Clone from any thread.  This takes an existing script engine and gives you a new script engine with exactly the same compiled state, but able to run on a different thread. Each engine maintains its own runtime state – variable values, etc – but the compiled state is shared.

So in this scenario, ASP clones the running engine onto another thread and then runs the new engine concurrently.  This is somewhat expensive – it has to create a new engine, after all – but is much cheaper than compiling up all that state again.

Of course, ASP is much more complicated than that quick sketch.  What I’m getting at here is that there actually is some rhyme and reason to our bizarre-seeming choices of threading model.

The script engine design was driven by the need to solve a very specific set of very disparate problems.  Without knowing what the problems were, the resulting design looks kind of random.  But once you know the history, well, I guess it looks a little less random.

What are threading models, and what threading model do the script engines use?

I’ve got a few ideas for some future posts that depend on the reader understanding a little bit about COM threading. Since I myself understand only a little bit about COM threading, I’ll just do a brain dump for you all right here.

I’m sure you all know about multi-threaded applications. The idea is that the operating system switches back and forth between threads within a process using a scheduling algorithm of some sort. When a thread is “frozen” all the context for that thread — basically, the values of the registers in the processor — is saved, and when it is “thawed” the state is restored and the thread continues like it was never interrupted.

That works great right up to the point where two threads try to access the same memory at the same time. Consider, for example, the standard implementation of IUnknown::Release():

ULONG MyClass::Release()
{
  --this->m_cRef;
  if (this->m_cRef == 0)
  {
    delete this;
    return 0;
  }
  return this->m_cRef;
}

Now suppose the ref count is two and two threads try to each do a single release. That should work just fine, right?

Wrong. The problem is that though --this->m_cRef looks like a single “atomic” operation, the compiler actually spits out code that acts something vaguely like this pseudo-code:

  • this is stored in Register1
  • copy address of m_cRef field to Register2 (which is an offset from Register1)
  • copy contents of address stored in Register2 to Register3
  • decrease contents of Register3 by one
  • copy contents of Register3 back to address stored in Register2
  • compare contents of Register3 to zero, store Boolean result of comparison in Register4
  • if Register4 is false then return contents of Register3
  • And so on; do the deletion, return zero

Notice that the compiler can be smart and re-use the contents of Register3 instead of fetching this->m_cRef three times. The compiler knows that no one has changed it since the decrease.

Suppose we have a red thread and a blue thread. Each has their own registers. Suppose the processor schedules them in this order:

  • copy address of m_cRef field of Register1 to Register2
  • copy contents of address stored in Register2 to Register3

CONTEXT SWITCH TO BLUE

At this point we save Register1 = redthis, Register2 = red &m_cRef, Register3 = 2

  • copy address of m_cRef field of Register 1 to Register 2
  • copy contents of address stored in Register 2 to Register 3

CONTEXT SWITCH TO RED

At this point we save Register1 = blue this, Register2 = blue &m_cRef, Register3 = 2and restore the red registers.

  • decrease contents of Register3 by one
  • copy contents of Register3 to address stored in Register2
  • compare contents of Register3 to zero, store Boolean result of comparison in Register4
  • if Register4 is false then return contents of Register3
  • Register 4 is false because Register3 = 1, so this returns 1.

CONTEXT SWITCH TO BLUE

Restore Register1 = blue this, Register2 = blue &m_cRef, Register3 = 2

And now you see where this is going, I’m sure. Because the original value was stored in the red thread before the blue thread decremented it, we’ve lost a decrement.  Both threads will return 1. This object’s ref count will never go to zero, and its memory will leak. A similar problem plagues AddRef — you can lose increment operations, which causes memory to be freed too soon, which is even worse.

How do we solve this problem? Basically there are two ways to do it:

  • Do the necessary work to ensure thread safety, or
  • Require your callers to behave in a manner such that you never get into this situation in the first place.

The operating system provides tools to make multi-threaded programming work. There are methods like InterlockedIncrement, which really do “atomically” bump up a counter. Signals and semaphores and critical sections and all the other tools you need to make multi-threaded programs are available. I’m not going to talk much about those.

Writing a truly free-threaded program is a lot of work. There are a lot of ways to get it wrong, and there are potential performance pitfalls as well. Fortunately, there is a middle ground between “only one thread allowed” and “any thread can call any method at any time”.

The idea of the COM threading models is to provide a contract between callers and callees so that, as long as both sides follow the contract, situations like the one above never come to pass.

Suppose a caller has several instances of an object (the callee), and the caller has several threads going. The commonly used standard threading contracts are as follows:

  • Single threaded — all calls to all instances of the object must always be on the same thread. There are no synchronization issues because there is always only one thread no matter how many object instances there are. The caller is responsible for ensuring that all calls to all instances are on the same thread.
  • Free threaded — calls to the object can be on any thread at any time, including multiple threads at the same time. The object is responsible for all synchronization issues.
  • Apartment threaded — all calls to any given instance of the object must always be on the same thread, but different instances can be called on different threads at the same time. The caller is responsible for ensuring that given an instance, all calls to that instance happen on the same thread. The object is responsible for synchronizing access to global (that is, not-per-instance) data that it owns.

An analogy might help. Think of an apartment building where each apartment is a thread and each person is an object instance. You can put as many people into one apartment as you want, and you can put people into lots of different apartments, but once you’ve done so, you always have to go to a person’s apartment if you want to talk to them.  Why? Because they never move out once they’re in an apartment, you have to wait for them to die before they ever leave.  (Insert New Yorker joke here.)

Furthermore, you can’t talk “through the walls” from one apartment to someone in another apartment.  (Well, actually you can — that’s called “marshaling”, and that’s a subject for a future post.)  And finally, if the people jointly own a shared resource — say, a rooftop barbecue, to stretch this silly analogy to its limit — then they must sort out amongst themselves how to synchronize access to the shared resource.

  • Rental threaded — calls to an object can be on any thread but the caller guarantees that only one thread is calling into the object at any time. Rental threading requires a different analogy: suppose the object instances are rented televisions and again  threads are apartments.  A television can be moved from apartment to apartment but can never be in more than one apartment at the same time. Multiple televisions can be in the same apartment, and multiple apartments can have multiple televisions.  But if you want to watch a television, you have to go to the apartment where it is.

Whew, that was a long preamble. How does this pertain to the script engines?

Most COM objects — almost all ActiveX objects, and all of the object models commonly used by script — are apartment threaded objects. They expect that multiple instances of the object can be created on multiple threads, but once an instance is created on a thread, it will always be called on that thread. This gives us the best of both worlds — the caller can be free threaded and can create multiple objects on multiple threads, but the callee does not have to synchronize access to any per-instance data.

But the script engines are free threaded objects. The script engines must ensure that they do not violate the apartment model contract.

So guess what? The script engines actually have a bizarre, custom contract that is a little more restrictive than free threading and less restrictive than apartment threading!

The script engine contract is as follows:

  • When the script engine is in a state where it cannot possibly call an ActiveX object — for instance, if it has just been created and has not started running code, or if it is just about to be shut down — then the script engine really is free threaded, but who cares? It can’t do much in this state.
  • When the script engine is initialized — when the script engine host has started the process of passing code and object model state to the engine — the script engine morphs into an apartment threaded object. All calls to the script engine must be on the initializing thread until the script engine is shut down again.
  • There are two exceptions to the previous rule — the InterruptScriptThread and Clone methods can always be called from any thread.

The remainder of this post was truncated in a previous blog migration; I’ll go back into my archives at some point and see if I can find the rest of it, but you get the idea.

There was a fair amount of reader responses to this post. I noted that I wanted to write an article describing how Active Server Pages used these mechanisms, particularly how setTimeout works; I do not think I ever did write those articles. I noted also that I could describe how timeouts worked from the perspective of continuation passing style; this seemed like an academic point to me at the time, but of course now, post “async/await” and so on, we can see how important CPS-like transformations are in modern programming languages.

There was also some discussion of how to write truly multi-threaded code in IE. That always struck me as a bad idea; if your code is processor bound then maybe don’t do it in the browser; if it is IO-bound then use an async callback, not a thread. Of course, in 2003 we did not have the mechanisms necessary to do so nearly so easily as we do now.