Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

VBScript is compiled to pcode, then pcode interpreted at runtime.

276 views
Skip to first unread message

Michael D. Kersey

unread,
Dec 8, 1999, 3:00:00 AM12/8/99
to
> The following information was posted by Juan T. Llibre [MVP]j.ll...@codetel.net.do in another topic("Newbie > The best and fastest way to get a recordset") in this newsgroup. The information therein is significant > enought that IMO it deserves publication as a separate topic.

Juan T. Llibre [MVP]j.ll...@codetel.net.do wrote:

Please excuse the HTML send, but there's quite a few long sentences [
and words...;>) ] in this post.

Since we're back on a purely technical discussion track,
here's what I've found out on this extremely interesting thread :

First of all, to address the point of whether the script engines are
compilers or not: yes and no.
(Just the kind of answer you expect to get from Microsoft, I suppose.
:-) )

The script engines compile into a proprietary bytecode format.

It's an utterly simple, unoptimized bytecode language, hardly more than
a linearization of the parse tree.
However, it's more sophisticated than a "classic" BASIC interpreter --
which is essentially just a tokenizer.

So in a sense it is both a compiler -- it does fully parse and compile
the code before execution
rather than merely lexically analyze each line -- and a bytecode
interpreter.

There's a tool to debug the code generator that dumps the bytecodes out
in human-readable format.

Consider this program:

Function Fib(n)
If n = 1 Or n = 2 Then
Fib = 1
Else
Fib = Fib(n-1) + Fib(n-2)
End If
End Function

window.alert Fib(5)

----- Here's the bytecode generated -----

Dump of EXEC at 00E563B0:
Function count = 1

Global code [max stack = 3]:
flags = (8000) noconnect
Pcode:
0000 OP_FnBind 'Fib' 1 PUBL
***BOS(135,154)*** window.alert Fib(5) *****
000A OP_Bos1 0
000C OP_NamedAdr 'window'
0011 OP_IntConst 5
0013 OP_CallNmdAdr 'Fib' 1
001A OP_CallMemVoid 'alert' 1
0021 OP_Bos0
0022 OP_FuncEnd

Function 1 ('Fib') [max stack = 3]:
flags = (8000) noconnect
arg count = 1
arg -1 = ref Variant 'n'
lcl count = 0
Pcode:
***BOS(21,43)*** If n = 1 Or n = 2 Then *****
0000 OP_Bos1 0
0002 OP_LocalAdr -1
0005 OP_IntConst 1
0007 OP_FixType
0008 OP_EQ
0009 OP_LocalAdr -1
000C OP_IntConst 2
000E OP_FixType
000F OP_EQ
0010 OP_BitOr
0011 OP_JccFalse 0023
***BOS(53,60)*** Fib = 1 *****
0016 OP_Bos1 1
0018 OP_IntConst 1
001A OP_LocalSt 0
001D OP_Bos0
001E OP_Jmp 0043
***BOS(80,105)*** Fib = Fib(n-1) + Fib(n-2) *****
0023 OP_Bos1 2
0025 OP_LocalAdr -1
0028 OP_IntConst 1
002A OP_Sub
002B OP_CallNmdAdr 'Fib' 1
0032 OP_LocalAdr -1
0035 OP_IntConst 2
0037 OP_Sub
0038 OP_CallNmdAdr 'Fib' 1
003F OP_Add
0040 OP_LocalSt 0
***BOS(119,131)*** End Function *****
0043 OP_Bos1 3
0045 OP_FnReturn
0046 OP_Bos0
0047 OP_FuncEnd

-----

By examining this bytecode sequence you can easily figure out how it
works.

There's a number of blocks that represent functions (and global code),
and those consist of a series of statements.
Statements are separated by BeginningOfStatement ( BOS ) codes.
The virtual machine is a simple stack machine with no registers.

Here's how Active Server Pages works :

First of all, the server maintains a cache of threads and a cache of
script engines.
Suppose a request comes in for this page, time.asp:

<html>
<% Response.write Now() %>
</html>

The first thing the server does is check to see if this page has been
compiled already.
Suppose it hasn't. It then transforms the ASP source code into script
source code.

It generates

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

ASP then fetches a thread from the thread pool, an engine from the
engine pool, and associates that engine with that thread.

It creates a Response object which has been initialized with the blocks
"<html>" and "</html>"
so that WriteBlock writes the correct code out to the HTML stream.

It passes the Response object to the script engine, passes the code in,
compiles it and runs it.
Once the run is complete, that engine goes back to the script engine
pool and the thread goes back to the thread pool.

Now suppose another request for time.asp comes in.

This time, ASP realizes that there already IS an engine in the pool that
has the compiled state!

So it grabs a thread, grabs the engine, adds the Response object to it
again, and runs the code.
No need to compile the code the second time -- the script engine already
has that state.

Now, suppose that time.asp is taking a while -- there might be a loop in
there or something --
and another request comes in before the first one is done.

This time ASP realizes "I have the compiled state but the engine is
already running on one thread".

So ASP calls a free-threaded function on the script engine "Clone",
which creates a new identical engine with the SAME compiled state as the
first.

This is more expensive than allocating a new engine but it is cheaper
than allocating a new engine AND re-compiling the code.
So now there are two threads and two engines running the same code, and
when they're done, they both go back to the pool.

The caches are designed so that in typical scenarios the code only needs
to be compiled once.
If the cache ever gets full, obviously state will be thrown away and
will have to be re-compiled later.

All the details of the symbol tables, the compiled code blocks, etc, are
managed by the script engine.

The ASP engine merely knows how to "reset" the engines (so that the
engine believes that none of the code
has been run yet and hence needs to be re-executed) and how to make new
engines cloned from old ones.

And of course how to turn .asp's into script code.
-----------

Thanks to Microsoft's Scripting Engine's Program Manager for this
detailed explanation.

So, it turns out that, essentially, Michael was right and both Aaron and
I were mistaken,
at least on the "compilation" part.

Though Michael wasn't 100% on target, he was closer to the truth than we
were.
That doesn't let you off the hook, Michael, for all the unneeded "ad
hominem" and "marketing ploy" stuff, though.
I had mentioned several times that you don't need to indulge in that
sort of wasted logic !

What's important is getting to the bottom of technical certainty.
As far as THAT is concerned, you'll always have all of my undivided
attention, effort and good will.

regards,


Juan T. Llibre
Director, Computer Sciences School
Universidad Nacional Pedro Henríquez Ureña
Microsoft Internet Development MVP [IIS/ASP]
Co-Author : "Beginning Active Server Pages 2.0"
ASP Resource : http://asptracker.com/
====================================

0 new messages