Unknown's avatar

About ericlippert

http://ericlippert.com

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.

 

How Do The Script Garbage Collectors Work?

NOTE: This article was written in 2003. Since that time the JavaScript garbage collector has been completely rewritten multiple times, so as to be more performant in general, to handle the larger working sets entailed by modern web applications that we had absolutely no idea were coming when we designed the JScript GC back in 1995, to be better at predicting when there is garbage that needs collecting, and to be better at handling circular references involving browser objects.

I did not do any of that work; I stopped working on scripting in 2001. I do not know how the modern JavaScript GC works. This article should be considered “for historical purposes only”; it does not reflect how JavaScript works today.


JScript and VBScript both are automatic storage languages. Unlike, say, C++, the script developer does not have to worry about explicitly allocating and freeing each chunk of memory used by the program. The internal device in the engine which takes care of this task for the developer is called the garbage collector.

Interestingly enough though, JScript and VBScript have completely different garbage collectors. Occasionally people ask me how the garbage collectors work and what the differences are.

JScript uses a nongenerational mark-and-sweep garbage collector. It works like this:

  • Every variable which is “in scope” is called a “scavenger”. A scavenger may refer to a number, an object, a string, whatever.
  • We maintain a list of scavengers — variables are moved on to the scavenger list when they come into scope and off the list when they go out of scope.
  • Every now and then the garbage collector runs.
  • First it puts a “mark” on every object, variable, string, etc – all the memory tracked by the GC. JScript uses the VARIANT data structure internally and there are plenty of extra unused bits in that structure, so we just set one of them.
  • Second, it clears the mark on the scavengers and the transitive closure of scavenger references. So if a scavenger object references a non-scavenger object then we clear the bits on the non-scavenger, and on everything that it refers to. (I am using the word “closure” in a different sense than in my earlier post.)
  • At this point we know that all the memory still marked is allocated memory which cannot be reached by any path from any in-scope variable.
  • All of those objects are instructed to tear themselves down, which destroys any circular references.
  • Actually it is a little more complex than that, as we must worry about details like “what if freeing an item causes a message loop to run, which handles an event, which calls back into the script, which runs code, which triggers another garbage collection?” But those are just implementation details.
  • Incidentally, every JScript engine running on the same thread shares a GC, which complicates the story even further.)

You’ll note that I hand-waved a bit there when I said “every now and then…” What we do is keep track of the number of strings, objects and array slots allocated. We check the current tallies at the beginning of each statement, and when the numbers exceed certain thresholds we trigger a collection.

The benefits of this approach are numerous, but the principle benefit is that circular references are not leaked unless the circular reference involves an object not owned by JScript.

However, there are some down sides as well.

Performance is potentially not good on large-working-set applications — if you have an app where there are lots of long-term things in memory and lots of short-term objects being created and destroyed then the GC will run often and will have to walk the same network of long-term objects over and over again. That’s not fast.

The opposite problem is that perhaps a GC will not run when you want one to. If you say blah = null then the memory owned by blah will not be released until the GC releases it. If blah is the sole remaining reference to a huge array or network of objects, you might want it to go away as soon as possible.

You can force the JScript garbage collector to run with the CollectGarbage() method, but I don’t recommend it. The whole point of JScript having a GC is that you don’t need to worry about object lifetime. If you do worry about it then you’re probably using the wrong tool for the job.

VBScript, on the other hand, has a much simpler stack-based garbage collector. Scavengers are added to a stack when they come into scope, removed when they go out of scope, and any time an object is discarded it is immediately freed.

You might wonder why we didn’t put a mark-and-sweep GC into VBScript. There are two reasons. First, VBScript did not have classes until version 5, but JScript had objects from day one; VBScript did not need a complex GC because there was no way to get circular references in the first place! Second, VBScript is supposed to be like VB6 where possible, and VB6 does not have a mark-n-sweep collector either.

The VBScript approach pretty much has the opposite pros and cons. It is fast, simple and predictable, but circular references of VBScript objects are not broken until the engine itself is shut down.

The CLR GC is also mark-n-sweep but it is generational – the more collections an object survives, the less often it is checked for life. This dramatically improves performance for large-working-set applications. Of course, the CLR GC was designed for industrial-grade applications, the JScript GC was designed for simple little web pages.

What happens when you have a web page, ASP page or WSH script with both VBScript and JScript? JScript and VBScript know nothing about each others garbage collection semantics. A VBScript program which gets a reference to a JScript object just sees another COM object. The same for a VBScript object passed to JScript. A circular reference between VBScript and JScript objects would not be broken and the memory would leak (until the engines were shut down). A noncircular reference will be freed when the object in question goes out of scope in both language (and the JS GC runs.)


This article created a large amount of feedback when it was first published, much of it, oddly enough, reacting negatively to the phrase “the JScript GC was designed for simple little web pages”.

I have no idea why this fact would elicit such strong reactions. The JScript GC, and everything else about JScript, was designed for simple little web pages. We designed it in 1995! As I have said many times: in 1995 the by-design purpose for JavaScript on a web page was “make the monkey dance when you move the mouse”. The idea that there would be a hundred thousand lines of Javascript frameworks downloaded for typical web pages was absurd. We literally designed the script engines assuming that one-line event handlers would be typical, thirty lines would be plausible, and a thousand lines would be crazy, but we should test it.

In a similar vein, Brendan Eich (the original designer of JavaScript who stepped down as CEO of Mozilla after it came to light that he donated to anti-equality causes) weighed in to note that the algorithm that predicted when to collect was deeply flawed and could produce poor behaviour in pages that allocate a lot of memory. That was completely correct. The collection trigger was designed for simple little web pages, not for scenarios in which the collector could exhibit quadratic behaviour under load.

You can certainly make the argument that all of this should have been improved as it became more obvious that large-scale programs were being written in JavaScript, a language which was then very unsuitable for large-scale programs. I made that argument myself. I did not stop improving the script engines by my choice; my team was de-funded. Take it up with Bill Gates, not me.

What are closures?

NOTE: This article was written in 2003; the circular-reference memory leak bug described here was fixed in IE shortly after this article was written. This blog archive is for historical purposes; go ahead and use closures today.


JavaScript, as I noted yesterday, is a functional language. That doesn’t mean that it works particularly well (though I hope it does) but rather that it treats functions as first-class objects. Functions can be passed around and assigned to variables just as strings or integers can be.

A reader commented yesterday that “closures are your friends”. Unfortunately there are important situations where closures are not your friends! Let’s talk a bit about those. First off, what’s a closure? Consider the following (contrived and silly, but pedagocially clear) code:

function AddFive(x) {
  return x + 5;
}
function AddTen(x) {
  return x + 10;
}
var MyFunc;
if (whatever)
  MyFunc = AddFive;
else
  MyFunc = AddTen;
print(MyFunc(123)); // Either 133 or 128.

Here we have a typical functional scenario. We’re deciding which function to call based on some runtime test. Now, one could imagine that you’d want to generalize this notion of an “adder function”, and you would not want to have to write dozens and dozens of adders. What we can do is create an adder factory:

function AdderFactory(y) {
  return function(x){return x + y;}
}
var MyFunc;
if (whatever)
  MyFunc = AdderFactory(5);
else
  MyFunc = AdderFactory(10);
print(MyFunc(123)); // Either 133 or 128.

The anonymous inner function remembers what the value of y was when it was returned, even though y has gone away by the time the inner function is called! We say that the inner function is closed over the containing scope, or for short, that the inner function is a closure.

This is an extremely powerful functional language feature, but it is important to not misuse it. There are ways to cause memory-leak-like situations using closures. Here’s an example:

< div id="myMenu" class="menu-bar" > </ div >
var menu = document.getElementById('myMenu');
AttachEvent(menu);
function AttachEvent(element) {
  element.attachEvent("onmouseover", mouseHandler);
  function mouseHandler(){ /* whatever */ }
}

Someone has, for whatever reason, nested the handler inside the attacher. This means that the handler is closed over the scope of the caller; the handler keeps around a reference to element which is equal to menu, which is that div. But the div has a reference to the handler.

That’s a circular reference.

The garbage collector is a mark-and-sweep collector so you’d think that it would be immune to circular references. But the div isn’t a JavaScript object; it is not in the JavaScript collector, so the circular reference between the div and the handler will not be broken until the browser completely tears down the div. Which never happens.

Doesn’t IE tear down the div when the page is navigated away? Though IE did briefly do that, the application compatibility lab discovered that there were actually web pages that broke when those semantics were implemented. (No, I don’t know the details.) The IE team considers breaking existing web pages that used to work to be worse than leaking a little memory here and there, so they’ve decided to take the hit and leak the memory in this case.

Don’t use closures unless you really need closure semantics. In most cases, non-nested functions are the right way to go.


Reader responses:

How can you say that JavaScript is a functional language?

I take an expansive view of what makes a functional language: it is a language that supports programming in a functional style, not a language that forces you to program in a functional style. Enforcing side-effect free programming like Haskell does is not a requirement of functional languages, and indeed if we made that requirement then many languages that people consider to be clearly functional, like Scheme and OCaml, would have to be considered non-functional.

Are JScript strings passed by reference?

Yesterday I asked “are JScript strings passed by reference (like objects) or by value (like numbers)?”

Trick question! It doesn’t matter, because you can’t change a string. Suppose they were passed by reference — how would you know? You can’t have two variables refer to the “same” string and then change that string. Strings are like numbers — immutable primitive values. (Note that JavaScript, unlike VBScript, does not support passing variables by reference at all. The question here is about whether the value passed as an argument is a reference to the string or a copy of the string.)

Of course, “under the covers” we actually have to pass the strings somehow. Generally speaking, strings are passed by reference where possible, as it is much cheaper in both time and memory to pass a pointer to a string than to make a copy, pass the value, and then destroy the copy.

That said, unfortunately there are scenarios in which strings are passed by reference, and then the callee immediately makes a copy of the string. Strings are represented internally as BSTRs which are not reference counted, so you have to make a copy if you want to express ownership.