Massive SemA/BC refactoring to support better type systems. Read on for more.
authorDavid Anderson <dvander@alliedmods.net>
Sat Nov 17 18:41:01 2012 -0800 (2012-11-17)
changeset 195c1ba166f3fc4
parent 194 b029d63565a2
child 196 9904633b1dfc
Massive SemA/BC refactoring to support better type systems. Read on for more.

The previous compiler had a simple pipeline, best outlined as:
(1) Parsing and name binding -> AST
(2) Storage allocation -> AST
(3) Semantic Analysis (SemA) -> AST
(4) Bytecode Compilation (BC) -> Code

This pipeline, unfortunately, had two problems. First, name binding cannot be performed in one pass if we wish to have multi-file support in the form of modules. Name binding must be two-pass.

Second, because SemA was only capable of annotating AST nodes with a single type, most coercion work had to be duplicated in the BC phase, as coercion was not explicit in the SemA output. This made introducing new type rules extremely difficult, and all but precluded concepts like operator overloading (or overloading at all).

This patch rewrites most of Keima's backend. Of interest are the following changes:
(1) CompileContext has been refactored around future multi-file support.
(2) Parsing no longer performs any name binding.
(3) The grammar for type-and-name has been changed from:
(Label | Identifier)? Identifier
to:
Type? Identifier
where:
Type ::= OldType | NewType
OldType ::= Label
NewType ::= Identifier (. NewType)*


Although we do not implement the full production for Type yet, this
distinction is important. A type identifier is now affixed to the AST
as an Expression (right now, always a NameProxy), so it can fully
participate in name binding.

(4) Immediately after parsing, the AST goes through a NamePopulation phase.
This phase creates Scope objects for every scope which declares a name,
and if those names are declaring types or functions, a Symbol is created
and entered into the scope. Symbols entirely replace the old BoundName
classes.

(5) After NamePopulation comes NameBinding. This phase performs three steps:
(a) Links Scope objects together, to form a tree.
(b) Binds any free name to an existing name in the scope chain.
(c) Creates and registers any Symbols for names which have not yet been
added to the scope (for example, local variables).

In accordance, all "allocation" and "binding" concepts have been removed
from Scopes, which are now lightweight container classes.

(6) SemA now generates bytecode for each statement in the AST. Expression
compilation is performed via a separate mechanism called HIR (High-level
Intermediate Representation). To analyze an expression, SemA will walk
the AST, and produce a HIR object for each node. HIR is typed, and SemA
may insert coercion nodes, or even expand an AST node into multiple HIR
nodes. The result of evaluating an expression in SemA is therefore the
the root of a HIR tree, which SemA then sends to the HIRTranslator, which
performs bytecode generation.

As before, SemA still performs full semantic analysis. However, not it
also produces each function's bytecode.

This split allows us to decompose potentially complex semantics into
a more fine-grained, AST-like structure, which can have very simple
code-generation logic. For example, (1.0 + 5) might look like:

HAdd(HFloat(1.0), HConvert(HInteger(5), <Float>))

As part of this decomposition, many opcodes have been removed. Rather than
using typed jumps, we now expand jumps into longer tests. For example:
jge.f <label>
becomes:
ge.f
cvt.f2b
jt <label>

This simplifies the pipeline, and JITs should be able to melt the added
work away.

HIR is not used at a statement level, and HIR does not have any concept
of control-flow.

(7) The old BytecodeCompiler has been removed, as its work is now split
between SemA and HIRTranslator.


In addition, some minor refactorings have taken place:

(1) Opcodes.tbl no longer hardcodes numbers (aaah).
(2) Type has been split into smaller, typed structs.
(3) BytecodeEmitter no longer relies on Pools or RootScopes.
(4) SemA is now responsible for variable/storage allocation.
(5) Native table are now global, rather than per-module. As such, native
declarations now result in a Native object (which still requires a
CALLNATIVE opcode), which is an index into the global table. Natives
must be bound globally. This is in preparation for module support.
(6) Publics are no longer tracked, but rather registered via a global
callback upon module load. This callback can be set by embedders. This
is in preparation for multi-file support.
(7) The BytecodeEmitter now performs Symbol allocations itself, and it
also generates Code objects itself, which removes a good deal of
complexity.

Finally, a test harness has been added. This harness is a python script which finds *.test files, recursively, in the tests folder. For each file it runs the corresponding .sp. The contents of the .test file must match stdout+stderr.
include/keima.h
include/keima_util.h
src/API.cpp
src/AST.h
src/BytecodeCompiler.cpp
src/BytecodeCompiler.h
src/BytecodeEmitter.cpp
src/BytecodeEmitter.h
src/Code.h
src/CompileContext.cpp
src/CompileContext.h
src/Environments.cpp
src/Functions.cpp
src/Functions.h
src/GlobalRoots.cpp
src/GlobalRoots.h
src/Handles.h
src/HashTable.h
src/Interpreter.cpp
src/Messages.tbl
src/Modules.cpp
src/Modules.h
src/NameBinding.cpp
src/NameBinding.h
src/NativeTable.cpp
src/NativeTable.h
src/ObjectVisitor.h
src/Objects.h
src/OldByCo.cpp
src/OldByCo.h
src/OldSema.cpp
src/OldSema.h
src/Opcodes.cpp
src/Opcodes.h
src/Opcodes.tbl
src/Parser.cpp
src/Parser.h
src/PoolAllocator.cpp
src/PoolAllocator.h
src/QualType.h
src/Reference.cpp
src/Reference.h
src/Scanner.cpp
src/Scanner.h
src/Scopes.cpp
src/Scopes.h
src/SemanticAnalysis.cpp
src/SemanticAnalysis.h
src/Stack.cpp
src/StringPool.h
src/Strings.h
src/Structures.cpp
src/Structures.h
src/Token.h
src/TypeManager.cpp
src/TypeManager.h
src/Types.cpp
src/Types.h
src/Utility.h
src/Vector.h
src/VirtualObjectVisitor.h
src/Zone.cpp
src/Zone.h
src/comment
src/compiler/AST.h
src/compiler/BytecodeEmitter.cpp
src/compiler/BytecodeEmitter.h
src/compiler/CompileContext.cpp
src/compiler/CompileContext.h
src/compiler/HIR.cpp
src/compiler/HIR.h
src/compiler/NameBinding.cpp
src/compiler/NameBinding.h
src/compiler/Parser.cpp
src/compiler/Parser.h
src/compiler/Scanner.cpp
src/compiler/Scanner.h
src/compiler/Scopes.cpp
src/compiler/Scopes.h
src/compiler/SemanticAnalysis.cpp
src/compiler/SemanticAnalysis.h
src/compiler/Symbols.cpp
src/compiler/Symbols.h
src/compiler/Token.h
src/jitcraft.vcxproj
src/main.cpp
tests/basic/floats.out
tests/basic/floats.sp
tests/display.py
tests/harness.py
tests/prototype/floats.sp
tests/test.py
     1.1 --- a/include/keima.h	Mon Sep 17 00:10:01 2012 -0700
     1.2 +++ b/include/keima.h	Sat Nov 17 18:41:01 2012 -0800
     1.3 @@ -43,6 +43,7 @@
     1.4  template <typename T>
     1.5  class Handle
     1.6  {
     1.7 +    template <typename S> friend class Root;
     1.8    protected:
     1.9      template <typename S> void typeCheck() {
    1.10          while (false) {
    1.11 @@ -111,46 +112,45 @@
    1.12  };
    1.13  
    1.14  /*
    1.15 - * A non-local variable that outlives HandleScopes. A Root is reference-
    1.16 - * counted. When its reference count reaches 0, the Root is removed.
    1.17 + * A non-local variable that outlives HandleScopes. Unlike Local, a Root
    1.18 + * actually represents a rooted location. Roots must be allocated and
    1.19 + * disposed, and assignment to a root changes its contained object, not
    1.20 + * the location of the object.
    1.21   */
    1.22  template <typename T>
    1.23 -class Root : public Handle<T>
    1.24 +class Root
    1.25  {
    1.26    public:
    1.27 -    Root<T>()
    1.28 -      : Handle<T>()
    1.29 +    Root()
    1.30 +      : root_(NULL)
    1.31      {
    1.32      }
    1.33  
    1.34 -    Root<T>(const Root<T> &other)
    1.35 -      : Handle<T>(reinterpret_cast<T *>(*other))
    1.36 +    Root(Handle<T> other)
    1.37 +      : root_(NULL)
    1.38      {
    1.39 -        incref();
    1.40 +        set(other);
    1.41      }
    1.42  
    1.43 -    explicit Root(ke::HeapRoot *obj)
    1.44 -      : Handle<T>(reinterpret_cast<T *>(obj))
    1.45 -    {
    1.46 -incref();
    1.47 +    inline ~Root();
    1.48 +
    1.49 +    operator const Handle<T>() const {
    1.50 +        return obj_;
    1.51      }
    1.52  
    1.53 -    static inline Root<T> New(Handle<T> other);
    1.54 -
    1.55 -    ~Root() {
    1.56 -        decref();
    1.57 +    bool operator ==(Handle<T> other) {
    1.58 +        return Handle<T>(*this) == other;
    1.59      }
    1.60 -
    1.61 -    Root<T> &operator =(const Root<T> &other) {
    1.62 -        decref();
    1.63 -        this->obj_ = other.obj_;
    1.64 -        incref();
    1.65 +    Root<T> &operator =(Handle<T> other) {
    1.66 +        set(other);
    1.67          return *this;
    1.68      }
    1.69  
    1.70    private:
    1.71 -    void incref();
    1.72 -    void decref();
    1.73 +    void set(Handle<T> other);
    1.74 +
    1.75 +    ke::HeapRoot *root_;
    1.76 +    Handle<T> obj_;
    1.77  };
    1.78  
    1.79  /*
    1.80 @@ -211,7 +211,8 @@
    1.81  class IStackFrameIterator
    1.82  {
    1.83    public:
    1.84 -    virtual ~IStackFrameIterator() { }
    1.85 +    virtual ~IStackFrameIterator() {
    1.86 +    }
    1.87  
    1.88      // Returns true if there are more frames, false otherwise.
    1.89      virtual bool done() = 0;
    1.90 @@ -232,6 +233,20 @@
    1.91      virtual void prev() = 0;
    1.92  };
    1.93  
    1.94 +// Listener interface for when public functions are registered or unregisted.
    1.95 +class IPublicFunctionListener
    1.96 +{
    1.97 +  public:
    1.98 +    virtual ~IPublicFunctionListener() {
    1.99 +    }
   1.100 +
   1.101 +    // Called when a public function becomes available to the runtime.
   1.102 +    virtual void registerPublic(Handle<Function> fun) = 0;
   1.103 +
   1.104 +    // Called when a public is no longer available to the runtime.
   1.105 +    virtual void unregisterPublic(Handle<Function> fun) = 0;
   1.106 +};
   1.107 +
   1.108  // A string is an immutable UTF8 buffer.
   1.109  class KE_EXPORT String
   1.110  {
   1.111 @@ -253,21 +268,6 @@
   1.112      Local<String> name();
   1.113  };
   1.114  
   1.115 -// A native is an ISourcePawnEngine-compatible function provided by C++.
   1.116 -class KE_EXPORT Native
   1.117 -{
   1.118 -  public:
   1.119 -    // Returns the name of a native, which is never NULL. The string is
   1.120 -    // guaranteed to be interned.
   1.121 -    Local<String> name();
   1.122 -
   1.123 -    // Returns the function pointer of the native.
   1.124 -    void *function();
   1.125 -
   1.126 -    // Sets the function pointer of the native.
   1.127 -    void bind(void *function);
   1.128 -};
   1.129 -
   1.130  // A pubvar is an ISourcePawnEngine-compatible structure that holds information
   1.131  // about public variables.
   1.132  class KE_EXPORT Pubvar
   1.133 @@ -283,21 +283,9 @@
   1.134  class KE_EXPORT Module
   1.135  {
   1.136    public:
   1.137 -    // Returns publics that are based on forwards.
   1.138 -    unsigned numPublics();
   1.139 -    Local<Function> getPublic(unsigned index);
   1.140 -
   1.141 -    // Returns natives.
   1.142 -    unsigned numNatives();
   1.143 -    Local<Native> getNative(unsigned index);
   1.144 -
   1.145      // Sets the native identity pointer, which is passed as the first argument
   1.146      // to natives.
   1.147      void setNativeIdentity(void *ptr);
   1.148 -
   1.149 -    // Returns the number of public variables.
   1.150 -    unsigned numPubvars();
   1.151 -    Local<Pubvar> getPubvar(unsigned index);
   1.152  };
   1.153  
   1.154  class Keima
   1.155 @@ -346,7 +334,23 @@
   1.156       */
   1.157      static void InstallMessageReporter(IMessageReporter *reporter);
   1.158  
   1.159 +    /* Returns a new stack frame iterator object. */
   1.160      static IStackFrameIterator *NewStackFrameIterator();
   1.161 +
   1.162 +    /*
   1.163 +     * Binds a native, by name, to an address. Natives are an ISPE1 concept
   1.164 +     * (originally from Pawn/Small's AMX API). In SourceMod 1, natives were
   1.165 +     * registered globally, but bound to plugins individually. We roughly
   1.166 +     * preserve that functionality here, by allowing host applications to
   1.167 +     * give us the name -> address mappings.
   1.168 +     *
   1.169 +     * Natives can be rebound or unbound any number of times. This function
   1.170 +     * fails if there is not enough memory.
   1.171 +     */
   1.172 +    static bool BindNative(const char *name, void *address);
   1.173 +
   1.174 +    /* Sets the object that will listen for public functions. */
   1.175 +    static void SetPublicFunctionListener(IPublicFunctionListener *listener);
   1.176  };
   1.177  
   1.178  /*
   1.179 @@ -470,37 +474,37 @@
   1.180      template <typename T> friend class Root;
   1.181  
   1.182    private:
   1.183 -    static ke::HeapRoot *NewHeapRoot(ke::Object **objp);
   1.184 -    static void IncRef(ke::HeapRoot *root);
   1.185 -    static void DecRef(ke::HeapRoot *root);
   1.186 +    static ke::HeapRoot *NewHeapRoot();
   1.187 +    static void Destroy(ke::HeapRoot *root);
   1.188  };
   1.189  
   1.190 -template <typename T> Root<T>
   1.191 -Root<T>::New(Handle<T> other)
   1.192 +template <typename T> void
   1.193 +Root<T>::set(Handle<T> other)
   1.194  {
   1.195 -    if (!other)
   1.196 -        return Root<T>();
   1.197 +    if (!other) {
   1.198 +        obj_ = other;
   1.199 +        return;
   1.200 +    }
   1.201 +
   1.202      ke::Object **ptr = reinterpret_cast<ke::Object **>(*other);
   1.203 -    return Root<T>(Internals::NewHeapRoot(ptr));
   1.204 +    if (!root_) {
   1.205 +        root_ = Internals::NewHeapRoot();
   1.206 +        if (!root_)
   1.207 +            return;
   1.208 +    }
   1.209 +
   1.210 +    *reinterpret_cast<ke::Object **>(root_) = *ptr;
   1.211 +    obj_.obj_ = reinterpret_cast<T *>(root_);
   1.212  }
   1.213  
   1.214 -template <typename T> void
   1.215 -Root<T>::incref()
   1.216 +template <typename T>
   1.217 +Root<T>::~Root()
   1.218  {
   1.219 -    if (!*this)
   1.220 +    if (!root_)
   1.221          return;
   1.222 -    ke::HeapRoot *ptr = reinterpret_cast<ke::HeapRoot *>(**this);
   1.223 -    Internals::IncRef(ptr);
   1.224 +    Internals::Destroy(root_);
   1.225  }
   1.226  
   1.227 -template <typename T> void
   1.228 -Root<T>::decref()
   1.229 -{
   1.230 -    if (!*this)
   1.231 -        return;
   1.232 -    ke::HeapRoot *ptr = reinterpret_cast<ke::HeapRoot *>(**this);
   1.233 -    Internals::DecRef(ptr);
   1.234 -}
   1.235  
   1.236  }
   1.237  
     2.1 --- a/include/keima_util.h	Mon Sep 17 00:10:01 2012 -0700
     2.2 +++ b/include/keima_util.h	Sat Nov 17 18:41:01 2012 -0800
     2.3 @@ -1,4 +1,5 @@
     2.4 -/*
     2.5 +/* vim: set ts=4 sw=4 tw=99 et:
     2.6 + *
     2.7   * Copyright (C) 2004-2012 David Anderson
     2.8   *
     2.9   * This file is part of SourcePawn.
    2.10 @@ -26,6 +27,23 @@
    2.11  # endif
    2.12  #endif
    2.13  
    2.14 +// 64-bit detection.
    2.15 +#if defined(_M_X64) || defined(__64bit__)
    2.16 +# define KE_64BIT
    2.17 +#endif
    2.18 +
    2.19 +// 32-bit detection.
    2.20 +#if defined(_M_IX86) || defined(__i386__)
    2.21 +# if defined KE_64BIT
    2.22 +#  error "Detected 32-bit and 64-bit!"
    2.23 +# endif
    2.24 +# define KE_32BIT
    2.25 +#endif
    2.26 +
    2.27 +#if !defined(KE_32BIT) && !defined(KE_64BIT)
    2.28 +# error "Could not detect CPU type"
    2.29 +#endif
    2.30 +
    2.31  #if !defined(KE_EXPORT)
    2.32  # define KE_EXPORT
    2.33  #endif
     3.1 --- a/src/API.cpp	Mon Sep 17 00:10:01 2012 -0700
     3.2 +++ b/src/API.cpp	Sat Nov 17 18:41:01 2012 -0800
     3.3 @@ -20,11 +20,7 @@
     3.4  #include "../include/keima.h"
     3.5  #include "Zone.h"
     3.6  #include "RootScopes.h"
     3.7 -#include "CompileContext.h"
     3.8 -#include "Parser.h"
     3.9 -#include "Scopes.h"
    3.10 -#include "SemanticAnalysis.h"
    3.11 -#include "BytecodeCompiler.h"
    3.12 +#include "compiler/CompileContext.h"
    3.13  #include "Modules.h"
    3.14  #include "GlobalRoots.h"
    3.15  #include "Reference.h"
    3.16 @@ -32,6 +28,7 @@
    3.17  #include "Interpreter.h"
    3.18  #include "Stack.h"
    3.19  #include "Strings.h"
    3.20 +#include "NativeTable.h"
    3.21  #include "Spaces-inl.h"
    3.22  #include "Heap-inl.h"
    3.23  
    3.24 @@ -94,76 +91,25 @@
    3.25      return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
    3.26  }
    3.27  
    3.28 -static ke::Module *
    3.29 -CompileFromSource(CompileContext &cc, const char *path, const char *stream, size_t length)
    3.30 -{
    3.31 -    Parser parser(ZONE(), cc, stream, length);
    3.32 -    ParseTree *tree = parser.parse();
    3.33 -    if (!tree)
    3.34 -        return NULL;
    3.35 -    tree->dump(stdout);
    3.36 -
    3.37 -    if (!Scope::Bind(cc, tree))
    3.38 -        return NULL;
    3.39 -
    3.40 -    SemanticAnalysis semantics(ZONE(), cc, tree);
    3.41 -    if (!semantics.analyze())
    3.42 -        return NULL;
    3.43 -
    3.44 -    Scope::Allocate(tree);
    3.45 -
    3.46 -    BytecodeCompiler compiler(ZONE(), tree, NULL);
    3.47 -    ke::Local<Module> module(ke::ZONE(), compiler.compile());
    3.48 -    if (!module)
    3.49 -        return NULL;
    3.50 -
    3.51 -    ke::InvokeArgs args;
    3.52 -    if (!ke::ZONE()->stack().pushModuleFrame(module, args))
    3.53 -        return NULL;
    3.54 -    if (!ke::Interpret(ke::ZONE(), NULL, NULL))
    3.55 -        return NULL;
    3.56 -
    3.57 -    return module;
    3.58 -}
    3.59 -
    3.60  ke::Module *
    3.61  InternalCompile(const char *path)
    3.62  {
    3.63 +    PoolScope poolScope(ZONE()->pool());
    3.64      RootScope roots(ZONE());
    3.65      CompileContext cc(ZONE(), path);
    3.66  
    3.67 -    char *bytes = NULL;
    3.68 -    size_t length;
    3.69 -    {
    3.70 -        FILE *fp = fopen(path, "rb");
    3.71 -        if (!fp) {
    3.72 -            cc.reportError(SourcePosition(), Message_CantOpenFile);
    3.73 -            return NULL;
    3.74 -        }
    3.75 +    TranslationUnit *unit = new (ZONE()->pool()) TranslationUnit();
    3.76 +    unit->path_ = path;
    3.77  
    3.78 -        if (fseek(fp, 0, SEEK_END)) {
    3.79 -            cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
    3.80 -            fclose(fp);
    3.81 -            return NULL;
    3.82 -        }
    3.83 -        long size = ftell(fp);
    3.84 -        if (size < 0) {
    3.85 -            cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
    3.86 -            fclose(fp);
    3.87 -            return NULL;
    3.88 -        }
    3.89 -        rewind(fp);
    3.90 -        length = size_t(size);
    3.91 -        bytes = new char[length + 1];
    3.92 -        if (fread(bytes, 1, length, fp) != length) {
    3.93 -            cc.reportError(SourcePosition(), Message_ErrorReadingFile);
    3.94 -            fclose(fp);
    3.95 -            delete [] bytes;
    3.96 -            return NULL;
    3.97 -        }
    3.98 -        fclose(fp);
    3.99 -    }
   3.100 +    if (!cc.addTranslationUnit(unit))
   3.101 +        return NULL;
   3.102  
   3.103 +    if (!cc.compile())
   3.104 +        return NULL;
   3.105 +
   3.106 +    return NULL;
   3.107 +
   3.108 +#if 0
   3.109      ke::Local<ke::Module> module(ZONE(),  CompileFromSource(cc, path, bytes, length));
   3.110      delete [] bytes;
   3.111      if (!module)
   3.112 @@ -175,6 +121,8 @@
   3.113  
   3.114      module->setPath(pathstr);
   3.115      return module;
   3.116 +#endif
   3.117 +    return NULL;
   3.118  }
   3.119  
   3.120  // This is split out from InternalCompile so the RootScope doesn't conflict
   3.121 @@ -238,10 +186,9 @@
   3.122  }
   3.123  
   3.124  ke::HeapRoot *
   3.125 -Ke::Internals::NewHeapRoot(ke::Object **ptr)
   3.126 +Ke::Internals::NewHeapRoot()
   3.127  {
   3.128 -    ke::Local<ke::Object> obj(ZONE(), *ptr);
   3.129 -    ke::HeapRoot *root = ke::ZONE()->globalRoots()->create(obj);
   3.130 +    ke::HeapRoot *root = ke::ZONE()->globalRoots()->create();
   3.131      if (!root)
   3.132          return NULL;
   3.133  
   3.134 @@ -250,15 +197,9 @@
   3.135  }
   3.136  
   3.137  void
   3.138 -Ke::Internals::IncRef(ke::HeapRoot *root)
   3.139 +Ke::Internals::Destroy(ke::HeapRoot *root)
   3.140  {
   3.141 -    ZONE()->globalRoots()->incref(FromAPI(root));
   3.142 -}
   3.143 -
   3.144 -void
   3.145 -Ke::Internals::DecRef(ke::HeapRoot *root)
   3.146 -{
   3.147 -    ZONE()->globalRoots()->decref(FromAPI(root));
   3.148 +    ZONE()->globalRoots()->destroy(FromAPI(root));
   3.149  }
   3.150  
   3.151  bool
   3.152 @@ -280,40 +221,6 @@
   3.153      ke::ZONE()->clearPendingException();
   3.154  }
   3.155  
   3.156 -unsigned
   3.157 -Ke::Module::numPublics()
   3.158 -{
   3.159 -    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   3.160 -    if (!module->publics())
   3.161 -        return 0;
   3.162 -    return module->publics()->length();
   3.163 -}
   3.164 -
   3.165 -Ke::Local<Ke::Function>
   3.166 -Ke::Module::getPublic(unsigned index)
   3.167 -{
   3.168 -    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   3.169 -    ke::Local<ke::Function> fun(ke::ZONE(), ke::Function::cast(module->publics()->at(index)));
   3.170 -    return ToLocal<ke::Function, Ke::Function>(fun);
   3.171 -}
   3.172 -
   3.173 -unsigned
   3.174 -Ke::Module::numNatives()
   3.175 -{
   3.176 -    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   3.177 -    if (!module->natives())
   3.178 -        return 0;
   3.179 -    return module->natives()->length();
   3.180 -}
   3.181 -
   3.182 -Ke::Local<Ke::Native>
   3.183 -Ke::Module::getNative(unsigned index)
   3.184 -{
   3.185 -    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   3.186 -    ke::Local<ke::Native> fun(ke::ZONE(), ke::Native::cast(module->natives()->at(index)));
   3.187 -    return ToLocal<ke::Native, Ke::Native>(fun);
   3.188 -}
   3.189 -
   3.190  void
   3.191  Ke::Module::setNativeIdentity(void *identity)
   3.192  {
   3.193 @@ -342,20 +249,6 @@
   3.194      return ToLocal<ke::String, Ke::String>(fun->name());
   3.195  }
   3.196  
   3.197 -Ke::Local<Ke::String>
   3.198 -Ke::Native::name()
   3.199 -{
   3.200 -    ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
   3.201 -    return ToLocal<ke::String, Ke::String>(native->name());
   3.202 -}
   3.203 -
   3.204 -void
   3.205 -Ke::Native::bind(void *function)
   3.206 -{
   3.207 -    ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
   3.208 -    native->bind(function);
   3.209 -}
   3.210 -
   3.211  static inline const char *
   3.212  GetInvokeTypeName(Ke::Parameter::Type type)
   3.213  {
   3.214 @@ -535,3 +428,25 @@
   3.215      *retval = result.i32;
   3.216      return true;
   3.217  }
   3.218 +
   3.219 +bool
   3.220 +Ke::Keima::BindNative(const char *name, void *address)
   3.221 +{
   3.222 +    return ke::ZONE()->nativeTable()->bind(name, address);
   3.223 +}
   3.224 +
   3.225 +void
   3.226 +Ke::Keima::SetPublicFunctionListener(IPublicFunctionListener *listener)
   3.227 +{
   3.228 +    ke::ZONE()->setPublicFunctionListener(listener);
   3.229 +}
   3.230 +
   3.231 +void
   3.232 +Zone::registerPublic(ke::Handle<Function> fun)
   3.233 +{
   3.234 +    if (!publicFunctionListener_)
   3.235 +        return;
   3.236 +
   3.237 +    Ke::Local<Ke::Function> local = ToLocal<ke::Function, Ke::Function>(fun);
   3.238 +    publicFunctionListener_->registerPublic(local);
   3.239 +}
     4.1 --- a/src/AST.h	Mon Sep 17 00:10:01 2012 -0700
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,1171 +0,0 @@
     4.4 -/* vim: set ts=4 sw=4 tw=99 et:
     4.5 - *
     4.6 - * Copyright (C) 2012 David Anderson
     4.7 - *
     4.8 - * This file is part of SourcePawn.
     4.9 - *
    4.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
    4.11 - * the terms of the GNU General Public License as published by the Free
    4.12 - * Software Foundation, either version 3 of the License, or (at your option)
    4.13 - * any later version.
    4.14 - * 
    4.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    4.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    4.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    4.18 - *
    4.19 - * You should have received a copy of the GNU General Public License along with
    4.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
    4.21 - */
    4.22 -#ifndef _include_sourcepawn_ast_h_
    4.23 -#define _include_sourcepawn_ast_h_
    4.24 -
    4.25 -#include "PoolAllocator.h"
    4.26 -#include "Token.h"
    4.27 -#include "NameBinding.h"
    4.28 -#include "Vector.h"
    4.29 -
    4.30 -namespace ke {
    4.31 -
    4.32 -#define ASTKINDS(_)             \
    4.33 -    _(VariableDeclaration)      \
    4.34 -    _(ForStatement)             \
    4.35 -    _(ReturnStatement)          \
    4.36 -    _(IntegerLiteral)           \
    4.37 -    _(FloatLiteral)             \
    4.38 -    _(StringLiteral)            \
    4.39 -    _(BinaryExpression)         \
    4.40 -    _(BlockStatement)           \
    4.41 -    _(Assignment)               \
    4.42 -    _(NameProxy)                \
    4.43 -    _(ExpressionStatement)      \
    4.44 -    _(FunctionStatement)        \
    4.45 -    _(CallExpression)           \
    4.46 -    _(IfStatement)              \
    4.47 -    _(IndexExpression)          \
    4.48 -    _(FieldExpression)          \
    4.49 -    _(EnumStatement)            \
    4.50 -    _(WhileStatement)           \
    4.51 -    _(BreakStatement)           \
    4.52 -    _(ContinueStatement)        \
    4.53 -    _(FunctionTypeStatement)    \
    4.54 -    _(IncDecExpression)         \
    4.55 -    _(UnaryExpression)          \
    4.56 -    _(TernaryExpression)        \
    4.57 -    _(BooleanLiteral)           \
    4.58 -    _(StructureStatement)       \
    4.59 -    _(SwitchStatement)          \
    4.60 -    _(ArrayLiteral)
    4.61 -
    4.62 -// Forward declarations.
    4.63 -#define _(name) class name;
    4.64 -ASTKINDS(_)
    4.65 -#undef _
    4.66 -
    4.67 -class AstVisitor;
    4.68 -
    4.69 -// Interface for AST nodes.
    4.70 -class AstNode : public PoolObject
    4.71 -{
    4.72 -    SourcePosition pos_;
    4.73 -
    4.74 -  public:
    4.75 -    enum Kind {
    4.76 -#       define _(name) k##name,
    4.77 -        ASTKINDS(_)
    4.78 -#       undef _
    4.79 -        AstKind_Invalid
    4.80 -    };
    4.81 -
    4.82 -    AstNode(const SourcePosition &pos)
    4.83 -      : pos_(pos)
    4.84 -    {
    4.85 -    }
    4.86 -    
    4.87 -    virtual Kind kind() const = 0;
    4.88 -
    4.89 -#define _(name)     bool is##name() { return kind() == k##name; }                   \
    4.90 -                    name *to##name() { assert(is##name()); return (name *)this; }   \
    4.91 -                    name *as##name() { if (!is##name()) return NULL; return to##name(); }
    4.92 -    ASTKINDS(_)
    4.93 -#undef _
    4.94 -
    4.95 -    virtual void accept(AstVisitor *visitor) = 0;
    4.96 -
    4.97 -    const SourcePosition &pos() const {
    4.98 -        return pos_;
    4.99 -    }
   4.100 -};
   4.101 -
   4.102 -class AstVisitor
   4.103 -{
   4.104 -  public:
   4.105 -#define _(name) virtual void visit(name *node) = 0;
   4.106 -    ASTKINDS(_)
   4.107 -#undef _
   4.108 -};
   4.109 -
   4.110 -class Statement : public AstNode
   4.111 -{
   4.112 -  public:
   4.113 -    Statement(const SourcePosition &pos)
   4.114 -      : AstNode(pos)
   4.115 -    {
   4.116 -    }
   4.117 -};
   4.118 -
   4.119 -class Expression : public AstNode
   4.120 -{
   4.121 -    ScopedRoot<Type> type_;
   4.122 -
   4.123 -  public:
   4.124 -    Expression(const SourcePosition &pos)
   4.125 -      : AstNode(pos),
   4.126 -        type_(NULL)
   4.127 -    {
   4.128 -    }
   4.129 -
   4.130 -    void setType(Type *type) {
   4.131 -        type_ = type;
   4.132 -    }
   4.133 -    Type *type() const {
   4.134 -        return type_;
   4.135 -    }
   4.136 -};
   4.137 -
   4.138 -typedef PoolList<Statement *> StatementList;
   4.139 -typedef PoolList<Expression *> ExpressionList;
   4.140 -
   4.141 -class VariableDeclaration : public Statement
   4.142 -{
   4.143 -    Variable *variable_;
   4.144 -    Expression *initialization_;
   4.145 -    ExpressionList *postDimensions_;
   4.146 -    BoundName *type_;
   4.147 -    TokenKind declarator_;
   4.148 -
   4.149 -  public:
   4.150 -    VariableDeclaration(const SourcePosition &pos, TokenKind declarator, Variable *var,
   4.151 -                        BoundName *type, ExpressionList *postDimensions,
   4.152 -                        Expression *initialization)
   4.153 -      : Statement(pos),
   4.154 -        variable_(var),
   4.155 -        initialization_(initialization),
   4.156 -        postDimensions_(postDimensions),
   4.157 -        type_(type),
   4.158 -        declarator_(declarator)
   4.159 -    {
   4.160 -    }
   4.161 -
   4.162 -    BoundName *type() const {
   4.163 -        return type_;
   4.164 -    }
   4.165 -    Kind kind() const {
   4.166 -        return kVariableDeclaration;
   4.167 -    }
   4.168 -    Variable *variable() const {
   4.169 -        return variable_;
   4.170 -    }
   4.171 -    Expression *initialization() const {
   4.172 -        return initialization_;
   4.173 -    }
   4.174 -    ExpressionList *postDimensions() const {
   4.175 -        return postDimensions_;
   4.176 -    }
   4.177 -    void accept(AstVisitor *visitor) {
   4.178 -        visitor->visit(this);
   4.179 -    }
   4.180 -    TokenKind declarator() const {
   4.181 -        return declarator_;
   4.182 -    }
   4.183 -};
   4.184 -
   4.185 -class Parameter : public PoolObject
   4.186 -{
   4.187 -    Variable *variable_;
   4.188 -    BoundName *type_;
   4.189 -    bool reference_;
   4.190 -    bool const_;
   4.191 -    ExpressionList *dimensions_;
   4.192 -    Expression *initializer_;
   4.193 -
   4.194 -  public:
   4.195 -    Parameter(Variable *var, BoundName *type, bool reference, bool isConst,
   4.196 -              ExpressionList *dimensions, Expression *initializer)
   4.197 -      : variable_(var),
   4.198 -        type_(type),
   4.199 -        reference_(reference),
   4.200 -        const_(isConst),
   4.201 -        dimensions_(dimensions),
   4.202 -        initializer_(initializer)
   4.203 -    {
   4.204 -    }
   4.205 -
   4.206 -    BoundName *type() const {
   4.207 -        return type_;
   4.208 -    }
   4.209 -    Variable *variable() const {
   4.210 -        return variable_;
   4.211 -    }
   4.212 -    bool reference() const {
   4.213 -        return reference_;
   4.214 -    }
   4.215 -    ExpressionList *dimensions() const {
   4.216 -        return dimensions_;
   4.217 -    }
   4.218 -    bool isConst() const {
   4.219 -        return const_;
   4.220 -    }
   4.221 -    Expression *initializer() const {
   4.222 -        return initializer_;
   4.223 -    }
   4.224 -};
   4.225 -
   4.226 -class NameProxy : public Expression
   4.227 -{
   4.228 -    ScopedRoot<String> name_;
   4.229 -    BoundName *binding_;
   4.230 -
   4.231 -  public:
   4.232 -    NameProxy(const SourcePosition &pos, Handle<String> name, BoundName *binding)
   4.233 -      : Expression(pos),
   4.234 -        name_(name),
   4.235 -        binding_(binding)
   4.236 -    {
   4.237 -    }
   4.238 -
   4.239 -    Kind kind() const {
   4.240 -        return kNameProxy;
   4.241 -    }
   4.242 -    String *name() const {
   4.243 -        return name_;
   4.244 -    }
   4.245 -    void accept(AstVisitor *visitor) {
   4.246 -        visitor->visit(this);
   4.247 -    }
   4.248 -    BoundName *binding() const {
   4.249 -        return binding_;
   4.250 -    }
   4.251 -    void bind(BoundName *name) {
   4.252 -        assert(!binding());
   4.253 -        binding_ = name;
   4.254 -    }
   4.255 -};
   4.256 -
   4.257 -class BooleanLiteral : public Expression
   4.258 -{
   4.259 -    TokenKind token_;
   4.260 -
   4.261 -  public:
   4.262 -    BooleanLiteral(const SourcePosition &pos, TokenKind token)
   4.263 -      : Expression(pos),
   4.264 -        token_(token)
   4.265 -    {
   4.266 -    }
   4.267 -
   4.268 -    Kind kind() const {
   4.269 -        return kBooleanLiteral;
   4.270 -    }
   4.271 -    TokenKind token() const {
   4.272 -        return token_;
   4.273 -    }
   4.274 -    void accept(AstVisitor *visitor) {
   4.275 -        visitor->visit(this);
   4.276 -    }
   4.277 -};
   4.278 -
   4.279 -class IntegerLiteral : public Expression
   4.280 -{
   4.281 -    int value_;
   4.282 -
   4.283 -  public:
   4.284 -    IntegerLiteral(const SourcePosition &pos, int value)
   4.285 -      : Expression(pos),
   4.286 -        value_(value)
   4.287 -    {
   4.288 -    }
   4.289 -
   4.290 -    Kind kind() const {
   4.291 -        return kIntegerLiteral;
   4.292 -    }
   4.293 -    int value() const {
   4.294 -        return value_;
   4.295 -    }
   4.296 -    void accept(AstVisitor *visitor) {
   4.297 -        visitor->visit(this);
   4.298 -    }
   4.299 -};
   4.300 -
   4.301 -class FloatLiteral : public Expression
   4.302 -{
   4.303 -    double value_;
   4.304 -
   4.305 -  public:
   4.306 -    FloatLiteral(const SourcePosition &pos, double value)
   4.307 -      : Expression(pos),
   4.308 -        value_(value)
   4.309 -    {
   4.310 -    }
   4.311 -
   4.312 -    Kind kind() const {
   4.313 -        return kFloatLiteral;
   4.314 -    }
   4.315 -    double value() const {
   4.316 -        return value_;
   4.317 -    }
   4.318 -    void accept(AstVisitor *visitor) {
   4.319 -        visitor->visit(this);
   4.320 -    }
   4.321 -};
   4.322 -
   4.323 -class StringLiteral : public Expression
   4.324 -{
   4.325 -    ScopedRoot<ByteArray> string_;
   4.326 -
   4.327 -  public:
   4.328 -    StringLiteral(const SourcePosition &pos, ByteArray *array)
   4.329 -      : Expression(pos),
   4.330 -        string_(array)
   4.331 -    {
   4.332 -    }
   4.333 -
   4.334 -    Kind kind() const {
   4.335 -        return kStringLiteral;
   4.336 -    }
   4.337 -    ByteArray *string() const {
   4.338 -        return string_;
   4.339 -    }
   4.340 -    void accept(AstVisitor *visitor) {
   4.341 -        visitor->visit(this);
   4.342 -    }
   4.343 -};
   4.344 -
   4.345 -class ArrayLiteral : public Expression
   4.346 -{
   4.347 -    TokenKind token_;
   4.348 -    ExpressionList *expressions_;
   4.349 -
   4.350 -  public:
   4.351 -    ArrayLiteral(const SourcePosition &pos, TokenKind token, ExpressionList *expressions)
   4.352 -      : Expression(pos),
   4.353 -        token_(token),
   4.354 -        expressions_(expressions)
   4.355 -    {
   4.356 -    }
   4.357 -
   4.358 -    Kind kind() const {
   4.359 -        return kArrayLiteral;
   4.360 -    }
   4.361 -    TokenKind token() const {
   4.362 -        return token_;
   4.363 -    }
   4.364 -    ExpressionList *expressions() const {
   4.365 -        return expressions_;
   4.366 -    }
   4.367 -    bool isFixed() const {
   4.368 -        return token_ == TOK_LBRACE;
   4.369 -    }
   4.370 -    void accept(AstVisitor *visitor) {
   4.371 -        visitor->visit(this);
   4.372 -    }
   4.373 -};
   4.374 -
   4.375 -class UnaryExpression : public Expression
   4.376 -{
   4.377 -    Expression *expression_;
   4.378 -    TokenKind token_;
   4.379 -    BoundName *type_;
   4.380 -
   4.381 -  public:
   4.382 -    UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr)
   4.383 -      : Expression(pos),
   4.384 -        expression_(expr),
   4.385 -        token_(token)
   4.386 -    {
   4.387 -    }
   4.388 -
   4.389 -    UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr,
   4.390 -                    BoundName *type)
   4.391 -      : Expression(pos),
   4.392 -        expression_(expr),
   4.393 -        token_(token),
   4.394 -        type_(type)
   4.395 -    {
   4.396 -    }
   4.397 -
   4.398 -    Kind kind() const {
   4.399 -        return kUnaryExpression;
   4.400 -    }
   4.401 -    Expression *expression() const {
   4.402 -        return expression_;
   4.403 -    }
   4.404 -    TokenKind token() const {
   4.405 -        return token_;
   4.406 -    }
   4.407 -    BoundName *type() const {
   4.408 -        return type_;
   4.409 -    }
   4.410 -    void accept(AstVisitor *visitor) {
   4.411 -        visitor->visit(this);
   4.412 -    }
   4.413 -};
   4.414 -
   4.415 -class BinaryExpression : public Expression
   4.416 -{
   4.417 -    Expression *left_;
   4.418 -    Expression *right_;
   4.419 -    TokenKind token_;
   4.420 -
   4.421 -  public:
   4.422 -    BinaryExpression(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
   4.423 -      : Expression(pos),
   4.424 -        left_(left),
   4.425 -        right_(right),
   4.426 -        token_(token)
   4.427 -    {
   4.428 -    }
   4.429 -
   4.430 -    Kind kind() const {
   4.431 -        return kBinaryExpression;
   4.432 -    }
   4.433 -    Expression *left() const {
   4.434 -        return left_;
   4.435 -    }
   4.436 -    Expression *right() const {
   4.437 -        return right_;
   4.438 -    }
   4.439 -    TokenKind token() const {
   4.440 -        return token_;
   4.441 -    }
   4.442 -    void accept(AstVisitor *visitor) {
   4.443 -        visitor->visit(this);
   4.444 -    }
   4.445 -};
   4.446 -
   4.447 -class TernaryExpression : public Expression
   4.448 -{
   4.449 -    Expression *condition_;
   4.450 -    Expression *left_;
   4.451 -    Expression *right_;
   4.452 -
   4.453 -  public:
   4.454 -    TernaryExpression(const SourcePosition &pos, Expression *condition, Expression *left, Expression *right)
   4.455 -      : Expression(pos),
   4.456 -        condition_(condition),
   4.457 -        left_(left),
   4.458 -        right_(right)
   4.459 -    {
   4.460 -    }
   4.461 -
   4.462 -    Kind kind() const {
   4.463 -        return kTernaryExpression;
   4.464 -    }
   4.465 -    Expression *condition() const {
   4.466 -        return condition_;
   4.467 -    }
   4.468 -    Expression *left() const {
   4.469 -        return left_;
   4.470 -    }
   4.471 -    Expression *right() const {
   4.472 -        return right_;
   4.473 -    }
   4.474 -    void accept(AstVisitor *visitor) {
   4.475 -        visitor->visit(this);
   4.476 -    }
   4.477 -};
   4.478 -
   4.479 -class IndexExpression : public Expression
   4.480 -{
   4.481 -    Expression *left_;
   4.482 -    Expression *right_;
   4.483 -
   4.484 -  public:
   4.485 -    IndexExpression(const SourcePosition &pos, Expression *left, Expression *right)
   4.486 -      : Expression(pos),
   4.487 -        left_(left),
   4.488 -        right_(right)
   4.489 -    {
   4.490 -    }
   4.491 -
   4.492 -    Kind kind() const {
   4.493 -        return kIndexExpression;
   4.494 -    }
   4.495 -    Expression *left() const {
   4.496 -        return left_;
   4.497 -    }
   4.498 -    Expression *right() const {
   4.499 -        return right_;
   4.500 -    }
   4.501 -    void accept(AstVisitor *visitor) {
   4.502 -        visitor->visit(this);
   4.503 -    }
   4.504 -};
   4.505 -
   4.506 -class FieldExpression : public Expression
   4.507 -{
   4.508 -    Expression *left_;
   4.509 -    ScopedRoot<String> field_;
   4.510 -    unsigned fieldIndex_;
   4.511 -
   4.512 -  public:
   4.513 -    FieldExpression(const SourcePosition &pos, Expression *left, Handle<String> field)
   4.514 -      : Expression(pos),
   4.515 -        left_(left),
   4.516 -        field_(field),
   4.517 -        fieldIndex_(unsigned(-1))
   4.518 -    {
   4.519 -    }
   4.520 -
   4.521 -    Kind kind() const {
   4.522 -        return kFieldExpression;
   4.523 -    }
   4.524 -    Expression *left() const {
   4.525 -        return left_;
   4.526 -    }
   4.527 -    String *field() const {
   4.528 -        return field_;
   4.529 -    }
   4.530 -    void setFieldIndex(unsigned index) {
   4.531 -        assert(fieldIndex_ == unsigned(-1));
   4.532 -        fieldIndex_ = index;
   4.533 -    }
   4.534 -    unsigned fieldIndex() const {
   4.535 -        assert(fieldIndex_ != unsigned(-1));
   4.536 -        return fieldIndex_;
   4.537 -    }
   4.538 -    void accept(AstVisitor *visitor) {
   4.539 -        visitor->visit(this);
   4.540 -    }
   4.541 -};
   4.542 -
   4.543 -class CallExpression : public Expression
   4.544 -{
   4.545 -    Expression *callee_;
   4.546 -    ExpressionList *arguments_;
   4.547 -
   4.548 -  public:
   4.549 -    CallExpression(const SourcePosition &pos, Expression *callee, ExpressionList *arguments)
   4.550 -      : Expression(pos),
   4.551 -        callee_(callee),
   4.552 -        arguments_(arguments)
   4.553 -    {
   4.554 -    }
   4.555 -
   4.556 -    Kind kind() const {
   4.557 -        return kCallExpression;
   4.558 -    }
   4.559 -    Expression *callee() const {
   4.560 -        return callee_;
   4.561 -    }
   4.562 -    ExpressionList *arguments() const {
   4.563 -        return arguments_;
   4.564 -    }
   4.565 -    void accept(AstVisitor *visitor) {
   4.566 -        visitor->visit(this);
   4.567 -    }
   4.568 -};
   4.569 -
   4.570 -class ForStatement : public Statement
   4.571 -{
   4.572 -    Scope *scope_;
   4.573 -    Statement *initialization_;
   4.574 -    Expression *condition_;
   4.575 -    Statement *update_;
   4.576 -    Statement *body_;
   4.577 -
   4.578 -  public:
   4.579 -    ForStatement(const SourcePosition &pos, Scope *scope, Statement *initialization,
   4.580 -                 Expression *condition, Statement *update, Statement *body)
   4.581 -      : Statement(pos),
   4.582 -        scope_(scope),
   4.583 -        initialization_(initialization),
   4.584 -        condition_(condition),
   4.585 -        update_(update),
   4.586 -        body_(body)
   4.587 -    {
   4.588 -    }
   4.589 -
   4.590 -    Kind kind() const {
   4.591 -        return kForStatement;
   4.592 -    }
   4.593 -    Statement *initialization() const {
   4.594 -        return initialization_;
   4.595 -    }
   4.596 -    Scope *scope() const {
   4.597 -        return scope_;
   4.598 -    }
   4.599 -    Expression *condition() const {
   4.600 -        return condition_;
   4.601 -    }
   4.602 -    Statement *update() const {
   4.603 -        return update_;
   4.604 -    }
   4.605 -    Statement *body() const {
   4.606 -        return body_;
   4.607 -    }
   4.608 -    void accept(AstVisitor *visitor) {
   4.609 -        visitor->visit(this);
   4.610 -    }
   4.611 -};
   4.612 -
   4.613 -class WhileStatement : public Statement
   4.614 -{
   4.615 -    TokenKind token_;
   4.616 -    Expression *condition_;
   4.617 -    Statement *body_;
   4.618 -
   4.619 -  public:
   4.620 -    WhileStatement(const SourcePosition &pos, TokenKind kind, Expression *condition, Statement *body)
   4.621 -      : Statement(pos),
   4.622 -        token_(kind),
   4.623 -        condition_(condition),
   4.624 -        body_(body)
   4.625 -    {
   4.626 -    }
   4.627 -    
   4.628 -    Kind kind() const {
   4.629 -        return kWhileStatement;
   4.630 -    }
   4.631 -    TokenKind token() const {
   4.632 -        return token_;
   4.633 -    }
   4.634 -    Expression *condition() const {
   4.635 -        return condition_;
   4.636 -    }
   4.637 -    Statement *body() const {
   4.638 -        return body_;
   4.639 -    }
   4.640 -    void accept(AstVisitor *visitor) {
   4.641 -        visitor->visit(this);
   4.642 -    }
   4.643 -};
   4.644 -
   4.645 -class ReturnStatement : public Statement
   4.646 -{
   4.647 -    Expression *expression_;
   4.648 -
   4.649 -  public:
   4.650 -    ReturnStatement(const SourcePosition &pos, Expression *expression)
   4.651 -      : Statement(pos),
   4.652 -        expression_(expression)
   4.653 -    {
   4.654 -    }
   4.655 -
   4.656 -    Kind kind() const {
   4.657 -        return kReturnStatement;
   4.658 -    }
   4.659 -    Expression *expression() const {
   4.660 -        return expression_;
   4.661 -    }
   4.662 -    void accept(AstVisitor *visitor) {
   4.663 -        visitor->visit(this);
   4.664 -    }
   4.665 -};
   4.666 -
   4.667 -class BreakStatement : public Statement
   4.668 -{
   4.669 -  public:
   4.670 -    BreakStatement(const SourcePosition &pos)
   4.671 -      : Statement(pos)
   4.672 -    {
   4.673 -    }
   4.674 -
   4.675 -    Kind kind() const {
   4.676 -        return kBreakStatement;
   4.677 -    }
   4.678 -    void accept(AstVisitor *visitor) {
   4.679 -        visitor->visit(this);
   4.680 -    }
   4.681 -};
   4.682 -
   4.683 -class ContinueStatement : public Statement
   4.684 -{
   4.685 -  public:
   4.686 -    ContinueStatement(const SourcePosition &pos)
   4.687 -      : Statement(pos)
   4.688 -    {
   4.689 -    }
   4.690 -
   4.691 -    Kind kind() const {
   4.692 -        return kContinueStatement;
   4.693 -    }
   4.694 -    void accept(AstVisitor *visitor) {
   4.695 -        visitor->visit(this);
   4.696 -    }
   4.697 -};
   4.698 -
   4.699 -class Assignment : public Expression
   4.700 -{
   4.701 -    TokenKind token_;
   4.702 -    Expression *lvalue_;
   4.703 -    Expression *expression_;
   4.704 -
   4.705 -  public:
   4.706 -    Assignment(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
   4.707 -      : Expression(pos),
   4.708 -        token_(token),
   4.709 -        lvalue_(left),
   4.710 -        expression_(right)
   4.711 -    {
   4.712 -    }
   4.713 -
   4.714 -    Kind kind() const {
   4.715 -        return kAssignment;
   4.716 -    }
   4.717 -    TokenKind token() const {
   4.718 -        return token_;
   4.719 -    }
   4.720 -    Expression *lvalue() const {
   4.721 -        return lvalue_;
   4.722 -    }
   4.723 -    Expression *expression() const {
   4.724 -        return expression_;
   4.725 -    }
   4.726 -    void accept(AstVisitor *visitor) {
   4.727 -        visitor->visit(this);
   4.728 -    }
   4.729 -};
   4.730 -
   4.731 -class ExpressionStatement : public Statement
   4.732 -{
   4.733 -    Expression *expression_;
   4.734 -
   4.735 -  public:
   4.736 -    ExpressionStatement(Expression *expression)
   4.737 -      : Statement(expression->pos()),
   4.738 -        expression_(expression)
   4.739 -    {
   4.740 -    }
   4.741 -
   4.742 -    Kind kind() const {
   4.743 -        return kExpressionStatement;
   4.744 -    }
   4.745 -    Expression *expression() const {
   4.746 -        return expression_;
   4.747 -    }
   4.748 -    void accept(AstVisitor *visitor) {
   4.749 -        visitor->visit(this);
   4.750 -    }
   4.751 -};
   4.752 -
   4.753 -class BlockStatement : public Statement
   4.754 -{
   4.755 -    Scope *scope_;
   4.756 -    StatementList *statements_;
   4.757 -
   4.758 -  public:
   4.759 -    BlockStatement(const SourcePosition &pos, Scope *scope, StatementList *statements)
   4.760 -      : Statement(pos),
   4.761 -        scope_(scope),
   4.762 -        statements_(statements)
   4.763 -    {
   4.764 -    }
   4.765 -
   4.766 -    Kind kind() const {
   4.767 -        return kBlockStatement;
   4.768 -    }
   4.769 -    Scope *scope() const {
   4.770 -        return scope_;
   4.771 -    }
   4.772 -    StatementList *statements() const {
   4.773 -        return statements_;
   4.774 -    }
   4.775 -    void accept(AstVisitor *visitor) {
   4.776 -        visitor->visit(this);
   4.777 -    }
   4.778 -};
   4.779 -
   4.780 -typedef PoolList<Parameter *> ParameterList;
   4.781 -
   4.782 -class FunctionSignature
   4.783 -{
   4.784 -  public:
   4.785 -    FunctionSignature(BoundName *returnType, ExpressionList *returnDimensions, ParameterList *parameters)
   4.786 -      : returnType_(returnType),
   4.787 -        returnDimensions_(returnDimensions),
   4.788 -        parameters_(parameters)
   4.789 -    {
   4.790 -    }
   4.791 -
   4.792 -    BoundName *returnType() const {
   4.793 -        return returnType_;
   4.794 -    }
   4.795 -    ExpressionList *returnDimensions() const {
   4.796 -        return returnDimensions_;
   4.797 -    }
   4.798 -    ParameterList *parameters() const {
   4.799 -        return parameters_;
   4.800 -    }
   4.801 -
   4.802 -  private:
   4.803 -    BoundName *returnType_;
   4.804 -    ExpressionList *returnDimensions_;
   4.805 -    ParameterList *parameters_;
   4.806 -};
   4.807 -
   4.808 -class FunctionTypeStatement : public Statement
   4.809 -{
   4.810 -  public:
   4.811 -    FunctionTypeStatement(const SourcePosition &pos, NamedType *type, const FunctionSignature &signature)
   4.812 -      : Statement(pos),
   4.813 -        type_(type),
   4.814 -        signature_(signature)
   4.815 -    {
   4.816 -    }
   4.817 -
   4.818 -    Kind kind() const {
   4.819 -        return kFunctionTypeStatement;
   4.820 -    }
   4.821 -    NamedType *decl() const {
   4.822 -        return type_;
   4.823 -    }
   4.824 -    const FunctionSignature &signature() const {
   4.825 -        return signature_;
   4.826 -    }
   4.827 -    void accept(AstVisitor *visitor) {
   4.828 -        visitor->visit(this);
   4.829 -    }
   4.830 -
   4.831 -  private:
   4.832 -    NamedType *type_;
   4.833 -    FunctionSignature signature_;
   4.834 -};
   4.835 -
   4.836 -class FunctionStatement : public Statement
   4.837 -{
   4.838 -    Scope *scope_;
   4.839 -    NamedFunction *fun_;
   4.840 -    Statement *body_;
   4.841 -    FunctionSignature signature_;
   4.842 -    bool explicitReturn_;
   4.843 -
   4.844 -  public:
   4.845 -    FunctionStatement(const SourcePosition &pos, Scope *scope, NamedFunction *fun, Statement *body,
   4.846 -                      const FunctionSignature &signature, bool explicitReturn)
   4.847 -      : Statement(pos),
   4.848 -        scope_(scope),
   4.849 -        fun_(fun),
   4.850 -        body_(body),
   4.851 -        signature_(signature),
   4.852 -        explicitReturn_(explicitReturn)
   4.853 -    {
   4.854 -    }
   4.855 -
   4.856 -    Kind kind() const {
   4.857 -        return kFunctionStatement;
   4.858 -    }
   4.859 -    Scope *scope() const {
   4.860 -        return scope_;
   4.861 -    }
   4.862 -    NamedFunction *fun() const {
   4.863 -        return fun_;
   4.864 -    }
   4.865 -    Statement *body() const {
   4.866 -        return body_;
   4.867 -    }
   4.868 -    const FunctionSignature &signature() {
   4.869 -        return signature_;
   4.870 -    }
   4.871 -    void accept(AstVisitor *visitor) {
   4.872 -        visitor->visit(this);
   4.873 -    }
   4.874 -    bool hasExplicitReturn() const {
   4.875 -        return explicitReturn_;
   4.876 -    }
   4.877 -};
   4.878 -
   4.879 -class IfStatement : public Statement
   4.880 -{
   4.881 -    Expression *condition_;
   4.882 -    Statement *ifTrue_;
   4.883 -    Statement *ifFalse_;
   4.884 -
   4.885 -  public:
   4.886 -    IfStatement(const SourcePosition &pos, Expression *condition, Statement *ifTrue)
   4.887 -      : Statement(pos),
   4.888 -        condition_(condition),
   4.889 -        ifTrue_(ifTrue),
   4.890 -        ifFalse_(NULL)
   4.891 -    {
   4.892 -    }
   4.893 -
   4.894 -    Kind kind() const {
   4.895 -        return kIfStatement;
   4.896 -    }
   4.897 -    Expression *condition() const {
   4.898 -        return condition_;
   4.899 -    }
   4.900 -    Statement *ifTrue() const {
   4.901 -        return ifTrue_;
   4.902 -    }
   4.903 -    Statement *ifFalse() const {
   4.904 -        return ifFalse_;
   4.905 -    }
   4.906 -    void setIfFalse(Statement *ifFalse) {
   4.907 -        ifFalse_ = ifFalse;
   4.908 -    }
   4.909 -    void accept(AstVisitor *visitor) {
   4.910 -        visitor->visit(this);
   4.911 -    }
   4.912 -};
   4.913 -
   4.914 -class EnumStatement : public Statement
   4.915 -{
   4.916 -    ScopedRoot<String> name_;
   4.917 -    NamedType *type_;
   4.918 -
   4.919 -  public:
   4.920 -    struct Entry {
   4.921 -        NamedConstant *name;
   4.922 -        Expression *expr;
   4.923 -
   4.924 -        Entry(NamedConstant *name, Expression *expr)
   4.925 -          : name(name),
   4.926 -            expr(expr)
   4.927 -        {
   4.928 -        }
   4.929 -    };
   4.930 -
   4.931 -    typedef PoolList<Entry> EntryList;
   4.932 -
   4.933 -  public:
   4.934 -    EnumStatement(const SourcePosition &pos, NamedType *type, Handle<String> name, EntryList *entries)
   4.935 -      : Statement(pos),
   4.936 -        name_(name),
   4.937 -        type_(type),
   4.938 -        entries_(entries)
   4.939 -    {
   4.940 -    }
   4.941 -
   4.942 -    Kind kind() const {
   4.943 -        return kEnumStatement;
   4.944 -    }
   4.945 -    String *name() const {
   4.946 -        return name_;
   4.947 -    }
   4.948 -    EntryList *entries() const {
   4.949 -        return entries_;
   4.950 -    }
   4.951 -    NamedType *decl() const {
   4.952 -        return type_;
   4.953 -    }
   4.954 -    void accept(AstVisitor *visitor) {
   4.955 -        visitor->visit(this);
   4.956 -    }
   4.957 -
   4.958 -  private:
   4.959 -    EntryList *entries_;
   4.960 -};
   4.961 -
   4.962 -class IncDecExpression : public Expression
   4.963 -{
   4.964 -    TokenKind token_;
   4.965 -    Expression *expression_;
   4.966 -    bool postfix_;
   4.967 -
   4.968 -  public:
   4.969 -    IncDecExpression(const SourcePosition &pos, TokenKind token, Expression *expression, bool postfix)
   4.970 -      : Expression(pos),
   4.971 -        token_(token),
   4.972 -        expression_(expression),
   4.973 -        postfix_(postfix)
   4.974 -    {
   4.975 -    }
   4.976 -
   4.977 -    Kind kind() const {
   4.978 -        return kIncDecExpression;
   4.979 -    }
   4.980 -    TokenKind token() const {
   4.981 -        return token_;
   4.982 -    }
   4.983 -    Expression *expression() const {
   4.984 -        return expression_;
   4.985 -    }
   4.986 -    bool postfix() const {
   4.987 -        return postfix_;
   4.988 -    }
   4.989 -    void accept(AstVisitor *visitor) {
   4.990 -        visitor->visit(this);
   4.991 -    }
   4.992 -};
   4.993 -
   4.994 -class Case : public PoolObject
   4.995 -{
   4.996 -  public:
   4.997 -    Case(Expression *expression, ExpressionList *others, Statement *statement)
   4.998 -      : expression_(expression),
   4.999 -        others_(others),
  4.1000 -        statement_(statement)
  4.1001 -    {
  4.1002 -    }
  4.1003 -
  4.1004 -    Expression *expression() const {
  4.1005 -        return expression_;
  4.1006 -    }
  4.1007 -    PoolList<Expression *> *others() const {
  4.1008 -        return others_;
  4.1009 -    }
  4.1010 -    Statement *statement() const {
  4.1011 -        return statement_;
  4.1012 -    }
  4.1013 -
  4.1014 -  private:
  4.1015 -    Expression *expression_;
  4.1016 -    PoolList <Expression *> *others_;
  4.1017 -    Statement *statement_;
  4.1018 -};
  4.1019 -
  4.1020 -struct CaseValue
  4.1021 -{
  4.1022 -    BoxedPrimitive box;
  4.1023 -    size_t statement;
  4.1024 -
  4.1025 -    CaseValue(size_t statement)
  4.1026 -      : statement(statement)
  4.1027 -    {
  4.1028 -    }
  4.1029 -};
  4.1030 -
  4.1031 -typedef PoolList<CaseValue> CaseValueList;
  4.1032 -
  4.1033 -class SwitchStatement : public Statement
  4.1034 -{
  4.1035 -  public:
  4.1036 -    SwitchStatement(const SourcePosition &pos, Expression *expression, PoolList<Case *> *cases,
  4.1037 -                    Statement *def)
  4.1038 -      : Statement(pos),
  4.1039 -        expression_(expression),
  4.1040 -        cases_(cases),
  4.1041 -        default_(def),
  4.1042 -        table_(NULL)
  4.1043 -    {
  4.1044 -    }
  4.1045 -
  4.1046 -    Kind kind() const {
  4.1047 -        return kSwitchStatement;
  4.1048 -    }
  4.1049 -    Expression *expression() const {
  4.1050 -        return expression_;
  4.1051 -    }
  4.1052 -    PoolList<Case *> *cases() const {
  4.1053 -        return cases_;
  4.1054 -    }
  4.1055 -    Statement *defaultCase() const {
  4.1056 -        return default_;
  4.1057 -    }
  4.1058 -    void setCaseValueList(CaseValueList *list) {
  4.1059 -        table_ = list;
  4.1060 -    }
  4.1061 -    CaseValueList *caseValueList() const {
  4.1062 -        return table_;
  4.1063 -    }
  4.1064 -    void accept(AstVisitor *visitor) {
  4.1065 -        visitor->visit(this);
  4.1066 -    }
  4.1067 -
  4.1068 -  private:
  4.1069 -    Expression *expression_;
  4.1070 -    PoolList<Case *> *cases_;
  4.1071 -    Statement *default_;
  4.1072 -    CaseValueList *table_;
  4.1073 -};
  4.1074 -
  4.1075 -class StructureStatement : public Statement
  4.1076 -{
  4.1077 -  public:
  4.1078 -    class Field : public PoolObject
  4.1079 -    {
  4.1080 -        SourcePosition pos_;
  4.1081 -        BoundName *type_;
  4.1082 -        ScopedRoot<String> name_;
  4.1083 -        ExpressionList *dimensions_;
  4.1084 -
  4.1085 -      public:
  4.1086 -        Field(const SourcePosition &pos,
  4.1087 -              BoundName *type,
  4.1088 -              Handle<String> name,
  4.1089 -              ExpressionList *dimensions)
  4.1090 -          : pos_(pos),
  4.1091 -            type_(type),
  4.1092 -            name_(name),
  4.1093 -            dimensions_(dimensions)
  4.1094 -        {
  4.1095 -        }
  4.1096 -
  4.1097 -        const SourcePosition &pos() const {
  4.1098 -            return pos_;
  4.1099 -        }
  4.1100 -        BoundName *type() const {
  4.1101 -            return type_;
  4.1102 -        }
  4.1103 -        String *name() const {
  4.1104 -            return name_;
  4.1105 -        }
  4.1106 -        ExpressionList *dimensions() const {
  4.1107 -            return dimensions_;
  4.1108 -        }
  4.1109 -    };
  4.1110 -
  4.1111 -    typedef PoolList<StructureStatement::Field *> FieldList;
  4.1112 -
  4.1113 -  public:
  4.1114 -    StructureStatement(const SourcePosition &pos, NamedType *decl, FieldList *fields)
  4.1115 -      : Statement(pos),
  4.1116 -        decl_(decl),
  4.1117 -        fields_(fields)
  4.1118 -    {
  4.1119 -    }
  4.1120 -
  4.1121 -    Kind kind() const {
  4.1122 -        return kStructureStatement;
  4.1123 -    }
  4.1124 -    FieldList *fields() const {
  4.1125 -        return fields_;
  4.1126 -    }
  4.1127 -    NamedType *decl() const {
  4.1128 -        return decl_;
  4.1129 -    }
  4.1130 -    void accept(AstVisitor *visitor) {
  4.1131 -        visitor->visit(this);
  4.1132 -    }
  4.1133 -
  4.1134 -  private:
  4.1135 -    NamedType *decl_;
  4.1136 -    FieldList *fields_;
  4.1137 -};
  4.1138 -
  4.1139 -typedef StructureStatement::FieldList FieldList;
  4.1140 -
  4.1141 -class Scope;
  4.1142 -
  4.1143 -typedef PoolList<NameProxy *> NameProxyList;
  4.1144 -
  4.1145 -class ParseTree : public PoolObject
  4.1146 -{
  4.1147 -    StatementList *statements_;
  4.1148 -    Scope *scope_;
  4.1149 -    NameProxyList *unbound_;
  4.1150 -
  4.1151 -  public:
  4.1152 -    ParseTree(Scope *scope, StatementList *statements, NameProxyList *unbound)
  4.1153 -      : statements_(statements),
  4.1154 -        scope_(scope),
  4.1155 -        unbound_(unbound)
  4.1156 -    {
  4.1157 -    }
  4.1158 -
  4.1159 -    void dump(FILE *fp);
  4.1160 -
  4.1161 -    StatementList *statements() const {
  4.1162 -        return statements_;
  4.1163 -    }
  4.1164 -    Scope *scope() const {
  4.1165 -        return scope_;
  4.1166 -    }
  4.1167 -    NameProxyList *unbound() const {
  4.1168 -        return unbound_;
  4.1169 -    }
  4.1170 -};
  4.1171 -
  4.1172 -}
  4.1173 -
  4.1174 -#endif // _include_sourcepawn_ast_h_
     5.1 --- a/src/BytecodeCompiler.cpp	Mon Sep 17 00:10:01 2012 -0700
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,1576 +0,0 @@
     5.4 -/* vim: set ts=4 sw=4 tw=99 et:
     5.5 - *
     5.6 - * Copyright (C) 2012 David Anderson
     5.7 - *
     5.8 - * This file is part of JITCraft.
     5.9 - *
    5.10 - * JITCraft is free software: you can redistribute it and/or modify it under
    5.11 - * the terms of the GNU General Public License as published by the Free
    5.12 - * Software Foundation, either version 3 of the License, or (at your option)
    5.13 - * any later version.
    5.14 - * 
    5.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    5.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    5.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    5.18 - *
    5.19 - * You should have received a copy of the GNU General Public License along with
    5.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    5.21 - */
    5.22 -#include <string.h>
    5.23 -#include "BytecodeCompiler.h"
    5.24 -#include "Scopes.h"
    5.25 -#include "Modules.h"
    5.26 -#include "Types.h"
    5.27 -#include "Array.h"
    5.28 -#include "Strings.h"
    5.29 -#include "Zone.h"
    5.30 -#include "Environments.h"
    5.31 -#include "Box.h"
    5.32 -#include "Heap-inl.h"
    5.33 -
    5.34 -using namespace ke;
    5.35 -
    5.36 -typedef BytecodeEmitter::Label Label;
    5.37 -
    5.38 -#define __ emitter_.
    5.39 -
    5.40 -BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
    5.41 -  : zone_(zone),
    5.42 -    tree_(tree),
    5.43 -    emitter_(zone->pool()),
    5.44 -    locals_(NULL),
    5.45 -    scope_(NULL),
    5.46 -    moduleData_(module),
    5.47 -    loop_(NULL)
    5.48 -{
    5.49 -}
    5.50 -
    5.51 -static inline TokenKind
    5.52 -ToCompare(Expression *expr)
    5.53 -{
    5.54 -    if (expr->isBinaryExpression()) {
    5.55 -        BinaryExpression *b = expr->toBinaryExpression();
    5.56 -        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
    5.57 -            return b->token();
    5.58 -    } else if (expr->isUnaryExpression()) {
    5.59 -        UnaryExpression *u = expr->toUnaryExpression();
    5.60 -        if (u->token() == TOK_NOT)
    5.61 -            return TOK_NOT;
    5.62 -    }
    5.63 -    return TOK_EOF;
    5.64 -}
    5.65 -
    5.66 -static inline Opcode
    5.67 -CompareTokenToJump(TokenKind kind)
    5.68 -{
    5.69 -    switch (kind) {
    5.70 -      case TOK_EQUALS:
    5.71 -        return OP_JEQ;
    5.72 -      case TOK_NOTEQUALS:
    5.73 -        return OP_JNE;
    5.74 -      case TOK_GT:
    5.75 -        return OP_JG;
    5.76 -      case TOK_GE:
    5.77 -        return OP_JGE;
    5.78 -      case TOK_LT:
    5.79 -        return OP_JL;
    5.80 -      default:
    5.81 -        assert(kind == TOK_LE);
    5.82 -        return OP_JLE;
    5.83 -    }
    5.84 -}
    5.85 -
    5.86 -static inline Opcode
    5.87 -TokenToOpcode(TokenKind kind)
    5.88 -{
    5.89 -    switch (kind) {
    5.90 -      case TOK_PLUS:
    5.91 -        return OP_ADD;
    5.92 -      case TOK_MINUS:
    5.93 -        return OP_SUB;
    5.94 -      case TOK_STAR:
    5.95 -        return OP_MUL;
    5.96 -      case TOK_SLASH:
    5.97 -        return OP_DIV;
    5.98 -      case TOK_PERCENT:
    5.99 -        return OP_MOD;
   5.100 -      case TOK_SHR:
   5.101 -        return OP_SHR;
   5.102 -      case TOK_USHR:
   5.103 -        return OP_USHR;
   5.104 -      case TOK_SHL:
   5.105 -        return OP_SHL;
   5.106 -      case TOK_BITAND:
   5.107 -        return OP_BITAND;
   5.108 -      case TOK_BITOR:
   5.109 -        return OP_BITOR;
   5.110 -      case TOK_GT:
   5.111 -          return OP_GT;
   5.112 -      case TOK_GE:
   5.113 -          return OP_GE;
   5.114 -      case TOK_LT:
   5.115 -          return OP_LT;
   5.116 -      case TOK_LE:
   5.117 -          return OP_LE;
   5.118 -      case TOK_EQUALS:
   5.119 -          return OP_EQ;
   5.120 -      case TOK_NOTEQUALS:
   5.121 -          return OP_NE;
   5.122 -      default:
   5.123 -        assert(kind == TOK_BITXOR);
   5.124 -        return OP_BITXOR;
   5.125 -    }
   5.126 -}
   5.127 -
   5.128 -void
   5.129 -BytecodeCompiler::recordLifoSlot(Scope *scope)
   5.130 -{
   5.131 -    if (!scope)
   5.132 -        return;
   5.133 -
   5.134 -    if (Variable *var = scope->lifoSlot()) {
   5.135 -        locals_->set(zone_, var->slot(), var->type());
   5.136 -        __ savelifo(var->slot());
   5.137 -    }
   5.138 -}
   5.139 -
   5.140 -void
   5.141 -BytecodeCompiler::unwindTo(Scope *scope)
   5.142 -{
   5.143 -    // Note: we only need to unwind to the outermost scope's LIFO slot.
   5.144 -    Variable *var = NULL;
   5.145 -    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
   5.146 -        if (Variable *slot = current->lifoSlot())
   5.147 -            var = slot;
   5.148 -    }
   5.149 -
   5.150 -    if (var)
   5.151 -        __ unwindlifo(var->slot());
   5.152 -}
   5.153 -
   5.154 -void
   5.155 -BytecodeCompiler::visit(NameProxy *name)
   5.156 -{
   5.157 -    switch (name->binding()->kind()) {
   5.158 -      case BoundName::VARIABLE:
   5.159 -      {
   5.160 -        Variable *var = name->binding()->toVariable();
   5.161 -
   5.162 -        if (var->location() == Variable::STACK) {
   5.163 -            __ getlocal(var);
   5.164 -            assert(!name->type()->isReference());
   5.165 -        } else if (var->location() == Variable::ENVIRONMENT) {
   5.166 -            getEnvSlot(var);
   5.167 -        } else {
   5.168 -            assert(var->location() == Variable::PARAMETER);
   5.169 -            __ getarg(var);
   5.170 -
   5.171 -            // If this argument is actually a reference, dereference it now.
   5.172 -            if (var->type()->isReference())
   5.173 -                __ getref(var->type()->contained());
   5.174 -        }
   5.175 -        break;
   5.176 -      }
   5.177 -
   5.178 -      case BoundName::FUNCTION:
   5.179 -      {
   5.180 -        NamedFunction *fun = name->binding()->toNamedFunction();
   5.181 -        __ module();
   5.182 -        __ getmodule_fn(fun->slot());
   5.183 -        break;
   5.184 -      }
   5.185 -
   5.186 -      default:
   5.187 -      {
   5.188 -        NamedConstant *constant = name->binding()->toNamedConstant();
   5.189 -        __ int_(constant->value().toInt());
   5.190 -        break;
   5.191 -      }
   5.192 -    }
   5.193 -}
   5.194 -
   5.195 -void
   5.196 -BytecodeCompiler::visit(ExpressionStatement *node)
   5.197 -{
   5.198 -    // Expressions leave their value on the top of the stack, so we make sure
   5.199 -    // to balance the stack if they're used as a statement.
   5.200 -    node->expression()->accept(this);
   5.201 -    if (!node->expression()->type()->isVoid())
   5.202 -        __ pop();
   5.203 -}
   5.204 -
   5.205 -static inline bool
   5.206 -IsCompositeValueType(Type *type)
   5.207 -{
   5.208 -    return type->isStruct() ||
   5.209 -           (type->isArray() && type->isFixedLength());
   5.210 -}
   5.211 -
   5.212 -static inline Array *
   5.213 -StringLiteralToArray(Zone *zone, StringLiteral *node)
   5.214 -{
   5.215 -    Local<Type> type(zone, node->type());
   5.216 -    Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
   5.217 -    if (!map)
   5.218 -        return NULL;
   5.219 -
   5.220 -    return Array::NewString(zone,
   5.221 -                            map,
   5.222 -                            node->string()->raw(),
   5.223 -                            node->string()->length(),
   5.224 -                            Heap::Tenure_Old);
   5.225 -}
   5.226 -
   5.227 -void
   5.228 -BytecodeCompiler::visit(Assignment *node)
   5.229 -{
   5.230 -    Local<Type> left(zone_, node->type());
   5.231 -    Local<Type> right(zone_, node->expression()->type());
   5.232 -
   5.233 -    // The first step is three sub-steps:
   5.234 -    //
   5.235 -    //   (1) Bind the left-hand side.
   5.236 -    //   -- If a cumulative operation (+=, etc):
   5.237 -    //   (2) Save a copy of the binding on the stack.
   5.238 -    //   (3) Dereference the binding to get a value.
   5.239 -    //
   5.240 -    if (node->lvalue()->isNameProxy()) {
   5.241 -        NameProxy *proxy = node->lvalue()->toNameProxy();
   5.242 -        Variable *var = proxy->binding()->toVariable();
   5.243 -
   5.244 -        // We need to fetch the variable under the following circumstances:
   5.245 -        //  (1) The variable is a reference, since we'll store into the ref.
   5.246 -        //  (2) The variable is a fixed array, since we need to copy into it.
   5.247 -        //  (3) The variable is a struct, since we need to copy into it.
   5.248 -        if (var->type()->isReference() || IsCompositeValueType(var->type()))
   5.249 -            __ get(var);
   5.250 -
   5.251 -        // Get the value if needed.
   5.252 -        if (node->token() != TOK_ASSIGN) {
   5.253 -            // += etc is not allowed on arrays.
   5.254 -            assert(!var->type()->isArray());
   5.255 -
   5.256 -            if (var->location() == Variable::ENVIRONMENT)
   5.257 -                getEnvSlot(var);
   5.258 -
   5.259 -            if (var->type()->isReference()) {
   5.260 -                __ dup();
   5.261 -                __ getref(var->type()->contained());
   5.262 -            } else if (var->location() != Variable::ENVIRONMENT) {
   5.263 -                __ get(var);
   5.264 -            }
   5.265 -        }
   5.266 -    } else if (node->lvalue()->isFieldExpression()) {
   5.267 -        FieldExpression *expr = node->lvalue()->toFieldExpression();
   5.268 -        __ note_position(expr->pos());
   5.269 -
   5.270 -        expr->left()->accept(this);
   5.271 -
   5.272 -        if (node->token() != TOK_ASSIGN)
   5.273 -            __ dup();
   5.274 -
   5.275 -        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
   5.276 -            __ getfield(expr->fieldIndex(), left);
   5.277 -    } else {
   5.278 -        IndexExpression *index = node->lvalue()->toIndexExpression();
   5.279 -        __ note_position(index->pos());
   5.280 -
   5.281 -        index->left()->accept(this);
   5.282 -        index->right()->accept(this);
   5.283 -
   5.284 -        if (node->token() != TOK_ASSIGN)
   5.285 -            __ dup2();
   5.286 -
   5.287 -        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
   5.288 -            __ getelem(left);
   5.289 -    }
   5.290 -
   5.291 -    if (node->token() == TOK_ASSIGN) {
   5.292 -        // Special case: if the left-hand side is a string literal, we must
   5.293 -        // spawn a new copy (:TODO: something about const?)
   5.294 -        if (node->expression()->isStringLiteral() && !left->isFixedLength()) {
   5.295 -            Local<Array> string(zone_,
   5.296 -                    StringLiteralToArray(zone_, node->expression()->toStringLiteral()));
   5.297 -            if (!string)
   5.298 -                return;
   5.299 -
   5.300 -            Local<ArrayMap> arrayMap(zone_, ArrayMap::cast(string->map()));
   5.301 -            __ note_position(node->expression()->pos());
   5.302 -            __ int_(string->length());
   5.303 -            __ newarray(OP_NEWSIZED, arrayMap, Heap::Tenure_Default);
   5.304 -            __ object(string);
   5.305 -            __ copyarray();
   5.306 -        } else {
   5.307 -            node->expression()->accept(this);
   5.308 -        }
   5.309 -    } else {
   5.310 -        visitForALU(left, node->expression());
   5.311 -
   5.312 -        TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
   5.313 -        __ note_position(node->pos());
   5.314 -        __ binary(TokenToOpcode(alu));
   5.315 -    }
   5.316 -
   5.317 -    // Emit the store.
   5.318 -    if (left->isArray() && left->isFixedLength()) {
   5.319 -        // (x = y) returns the left-hand side; if |x| is a fixed-length array,
   5.320 -        // then |y| is as well, and we perform a deep copy.
   5.321 -        assert(right->isFixedLength());
   5.322 -        __ note_position(node->pos());
   5.323 -        __ copyarray();
   5.324 -    } else if (left->isStruct()) {
   5.325 -        // Structs have value semantics, so emit a full copy. We don't break
   5.326 -        // this down into u-ops, to avoid unnecessary bytecode explosion.
   5.327 -        assert(right->isStruct());
   5.328 -        __ note_position(node->pos());
   5.329 -        __ copystruct();
   5.330 -    } else if (node->lvalue()->isNameProxy()) {
   5.331 -        NameProxy *proxy = node->lvalue()->toNameProxy();
   5.332 -        Variable *var = proxy->binding()->toVariable();
   5.333 -
   5.334 -        if (var->type()->isReference())
   5.335 -            __ setref(var->type()->contained());
   5.336 -        else if (var->location() == Variable::ENVIRONMENT)
   5.337 -            setEnvSlot(var);
   5.338 -        else
   5.339 -            __ set(var);
   5.340 -    } else if (node->lvalue()->isFieldExpression()) {
   5.341 -        FieldExpression *expr = node->lvalue()->toFieldExpression();
   5.342 -        __ setfield(expr->fieldIndex(), left);
   5.343 -    } else {
   5.344 -        __ setelem(left);
   5.345 -    }
   5.346 -}
   5.347 -
   5.348 -void
   5.349 -BytecodeCompiler::visit(IncDecExpression *node)
   5.350 -{
   5.351 -    // In the postfix case, the logic looks like:
   5.352 -    //      (1) Bind       -> REF
   5.353 -    //      (2) Dup        -> REF REF
   5.354 -    //      (3) Fetch      -> REF VAL
   5.355 -    //      (4) Swap       -> VAL REF
   5.356 -    //      (5) Pick       -> VAL REF VAL
   5.357 -    //      (6) Add        -> VAL REF VAL+1
   5.358 -    //      (7) Store      -> VAL VAL+1
   5.359 -    //      (8) Drop       -> VAL
   5.360 -    //
   5.361 -    // In the prefix case, the logic looks like:
   5.362 -    //      (1) Bind       -> REF
   5.363 -    //      (2) Dup        -> REF REF
   5.364 -    //      (3) Fetch      -> REF VAL
   5.365 -    //      --
   5.366 -    //      --
   5.367 -    //      (6) Add        -> REF VAL+1
   5.368 -    //      (7) Store      -> VAL+1
   5.369 -    //      --
   5.370 -    //
   5.371 -    // This is squirrely enough such that we don't bother sharing too much
   5.372 -    // with the above.
   5.373 -    // 
   5.374 -    // Note: We simulate a "Pick" operation with a dup2+pop.
   5.375 -
   5.376 -    // This is steps (1) to (5).
   5.377 -    Expression *expr = node->expression();
   5.378 -    if (expr->isNameProxy()) {
   5.379 -        NameProxy *proxy = expr->toNameProxy();
   5.380 -        Variable *var = proxy->binding()->toVariable();
   5.381 -
   5.382 -        // Bind.
   5.383 -        if (var->location() == Variable::ENVIRONMENT)
   5.384 -            getEnvSlot(var);
   5.385 -        else if (var->type()->isReference() || var->type()->isArray())
   5.386 -            __ get(var);
   5.387 -
   5.388 -        // Dup and fetch.
   5.389 -        if (var->type()->isReference()) {
   5.390 -            __ dup();
   5.391 -            __ getref(node->type());
   5.392 -            if (node->postfix()) {
   5.393 -                __ swap();
   5.394 -                __ pick2();
   5.395 -            }
   5.396 -        } else {
   5.397 -            assert(!var->type()->isArray());
   5.398 -            if (var->location() != Variable::ENVIRONMENT)
   5.399 -                __ get(var);
   5.400 -            if (node->postfix())
   5.401 -                __ dup();
   5.402 -        }
   5.403 -    } else if (expr->isFieldExpression()) {
   5.404 -        FieldExpression *field = expr->toFieldExpression();
   5.405 -
   5.406 -        field->left()->accept(this);
   5.407 -        __ dup();
   5.408 -        __ getfield(field->fieldIndex(), field->type());
   5.409 -
   5.410 -        if (node->postfix()) {
   5.411 -            // The stack looks like this now:
   5.412 -            // OBJECT VALUE
   5.413 -            __ swap();          // VALUE OBJECT
   5.414 -            __ pick2();         // VALUE OBJECT VALUE
   5.415 -        }
   5.416 -    } else {
   5.417 -        IndexExpression *index = expr->toIndexExpression();
   5.418 -        __ note_position(index->pos());
   5.419 -
   5.420 -        index->left()->accept(this);
   5.421 -        index->right()->accept(this);
   5.422 -
   5.423 -        assert(!node->type()->isArray());
   5.424 -        __ dup2();
   5.425 -        __ getelem(node->type());
   5.426 -
   5.427 -        if (node->postfix()) {
   5.428 -            // The stack looks like this now:
   5.429 -            // ARRAY INDEX VALUE
   5.430 -            //
   5.431 -            // So we must use a PICK operation to rotate the stack into position.
   5.432 -            __ roll3();         // INDEX VALUE ARRAY
   5.433 -            __ roll3();         // VALUE ARRAY INDEX
   5.434 -            __ pick3();         // VALUE ARRAY INDEX VALUE
   5.435 -        }
   5.436 -    }
   5.437 -
   5.438 -    // Perform step (6).
   5.439 -    if (node->type()->isFloat()) {
   5.440 -        __ float_(1.0);
   5.441 -    } else {
   5.442 -        assert(node->type()->isInt32());
   5.443 -        __ int_(1);
   5.444 -    }
   5.445 -
   5.446 -    __ note_position(node->pos());
   5.447 -    if (node->token() == TOK_INCREMENT)
   5.448 -        __ binary(OP_ADD);
   5.449 -    else
   5.450 -        __ binary(OP_SUB);
   5.451 -
   5.452 -    // Perform step (7).
   5.453 -    if (expr->isNameProxy()) {
   5.454 -        NameProxy *proxy = expr->toNameProxy();
   5.455 -        Variable *var = proxy->binding()->toVariable();
   5.456 -
   5.457 -        if (var->type()->isReference())
   5.458 -            __ setref(node->type());
   5.459 -        else if (var->location() == Variable::ENVIRONMENT)
   5.460 -            setEnvSlot(var);
   5.461 -        else
   5.462 -            __ set(var);
   5.463 -    } else if (expr->isFieldExpression()) {
   5.464 -        FieldExpression *field = expr->toFieldExpression();
   5.465 -        __ setfield(field->fieldIndex(), field->type());
   5.466 -    } else {
   5.467 -        assert(expr->isIndexExpression());
   5.468 -        __ setelem(node->type());
   5.469 -    }
   5.470 -
   5.471 -    // Perform step (8).
   5.472 -    if (node->postfix())
   5.473 -        __ pop();
   5.474 -}
   5.475 -
   5.476 -void
   5.477 -BytecodeCompiler::visitForALU(Type *needed, Expression *node)
   5.478 -{
   5.479 -    node->accept(this);
   5.480 -    if (needed->isFloat() && !node->type()->isFloat())
   5.481 -        __ cvt_i2f();
   5.482 -    else
   5.483 -        assert(needed->primitive() == node->type()->primitive());
   5.484 -}
   5.485 -
   5.486 -static inline Type *
   5.487 -GetCoercionType(TokenKind tok, Type *left, Type *right)
   5.488 -{
   5.489 -    if (left->isFloat())
   5.490 -        return left;
   5.491 -    return right;
   5.492 -}
   5.493 -
   5.494 -void
   5.495 -BytecodeCompiler::visit(UnaryExpression *node)
   5.496 -{
   5.497 -    Local<Type> out(zone_, ((Expression *)node)->type());
   5.498 -
   5.499 -    switch (node->token()) {
   5.500 -      case TOK_MINUS:
   5.501 -      {
   5.502 -        Local<Type> type(zone_, node->expression()->type());
   5.503 -        node->expression()->accept(this);
   5.504 -        
   5.505 -        if (out->isFloat())
   5.506 -            __ neg_f();
   5.507 -        else
   5.508 -            __ neg();
   5.509 -        break;
   5.510 -      }
   5.511 -
   5.512 -      case TOK_NOT:
   5.513 -      {
   5.514 -        Local<Type> type(zone_, node->expression()->type());
   5.515 -        node->expression()->accept(this);
   5.516 -        
   5.517 -        if (out->isFloat())
   5.518 -            __ not_f();
   5.519 -        else
   5.520 -            __ not_();
   5.521 -        break;
   5.522 -      }
   5.523 -
   5.524 -      case TOK_LABEL:
   5.525 -      {
   5.526 -        Local<Type> from(zone_, node->expression()->type());
   5.527 -
   5.528 -        node->expression()->accept(this);
   5.529 -        if (!from->isFloat() && out->isFloat())
   5.530 -            __ bits_f2i();
   5.531 -        else if (from->isFloat() && !out->isFloat())
   5.532 -            __ bits_i2f();
   5.533 -        break;
   5.534 -      }
   5.535 -
   5.536 -      case TOK_SIZEOF:
   5.537 -      {
   5.538 -        Local<Type> type(zone_, node->expression()->type());
   5.539 -        if (type->isFixedLength()) {
   5.540 -            __ int_(type->fixedLength());
   5.541 -        } else {
   5.542 -            node->expression()->accept(this);
   5.543 -            __ sizeof_();
   5.544 -        }
   5.545 -        break;
   5.546 -      }
   5.547 -
   5.548 -      default:
   5.549 -        assert(node->token() == TOK_TILDE);
   5.550 -        node->expression()->accept(this);
   5.551 -        __ bitnot();
   5.552 -        break;
   5.553 -    }
   5.554 -}
   5.555 -
   5.556 -void
   5.557 -BytecodeCompiler::visit(BinaryExpression *node)
   5.558 -{
   5.559 -    if (node->token() == TOK_AND || node->token() == TOK_OR) {
   5.560 -        Label success, failure, done;
   5.561 -        visitForTest(node, &success, &failure, &success);
   5.562 -        __ bind(&success);
   5.563 -        __ int_(1);
   5.564 -        __ drop(1);         // Otherwise, the stack depth will be +1 too much.
   5.565 -        __ jump(&done);
   5.566 -        __ bind(&failure);
   5.567 -        __ int_(0);
   5.568 -        __ bind(&done);
   5.569 -        return;
   5.570 -    }
   5.571 -
   5.572 -    Local<Type> leftType(zone_, node->left()->type());
   5.573 -    Local<Type> rightType(zone_, node->right()->type());
   5.574 -    Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
   5.575 -
   5.576 -    visitForALU(coerce, node->left());
   5.577 -    visitForALU(coerce, node->right());
   5.578 -
   5.579 -    Opcode op = TokenToOpcode(node->token());
   5.580 -    if (node->type()->isFloat())
   5.581 -        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
   5.582 -
   5.583 -    __ note_position(node->pos());
   5.584 -    __ binary(op);
   5.585 -}
   5.586 -
   5.587 -void
   5.588 -BytecodeCompiler::visit(IndexExpression *node)
   5.589 -{
   5.590 -    node->left()->accept(this);
   5.591 -    node->right()->accept(this);
   5.592 -    __ note_position(node->pos());
   5.593 -    __ getelem(node->type());
   5.594 -}
   5.595 -
   5.596 -void
   5.597 -BytecodeCompiler::visit(FieldExpression *node)
   5.598 -{
   5.599 -    node->left()->accept(this);
   5.600 -    __ getfield(node->fieldIndex(), node->type());
   5.601 -}
   5.602 -
   5.603 -void
   5.604 -BytecodeCompiler::visit(ReturnStatement *node)
   5.605 -{
   5.606 -    if (node->expression()) {
   5.607 -        node->expression()->accept(this);
   5.608 -        __ return_();
   5.609 -    } else {
   5.610 -        __ returnvoid();
   5.611 -    }
   5.612 -}
   5.613 -
   5.614 -void
   5.615 -BytecodeCompiler::visitForTest(Expression *expression,
   5.616 -                               Label *trueBranch,
   5.617 -                               Label *falseBranch,
   5.618 -                               Label *fallthrough)
   5.619 -{
   5.620 -    TokenKind token = ToCompare(expression);
   5.621 -    if (token == TOK_EOF || token == TOK_NOT) {
   5.622 -        if (token == TOK_EOF)
   5.623 -            expression->accept(this);
   5.624 -        else
   5.625 -            expression->toUnaryExpression()->expression()->accept(this);
   5.626 -        
   5.627 -        bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
   5.628 -
   5.629 -        Opcode op = jumpOnTrue ? OP_JT : OP_JF;
   5.630 -        if (expression->type()->isFloat())
   5.631 -            op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
   5.632 -
   5.633 -        if (fallthrough == falseBranch)
   5.634 -            __ j(op, trueBranch);
   5.635 -        else
   5.636 -            __ j(op, falseBranch); 
   5.637 -        return;
   5.638 -    }
   5.639 -
   5.640 -    BinaryExpression *binary = expression->toBinaryExpression();
   5.641 -
   5.642 -    if (token == TOK_AND || token == TOK_OR) {
   5.643 -        Label next;
   5.644 -        if (token == TOK_AND)
   5.645 -            visitForTest(binary->left(), &next, falseBranch, &next);
   5.646 -        else
   5.647 -            visitForTest(binary->left(), trueBranch, &next, &next);
   5.648 -        __ bind(&next);
   5.649 -        visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
   5.650 -        return;
   5.651 -    }
   5.652 -
   5.653 -    Opcode op = CompareTokenToJump(token);
   5.654 -    if (fallthrough == trueBranch)
   5.655 -        op = Invert(op);
   5.656 -
   5.657 -    Local<Type> leftType(zone_, binary->left()->type());
   5.658 -    Local<Type> rightType(zone_, binary->right()->type());
   5.659 -    Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
   5.660 -
   5.661 -    visitForALU(coerce, binary->left());
   5.662 -    visitForALU(coerce, binary->right());
   5.663 -    if (coerce->isFloat())
   5.664 -        op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
   5.665 -
   5.666 -    if (fallthrough == trueBranch)
   5.667 -        __ j(op, falseBranch);
   5.668 -    else
   5.669 -        __ j(op, trueBranch);
   5.670 -}
   5.671 -
   5.672 -void
   5.673 -BytecodeCompiler::visit(ForStatement *node)
   5.674 -{
   5.675 -    AutoEnterScope forScope(this, node->scope());
   5.676 -
   5.677 -    recordLifoSlot(node->scope());
   5.678 -
   5.679 -    Label join, update;
   5.680 -    LoopScope loop(scope_, &join, &update, &loop_);
   5.681 -
   5.682 -    if (node->initialization())
   5.683 -        node->initialization()->accept(this);
   5.684 -
   5.685 -    Label header, test;
   5.686 -    if (node->condition())
   5.687 -        __ jump(&test);
   5.688 -
   5.689 -    __ bind(&header);
   5.690 -    node->body()->accept(this);
   5.691 -
   5.692 -    __ bind(&update);
   5.693 -    if (node->update())
   5.694 -        node->update()->accept(this);
   5.695 -
   5.696 -    if (node->condition()) {
   5.697 -        __ bind(&test);
   5.698 -        visitForTest(node->condition(), &header, &join, &join);
   5.699 -    } else {
   5.700 -        __ jump(&header);
   5.701 -    }
   5.702 -
   5.703 -    __ bind(&join);
   5.704 -
   5.705 -    if (node->scope())
   5.706 -        unwindTo(node->scope()->enclosing());
   5.707 -    assert(__ stackDepth() == 0);
   5.708 -}
   5.709 -
   5.710 -void
   5.711 -BytecodeCompiler::visit(WhileStatement *node)
   5.712 -{
   5.713 -    Label header, join;
   5.714 -
   5.715 -    __ bind(&header);
   5.716 -
   5.717 -    LoopScope loop(scope_, &join, &header, &loop_);
   5.718 -
   5.719 -    if (node->token() == TOK_WHILE) {
   5.720 -        Label body;
   5.721 -
   5.722 -        visitForTest(node->condition(), &body, &join, &body);
   5.723 -        __ bind(&body);
   5.724 -        node->body()->accept(this);
   5.725 -        __ jump(&header);
   5.726 -    } else {
   5.727 -        node->body()->accept(this);
   5.728 -        visitForTest(node->condition(), &header, &join, &join);
   5.729 -    }
   5.730 -
   5.731 -    __ bind(&join);
   5.732 -}
   5.733 -
   5.734 -void
   5.735 -BytecodeCompiler::visit(BreakStatement *node)
   5.736 -{
   5.737 -    unwindTo(loop_->scope());
   5.738 -    __ jump(loop_->break_());
   5.739 -}
   5.740 -
   5.741 -void
   5.742 -BytecodeCompiler::visit(ContinueStatement *node)
   5.743 -{
   5.744 -    unwindTo(loop_->scope());
   5.745 -    __ jump(loop_->continue_());
   5.746 -}
   5.747 -
   5.748 -void
   5.749 -BytecodeCompiler::visit(BlockStatement *node)
   5.750 -{
   5.751 -    AutoEnterScope blockScope(this, node->scope());
   5.752 -
   5.753 -    recordLifoSlot(node->scope());
   5.754 -
   5.755 -    for (size_t i = 0; i < node->statements()->length(); i++) {
   5.756 -        Statement *statement = node->statements()->at(i);
   5.757 -        statement->accept(this);
   5.758 -        assert(__ stackDepth() == 0);
   5.759 -    }
   5.760 -
   5.761 -    // We don't bother emitting an "unwind" instruction for function scopes,
   5.762 -    // since this is taken care of by the calling convention.
   5.763 -    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
   5.764 -        unwindTo(node->scope()->enclosing());
   5.765 -}
   5.766 -
   5.767 -void
   5.768 -BytecodeCompiler::visit(IntegerLiteral *node)
   5.769 -{
   5.770 -    __ int_(node->value());
   5.771 -}
   5.772 -
   5.773 -void
   5.774 -BytecodeCompiler::visit(BooleanLiteral *node)
   5.775 -{
   5.776 -    if (node->token() == TOK_TRUE)
   5.777 -        __ true_();
   5.778 -    else
   5.779 -        __ false_();
   5.780 -}
   5.781 -
   5.782 -void
   5.783 -BytecodeCompiler::visit(FloatLiteral *node)
   5.784 -{
   5.785 -    __ float_((float)node->value());
   5.786 -}
   5.787 -
   5.788 -void
   5.789 -BytecodeCompiler::visit(StringLiteral *node)
   5.790 -{
   5.791 -    Local<Array> array(zone_, StringLiteralToArray(zone_, node));
   5.792 -    if (!array)
   5.793 -        return;
   5.794 -
   5.795 -    __ note_position(node->pos());
   5.796 -    __ object(array);
   5.797 -}
   5.798 -
   5.799 -void
   5.800 -BytecodeCompiler::getEnvSlot(Variable *var)
   5.801 -{
   5.802 -    assert(var->scope()->kind() == Scope::GLOBAL);
   5.803 -    __ getglobal(var);
   5.804 -}
   5.805 -
   5.806 -void
   5.807 -BytecodeCompiler::setEnvSlot(Variable *var)
   5.808 -{
   5.809 -    assert(var->scope()->kind() == Scope::GLOBAL);
   5.810 -    __ setglobal(var);
   5.811 -}
   5.812 -
   5.813 -static bool
   5.814 -FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
   5.815 -{
   5.816 -    Local<Array> string(zone);
   5.817 -    for (size_t i = 0; i < literal->expressions()->length(); i++) {
   5.818 -        Expression *expr = literal->expressions()->at(i);
   5.819 -        StringLiteral *lit = expr->toStringLiteral();
   5.820 -        if ((string = StringLiteralToArray(zone, lit)) == NULL)
   5.821 -            return false;
   5.822 -
   5.823 -        array->writeObject(zone, i, string);
   5.824 -
   5.825 -        if (string->length() > *maxsize)
   5.826 -            *maxsize = string->length();
   5.827 -
   5.828 -        assert(!array->type()->contained()->isFixedLength() ||
   5.829 -                array->type()->contained()->fixedLength() >= string->length());
   5.830 -    }
   5.831 -
   5.832 -    return true;
   5.833 -}
   5.834 -
   5.835 -static bool
   5.836 -FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
   5.837 -{
   5.838 -    assert(array->type()->fixedLength() == literal->expressions()->length());
   5.839 -
   5.840 -    for (size_t i = 0; i < literal->expressions()->length(); i++) {
   5.841 -        Expression *expr = literal->expressions()->at(i);
   5.842 -        if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
   5.843 -            array->writeInt32(i, lit->value());
   5.844 -            continue;
   5.845 -        }
   5.846 -        if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
   5.847 -            if (lit->token() == TOK_TRUE)
   5.848 -                array->writeInt32(i, 1);
   5.849 -            else
   5.850 -                array->writeInt32(i, 0);
   5.851 -            continue;
   5.852 -        }
   5.853 -        if (FloatLiteral *lit = expr->asFloatLiteral()) {
   5.854 -            array->writeFloat(i, lit->value());
   5.855 -            continue;
   5.856 -        }
   5.857 -
   5.858 -        // Unrecognized literal type.
   5.859 -        assert(false);
   5.860 -    }
   5.861 -
   5.862 -    return true;
   5.863 -}
   5.864 -
   5.865 -static bool
   5.866 -TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
   5.867 -                     unsigned *maxsize)
   5.868 -{
   5.869 -    assert(type->fixedLength() == literal->expressions()->length());
   5.870 -
   5.871 -    Local<Type> contained(zone, type->contained());
   5.872 -    if (contained->isCharArray())
   5.873 -        return FillArrayLiteral_String(zone, array, literal, maxsize);
   5.874 -
   5.875 -    if (!contained->isArray())
   5.876 -        return FillArrayLiteral_Primitive(zone, array, literal);
   5.877 -
   5.878 -    Local<Array> subarray(zone);
   5.879 -    for (size_t i = 0; i < literal->expressions()->length(); i++) {
   5.880 -        Expression *expr = literal->expressions()->at(i);
   5.881 -        subarray = Array::cast(array->readObject(i));
   5.882 -        if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
   5.883 -            return false;
   5.884 -    }
   5.885 -
   5.886 -    return true;
   5.887 -}
   5.888 -
   5.889 -static Array *
   5.890 -BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
   5.891 -{
   5.892 -    Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
   5.893 -    if (!root)
   5.894 -        return NULL;
   5.895 -
   5.896 -    // This should have allocated everything in the array, so all we need to
   5.897 -    // do is traverse down to the lowest levels and copy things.
   5.898 -    Local<Type> type(zone, map->type());
   5.899 -    if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
   5.900 -        return NULL;
   5.901 -
   5.902 -    return root;
   5.903 -}
   5.904 -
   5.905 -static inline bool
   5.906 -ArrayContainsCharBuffers(Type *type)
   5.907 -{
   5.908 -    if (type->contained()->isArray())
   5.909 -        return ArrayContainsCharBuffers(type->contained());
   5.910 -    return type->isCharArray();
   5.911 -}
   5.912 -
   5.913 -void
   5.914 -BytecodeCompiler::visit(VariableDeclaration *node)
   5.915 -{
   5.916 -    Variable *var = node->variable();
   5.917 -    
   5.918 -    Local<Type> type(zone_, var->type());
   5.919 -    if (type->isArray()) {
   5.920 -        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
   5.921 -        __ note_position(node->pos());
   5.922 -
   5.923 -        Local<Type> right(zone_);
   5.924 -        if (node->initialization())
   5.925 -            right = node->initialization()->type();
   5.926 -
   5.927 -        // There are a few methods for allocating, here:
   5.928 -        // (1) If the array is fixed,
   5.929 -        //    (a) Initializer not present,
   5.930 -        //              NEWFIXED
   5.931 -        //    (b) Left is const non-string:
   5.932 -        //              <nothing>
   5.933 -        //    (b) Otherwise:
   5.934 -        //              NEWFIXED
   5.935 -        //              COPYARRAY
   5.936 -        // (2) If the array is not fixed,
   5.937 -        //    (a) Initializer is not present,
   5.938 -        //              NEWEMPTY
   5.939 -        //    (b) Initializer is not a string literal,
   5.940 -        //        or left is const:
   5.941 -        //              <nothing>
   5.942 -        //    (c) Initializer is a string literal,
   5.943 -        //              NEWSIZED
   5.944 -        //              COPYARRAY
   5.945 -        //
   5.946 -
   5.947 -        Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
   5.948 -                              ? Heap::Tenure_Old
   5.949 -                              : Heap::Tenure_Default;
   5.950 -
   5.951 -        if (Expression *init = node->initialization()) {
   5.952 -            if (init->isArrayLiteral()) {
   5.953 -                unsigned maxsize = 0;
   5.954 -                Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
   5.955 -                if (!array)
   5.956 -                    return;
   5.957 -
   5.958 -                assert(type->isFixedLength());
   5.959 -
   5.960 -                if (type->isConst()) {
   5.961 -                    __ object(array);
   5.962 -                } else if (ArrayContainsCharBuffers(type)) {
   5.963 -                    // This array contains mutable char buffers, so
   5.964 -                    // unfortunately this gets a little more complicated. We
   5.965 -                    // compute the maximum size needed for the innermost
   5.966 -                    // string, which is similar to SP1. This means we can use
   5.967 -                    // CopyArray rather than individually emit opcodes to clone
   5.968 -                    // every string.
   5.969 -                    Local<Type> child(zone_, type);
   5.970 -                    for (size_t i = 0; i < type->levels() - 1; i++) {
   5.971 -                        __ int_(child->fixedLength());
   5.972 -                        child = child->contained();
   5.973 -                    }
   5.974 -                    __ int_(maxsize);
   5.975 -                    __ newarray(OP_NEWSIZED, map, tenure);
   5.976 -                    __ object(array);
   5.977 -                    __ copyarray();
   5.978 -                } else {
   5.979 -                    __ newarray(OP_NEWFIXED, map, tenure);
   5.980 -                    __ object(array);
   5.981 -                    __ copyarray();
   5.982 -                }
   5.983 -            } else if (type->isFixedLength()) {
   5.984 -                // Note in the case of:
   5.985 -                // const String:buffer[50] = "hello";
   5.986 -                //
   5.987 -                // We want to preserve sizeof(buffer) == 50.
   5.988 -                if (type->isConst() && !type->isCharArray()) {
   5.989 -                    init->accept(this);
   5.990 -                } else {
   5.991 -                    __ newarray(OP_NEWFIXED, map, tenure);
   5.992 -                    init->accept(this);
   5.993 -                    __ copyarray();
   5.994 -                }
   5.995 -            } else if (!type->isConst() && init->isStringLiteral()) {
   5.996 -                // This is a degenerate case of ArrayLiteral.
   5.997 -                __ int_(right->fixedLength());
   5.998 -                __ newarray(OP_NEWSIZED, map, tenure);
   5.999 -                init->accept(this);
  5.1000 -                __ copyarray();
  5.1001 -            } else if (type->isConst()) {
  5.1002 -                init->accept(this);
  5.1003 -            }
  5.1004 -        } else if (type->isFixedLength()) {
  5.1005 -            __ newarray(OP_NEWFIXED, map, tenure);
  5.1006 -        } else {
  5.1007 -            if (node->postDimensions()) {
  5.1008 -                for (size_t i = 0; i < node->postDimensions()->length(); i++) {
  5.1009 -                    Expression *expr = node->postDimensions()->at(i);
  5.1010 -                    if (expr)
  5.1011 -                        expr->accept(this);
  5.1012 -                    else
  5.1013 -                        __ int_(0);
  5.1014 -                }
  5.1015 -                __ newarray(OP_NEWSIZED, map, tenure);
  5.1016 -            } else {
  5.1017 -                __ newarray(OP_NEWEMPTY, map, tenure);
  5.1018 -            }
  5.1019 -        }
  5.1020 -    } else if (type->isStruct()) {
  5.1021 -        Local<StructMap> map(zone_, StructMap::cast(type->newMap()));
  5.1022 -
  5.1023 -        // Because structs can contain arrays, any sort of composition
  5.1024 -        // triggers non-LIFO allocation. This is just for correctness.
  5.1025 -        // We could do better by:
  5.1026 -        //  (1) Limiting to structs that just (recursively) contain arrays,
  5.1027 -        //  (2) Swap Stack for Default tenure in Struct::New
  5.1028 -        //  (3) JIT analysis
  5.1029 -        if (var->scope()->kind() == Scope::GLOBAL)
  5.1030 -            __ newstruct(map, Heap::Tenure_Old);
  5.1031 -        else if (var->needsHeapAllocation() || map->composed())
  5.1032 -            __ newstruct(map, Heap::Tenure_Default);
  5.1033 -        else
  5.1034 -            __ newstruct(map, Heap::Tenure_Stack);
  5.1035 -    } else {
  5.1036 -        if (node->initialization()) {
  5.1037 -            node->initialization()->accept(this);
  5.1038 -        } else {
  5.1039 -            if (type->isInt32OrEnum() || type->isBool()) {
  5.1040 -                __ int_(0);
  5.1041 -            } else {
  5.1042 -                assert(type->isFloat());
  5.1043 -                __ float_(0);
  5.1044 -            }
  5.1045 -        }
  5.1046 -    }
  5.1047 -
  5.1048 -    if (var->location() == Variable::STACK) {
  5.1049 -        __ setlocal(var);
  5.1050 -        locals_->set(zone_, var->slot(), var->type());
  5.1051 -    } else {
  5.1052 -        assert(var->location() == Variable::ENVIRONMENT);
  5.1053 -        setEnvSlot(var);
  5.1054 -    }
  5.1055 -
  5.1056 -    __ pop();
  5.1057 -}
  5.1058 -
  5.1059 -void
  5.1060 -BytecodeCompiler::visit(CallExpression *node)
  5.1061 -{
  5.1062 -    Local<Type> funType(zone_, node->callee()->type());
  5.1063 -
  5.1064 -    // Sniff out natives, which have a specific opcode and are guaranteed to
  5.1065 -    // be called via name proxy.
  5.1066 -    NamedFunction *native = NULL;
  5.1067 -    if (funType->isNative())
  5.1068 -        native = node->callee()->toNameProxy()->binding()->toNamedFunction();
  5.1069 -
  5.1070 -    Local<Type> given(zone_);
  5.1071 -    for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
  5.1072 -        Expression *arg = node->arguments()->at(i);
  5.1073 -
  5.1074 -        given = arg->type();
  5.1075 -
  5.1076 -        // We need to compute a reference if the parameter was in the form:
  5.1077 -        //  f(&a)
  5.1078 -        // Note this form does not allow: f({})
  5.1079 -        // 
  5.1080 -        // We also need to compute references for all variadic native
  5.1081 -        // arguments, but arrays and references are already in the
  5.1082 -        // appropriate form.
  5.1083 -        bool mustPushReference = false;
  5.1084 -        if (i >= funType->parameters()->length()) {
  5.1085 -            assert(funType->isNative() && funType->isNativeVariadic());
  5.1086 -            mustPushReference = !given->isArray() && !given->isReference();
  5.1087 -        } else if (funType->parameterAt(i)->isReference()) {
  5.1088 -            mustPushReference = !given->isReference();
  5.1089 -        }
  5.1090 -
  5.1091 -        // If a native is passed to a native, it must only be one level deep.
  5.1092 -        assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
  5.1093 -
  5.1094 -        if (mustPushReference) {
  5.1095 -            if (arg->isNameProxy()) {
  5.1096 -                // :TODO: test with functions and globals
  5.1097 -                // Compute a reference to the name.
  5.1098 -                Variable *var = arg->toNameProxy()->binding()->toVariable();
  5.1099 -                __ note_position(node->pos());
  5.1100 -                __ newref(var);
  5.1101 -            } else if (arg->isFieldExpression()) {
  5.1102 -                FieldExpression *expr = arg->toFieldExpression();
  5.1103 -                expr->left()->accept(this);
  5.1104 -                __ note_position(expr->pos());
  5.1105 -                __ fieldref_lifo(expr->fieldIndex());
  5.1106 -            } else {
  5.1107 -                // We don't know how to, or can't, build a direct reference to
  5.1108 -                // this type. Make an indirect one, by taking the top of the
  5.1109 -                // stack and boxing it up.
  5.1110 -                arg->accept(this);
  5.1111 -                __ note_position(node->pos());
  5.1112 -                __ slotref_lifo();
  5.1113 -            }
  5.1114 -        } else {
  5.1115 -            arg->accept(this);
  5.1116 -        }
  5.1117 -    }
  5.1118 -
  5.1119 -    unsigned argc = node->arguments()->length();
  5.1120 -
  5.1121 -    // If there are missing arguments, then we're not done and have to push
  5.1122 -    // default parameters.
  5.1123 -    Local<Box> box(zone_);
  5.1124 -    Local<Array> array(zone_);
  5.1125 -    Local<ArrayMap> map(zone_);
  5.1126 -    for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
  5.1127 -        box = Box::cast(funType->defaults()->at(i));
  5.1128 -
  5.1129 -        if (box->type()->isPod()) {
  5.1130 -            if (box->type()->pod() == PrimitiveType_Int32)
  5.1131 -                __ int_(box->toInt32());
  5.1132 -            else if (box->type()->pod() == PrimitiveType_Float)
  5.1133 -                __ float_(box->toFloat());
  5.1134 -            else
  5.1135 -                assert(false);
  5.1136 -
  5.1137 -            if (funType->parameterAt(i)->isReference()) {
  5.1138 -                __ note_position(node->pos());
  5.1139 -                __ slotref_lifo();
  5.1140 -            }
  5.1141 -        } else {
  5.1142 -            assert(box->type()->isArray());
  5.1143 -
  5.1144 -            array = Array::cast(box->toObject());
  5.1145 -            if (funType->parameterAt(i)->isConst()) {
  5.1146 -                __ object(array);
  5.1147 -            } else {
  5.1148 -                // We need to copy the array since it's mutable. Note that
  5.1149 -                // although COPYARRAY returns its left-hand side, this may
  5.1150 -                // change in the future, we do the same thing and dupe the
  5.1151 -                // newly allocated array.
  5.1152 -                map = ArrayMap::cast(array->map());
  5.1153 -                
  5.1154 -                // Natives cannot escape array references, so we can allocate
  5.1155 -                // them on the LIFO stack.
  5.1156 -                if (funType->isNative())
  5.1157 -                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack);
  5.1158 -                else
  5.1159 -                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default);
  5.1160 -                __ dup();
  5.1161 -                __ object(array);
  5.1162 -                __ copyarray();
  5.1163 -                __ pop();
  5.1164 -            }
  5.1165 -        }
  5.1166 -
  5.1167 -        argc++;
  5.1168 -    }
  5.1169 -
  5.1170 -    __ note_position(node->pos());
  5.1171 -    if (native) {
  5.1172 -        __ callnative(native->slot(), argc);
  5.1173 -        __ drop(argc);
  5.1174 -    } else {
  5.1175 -        node->callee()->accept(this);
  5.1176 -        __ call(funType);
  5.1177 -        __ drop(argc + 1);
  5.1178 -    }
  5.1179 -}
  5.1180 -
  5.1181 -void
  5.1182 -BytecodeCompiler::visit(TernaryExpression *node)
  5.1183 -{
  5.1184 -    Label success, failure, join;
  5.1185 -
  5.1186 -    visitForTest(node->condition(), &success, &failure, &success);
  5.1187 -    __ bind(&success);
  5.1188 -    node->left()->accept(this);
  5.1189 -    __ drop(1);
  5.1190 -    __ jump(&join);
  5.1191 -    __ bind(&failure);
  5.1192 -    node->right()->accept(this);
  5.1193 -    __ bind(&join);
  5.1194 -}
  5.1195 -
  5.1196 -void
  5.1197 -BytecodeCompiler::visit(IfStatement *node)
  5.1198 -{
  5.1199 -    Label join;
  5.1200 -    if (!node->ifFalse()) {
  5.1201 -        Label success;
  5.1202 -
  5.1203 -        visitForTest(node->condition(), &success, &join, &success);
  5.1204 -        __ bind(&success);
  5.1205 -        node->ifTrue()->accept(this);
  5.1206 -    } else {
  5.1207 -        Label success, next;
  5.1208 -
  5.1209 -        visitForTest(node->condition(), &success, &next, &success);
  5.1210 -        __ bind(&success);
  5.1211 -        node->ifTrue()->accept(this);
  5.1212 -        __ jump(&join);
  5.1213 -        __ bind(&next);
  5.1214 -        node->ifFalse()->accept(this);
  5.1215 -    }
  5.1216 -
  5.1217 -    __ bind(&join);
  5.1218 -}
  5.1219 -
  5.1220 -bool
  5.1221 -BytecodeCompiler::tableswitch(SwitchStatement *node)
  5.1222 -{
  5.1223 -    CaseValueList *values = node->caseValueList();
  5.1224 -
  5.1225 -    if (values->length() < 3)
  5.1226 -        return false;
  5.1227 -
  5.1228 -    // Find the delta between the largest and smallest value.
  5.1229 -    int hi = values->at(values->length() - 1).box.toInt();
  5.1230 -    int lo = values->at(0).box.toInt();
  5.1231 -    assert(hi > lo);
  5.1232 -
  5.1233 -    unsigned tablesize = TableSwitchEntries(lo, hi);
  5.1234 -    if (tablesize > MAX_TABLESWITCH_ENTRIES)
  5.1235 -        return false;
  5.1236 -
  5.1237 -    Label def, join;
  5.1238 -
  5.1239 -    // Create the list of labels that each statement will bind to.
  5.1240 -    Label *labels = new Label[node->cases()->length()];
  5.1241 -
  5.1242 -    // Create the table of labels we'll use for each case.
  5.1243 -    Label **table = new Label *[tablesize];
  5.1244 -
  5.1245 -    // Link all cases, by default, to the default label.
  5.1246 -    for (size_t i = 0; i < tablesize; i++)
  5.1247 -        table[i] = &def;
  5.1248 -
  5.1249 -    // Now patch actual cases to their correct labels.
  5.1250 -    for (size_t i = 0; i < values->length(); i++) {
  5.1251 -        CaseValue &v = values->at(i);
  5.1252 -        assert(v.statement < node->cases()->length());
  5.1253 -
  5.1254 -        unsigned index = unsigned(v.box.toInt() - lo);
  5.1255 -        assert(index < tablesize);
  5.1256 -
  5.1257 -        table[index] = &labels[v.statement];
  5.1258 -    }
  5.1259 -
  5.1260 -    // Emit the tableswitch opcode and the jump table.
  5.1261 -    __ tableswitch(lo, hi, &def, table);
  5.1262 -
  5.1263 -    // We're done with the jump table now.
  5.1264 -    delete [] table;
  5.1265 -
  5.1266 -    // Emit each statement.
  5.1267 -    for (size_t i = 0; i < node->cases()->length(); i++) {
  5.1268 -        Statement *stmt = node->cases()->at(i)->statement();
  5.1269 -
  5.1270 -        __ bind(&labels[i]);
  5.1271 -        stmt->accept(this);
  5.1272 -        __ jump(&join);
  5.1273 -    }
  5.1274 -
  5.1275 -    // We're done with the statement labels.
  5.1276 -    delete [] labels;
  5.1277 -
  5.1278 -    // Emit the default case.
  5.1279 -    __ bind(&def);
  5.1280 -    if (node->defaultCase())
  5.1281 -        node->defaultCase()->accept(this);
  5.1282 -
  5.1283 -    __ bind(&join);
  5.1284 -
  5.1285 -    return true;
  5.1286 -}
  5.1287 -
  5.1288 -void
  5.1289 -BytecodeCompiler::visit(SwitchStatement *node)
  5.1290 -{
  5.1291 -    node->expression()->accept(this);
  5.1292 -
  5.1293 -    if (tableswitch(node))
  5.1294 -        return;
  5.1295 -
  5.1296 -    Label join;
  5.1297 -
  5.1298 -    for (size_t i = 0; i < node->cases()->length(); i++) {
  5.1299 -        Case *c = node->cases()->at(i);
  5.1300 -
  5.1301 -        Label success, fail;
  5.1302 -        if (c->others()) {
  5.1303 -            for (size_t j = 0; j < c->others()->length(); j++) {
  5.1304 -                Expression *expr = c->others()->at(j);
  5.1305 -
  5.1306 -                __ dup();
  5.1307 -                expr->accept(this);
  5.1308 -                __ j(OP_JEQ, &success);
  5.1309 -            }
  5.1310 -        }
  5.1311 -
  5.1312 -        // The final test.
  5.1313 -        __ dup();
  5.1314 -        c->expression()->accept(this);
  5.1315 -        __ j(OP_JNE, &fail);
  5.1316 -        __ bind(&success);
  5.1317 -        c->statement()->accept(this);
  5.1318 -        __ jump(&join);
  5.1319 -        __ bind(&fail);
  5.1320 -    }
  5.1321 -
  5.1322 -    if (node->defaultCase())
  5.1323 -        node->defaultCase()->accept(this);
  5.1324 -
  5.1325 -    __ pop();
  5.1326 -    __ bind(&join);
  5.1327 -}
  5.1328 -
  5.1329 -void
  5.1330 -BytecodeCompiler::visit(FunctionStatement *node)
  5.1331 -{
  5.1332 -    if (!node->fun()->used())
  5.1333 -        return;
  5.1334 -
  5.1335 -    if (node->fun()->isNative()) {
  5.1336 -        assert(!moduleData_->natives->at(node->fun()->slot()));
  5.1337 -
  5.1338 -        Local<Type> type(zone_, node->fun()->type());
  5.1339 -        Local<String> name(zone_, node->fun()->name());
  5.1340 -        Local<Native> native(zone_, Native::New(zone_, type, name));
  5.1341 -        if (!native)
  5.1342 -            return;
  5.1343 -
  5.1344 -        moduleData_->natives->set(zone_, node->fun()->slot(), native);
  5.1345 -        return;
  5.1346 -    }
  5.1347 -
  5.1348 -    // If the function has no body, then it's just a declaration.
  5.1349 -    if (!node->body()) {
  5.1350 -        assert(node->fun()->isForward() || node->fun()->isPublic());
  5.1351 -        return;
  5.1352 -    }
  5.1353 -
  5.1354 -    BytecodeCompiler child(zone_, tree_, moduleData_);
  5.1355 -    Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
  5.1356 -    if (!fun)
  5.1357 -        return;
  5.1358 -    
  5.1359 -    assert(!moduleData_->module->getFunction(node->fun()->slot()));
  5.1360 -    moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
  5.1361 -}
  5.1362 -
  5.1363 -void
  5.1364 -BytecodeCompiler::visit(FunctionTypeStatement *node)
  5.1365 -{
  5.1366 -}
  5.1367 -
  5.1368 -void
  5.1369 -BytecodeCompiler::visit(EnumStatement *node)
  5.1370 -{
  5.1371 -}
  5.1372 -
  5.1373 -void
  5.1374 -BytecodeCompiler::visit(StructureStatement *node)
  5.1375 -{
  5.1376 -}
  5.1377 -
  5.1378 -void
  5.1379 -BytecodeCompiler::visit(ArrayLiteral *node)
  5.1380 -{
  5.1381 -    // We shouldn't reach these; they're handled manually when initializing
  5.1382 -    // declared arrays.
  5.1383 -    assert(false);
  5.1384 -}
  5.1385 -
  5.1386 -Code *
  5.1387 -BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
  5.1388 -{
  5.1389 -    // STOP doubles as RETURNVOID.
  5.1390 -    __ stop();
  5.1391 -
  5.1392 -    if (__ oom() || zone_->hasPendingException())
  5.1393 -        return NULL;
  5.1394 -
  5.1395 -    Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
  5.1396 -    if (!bytes)
  5.1397 -        return NULL;
  5.1398 -    memcpy(bytes->raw(), __ buffer(), __ length());
  5.1399 -
  5.1400 -    for (size_t i = 0; i < scope->maxContainedLocals(); i++)
  5.1401 -        assert(locals_->at(i));
  5.1402 -
  5.1403 -    Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
  5.1404 -    if (!objects)
  5.1405 -        return NULL;
  5.1406 -
  5.1407 -    for (size_t i = 0; i < __ objects()->length(); i++)
  5.1408 -        objects->set(zone_, i, *(__ objects()->at(i)));
  5.1409 -
  5.1410 -    Local<ByteArray> safepoints(zone_);
  5.1411 -
  5.1412 -    // If any stack slots hold gc pointers at potential failure points in the
  5.1413 -    // bytecode, record them now. We do this by building a list of tuples;
  5.1414 -    // each tuple contains the pc offset, and a bitset containing which stack
  5.1415 -    // slots must be scanned by the gc.
  5.1416 -    if (__ oopRecords()->length()) {
  5.1417 -        size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
  5.1418 -        size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
  5.1419 -        safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
  5.1420 -        if (!safepoints)
  5.1421 -            return NULL;
  5.1422 -
  5.1423 -        Address cursor = safepoints->raw();
  5.1424 -        for (size_t i = 0; i < __ oopRecords()->length(); i++) {
  5.1425 -            OopRecord *record = __ oopRecords()->at(i);
  5.1426 -            assert(record->depth <= __ maxStackDepth());
  5.1427 -
  5.1428 -            *reinterpret_cast<unsigned *>(cursor) = record->offset;
  5.1429 -
  5.1430 -            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
  5.1431 -            for (unsigned i = 0; i < record->depth; i++)
  5.1432 -                bits[i / 8] |= (1 << (i % 8));
  5.1433 -
  5.1434 -            cursor += bytesPerSafepoint;
  5.1435 -        }
  5.1436 -
  5.1437 -        assert(cursor == safepoints->raw() + gcmapSize);
  5.1438 -    }
  5.1439 -
  5.1440 -    Local<ByteArray> sourcemap(zone_);
  5.1441 -    if (__ sourcemapLength()) {
  5.1442 -        sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
  5.1443 -        if (!sourcemap)
  5.1444 -            return NULL;
  5.1445 -
  5.1446 -        memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
  5.1447 -    }
  5.1448 -
  5.1449 -    Local<Code> code(zone_);
  5.1450 -
  5.1451 -    code = Code::New(zone_,
  5.1452 -                     bytes,
  5.1453 -                     locals_,
  5.1454 -                     objects,
  5.1455 -                     __ maxStackDepth(),
  5.1456 -                     moduleData_->module,
  5.1457 -                     safepoints,
  5.1458 -                     sourcemap,
  5.1459 -                     lineno);
  5.1460 -    return code;
  5.1461 -}
  5.1462 -
  5.1463 -Function *
  5.1464 -BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
  5.1465 -{
  5.1466 -    // Note: No need to record a life slot here, since it's part of the Frame.
  5.1467 -    AutoEnterScope functionScope(this, node->scope());
  5.1468 -
  5.1469 -    // Set the initial line, because line mappings are deltas.
  5.1470 -    __ setFirstLine(node->pos().line);
  5.1471 -    locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
  5.1472 -
  5.1473 -    node->body()->accept(this);
  5.1474 -
  5.1475 -    unsigned nargs = node->scope()->numArguments();
  5.1476 -    Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
  5.1477 -    if (!args)
  5.1478 -        return NULL;
  5.1479 -
  5.1480 -    for (size_t i = 0; i < node->scope()->numArguments(); i++)
  5.1481 -        args->set(zone_, i, node->scope()->getArgument(i)->type());
  5.1482 -
  5.1483 -
  5.1484 -    Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
  5.1485 -    if (!code)
  5.1486 -        return NULL;
  5.1487 -
  5.1488 -    Local<Type> type(zone_, node->fun()->type());
  5.1489 -    Local<String> name(zone_, node->fun()->name());
  5.1490 -    Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
  5.1491 -    if (!fun)
  5.1492 -        return NULL;
  5.1493 -
  5.1494 -    // If this function had a forward, export it as a named public.
  5.1495 -    if (node->fun()->isPublic()) {
  5.1496 -        assert(node->fun()->isPublic());
  5.1497 -        ScopedRoot<Function> root(fun);
  5.1498 -        if (!root)
  5.1499 -            return NULL;
  5.1500 -        if (!moduleData_->publics.append(root))
  5.1501 -            return NULL;
  5.1502 -    }
  5.1503 -
  5.1504 -#ifndef NDEBUG
  5.1505 -    Disassemble(code, stdout);
  5.1506 -#endif
  5.1507 -    
  5.1508 -    return fun;
  5.1509 -}
  5.1510 -
  5.1511 -Module *
  5.1512 -BytecodeCompiler::compile()
  5.1513 -{
  5.1514 -    AutoEnterScope scope(this, tree_->scope());
  5.1515 -
  5.1516 -    ModuleData moduleData;
  5.1517 -
  5.1518 -    moduleData_ = &moduleData;
  5.1519 -    moduleData_->module = Module::New(zone_, tree_->scope()->numFunctions());
  5.1520 -
  5.1521 -    if (!moduleData_)
  5.1522 -        return NULL;
  5.1523 -    
  5.1524 -    moduleData_->natives = FixedArray::New(zone_, tree_->scope()->numNatives(), Heap::Tenure_Old);
  5.1525 -    if (!moduleData_->natives)
  5.1526 -        return NULL;
  5.1527 -
  5.1528 -    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  5.1529 -        Statement *statement = tree_->statements()->at(i);
  5.1530 -        statement->accept(this);
  5.1531 -    }
  5.1532 -
  5.1533 -    if (zone_->hasPendingException())
  5.1534 -        return NULL;
  5.1535 -
  5.1536 -#ifndef NDEBUG
  5.1537 -    for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
  5.1538 -        assert(moduleData_->module->getFunction(i));
  5.1539 -    for (size_t i = 0; i < tree_->scope()->numNatives(); i++)
  5.1540 -        assert(moduleData_->natives->at(i));
  5.1541 -#endif
  5.1542 -
  5.1543 -    if (moduleData_->publics.length()) {
  5.1544 -        Local<Function> fun(zone_);
  5.1545 -        Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
  5.1546 -                               Heap::Tenure_Old));
  5.1547 -        if (!list)
  5.1548 -            return NULL;
  5.1549 -
  5.1550 -        for (size_t i = 0; i < moduleData_->publics.length(); i++)
  5.1551 -            list->set(zone_, i, moduleData_->publics[i]);
  5.1552 -
  5.1553 -        moduleData_->module->setPublics(list);
  5.1554 -    }
  5.1555 -
  5.1556 -    moduleData_->module->setNatives(moduleData_->natives);
  5.1557 -
  5.1558 -    if (scope_->numEnvironmentVars()) {
  5.1559 -        Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
  5.1560 -        if (!globalMap)
  5.1561 -            return NULL;
  5.1562 -
  5.1563 -        Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
  5.1564 -        if (!environment)
  5.1565 -            return NULL;
  5.1566 -
  5.1567 -        moduleData_->module->setEnvironment(environment);
  5.1568 -    }
  5.1569 -
  5.1570 -    Local<Code> code(zone_, compileCode(tree_->scope(), 1));
  5.1571 -    if (!code)
  5.1572 -        return NULL;
  5.1573 -
  5.1574 -    Disassemble(code, stdout);
  5.1575 -
  5.1576 -    moduleData_->module->setCode(code);
  5.1577 -
  5.1578 -    return moduleData_->module;
  5.1579 -}
     6.1 --- a/src/BytecodeCompiler.h	Mon Sep 17 00:10:01 2012 -0700
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,159 +0,0 @@
     6.4 -/* vim: set ts=4 sw=4 tw=99 et:
     6.5 - *
     6.6 - * Copyright (C) 2012 David Anderson
     6.7 - *
     6.8 - * This file is part of JITCraft.
     6.9 - *
    6.10 - * JITCraft is free software: you can redistribute it and/or modify it under
    6.11 - * the terms of the GNU General Public License as published by the Free
    6.12 - * Software Foundation, either version 3 of the License, or (at your option)
    6.13 - * any later version.
    6.14 - * 
    6.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    6.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    6.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    6.18 - *
    6.19 - * You should have received a copy of the GNU General Public License along with
    6.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    6.21 - */
    6.22 -#ifndef _include_bytecode_compiler_h_
    6.23 -#define _include_bytecode_compiler_h_
    6.24 -
    6.25 -#include "AST.h"
    6.26 -#include "BytecodeEmitter.h"
    6.27 -#include "Functions.h"
    6.28 -
    6.29 -namespace ke {
    6.30 -
    6.31 -class Module;
    6.32 -class Array;
    6.33 -class ArrayMap;
    6.34 -
    6.35 -struct ModuleData
    6.36 -{
    6.37 -    ScopedRoot<Module> module;
    6.38 -    PoolList<ScopedRoot<Function> > publics;
    6.39 -    ScopedRoot<FixedArray> natives;
    6.40 -};
    6.41 -
    6.42 -class BytecodeCompiler : public AstVisitor
    6.43 -{
    6.44 -    Zone *zone_;
    6.45 -    ParseTree *tree_;
    6.46 -    BytecodeEmitter emitter_;
    6.47 -    ScopedRoot<FixedArray> locals_;
    6.48 -    Scope *scope_;
    6.49 -    ModuleData *moduleData_;
    6.50 -
    6.51 -    class LoopScope
    6.52 -    {
    6.53 -        Scope *scope_;
    6.54 -        BytecodeEmitter::Label *bk_;
    6.55 -        BytecodeEmitter::Label *ct_;
    6.56 -        LoopScope **prevp_;
    6.57 -        LoopScope *prev_;
    6.58 -
    6.59 -      public:
    6.60 -        LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
    6.61 -                  LoopScope **prevp)
    6.62 -          : scope_(scope),
    6.63 -            bk_(bk),
    6.64 -            ct_(ct),
    6.65 -            prevp_(prevp),
    6.66 -            prev_(*prevp)
    6.67 -        {
    6.68 -            *prevp_ = this;
    6.69 -        }
    6.70 -
    6.71 -        ~LoopScope()
    6.72 -        {
    6.73 -            *prevp_ = prev_;
    6.74 -        }
    6.75 -
    6.76 -        BytecodeEmitter::Label *break_() {
    6.77 -            return bk_;
    6.78 -        }
    6.79 -        BytecodeEmitter::Label *continue_() {
    6.80 -            return ct_;
    6.81 -        }
    6.82 -        Scope *scope() {
    6.83 -            return scope_;
    6.84 -        }
    6.85 -    };
    6.86 -
    6.87 -    LoopScope *loop_;
    6.88 -
    6.89 -  public:
    6.90 -    class AutoEnterScope
    6.91 -    {
    6.92 -        BytecodeCompiler *bc_;
    6.93 -        Scope *saved_;
    6.94 -
    6.95 -      public:
    6.96 -        AutoEnterScope(BytecodeCompiler *bc, Scope *scope)
    6.97 -          : bc_(bc),
    6.98 -            saved_(bc->scope_)
    6.99 -        {
   6.100 -            if (scope)
   6.101 -                bc->scope_ = scope;
   6.102 -        }
   6.103 -        ~AutoEnterScope() {
   6.104 -            bc_->scope_ = saved_;
   6.105 -        }
   6.106 -    };
   6.107 -
   6.108 -  private:
   6.109 -    void recordLifoSlot(Scope *scope);
   6.110 -    void unwindTo(Scope *scope);
   6.111 -    void visitForTest(Expression *expression,
   6.112 -                      BytecodeEmitter::Label *trueBranch,
   6.113 -                      BytecodeEmitter::Label *falseBranch,
   6.114 -                      BytecodeEmitter::Label *fallthrough);
   6.115 -    Code *compileCode(Scope *scope, unsigned lineno);
   6.116 -    Function *compileFunction(ModuleData *module, FunctionStatement *fun);
   6.117 -    void visitForALU(Type *needed, Expression *node);
   6.118 -
   6.119 -    void getEnvSlot(Variable *var);
   6.120 -    void setEnvSlot(Variable *var);
   6.121 -
   6.122 -    bool tableswitch(SwitchStatement *node);
   6.123 -
   6.124 -  public:
   6.125 -    BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
   6.126 -
   6.127 -    Module *compile();
   6.128 -
   6.129 -  public:
   6.130 -    void visit(NameProxy *name);
   6.131 -    void visit(Assignment *node);
   6.132 -    void visit(BinaryExpression *node);
   6.133 -    void visit(ReturnStatement *node);
   6.134 -    void visit(ForStatement *node);
   6.135 -    void visit(BlockStatement *node);
   6.136 -    void visit(VariableDeclaration *node);
   6.137 -    void visit(IntegerLiteral *node);
   6.138 -    void visit(BooleanLiteral *node);
   6.139 -    void visit(FloatLiteral *node);
   6.140 -    void visit(StringLiteral *node);
   6.141 -    void visit(ExpressionStatement *node);
   6.142 -    void visit(FunctionStatement *node);
   6.143 -    void visit(CallExpression *node);
   6.144 -    void visit(IfStatement *node);
   6.145 -    void visit(IndexExpression *node);
   6.146 -    void visit(EnumStatement *node);
   6.147 -    void visit(WhileStatement *node);
   6.148 -    void visit(BreakStatement *node);
   6.149 -    void visit(ContinueStatement *node);
   6.150 -    void visit(IncDecExpression *node);
   6.151 -    void visit(UnaryExpression *node);
   6.152 -    void visit(TernaryExpression *node);
   6.153 -    void visit(StructureStatement *node);
   6.154 -    void visit(FieldExpression *node);
   6.155 -    void visit(SwitchStatement *node);
   6.156 -    void visit(FunctionTypeStatement *node);
   6.157 -    void visit(ArrayLiteral *node);
   6.158 -};
   6.159 -
   6.160 -}
   6.161 -
   6.162 -#endif // _include_bytecode_generator_h_
     7.1 --- a/src/BytecodeEmitter.cpp	Mon Sep 17 00:10:01 2012 -0700
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,122 +0,0 @@
     7.4 -/* vim: set ts=4 sw=4 tw=99 et:
     7.5 - *
     7.6 - * Copyright (C) 2012 David Anderson
     7.7 - *
     7.8 - * This file is part of JITCraft.
     7.9 - *
    7.10 - * JITCraft is free software: you can redistribute it and/or modify it under
    7.11 - * the terms of the GNU General Public License as published by the Free
    7.12 - * Software Foundation, either version 3 of the License, or (at your option)
    7.13 - * any later version.
    7.14 - * 
    7.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    7.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    7.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    7.18 - *
    7.19 - * You should have received a copy of the GNU General Public License along with
    7.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    7.21 - */
    7.22 -#include <stdlib.h>
    7.23 -#include <string.h>
    7.24 -#include "BytecodeEmitter.h"
    7.25 -#include "Utility.h"
    7.26 -#include "Types.h"
    7.27 -#include "Zone.h"
    7.28 -#include "Spaces-inl.h"
    7.29 -#include "Heap-inl.h"
    7.30 -
    7.31 -using namespace ke;
    7.32 -
    7.33 -BytecodeEmitter::BytecodeEmitter(PoolAllocator &pool)
    7.34 -  : pool_(pool),
    7.35 -    buffer_(inline_buffer_),
    7.36 -    buffer_pos_(buffer_),
    7.37 -    buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
    7.38 -    oom_(false),
    7.39 -    maxStackDepth_(0)
    7.40 -{
    7.41 -    lastCodePosition_ = 0;
    7.42 -    firstLine_ = 1;
    7.43 -}
    7.44 -
    7.45 -bool
    7.46 -BytecodeEmitter::growBuffer(size_t nbytes)
    7.47 -{
    7.48 -    if (oom_) {
    7.49 -        buffer_pos_ = buffer_;
    7.50 -        return false;
    7.51 -    }
    7.52 -
    7.53 -    size_t newSize = size_t((buffer_end_ - buffer_) * 2);
    7.54 -    if (newSize >= MAX_LENGTH) {
    7.55 -        oom_ = true;
    7.56 -        buffer_pos_ = buffer_;
    7.57 -        ZONE()->reportOutOfMemory();
    7.58 -        return false;
    7.59 -    }
    7.60 -
    7.61 -    bytecode *newBuffer;
    7.62 -    if (buffer_ == inline_buffer_)
    7.63 -        newBuffer = (bytecode *)malloc(newSize);
    7.64 -    else
    7.65 -        newBuffer = (bytecode *)realloc(buffer_, newSize);
    7.66 -
    7.67 -    // If we can't allocate a buffer, reset the buffer to the start and set
    7.68 -    // a flag to indicate out-of-memory.
    7.69 -    if (!newBuffer) {
    7.70 -        oom_ = true;
    7.71 -        buffer_pos_ = buffer_;
    7.72 -        ZONE()->reportOutOfMemory();
    7.73 -        return false;
    7.74 -    }
    7.75 -
    7.76 -    if (buffer_ == inline_buffer_)
    7.77 -        memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
    7.78 -
    7.79 -    buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
    7.80 -    buffer_ = newBuffer;
    7.81 -    buffer_end_ = buffer_ + newSize;
    7.82 -    assert(buffer_pos_ + nbytes < buffer_end_);
    7.83 -
    7.84 -    return true;
    7.85 -}
    7.86 -
    7.87 -void
    7.88 -BytecodeEmitter::recordOops()
    7.89 -{
    7.90 -    OopRecord *record = new (pool_) OopRecord(oopMap_.length(), position());
    7.91 -
    7.92 -    record->slots = (bool *)pool_.allocate(record->depth);
    7.93 -    if (!record->slots) {
    7.94 -        oom_ = true;
    7.95 -        return;
    7.96 -    }
    7.97 -
    7.98 -    bool hadOops = false;
    7.99 -    for (size_t i = 0; i < oopMap_.length(); i++) {
   7.100 -        bool bit = oopMap_[i];
   7.101 -        record->slots[i] = bit;
   7.102 -        hadOops |= bit;
   7.103 -    }
   7.104 -
   7.105 -    if (!hadOops)
   7.106 -        return;
   7.107 -
   7.108 -    oom_ &= oopRecords_.append(record);
   7.109 -}
   7.110 -
   7.111 -void
   7.112 -BytecodeEmitter::note_position(const SourcePosition &pos)
   7.113 -{
   7.114 -    assert(pos.line > 0);
   7.115 -    assert(unsigned(pos.line) >= firstLine_);
   7.116 -
   7.117 -    unsigned lineDelta = unsigned(pos.line) - firstLine_;
   7.118 -    unsigned pcDelta = unsigned(position()) - lastCodePosition_;
   7.119 -
   7.120 -    sourcemap_.writeUint32(pcDelta);
   7.121 -    sourcemap_.writeUint32(lineDelta);
   7.122 -    sourcemap_.writeUint32(pos.col);
   7.123 -
   7.124 -    lastCodePosition_ = unsigned(position());
   7.125 -}
     8.1 --- a/src/BytecodeEmitter.h	Mon Sep 17 00:10:01 2012 -0700
     8.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.3 @@ -1,672 +0,0 @@
     8.4 -/* vim: set ts=4 sw=4 tw=99 et:
     8.5 - *
     8.6 - * Copyright (C) 2012 David Anderson
     8.7 - *
     8.8 - * This file is part of JITCraft.
     8.9 - *
    8.10 - * JITCraft is free software: you can redistribute it and/or modify it under
    8.11 - * the terms of the GNU General Public License as published by the Free
    8.12 - * Software Foundation, either version 3 of the License, or (at your option)
    8.13 - * any later version.
    8.14 - * 
    8.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    8.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    8.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    8.18 - *
    8.19 - * You should have received a copy of the GNU General Public License along with
    8.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
    8.21 - */
    8.22 -#ifndef _include_bytecode_emitter_h_
    8.23 -#define _include_bytecode_emitter_h_
    8.24 -
    8.25 -#include <assert.h>
    8.26 -#include <limits.h>
    8.27 -#include "Opcodes.h"
    8.28 -#include "NameBinding.h"
    8.29 -#include "Handles.h"
    8.30 -#include "CompactBuffer.h"
    8.31 -#include "Array.h"
    8.32 -
    8.33 -namespace ke {
    8.34 -
    8.35 -class Type;
    8.36 -class Map;
    8.37 -class ArrayMap;
    8.38 -
    8.39 -typedef PoolList<ScopedRoot<Object> > ObjectList;
    8.40 -
    8.41 -struct OopRecord : public PoolObject
    8.42 -{
    8.43 -    unsigned depth;
    8.44 -    unsigned offset;
    8.45 -    bool *slots;
    8.46 -
    8.47 -    OopRecord(unsigned length, unsigned offset)
    8.48 -      : depth(length),
    8.49 -        offset(offset),
    8.50 -        slots(NULL)
    8.51 -    {
    8.52 -    }
    8.53 -};
    8.54 -
    8.55 -class BytecodeEmitter
    8.56 -{
    8.57 -  private:
    8.58 -    PoolAllocator &pool_;
    8.59 -
    8.60 -    bytecode *buffer_;
    8.61 -    bytecode *buffer_pos_;
    8.62 -    bytecode *buffer_end_;
    8.63 -    bytecode inline_buffer_[512];
    8.64 -    bool oom_;
    8.65 -    unsigned maxStackDepth_;
    8.66 -    ObjectList objects_;
    8.67 -    PoolList<bool> oopMap_;
    8.68 -    PoolList<OopRecord *> oopRecords_;
    8.69 -    CompactBufferWriter sourcemap_;
    8.70 -    unsigned lastCodePosition_;
    8.71 -    unsigned firstLine_;
    8.72 -
    8.73 -  private:
    8.74 -    // The maximum size of a code object must be such that the distance between
    8.75 -    // two instructions fits into a signed, 31-bit integer. This ensures that
    8.76 -    // all code-bounded buffers (like the number of object literals or
    8.77 -    // safepoints) does not need to be bounds checked. It also means we can add
    8.78 -    // any two offsets and be guaranteed that they don't overflow.
    8.79 -    static const size_t MAX_LENGTH = INT_MAX / 2;
    8.80 -
    8.81 -  private:
    8.82 -    bool growBuffer(size_t bytes);
    8.83 -
    8.84 -    // Checking the return value is not necessary, since the inline buffer is
    8.85 -    // used as a ballast.
    8.86 -    bool ensure(size_t bytes) {
    8.87 -        if (buffer_pos_ + bytes > buffer_end_)
    8.88 -            return growBuffer(bytes);
    8.89 -        return true;
    8.90 -    }
    8.91 -
    8.92 -    void writeUint8(unsigned value) {
    8.93 -        assert(value <= UCHAR_MAX);
    8.94 -        *buffer_pos_++ = value;
    8.95 -    }
    8.96 -    void writeFloat(float value) {
    8.97 -        *(float *)buffer_pos_ = value;
    8.98 -        buffer_pos_ += sizeof(float);
    8.99 -    }
   8.100 -    void writeInt32(int value) {
   8.101 -        *(int *)buffer_pos_ = value;
   8.102 -        buffer_pos_ += sizeof(int);
   8.103 -    }
   8.104 -    void writeUint32(unsigned value) {
   8.105 -        *(unsigned *)buffer_pos_ = value;
   8.106 -        buffer_pos_ += sizeof(unsigned);
   8.107 -    }
   8.108 -    void writeOp(Opcode op) {
   8.109 -        if (oom_)
   8.110 -            return;
   8.111 -
   8.112 -        writeUint8(op);
   8.113 -        for (int i = 0; i < OpcodeInfo[op].nuses; i++)
   8.114 -            oopMap_.pop();
   8.115 -        for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
   8.116 -            oopMap_.append(false);
   8.117 -        if (oopMap_.length() > maxStackDepth_)
   8.118 -            maxStackDepth_ = oopMap_.length();
   8.119 -    }
   8.120 -    void writeObject(Object *obj) {
   8.121 -        writeUint32(objects_.length());
   8.122 -        ScopedRoot<Object> root(obj);
   8.123 -        if (!objects_.append(root))
   8.124 -            oom_ = true;
   8.125 -    }
   8.126 -
   8.127 -    int position() const {
   8.128 -        assert(buffer_pos_ - buffer_ < INT_MAX / 2);
   8.129 -        return int(buffer_pos_ - buffer_);
   8.130 -    }
   8.131 -
   8.132 -  public:
   8.133 -    BytecodeEmitter(PoolAllocator &pool);
   8.134 -
   8.135 -    bytecode *buffer() const {
   8.136 -        return buffer_;
   8.137 -    }
   8.138 -    unsigned length() const {
   8.139 -        return unsigned(buffer_pos_ - buffer_);
   8.140 -    }
   8.141 -    bool oom() const {
   8.142 -        return oom_ || sourcemap_.oom();
   8.143 -    }
   8.144 -    unsigned stackDepth() const {
   8.145 -        return oopMap_.length();
   8.146 -    }
   8.147 -    unsigned maxStackDepth() const {
   8.148 -        return maxStackDepth_;
   8.149 -    }
   8.150 -    const ObjectList *objects() const {
   8.151 -        return &objects_;
   8.152 -    }
   8.153 -    PoolList<OopRecord *> *oopRecords() {
   8.154 -        return &oopRecords_;
   8.155 -    }
   8.156 -
   8.157 -    void drop(unsigned amt) {
   8.158 -        assert(amt <= stackDepth());
   8.159 -        for (unsigned i = 0; i < amt; i++)
   8.160 -            oopMap_.pop();
   8.161 -    }
   8.162 -
   8.163 -    void note_position(const SourcePosition &pos);
   8.164 -    uint8 *sourcemap() const {
   8.165 -        return sourcemap_.buffer();
   8.166 -    }
   8.167 -    size_t sourcemapLength() const {
   8.168 -        return sourcemap_.length();
   8.169 -    }
   8.170 -    void setFirstLine(unsigned line) {
   8.171 -        assert(!sourcemap_.length());
   8.172 -        firstLine_ = line;
   8.173 -    }
   8.174 -
   8.175 -  public:
   8.176 -    // A label represents a local control-flow target in the bytecode. A label
   8.177 -    // may be in three states:
   8.178 -    //
   8.179 -    // (1) Empty - the label is not used yet.
   8.180 -    // (2) Pending - the label has incoming jumps, but the actual location of
   8.181 -    //               is not yet known. The list of jumps is threaded through
   8.182 -    //               the four bytes reserved for each emitted jump target. In
   8.183 -    //               this case, the offset field is the location of the most
   8.184 -    //               recently emitted incoming jump.
   8.185 -    // (3) Bound   - the label's position has been pinned.
   8.186 -    //
   8.187 -    // A jump can be emitted to a label in any state. Binding a label
   8.188 -    // immediately backpatches all pending incoming jumps. A label must be
   8.189 -    // bound if it is used.
   8.190 -    class Label
   8.191 -    {
   8.192 -        int offset_ : 31;
   8.193 -        bool bound_ : 1;
   8.194 -
   8.195 -        void setOffset(int offset) {
   8.196 -            offset_ = offset;
   8.197 -            assert(offset_ == offset);
   8.198 -        }
   8.199 -
   8.200 -      public:
   8.201 -        static const int INVALID_OFFSET = -1;
   8.202 -
   8.203 -      public:
   8.204 -        Label()
   8.205 -          : offset_(INVALID_OFFSET),
   8.206 -            bound_(false)
   8.207 -        {
   8.208 -        }
   8.209 -        ~Label()
   8.210 -        {
   8.211 -            assert(bound_ || offset_ == INVALID_OFFSET);
   8.212 -        }
   8.213 -        
   8.214 -        bool bound() const {
   8.215 -            return bound_;
   8.216 -        }
   8.217 -        int offset() const {
   8.218 -            return offset_;
   8.219 -        }
   8.220 -        void bind(int offset) {
   8.221 -            assert(!bound_);
   8.222 -            setOffset(offset);
   8.223 -            bound_ = true;
   8.224 -        }
   8.225 -        int link(int offset) {
   8.226 -            assert(!bound_);
   8.227 -            int old = offset_;
   8.228 -            setOffset(offset);
   8.229 -            return old;
   8.230 -        }
   8.231 -    };
   8.232 -
   8.233 -  private:
   8.234 -    int patchJumpAt(int at, int to) {
   8.235 -        assert(at >= 0 && at < position());
   8.236 -        int old = *(int *)(buffer_ + at + 1);
   8.237 -        *(int *)(buffer_ + at + 1) = (to - at);
   8.238 -        return old;
   8.239 -    }
   8.240 -
   8.241 -    void singleByteOp(Opcode op) {
   8.242 -        assert(OpcodeInfo[op].length == 1);
   8.243 -        ensure(OpcodeInfo[op].length);
   8.244 -        writeOp(op);
   8.245 -    }
   8.246 -
   8.247 -    // Mark a stack slot as having an object pointer.
   8.248 -    void markOop(unsigned depth, bool oop = true) {
   8.249 -        if (oom_)
   8.250 -            return;
   8.251 -        oopMap_[oopMap_.length() - depth] = oop;
   8.252 -    }
   8.253 -    bool getOop(unsigned depth) {
   8.254 -        if (oom_)
   8.255 -            return false;
   8.256 -        return oopMap_[oopMap_.length() - depth];
   8.257 -    }
   8.258 -
   8.259 -    // Mark the current bytecode position as either re-entrant (meaning, it
   8.260 -    // can leave the interpreter or call to another function), or causing GC.
   8.261 -    // This will record which stack slots have objects and associate that
   8.262 -    // information with the current pc.
   8.263 -    void recordOops();
   8.264 -
   8.265 -  public:
   8.266 -    void int_(int value) {
   8.267 -        ensure(OP_INT);
   8.268 -        writeOp(OP_INT);
   8.269 -        writeInt32(value);
   8.270 -    }
   8.271 -    void return_() {
   8.272 -        ensure(OP_RETURN);
   8.273 -        writeOp(OP_RETURN);
   8.274 -    }
   8.275 -    void getlocal(Variable *var) {
   8.276 -        ensure(OP_GETLOCAL_LENGTH);
   8.277 -        writeOp(OP_GETLOCAL);
   8.278 -        writeUint32(var->slot());
   8.279 -
   8.280 -        if (var->type()->isTraceable())
   8.281 -            markOop(1);
   8.282 -    }
   8.283 -    void setlocal(Variable *var) {
   8.284 -        ensure(OP_SETLOCAL_LENGTH);
   8.285 -        writeOp(OP_SETLOCAL);
   8.286 -        writeUint32(var->slot());
   8.287 -
   8.288 -        if (var->type()->isTraceable())
   8.289 -            markOop(1);
   8.290 -    }
   8.291 -    void getarg(Variable *var) {
   8.292 -        ensure(OP_GETARG_LENGTH);
   8.293 -        writeOp(OP_GETARG);
   8.294 -        writeUint32(var->slot());
   8.295 -
   8.296 -        if (var->type()->isTraceable())
   8.297 -            markOop(1);
   8.298 -    }
   8.299 -    void setarg(Variable *var) {
   8.300 -        ensure(OP_SETARG_LENGTH);
   8.301 -        writeOp(OP_SETARG);
   8.302 -        writeUint32(var->slot());
   8.303 -
   8.304 -        if (var->type()->isTraceable())
   8.305 -            markOop(1);
   8.306 -    }
   8.307 -
   8.308 -    void j(Opcode op, Label *label) {
   8.309 -        // Since jumps can skip around the stream, do not try to do anything
   8.310 -        // in a potentially truncated state.
   8.311 -        if (oom())
   8.312 -            return;
   8.313 -
   8.314 -        assert(op >= OP_JL && op <= OP_JUMP);
   8.315 -        ensure(OP_JUMP_LENGTH);
   8.316 -
   8.317 -        if (label->bound()) {
   8.318 -            // We can immediately emit this jump.
   8.319 -            int distance = label->offset() - position();
   8.320 -            writeOp(op);
   8.321 -            writeInt32(distance);
   8.322 -        } else {
   8.323 -            // We can't emit this jump yet. Add a placeholder.
   8.324 -            int old = label->link(position());
   8.325 -            writeOp(op);
   8.326 -            writeInt32(old);
   8.327 -        }
   8.328 -    }
   8.329 -    void bind(Label *label) {
   8.330 -        if (oom())
   8.331 -            return;
   8.332 -
   8.333 -        assert(!label->bound());
   8.334 -
   8.335 -        int offset = label->offset();
   8.336 -        while (offset != Label::INVALID_OFFSET)
   8.337 -            offset = patchJumpAt(offset, position());
   8.338 -
   8.339 -        label->bind(position());
   8.340 -    }
   8.341 -    void jump(Label *label) {
   8.342 -        j(OP_JUMP, label);
   8.343 -    }
   8.344 -
   8.345 -    void binary(Opcode op) {
   8.346 -        singleByteOp(op);
   8.347 -    }
   8.348 -
   8.349 -    void pop() {
   8.350 -        singleByteOp(OP_POP);
   8.351 -    }
   8.352 -    void stop() {
   8.353 -        singleByteOp(OP_STOP);
   8.354 -    }
   8.355 -    void call(Handle<Type> fun) {
   8.356 -        recordOops();
   8.357 -        ensure(OP_CALL_LENGTH);
   8.358 -        writeOp(OP_CALL);
   8.359 -
   8.360 -        if (fun->returnType()->isVoid())
   8.361 -            drop(1);
   8.362 -        else if (fun->returnType()->isTraceable())
   8.363 -            markOop(1);
   8.364 -    }
   8.365 -    void callnative(unsigned index, unsigned argc) {
   8.366 -        recordOops();
   8.367 -        ensure(OP_CALLNATIVE_LENGTH);
   8.368 -        writeOp(OP_CALLNATIVE);
   8.369 -        writeUint32(index);
   8.370 -        writeUint32(argc);
   8.371 -    }
   8.372 -
   8.373 -    void getelem(Type *type) {
   8.374 -        singleByteOp(OP_GETELEM);
   8.375 -
   8.376 -        if (type->isTraceable())
   8.377 -            markOop(1);
   8.378 -    }
   8.379 -    void setelem(Type *type) {
   8.380 -        singleByteOp(OP_SETELEM);
   8.381 -    }
   8.382 -
   8.383 -    void getfield(unsigned index, Type *type) {
   8.384 -        ensure(OP_GETFIELD_LENGTH);
   8.385 -        writeOp(OP_GETFIELD);
   8.386 -        writeUint32(index);
   8.387 -
   8.388 -        if (type->isTraceable())
   8.389 -            markOop(1);
   8.390 -    }
   8.391 -    void setfield(unsigned index, Type *type) {
   8.392 -        ensure(OP_SETFIELD_LENGTH);
   8.393 -        writeOp(OP_SETFIELD);
   8.394 -        writeUint32(index);
   8.395 -
   8.396 -        if (type->isTraceable())
   8.397 -            markOop(1);
   8.398 -    }
   8.399 -
   8.400 -    void getglobal(Variable *var) {
   8.401 -        ensure(OP_GETGLOBAL_F_LENGTH);
   8.402 -        if (var->type()->isPrimitive()) {
   8.403 -            switch (var->type()->primitive()) {
   8.404 -              case PrimitiveType_Float:
   8.405 -                writeOp(OP_GETGLOBAL_F);
   8.406 -                break;
   8.407 -              default:
   8.408 -                assert(var->type()->primitive() == PrimitiveType_Int32);
   8.409 -                writeOp(OP_GETGLOBAL_I);
   8.410 -                break;
   8.411 -            }
   8.412 -        } else {
   8.413 -            writeOp(OP_GETGLOBAL_O);
   8.414 -            markOop(1);
   8.415 -        }
   8.416 -        writeUint32(var->slot());
   8.417 -    }
   8.418 -    void setglobal(Variable *var) {
   8.419 -        ensure(OP_SETGLOBAL_F_LENGTH);
   8.420 -        if (var->type()->isPrimitive()) {
   8.421 -            switch (var->type()->primitive()) {
   8.422 -              case PrimitiveType_Float:
   8.423 -                writeOp(OP_SETGLOBAL_F);
   8.424 -                break;
   8.425 -              default:
   8.426 -                assert(var->type()->primitive() == PrimitiveType_Int32);
   8.427 -                writeOp(OP_SETGLOBAL_I);
   8.428 -                break;
   8.429 -            }
   8.430 -        } else {
   8.431 -            writeOp(OP_SETGLOBAL_O);
   8.432 -        }
   8.433 -        writeUint32(var->slot());
   8.434 -    }
   8.435 -
   8.436 -    void float_(float value) {
   8.437 -        ensure(OP_FLOAT_LENGTH);
   8.438 -        writeOp(OP_FLOAT);
   8.439 -        writeFloat(value);
   8.440 -    }
   8.441 -    void cvt_i2f() {
   8.442 -        singleByteOp(OP_CVT_I2F);
   8.443 -    }
   8.444 -    void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
   8.445 -        assert(op == OP_NEWFIXED ||
   8.446 -               op == OP_NEWEMPTY ||
   8.447 -               op == OP_NEWSIZED);
   8.448 -
   8.449 -        recordOops();
   8.450 -        ensure(OpcodeInfo[op].length);
   8.451 -        writeOp(op);
   8.452 -        writeUint8(tenure);
   8.453 -        writeObject(map);
   8.454 -
   8.455 -        if (op == OP_NEWSIZED)
   8.456 -            drop(map->type()->levels());
   8.457 -
   8.458 -        markOop(1);
   8.459 -    }
   8.460 -    void newstruct(Handle<Map> map, Heap::Tenure tenure) {
   8.461 -        recordOops();
   8.462 -        ensure(OP_NEWSTRUCT_LENGTH);
   8.463 -        writeOp(OP_NEWSTRUCT);
   8.464 -        writeUint8(tenure);
   8.465 -        writeObject(map);
   8.466 -        markOop(1);
   8.467 -    }
   8.468 -    void savelifo(unsigned slot) {
   8.469 -        ensure(OP_SAVELIFO_LENGTH);
   8.470 -        writeOp(OP_SAVELIFO);
   8.471 -        writeUint32(slot);
   8.472 -    }
   8.473 -    void unwindlifo(unsigned slot) {
   8.474 -        ensure(OP_UNWINDLIFO_LENGTH);
   8.475 -        writeOp(OP_UNWINDLIFO);
   8.476 -        writeUint32(slot);
   8.477 -    }
   8.478 -    void newref(Variable *var) {
   8.479 -        recordOops();
   8.480 -        if (var->location() == Variable::STACK) {
   8.481 -            ensure(OP_VARREF_LIFO_LENGTH);
   8.482 -            writeOp(OP_VARREF_LIFO);
   8.483 -        } else {
   8.484 -            assert(var->location() == Variable::PARAMETER);
   8.485 -            ensure(OP_ARGREF_LIFO_LENGTH);
   8.486 -            writeOp(OP_ARGREF_LIFO);
   8.487 -        }
   8.488 -        writeUint32(var->slot());
   8.489 -        markOop(1);
   8.490 -    }
   8.491 -
   8.492 -    void slotref_lifo() {
   8.493 -        recordOops();
   8.494 -        singleByteOp(OP_SLOTREF_LIFO);
   8.495 -        markOop(1);
   8.496 -    }
   8.497 -    void fieldref_lifo(unsigned index) {
   8.498 -        recordOops();
   8.499 -        ensure(OP_FIELDREF_LIFO_LENGTH);
   8.500 -        writeOp(OP_FIELDREF_LIFO);
   8.501 -        writeUint32(index);
   8.502 -        markOop(1);
   8.503 -    }
   8.504 -    void getref(Type *type) {
   8.505 -        if (type->pod() == PrimitiveType_Int32) {
   8.506 -            singleByteOp(OP_GETREF_I);
   8.507 -        } else {
   8.508 -            assert(type->pod() == PrimitiveType_Float);
   8.509 -            singleByteOp(OP_GETREF_F);
   8.510 -        }
   8.511 -    }
   8.512 -    void setref(Type *type) {
   8.513 -        if (type->pod() == PrimitiveType_Int32) {
   8.514 -            singleByteOp(OP_SETREF_I);
   8.515 -        } else {
   8.516 -            assert(type->pod() == PrimitiveType_Float);
   8.517 -            singleByteOp(OP_SETREF_F);
   8.518 -        }
   8.519 -    }
   8.520 -    void object(Handle<Object> obj) {
   8.521 -        ensure(OP_OBJECT_LENGTH);
   8.522 -        writeOp(OP_OBJECT);
   8.523 -        writeObject(obj);
   8.524 -        markOop(1);
   8.525 -    }
   8.526 -    void copyarray() {
   8.527 -        singleByteOp(OP_COPYARRAY);
   8.528 -        markOop(1);
   8.529 -    }
   8.530 -    void copystruct() {
   8.531 -        singleByteOp(OP_COPYSTRUCT);
   8.532 -        markOop(1);
   8.533 -    }
   8.534 -    void sizeof_() {
   8.535 -        singleByteOp(OP_SIZEOF);
   8.536 -    }
   8.537 -
   8.538 -    void dup() {
   8.539 -        bool oop = getOop(1);
   8.540 -        singleByteOp(OP_DUP);
   8.541 -        markOop(1, oop);
   8.542 -    }
   8.543 -    void dup2() {
   8.544 -        bool oop2 = getOop(2);
   8.545 -        bool oop1 = getOop(1);
   8.546 -
   8.547 -        singleByteOp(OP_DUP2);
   8.548 -
   8.549 -        markOop(2, oop2);
   8.550 -        markOop(1, oop1);
   8.551 -    }
   8.552 -    void swap() {
   8.553 -        bool oop2 = getOop(2);
   8.554 -        bool oop1 = getOop(1);
   8.555 -
   8.556 -        singleByteOp(OP_SWAP);
   8.557 -
   8.558 -        markOop(2, oop1);
   8.559 -        markOop(1, oop2);
   8.560 -    }
   8.561 -    void roll3() {
   8.562 -        bool oop3 = getOop(3);
   8.563 -        bool oop2 = getOop(2);
   8.564 -        bool oop1 = getOop(1);
   8.565 -
   8.566 -        singleByteOp(OP_ROLL3);
   8.567 -
   8.568 -        markOop(3, oop2);
   8.569 -        markOop(2, oop1);
   8.570 -        markOop(1, oop3);
   8.571 -    }
   8.572 -    void pick2() {
   8.573 -        bool oop2 = getOop(2);
   8.574 -        bool oop1 = getOop(1);
   8.575 -
   8.576 -        singleByteOp(OP_PICK2);
   8.577 -
   8.578 -        markOop(3, oop2);
   8.579 -        markOop(2, oop1);
   8.580 -        markOop(1, oop2);
   8.581 -    }
   8.582 -    void pick3() {
   8.583 -        bool oop3 = getOop(3);
   8.584 -        bool oop2 = getOop(2);
   8.585 -        bool oop1 = getOop(1);
   8.586 -
   8.587 -        singleByteOp(OP_PICK3);
   8.588 -
   8.589 -        markOop(4, oop3);
   8.590 -        markOop(3, oop2);
   8.591 -        markOop(2, oop1);
   8.592 -        markOop(1, oop3);
   8.593 -    }
   8.594 -
   8.595 -    void returnvoid() {
   8.596 -        singleByteOp(OP_RETURNVOID);
   8.597 -    }
   8.598 -    void module() {
   8.599 -        singleByteOp(OP_MODULE);
   8.600 -        markOop(1);
   8.601 -    }
   8.602 -    void getmodule_fn(unsigned index) {
   8.603 -        ensure(OP_GETMODULE_FN_LENGTH);
   8.604 -        writeOp(OP_GETMODULE_FN);
   8.605 -        writeUint32(index);
   8.606 -        markOop(1);
   8.607 -    }
   8.608 -    void bitnot() {
   8.609 -        singleByteOp(OP_BITNOT);
   8.610 -    }
   8.611 -    void not_() {
   8.612 -        singleByteOp(OP_NOT);
   8.613 -    }
   8.614 -    void not_f() {
   8.615 -        singleByteOp(OP_NOT_F);
   8.616 -    }
   8.617 -    void neg() {
   8.618 -        singleByteOp(OP_NEG);
   8.619 -    }
   8.620 -    void neg_f() {
   8.621 -        singleByteOp(OP_NEG_F);
   8.622 -    }
   8.623 -    void bits_i2f() {
   8.624 -        singleByteOp(OP_BITS_I2F);
   8.625 -    }
   8.626 -    void bits_f2i() {
   8.627 -        singleByteOp(OP_BITS_F2I);
   8.628 -    }
   8.629 -    void true_() {
   8.630 -        singleByteOp(OP_TRUE);
   8.631 -    }
   8.632 -    void false_() {
   8.633 -        singleByteOp(OP_FALSE);
   8.634 -    }
   8.635 -
   8.636 -    void tableswitch(int low, int high, Label *def, Label **labels) {
   8.637 -        unsigned tablesize = TableSwitchEntries(low, high);
   8.638 -        assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
   8.639 -
   8.640 -        ensure(OP_TABLESWITCH_LENGTH);
   8.641 -        writeOp(OP_TABLESWITCH);
   8.642 -        writeInt32(low);
   8.643 -        writeInt32(high);
   8.644 -        jump(def);
   8.645 -
   8.646 -        // When labels are patched, we assume each position is a jump. Rather
   8.647 -        // than hack position offsets to make labels work without actual
   8.648 -        // incoming jumps, we emit a jump inline.
   8.649 -        for (unsigned i = 0; i < tablesize; i++)
   8.650 -            jump(labels[i]);
   8.651 -    }
   8.652 -
   8.653 -    // Helpers.
   8.654 -    void get(Variable *var) {
   8.655 -        if (var->location() == Variable::STACK) {
   8.656 -            getlocal(var);
   8.657 -        } else {
   8.658 -            assert(var->location() == Variable::PARAMETER);
   8.659 -            getarg(var);
   8.660 -        }
   8.661 -    }
   8.662 -    void set(Variable *var) {
   8.663 -        assert(!var->type()->isReference());
   8.664 -        if (var->location() == Variable::STACK) {
   8.665 -            setlocal(var);
   8.666 -        } else {
   8.667 -            assert(var->location() == Variable::PARAMETER);
   8.668 -            setarg(var);
   8.669 -        }
   8.670 -    }
   8.671 -};
   8.672 -
   8.673 -}
   8.674 -
   8.675 -#endif // _include_bytecode_emitter_h_
     9.1 --- a/src/Code.h	Mon Sep 17 00:10:01 2012 -0700
     9.2 +++ b/src/Code.h	Sat Nov 17 18:41:01 2012 -0800
     9.3 @@ -24,7 +24,6 @@
     9.4  #include "Heap.h"
     9.5  #include "Types.h"
     9.6  #include "FixedArray.h"
     9.7 -#include "Token.h"
     9.8  
     9.9  namespace ke {
    9.10  
    9.11 @@ -40,6 +39,7 @@
    9.12      Barriered<ByteArray> bytecode_;
    9.13      Barriered<FixedArray> locals_;
    9.14      Barriered<FixedArray> objects_;
    9.15 +    Barriered<FixedArray> strings_;
    9.16      Barriered<ByteArray> safepoints_;
    9.17      Barriered<ByteArray> sourcemap_;
    9.18      unsigned maxStackDepth_;
    9.19 @@ -52,9 +52,8 @@
    9.20  
    9.21    public:
    9.22      static Code *New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
    9.23 -                     Handle<FixedArray> objects, unsigned maxStackDepth, Handle<Module> module,
    9.24 -                     Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap,
    9.25 -                     unsigned lineNumber);
    9.26 +                     Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
    9.27 +                     Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap);
    9.28  
    9.29      Module *module() {
    9.30          return module_;
    9.31 @@ -83,8 +82,15 @@
    9.32      ByteArray *safepoints() {
    9.33          return safepoints_;
    9.34      }
    9.35 +    FixedArray *strings() {
    9.36 +        return strings_;
    9.37 +    }
    9.38      uint8 *safepointAt(unsigned pcOffset);
    9.39  
    9.40 +    void setModule(Handle<Module> module) {
    9.41 +        module_ = module;
    9.42 +    }
    9.43 +
    9.44      unsigned pcToOffset(bytecode *pc) {
    9.45          assert(pc >= start() && pc < start() + length());
    9.46          return unsigned(pc - start());
    9.47 @@ -108,6 +114,9 @@
    9.48      static inline size_t offsetOfObjects() {
    9.49          return OFFSETOF(Code, objects_);
    9.50      }
    9.51 +    static inline size_t offsetOfStrings() {
    9.52 +        return OFFSETOF(Code, strings_);
    9.53 +    }
    9.54      static inline size_t offsetOfSafepoints() {
    9.55          return OFFSETOF(Code, safepoints_);
    9.56      }
    10.1 --- a/src/CompileContext.cpp	Mon Sep 17 00:10:01 2012 -0700
    10.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.3 @@ -1,58 +0,0 @@
    10.4 -/*
    10.5 - * Copyright (C) 2012 David Anderson
    10.6 - *
    10.7 - * This file is part of JITCraft.
    10.8 - *
    10.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   10.10 - * the terms of the GNU General Public License as published by the Free
   10.11 - * Software Foundation, either version 3 of the License, or (at your option)
   10.12 - * any later version.
   10.13 - * 
   10.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   10.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   10.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   10.17 - *
   10.18 - * You should have received a copy of the GNU General Public License along with
   10.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   10.20 - */
   10.21 -#include <stdio.h>
   10.22 -#include "Scanner.h"
   10.23 -#include "CompileContext.h"
   10.24 -#include "Zone.h"
   10.25 -#include "Spaces-inl.h"
   10.26 -#include "Heap-inl.h"
   10.27 -
   10.28 -using namespace ke;
   10.29 -
   10.30 -CompileContext::CompileContext(Zone *zone, const char *file)
   10.31 -  : zone_(zone),
   10.32 -    failures_(0),
   10.33 -    file_(file)
   10.34 -{
   10.35 -}
   10.36 -
   10.37 -CompileContext::~CompileContext()
   10.38 -{
   10.39 -    if (failures_)
   10.40 -        zone_->endCompilationErrors();
   10.41 -}
   10.42 -
   10.43 -void
   10.44 -CompileContext::reportErrorVa(const SourcePosition &pos, Message msg, va_list ap)
   10.45 -{
   10.46 -    if (!failures_)
   10.47 -        zone_->beginCompilationErrors(file_);
   10.48 -
   10.49 -    zone_->reportCompilationError(msg, pos.line, pos.col, ap);
   10.50 -
   10.51 -    failures_++;
   10.52 -}
   10.53 -
   10.54 -void
   10.55 -CompileContext::reportError(const SourcePosition &pos, Message msg, ...)
   10.56 -{
   10.57 -    va_list ap;
   10.58 -    va_start(ap, msg);
   10.59 -    reportErrorVa(pos, msg, ap);
   10.60 -    va_end(ap);
   10.61 -}
    11.1 --- a/src/CompileContext.h	Mon Sep 17 00:10:01 2012 -0700
    11.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.3 @@ -1,49 +0,0 @@
    11.4 -/*
    11.5 - * Copyright (C) 2012 David Anderson
    11.6 - *
    11.7 - * This file is part of JITCraft.
    11.8 - *
    11.9 - * JITCraft is free software: you can redistribute it and/or modify it under
   11.10 - * the terms of the GNU General Public License as published by the Free
   11.11 - * Software Foundation, either version 3 of the License, or (at your option)
   11.12 - * any later version.
   11.13 - * 
   11.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   11.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   11.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   11.17 - *
   11.18 - * You should have received a copy of the GNU General Public License along with
   11.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   11.20 - */
   11.21 -#ifndef _include_jitcraft_compile_context_h_
   11.22 -#define _include_jitcraft_compile_context_h_
   11.23 -
   11.24 -#include <stdarg.h>
   11.25 -#include "Messages.h"
   11.26 -
   11.27 -namespace ke {
   11.28 -
   11.29 -class Zone;
   11.30 -struct SourcePosition;
   11.31 -
   11.32 -class CompileContext
   11.33 -{
   11.34 -    Zone *zone_;
   11.35 -    unsigned failures_;
   11.36 -    const char *file_;
   11.37 -
   11.38 -  public:
   11.39 -    CompileContext(Zone *zone, const char *file);
   11.40 -    ~CompileContext();
   11.41 -
   11.42 -    void reportErrorVa(const SourcePosition &pos, Message msg, va_list ap);
   11.43 -    void reportError(const SourcePosition &pos, Message msg, ...);
   11.44 -
   11.45 -    unsigned failures() const {
   11.46 -        return failures_;
   11.47 -    }
   11.48 -};
   11.49 -
   11.50 -}
   11.51 -
   11.52 -#endif // _include_jitcraft_compile_context_h_
    12.1 --- a/src/Environments.cpp	Mon Sep 17 00:10:01 2012 -0700
    12.2 +++ b/src/Environments.cpp	Sat Nov 17 18:41:01 2012 -0800
    12.3 @@ -1,19 +1,19 @@
    12.4  /*
    12.5   * Copyright (C) 2012 David Anderson
    12.6   *
    12.7 - * This file is part of JITCraft.
    12.8 + * This file is part of SourcePawn.
    12.9   *
   12.10 - * JITCraft is free software: you can redistribute it and/or modify it under
   12.11 + * SourcePawn is free software: you can redistribute it and/or modify it under
   12.12   * the terms of the GNU General Public License as published by the Free
   12.13   * Software Foundation, either version 3 of the License, or (at your option)
   12.14   * any later version.
   12.15   * 
   12.16 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   12.17 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   12.18   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   12.19   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   12.20   *
   12.21   * You should have received a copy of the GNU General Public License along with
   12.22 - * JITCraft. If not, see http://www.gnu.org/licenses/.
   12.23 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   12.24   */
   12.25  #include <string.h>
   12.26  #include "Utility.h"
   12.27 @@ -21,7 +21,7 @@
   12.28  #include "Structures.h"
   12.29  #include "FixedArray.h"
   12.30  #include "Zone.h"
   12.31 -#include "NameBinding.h"
   12.32 +#include "compiler/NameBinding.h"
   12.33  #include "Spaces-inl.h"
   12.34  #include "Heap-inl.h"
   12.35  
   12.36 @@ -59,6 +59,7 @@
   12.37      return env;
   12.38  }
   12.39  
   12.40 +#if 0
   12.41  EnvironmentMap *
   12.42  EnvironmentMap::New(Zone *zone, unsigned nvars, Variable **vars)
   12.43  {
   12.44 @@ -98,3 +99,4 @@
   12.45  
   12.46      return map;
   12.47  }
   12.48 +#endif
   12.49 \ No newline at end of file
    13.1 --- a/src/Functions.cpp	Mon Sep 17 00:10:01 2012 -0700
    13.2 +++ b/src/Functions.cpp	Sat Nov 17 18:41:01 2012 -0800
    13.3 @@ -23,7 +23,7 @@
    13.4  using namespace ke;
    13.5  
    13.6  Function *
    13.7 -Function::New(Zone *zone, Handle<Code> code, Handle<Type> type, Handle<String> name,
    13.8 +Function::New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
    13.9                const SourcePosition &pos)
   13.10  {
   13.11      Function *fun = Function::cast(zone->allocate(MapKind_Function, sizeof(Function), Heap::Tenure_Old));
   13.12 @@ -38,14 +38,13 @@
   13.13  }
   13.14  
   13.15  Native *
   13.16 -Native::New(Zone *zone, Handle<Type> type, Handle<String> name)
   13.17 +Native::New(Zone *zone, Handle<FunctionType> type, size_t index)
   13.18  {
   13.19      Native *fun = Native::cast(zone->allocate(MapKind_Native, sizeof(Native), Heap::Tenure_Old));
   13.20      if (!fun)
   13.21          return NULL;
   13.22  
   13.23      fun->type_ = type;
   13.24 -    fun->name_ = name;
   13.25 -    fun->function_ = NULL;
   13.26 +    fun->index_ = index;
   13.27      return fun;
   13.28  }
    14.1 --- a/src/Functions.h	Mon Sep 17 00:10:01 2012 -0700
    14.2 +++ b/src/Functions.h	Sat Nov 17 18:41:01 2012 -0800
    14.3 @@ -20,31 +20,30 @@
    14.4  
    14.5  #include "Heap.h"
    14.6  #include "Barriers.h"
    14.7 -#include "Token.h"
    14.8  #include "Types.h"
    14.9 +#include "Opcodes.h"
   14.10  
   14.11  namespace ke {
   14.12  
   14.13  class Code;
   14.14  class Module;
   14.15 -class Type;
   14.16  class String;
   14.17  
   14.18  class Function : public Object
   14.19  {
   14.20      Barriered<Code> code_;
   14.21 -    Barriered<Type> type_;
   14.22 +    Barriered<FunctionType> type_;
   14.23      Barriered<String> name_;
   14.24      SourcePosition pos_;
   14.25  
   14.26   public:
   14.27 -    static Function *New(Zone *zone, Handle<Code> code, Handle<Type> type, Handle<String> name,
   14.28 +    static Function *New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
   14.29                           const SourcePosition &pos);
   14.30  
   14.31      Code *code() const {
   14.32          return code_;
   14.33      }
   14.34 -    Type *type() const {
   14.35 +    FunctionType *type() const {
   14.36          return type_;
   14.37      }
   14.38      String *name() const {
   14.39 @@ -82,33 +81,25 @@
   14.40  // for earlier ISourcePawnEngine API compatibility.
   14.41  class Native : public Object
   14.42  {
   14.43 -    Barriered<Type> type_;
   14.44 -    Barriered<String> name_;
   14.45 -    void *function_;
   14.46 +    Barriered<FunctionType> type_;
   14.47 +
   14.48 +    // Index into the Zone's native table.
   14.49 +    size_t index_;
   14.50  
   14.51    public:
   14.52 -    static Native *New(Zone *zone, Handle<Type> type, Handle<String> name);
   14.53 +    static Native *New(Zone *zone, Handle<FunctionType> type, size_t index);
   14.54  
   14.55 -    void *function() {
   14.56 -        return function_;
   14.57 -    }
   14.58 -    Type *type() {
   14.59 +    FunctionType *type() {
   14.60          return type_;
   14.61      }
   14.62 -    String *name() {
   14.63 -        return name_;
   14.64 -    }
   14.65 -    void bind(void *function) {
   14.66 -        function_ = function;
   14.67 +    size_t index() const {
   14.68 +        return index_;
   14.69      }
   14.70  
   14.71      // Begin GC Descriptor.
   14.72      static inline size_t offsetOfType() {
   14.73          return OFFSETOF(Native, type_);
   14.74      }
   14.75 -    static inline size_t offsetOfName() {
   14.76 -        return OFFSETOF(Native, name_);
   14.77 -    }
   14.78      // End GC Descriptor.
   14.79  
   14.80      static inline Native *cast(Object *obj) {
    15.1 --- a/src/GlobalRoots.cpp	Mon Sep 17 00:10:01 2012 -0700
    15.2 +++ b/src/GlobalRoots.cpp	Sat Nov 17 18:41:01 2012 -0800
    15.3 @@ -52,7 +52,7 @@
    15.4  }
    15.5  
    15.6  HeapRoot *
    15.7 -GlobalRoots::create(Handle<Object> obj)
    15.8 +GlobalRoots::create()
    15.9  {
   15.10      HeapRoot *root = new HeapRoot();
   15.11      if (!root) {
   15.12 @@ -60,25 +60,15 @@
   15.13          return NULL;
   15.14      }
   15.15  
   15.16 -    root->obj = obj;
   15.17 -    root->refcount = 1;
   15.18 +    root->obj = NULL;
   15.19  
   15.20      roots_.append(root);
   15.21      return root;
   15.22  }
   15.23  
   15.24  void
   15.25 -GlobalRoots::incref(HeapRoot *root)
   15.26 +GlobalRoots::destroy(HeapRoot *root)
   15.27  {
   15.28 -    root->refcount++;
   15.29 +    roots_.remove(root);
   15.30 +    delete root;
   15.31  }
   15.32 -
   15.33 -void
   15.34 -GlobalRoots::decref(HeapRoot *root)
   15.35 -{
   15.36 -    assert(root->refcount > 0);
   15.37 -    if (--root->refcount == 0) {
   15.38 -        roots_.remove(root);
   15.39 -        delete root;
   15.40 -    }
   15.41 -}
    16.1 --- a/src/GlobalRoots.h	Mon Sep 17 00:10:01 2012 -0700
    16.2 +++ b/src/GlobalRoots.h	Sat Nov 17 18:41:01 2012 -0800
    16.3 @@ -33,7 +33,6 @@
    16.4  {
    16.5    public:
    16.6      Object *obj;
    16.7 -    intptr_t refcount;
    16.8  };
    16.9  
   16.10  class GlobalRoots
   16.11 @@ -46,11 +45,8 @@
   16.12  
   16.13      bool initialize();
   16.14  
   16.15 -    // The caller must immediately incref this.
   16.16 -    HeapRoot *create(Handle<Object> ptr);
   16.17 -
   16.18 -    void incref(HeapRoot *root);
   16.19 -    void decref(HeapRoot *root);
   16.20 +    HeapRoot *create();
   16.21 +    void destroy(HeapRoot *root);
   16.22  
   16.23      void accept(VirtualObjectVisitor *visitor);
   16.24  
    17.1 --- a/src/Handles.h	Mon Sep 17 00:10:01 2012 -0700
    17.2 +++ b/src/Handles.h	Sat Nov 17 18:41:01 2012 -0800
    17.3 @@ -29,6 +29,11 @@
    17.4  template <typename T> class Local;
    17.5  template <typename T> class ScopedRoot;
    17.6  
    17.7 +struct NullAddress
    17.8 +{
    17.9 +    static void * const Sentinel;
   17.10 +};
   17.11 +
   17.12  /*
   17.13   * Internal handles work differently from API handles. An API handle is a
   17.14   * root, whereas as an internal handle points to a rooted location. This
   17.15 @@ -40,6 +45,12 @@
   17.16  {
   17.17      T * const *thingp_;
   17.18  
   17.19 +  private:
   17.20 +    Handle()
   17.21 +      : thingp_(reinterpret_cast<T * const *>(&NullAddress::Sentinel))
   17.22 +    {
   17.23 +    }
   17.24 +
   17.25    public:
   17.26      Handle(const Handle &other) {
   17.27          thingp_ = other.address();
   17.28 @@ -51,6 +62,10 @@
   17.29      template <typename S> inline Handle(const Local<S> &local);
   17.30      template <typename S> inline Handle(const ScopedRoot<S> &root);
   17.31  
   17.32 +    static inline Handle Null() {
   17.33 +        return Handle();
   17.34 +    }
   17.35 +
   17.36    public:
   17.37      T *operator ->() {
   17.38          return *thingp_;
    18.1 --- a/src/HashTable.h	Mon Sep 17 00:10:01 2012 -0700
    18.2 +++ b/src/HashTable.h	Sat Nov 17 18:41:01 2012 -0800
    18.3 @@ -127,7 +127,7 @@
    18.4          { }
    18.5  
    18.6          Payload * operator ->() {
    18.7 -            return entry_->payload();
    18.8 +            return &entry_->payload();
    18.9          }
   18.10          Payload & operator *() {
   18.11              return entry_->payload();
   18.12 @@ -421,6 +421,8 @@
   18.13      };
   18.14  };
   18.15  
   18.16 +
   18.17 +
   18.18  }
   18.19  
   18.20  #endif // _INCLUDE_KEIMA_HASHTABLE_H_
    19.1 --- a/src/Interpreter.cpp	Mon Sep 17 00:10:01 2012 -0700
    19.2 +++ b/src/Interpreter.cpp	Sat Nov 17 18:41:01 2012 -0800
    19.3 @@ -26,6 +26,7 @@
    19.4  #include "Strings.h"
    19.5  #include "Environments.h"
    19.6  #include "Structures.h"
    19.7 +#include "NativeTable.h"
    19.8  #include "Heap-inl.h"
    19.9  
   19.10  using namespace ke;
   19.11 @@ -218,7 +219,16 @@
   19.12  static void
   19.13  GetField(Struct *obj, unsigned index, LocalSlot *vp)
   19.14  {
   19.15 -    Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
   19.16 +    StructType *type = StructType::cast(obj->map()->type());
   19.17 +    Descriptor *desc = Descriptor::cast(type->fields()->at(index));
   19.18 +    GetField(obj, desc, vp);
   19.19 +}
   19.20 +
   19.21 +static void
   19.22 +GetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot *vp)
   19.23 +{
   19.24 +    Local<StructType> type(zone, StructType::cast(obj->map()->type()));
   19.25 +    Local<Descriptor> desc(zone, type->lookupField(name, NULL));
   19.26      GetField(obj, desc, vp);
   19.27  }
   19.28  
   19.29 @@ -246,7 +256,16 @@
   19.30  static void
   19.31  SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
   19.32  {
   19.33 -    Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
   19.34 +    StructType *type = StructType::cast(obj->map()->type());
   19.35 +    Descriptor *desc = Descriptor::cast(type->fields()->at(index));
   19.36 +    SetField(zone, obj, desc, v);
   19.37 +}
   19.38 +
   19.39 +static void
   19.40 +SetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot &v)
   19.41 +{
   19.42 +    Local<StructType> type(zone, StructType::cast(obj->map()->type()));
   19.43 +    Local<Descriptor> desc(zone, type->lookupField(name, NULL));
   19.44      SetField(zone, obj, desc, v);
   19.45  }
   19.46  
   19.47 @@ -257,7 +276,7 @@
   19.48  {
   19.49      assert(left->map()->type() == right->map()->type());
   19.50  
   19.51 -    Local<Type> type(zone, left->map()->type());
   19.52 +    Local<StructType> type(zone, StructType::cast(left->map()->type()));
   19.53      Local<Struct> leftStruct(zone);
   19.54      Local<Struct> rightStruct(zone);
   19.55      Local<Array> leftArray(zone);
   19.56 @@ -299,6 +318,13 @@
   19.57  {
   19.58      NativeArgs guard;
   19.59  
   19.60 +    void *address = zone->nativeTable()->address(native->index());
   19.61 +    if (!address) {
   19.62 +        Local<String> name(zone, zone->nativeTable()->name(native->index()));
   19.63 +        zone->reportError(Message_NativeNotBound, name->chars());
   19.64 +        return false;
   19.65 +    }
   19.66 +
   19.67      if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
   19.68          return false;
   19.69  
   19.70 @@ -308,7 +334,7 @@
   19.71      cells[0] = argc;
   19.72  
   19.73      // Pass the formal arguments.
   19.74 -    Local<Type> type(zone, native->type());
   19.75 +    Local<FunctionType> type(zone, native->type());
   19.76      Local<Type> param(zone);
   19.77      for (unsigned i = 0; i < type->parameters()->length(); i++) {
   19.78          param = type->parameterAt(i);
   19.79 @@ -338,7 +364,7 @@
   19.80      }
   19.81  
   19.82      typedef intptr_t (*INVOKE)(void *, intptr_t *);
   19.83 -    INVOKE invoke = (INVOKE)native->function();
   19.84 +    INVOKE invoke = (INVOKE)address;
   19.85      *result = invoke(identity, cells);
   19.86  
   19.87      return !zone->hasPendingException();
   19.88 @@ -399,42 +425,6 @@
   19.89      break;
   19.90  }
   19.91  
   19.92 -#define RELATIONAL_JUMP(op)                 \
   19.93 -    {                                       \
   19.94 -        int right = POP_I32(top);           \
   19.95 -        int left = POP_I32(top);            \
   19.96 -        if (left op right) {                \
   19.97 -            top.pc += READ_INT32(top.pc);   \
   19.98 -            continue;                       \
   19.99 -        }                                   \
  19.100 -    }
  19.101 -
  19.102 -case OP_JL:
  19.103 -    RELATIONAL_JUMP(<);
  19.104 -    break;
  19.105 -
  19.106 -case OP_JLE:
  19.107 -    RELATIONAL_JUMP(<=);
  19.108 -    break;
  19.109 -
  19.110 -case OP_JG:
  19.111 -    RELATIONAL_JUMP(>);
  19.112 -    break;
  19.113 -
  19.114 -case OP_JGE:
  19.115 -    RELATIONAL_JUMP(>=);
  19.116 -    break;
  19.117 -
  19.118 -case OP_JEQ:
  19.119 -    RELATIONAL_JUMP(==);
  19.120 -    break;
  19.121 -
  19.122 -case OP_JNE:
  19.123 -    RELATIONAL_JUMP(!=);
  19.124 -    break;
  19.125 -
  19.126 -#undef RELATIONAL_JUMP
  19.127 -
  19.128  case OP_JT:
  19.129  {
  19.130      int value = POP_I32(top);
  19.131 @@ -455,74 +445,22 @@
  19.132      break;
  19.133  }
  19.134  
  19.135 -#define RELATIONAL_JUMP_F(op)               \
  19.136 -    {                                       \
  19.137 -        float right = POP_F(top);           \
  19.138 -        float left = POP_F(top);            \
  19.139 -        if (left op right) {                \
  19.140 -            top.pc += READ_INT32(top.pc);   \
  19.141 -            continue;                       \
  19.142 -        }                                   \
  19.143 -    }
  19.144 -
  19.145 -case OP_JL_F:
  19.146 -    RELATIONAL_JUMP_F(<);
  19.147 -    break;
  19.148 -
  19.149 -case OP_JLE_F:
  19.150 -    RELATIONAL_JUMP_F(<=);
  19.151 -    break;
  19.152 -
  19.153 -case OP_JG_F:
  19.154 -    RELATIONAL_JUMP_F(>);
  19.155 -    break;
  19.156 -
  19.157 -case OP_JGE_F:
  19.158 -    RELATIONAL_JUMP_F(>=);
  19.159 -    break;
  19.160 -
  19.161 -case OP_JEQ_F:
  19.162 -    RELATIONAL_JUMP_F(==);
  19.163 -    break;
  19.164 -
  19.165 -case OP_JNE_F:
  19.166 -    RELATIONAL_JUMP_F(!=);
  19.167 -    break;
  19.168 -
  19.169 -case OP_JT_F:
  19.170 -{
  19.171 -    float value = POP_F(top);
  19.172 -    if (value) {
  19.173 -        top.pc += READ_INT32(top.pc);
  19.174 -        continue;
  19.175 -    }
  19.176 -    break;
  19.177 -}
  19.178 -
  19.179 -case OP_JF_F:
  19.180 -{
  19.181 -    float value = POP_F(top);
  19.182 -    if (!value) {
  19.183 -        top.pc += READ_INT32(top.pc);
  19.184 -        continue;
  19.185 -    }
  19.186 -    break;
  19.187 -}
  19.188 -
  19.189  case OP_JUMP:
  19.190      top.pc += READ_INT32(top.pc);
  19.191      continue;
  19.192  
  19.193  case OP_GETLOCAL:
  19.194  {
  19.195 -    int slot = READ_INT32(top.pc);
  19.196 +    unsigned slot = READ_UINT32(top.pc);
  19.197 +    assert(slot < top.fp->code()->nlocals());
  19.198      *top.sp++ = locals[slot];
  19.199      break;
  19.200  }
  19.201  
  19.202  case OP_SETLOCAL:
  19.203  {
  19.204 -    int slot = READ_INT32(top.pc);
  19.205 +    unsigned slot = READ_UINT32(top.pc);
  19.206 +    assert(slot < top.fp->code()->nlocals());
  19.207      locals[slot] = top.sp[-1];
  19.208      break;
  19.209  }
  19.210 @@ -756,7 +694,7 @@
  19.211  
  19.212  case OP_CALL:
  19.213  {
  19.214 -    Local<Function> newFun(zone, top.sp[-1].fun);
  19.215 +    Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
  19.216      top.sp--;
  19.217  
  19.218      if (!zone->stack().pushInlineFrame(newFun))
  19.219 @@ -911,15 +849,6 @@
  19.220      break;
  19.221  }
  19.222  
  19.223 -case OP_FIELDREF_LIFO:
  19.224 -{
  19.225 -    Local<Struct> obj(zone, Struct::cast(top.sp[-1].obj));
  19.226 -    top.sp[-1].obj = Reference::NewField(zone, obj, READ_UINT32(top.pc), Heap::Tenure_Stack);
  19.227 -    if (!top.sp[-1].obj)
  19.228 -        goto error;
  19.229 -    break;
  19.230 -}
  19.231 -
  19.232  case OP_GETREF_I:
  19.233  {
  19.234      top.sp[-1].i32 = top.sp[-1].ref->getInt();
  19.235 @@ -1014,14 +943,10 @@
  19.236  
  19.237  case OP_CALLNATIVE:
  19.238  {
  19.239 -    unsigned index = READ_UINT32(top.pc);
  19.240 -    unsigned argc = READ_UINT32(top.pc + 4);
  19.241 +    unsigned argc = READ_UINT32(top.pc);
  19.242  
  19.243 -    Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
  19.244 -    if (!native->function()) {
  19.245 -        zone->reportError(Message_NativeNotBound, native->name()->chars());
  19.246 -        goto error;
  19.247 -    }
  19.248 +    Local<Native> native(zone, Native::cast(top.sp[-1].obj));
  19.249 +    top.sp--;
  19.250  
  19.251      int result;
  19.252      void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
  19.253 @@ -1033,64 +958,6 @@
  19.254      break;
  19.255  }
  19.256  
  19.257 -case OP_MODULE:
  19.258 -{
  19.259 -    top.sp++;
  19.260 -    top.sp[-1].module = top.fp->code()->module();
  19.261 -    break;
  19.262 -}
  19.263 -
  19.264 -case OP_GETMODULE_FN:
  19.265 -{
  19.266 -    top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
  19.267 -    break;
  19.268 -}
  19.269 -
  19.270 -case OP_GETGLOBAL_I:
  19.271 -{
  19.272 -    unsigned slot = READ_UINT32(top.pc);
  19.273 -    top.sp++;
  19.274 -    top.sp[-1].i32 = top.fp->code()->module()->environment()->getInt32(slot);
  19.275 -    break;
  19.276 -}
  19.277 -
  19.278 -case OP_GETGLOBAL_F:
  19.279 -{
  19.280 -    unsigned slot = READ_UINT32(top.pc);
  19.281 -    top.sp++;
  19.282 -    top.sp[-1].f = top.fp->code()->module()->environment()->getFloat(slot);
  19.283 -    break;
  19.284 -}
  19.285 -
  19.286 -case OP_GETGLOBAL_O:
  19.287 -{
  19.288 -    unsigned slot = READ_UINT32(top.pc);
  19.289 -    top.sp++;
  19.290 -    top.sp[-1].obj = top.fp->code()->module()->environment()->getObject(slot);
  19.291 -    break;
  19.292 -}
  19.293 -
  19.294 -case OP_SETGLOBAL_I:
  19.295 -{
  19.296 -    unsigned slot = READ_UINT32(top.pc);
  19.297 -    top.fp->code()->module()->environment()->setInt32(slot, top.sp[-1].i32);
  19.298 -    break;
  19.299 -}
  19.300 -
  19.301 -case OP_SETGLOBAL_F:
  19.302 -{
  19.303 -    unsigned slot = READ_UINT32(top.pc);
  19.304 -    top.fp->code()->module()->environment()->setFloat(slot, top.sp[-1].f);
  19.305 -    break;
  19.306 -}
  19.307 -
  19.308 -case OP_SETGLOBAL_O:
  19.309 -{
  19.310 -    unsigned slot = READ_UINT32(top.pc);
  19.311 -    top.fp->code()->module()->environment()->setObject(slot, top.sp[-1].obj);
  19.312 -    break;
  19.313 -}
  19.314 -
  19.315  case OP_BITS_I2F:
  19.316  case OP_BITS_F2I:
  19.317  {
  19.318 @@ -1165,6 +1032,33 @@
  19.319      break;
  19.320  }
  19.321  
  19.322 +case OP_PUBLIC:
  19.323 +{
  19.324 +    Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
  19.325 +    zone->registerPublic(fun);
  19.326 +    top.sp--;
  19.327 +    break;
  19.328 +}
  19.329 +
  19.330 +case OP_SETGLOBAL:
  19.331 +{
  19.332 +    Local<Code> code(zone, top.fp->code());
  19.333 +    Local<Struct> obj(zone, code->module()->globals());
  19.334 +    Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
  19.335 +    SetGlobal(zone, obj, name, top.sp[-1]);
  19.336 +    break;
  19.337 +}
  19.338 +
  19.339 +case OP_GETGLOBAL:
  19.340 +{
  19.341 +    Local<Code> code(zone, top.fp->code());
  19.342 +    Local<Struct> obj(zone, code->module()->globals());
  19.343 +    Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
  19.344 +    GetGlobal(zone, obj, name, top.sp);
  19.345 +    top.sp++;
  19.346 +    break;
  19.347 +}
  19.348 +
  19.349  default:
  19.350      assert(false);
  19.351      return false;
    20.1 --- a/src/Messages.tbl	Mon Sep 17 00:10:01 2012 -0700
    20.2 +++ b/src/Messages.tbl	Sat Nov 17 18:41:01 2012 -0800
    20.3 @@ -61,7 +61,6 @@
    20.4  MSG(IdentifierNotFound,             SyntaxError,            "identifier '%s' could not be found")
    20.5  MSG(TypeMismatchDuringInvoke,       TypeError,              "incoming type '%s' does not match signature type '%s'")
    20.6  MSG(CannotInvokeReturnType,         SyntaxError,            "cannot invoke function with return type '%s'")
    20.7 -MSG(TypeNotFound,                   SyntaxError,            "type '%s' could not be found")
    20.8  MSG(IdentifierIsNotAType,           SyntaxError,            "identifier '%s' cannot be used as a type")
    20.9  MSG(TypeMismatch,                   TypeError,              "type mismatch (expected '%s', got '%s')")
   20.10  MSG(PropertyNotFound,               TypeError,              "property '%s' not found on type '%s'")
   20.11 @@ -80,4 +79,6 @@
   20.12  MSG(CannotComputeIndexRef,          SyntaxError,            "cannot use an array index as a reference")
   20.13  MSG(BadDynamicInitializer,          SyntaxError,            "dynamic length specified, but preceding array is empty")
   20.14  MSG(SizeofNeedsArray,               TypeError,              "sizeof requires an array")
   20.15 -
   20.16 +MSG(ImportsMustBeFirst,             SyntaxError,            "import statements must come before other statements")
   20.17 +MSG(ImportedNameAlreadyBound,       TypeError,              "imported name has already been bound")
   20.18 +MSG(CannotResolveImport,            TypeError,              "cannot resolve import %s")
   20.19 \ No newline at end of file
    21.1 --- a/src/Modules.cpp	Mon Sep 17 00:10:01 2012 -0700
    21.2 +++ b/src/Modules.cpp	Sat Nov 17 18:41:01 2012 -0800
    21.3 @@ -23,21 +23,15 @@
    21.4  using namespace ke;
    21.5  
    21.6  Module *
    21.7 -Module::New(Zone *zone, unsigned nfunctions)
    21.8 +Module::New(Zone *zone)
    21.9  {
   21.10      Local<Module> module(zone, Module::cast(zone->allocate(MapKind_Module, sizeof(Module), Heap::Tenure_Old)));
   21.11      if (!module)
   21.12          return NULL;
   21.13  
   21.14 -    Local<FixedArray> functions(zone, FixedArray::New(zone, nfunctions, Heap::Tenure_Old));
   21.15 -    if (!functions)
   21.16 -        return NULL;
   21.17 -
   21.18 -    module->functions_ = functions;
   21.19      module->file_ = NULL;
   21.20 -    module->publics_ = NULL;
   21.21 -    module->natives_ = NULL;
   21.22 -    module->environment_ = NULL;
   21.23 +    module->globals_ = NULL;
   21.24      module->nativeIdentity_ = NULL;
   21.25 +    module->globals_ = NULL;
   21.26      return module;
   21.27  }
    22.1 --- a/src/Modules.h	Mon Sep 17 00:10:01 2012 -0700
    22.2 +++ b/src/Modules.h	Sat Nov 17 18:41:01 2012 -0800
    22.3 @@ -25,60 +25,37 @@
    22.4  namespace ke {
    22.5  
    22.6  class Environment;
    22.7 +class Struct;
    22.8  
    22.9  class Module : public Object
   22.10  {
   22.11 -    Barriered<FixedArray> functions_;
   22.12 -    Barriered<FixedArray> publics_;
   22.13 -    Barriered<FixedArray> natives_;
   22.14      Barriered<String> file_;
   22.15 -    Barriered<Environment> environment_;
   22.16      Barriered<Code> code_;
   22.17 +    Barriered<Struct> globals_;
   22.18      void *nativeIdentity_;
   22.19  
   22.20    public:
   22.21 -    static Module *New(Zone *zone, unsigned nfunctions);
   22.22 -
   22.23 -    Function *getFunction(size_t i) {
   22.24 -        return Function::cast(functions_->at(i));
   22.25 -    }
   22.26 -    void setFunction(Zone *zone, size_t i, Function *fun) {
   22.27 -        assert(!functions_->at(i));
   22.28 -        assert(fun);
   22.29 -        functions_->set(zone, i, fun);
   22.30 -    }
   22.31 -
   22.32 -    FixedArray *publics() {
   22.33 -        return publics_;
   22.34 -    }
   22.35 -    FixedArray *natives() {
   22.36 -        return natives_;
   22.37 -    }
   22.38 +    static Module *New(Zone *zone);
   22.39 +    
   22.40      String *file() {
   22.41          return file_;
   22.42      }
   22.43 -    Environment *environment() {
   22.44 -        return environment_;
   22.45 -    }
   22.46      Code *code() {
   22.47          return code_;
   22.48      }
   22.49 +    Struct *globals() {
   22.50 +        return globals_;
   22.51 +    }
   22.52  
   22.53 -    void setPublics(Handle<FixedArray> publics) {
   22.54 -        publics_ = publics;
   22.55 -    }
   22.56 -    void setNatives(Handle<FixedArray> natives) {
   22.57 -        natives_ = natives;
   22.58 -    }
   22.59      void setPath(Handle<String> path) {
   22.60          file_ = path;
   22.61      }
   22.62 -    void setEnvironment(Handle<Environment> environment) {
   22.63 -        environment_ = environment;
   22.64 -    }
   22.65      void setCode(Handle<Code> code) {
   22.66          code_ = code;
   22.67      }
   22.68 +    void setGlobals(Handle<Struct> globals) {
   22.69 +        globals_ = globals;
   22.70 +    }
   22.71  
   22.72      void *nativeIdentity() {
   22.73          return nativeIdentity_;
   22.74 @@ -88,24 +65,15 @@
   22.75      }
   22.76  
   22.77      // Begin GC Descriptor.
   22.78 -    static inline size_t offsetOfFunctions() {
   22.79 -        return OFFSETOF(Module, functions_);
   22.80 -    }
   22.81 -    static inline size_t offsetOfPublics() {
   22.82 -        return OFFSETOF(Module, publics_);
   22.83 -    }
   22.84 -    static inline size_t offsetOfNatives() {
   22.85 -        return OFFSETOF(Module, natives_);
   22.86 -    }
   22.87      static inline size_t offsetOfFile() {
   22.88          return OFFSETOF(Module, file_);
   22.89      }
   22.90 -    static inline size_t offsetOfEnvironment() {
   22.91 -        return OFFSETOF(Module, environment_);
   22.92 -    }
   22.93      static inline size_t offsetOfCode() {
   22.94          return OFFSETOF(Module, code_);
   22.95      }
   22.96 +    static inline size_t offsetOfGlobals() {
   22.97 +        return OFFSETOF(Module, globals_);
   22.98 +    }
   22.99      // End GC Descriptor.
  22.100  
  22.101      static inline Module *cast(Object *obj) {
    23.1 --- a/src/NameBinding.cpp	Mon Sep 17 00:10:01 2012 -0700
    23.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.3 @@ -1,57 +0,0 @@
    23.4 -/* vim: set ts=4 sw=4 tw=99 et:
    23.5 - *
    23.6 - * Copyright (C) 2012 David Anderson
    23.7 - *
    23.8 - * This file is part of SourcePawn.
    23.9 - *
   23.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   23.11 - * the terms of the GNU General Public License as published by the Free
   23.12 - * Software Foundation, either version 3 of the License, or (at your option)
   23.13 - * any later version.
   23.14 - * 
   23.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   23.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   23.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   23.18 - *
   23.19 - * You should have received a copy of the GNU General Public License along with
   23.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   23.21 - */
   23.22 -#include "NameBinding.h"
   23.23 -#include "Strings.h"
   23.24 -#include "Zone.h"
   23.25 -#include "Scopes.h"
   23.26 -#include "Spaces-inl.h"
   23.27 -#include "Heap-inl.h"
   23.28 -
   23.29 -using namespace ke;
   23.30 -
   23.31 -BoundName::BoundName(Scope *scope, Handle<String> name, const SourcePosition &pos)
   23.32 -  : scope_(scope),
   23.33 -    name_(name),
   23.34 -    type_(NULL),
   23.35 -    used_(false),
   23.36 -    pos_(pos)
   23.37 -{
   23.38 -}
   23.39 -
   23.40 -NamedFunction::NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos,
   23.41 -                             TokenKind token)
   23.42 -  : BoundName(scope, name, pos),
   23.43 -    token_(token),
   23.44 -    isVariadicNative_(false)
   23.45 -{
   23.46 -}
   23.47 -
   23.48 -Variable::Variable(Scope *scope, Handle<String> name, const SourcePosition &pos)
   23.49 -  : BoundName(scope, name, pos),
   23.50 -    location_(UNALLOCATED),
   23.51 -    public_(false)
   23.52 -{
   23.53 -}
   23.54 -
   23.55 -bool
   23.56 -Variable::needsHeapAllocation()
   23.57 -{
   23.58 -    return scope()->kind() == Scope::GLOBAL;
   23.59 -}
   23.60 -
    24.1 --- a/src/NameBinding.h	Mon Sep 17 00:10:01 2012 -0700
    24.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.3 @@ -1,257 +0,0 @@
    24.4 -/* vim: set ts=4 sw=4 tw=99 et:
    24.5 - *
    24.6 - * Copyright (C) 2012 David Anderson
    24.7 - *
    24.8 - * This file is part of SourcePawn.
    24.9 - *
   24.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
   24.11 - * the terms of the GNU General Public License as published by the Free
   24.12 - * Software Foundation, either version 3 of the License, or (at your option)
   24.13 - * any later version.
   24.14 - * 
   24.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   24.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   24.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   24.18 - *
   24.19 - * You should have received a copy of the GNU General Public License along with
   24.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
   24.21 - */
   24.22 -#ifndef _include_name_binding_h_
   24.23 -#define _include_name_binding_h_
   24.24 -
   24.25 -#include "PoolAllocator.h"
   24.26 -#include "Types.h"
   24.27 -#include "Scanner.h"
   24.28 -
   24.29 -namespace ke {
   24.30 -
   24.31 -class Variable;
   24.32 -class NamedFunction;
   24.33 -class Scope;
   24.34 -class Type;
   24.35 -class NamedConstant;
   24.36 -class NamedType;
   24.37 -class UnboundName;
   24.38 -class String;
   24.39 -
   24.40 -class BoundName : public PoolObject
   24.41 -{
   24.42 -    Scope *scope_;
   24.43 -    ScopedRoot<String> name_;
   24.44 -    ScopedRoot<Type> type_;
   24.45 -    bool used_;
   24.46 -
   24.47 -  protected:
   24.48 -    SourcePosition pos_;
   24.49 -
   24.50 -  public:
   24.51 -    enum Kind {
   24.52 -      VARIABLE,
   24.53 -      FUNCTION,
   24.54 -      CONSTANT,
   24.55 -      TYPE,
   24.56 -      UNBOUND
   24.57 -    };
   24.58 -
   24.59 -    BoundName(Scope *scope, Handle<String> name, const SourcePosition &pos);
   24.60 -
   24.61 -    virtual Kind kind() const = 0;
   24.62 -
   24.63 -    String *name() const {
   24.64 -        return name_;
   24.65 -    }
   24.66 -    Scope *scope() const {
   24.67 -        return scope_;
   24.68 -    }
   24.69 -    Variable *toVariable() {
   24.70 -        assert(kind() == VARIABLE);
   24.71 -        return reinterpret_cast<Variable *>(this);
   24.72 -    }
   24.73 -    NamedFunction *toNamedFunction() {
   24.74 -        assert(kind() == FUNCTION);
   24.75 -        return reinterpret_cast<NamedFunction *>(this);
   24.76 -    }
   24.77 -    NamedConstant *toNamedConstant() {
   24.78 -        assert(kind() == CONSTANT);
   24.79 -        return reinterpret_cast<NamedConstant *>(this);
   24.80 -    }
   24.81 -    NamedType *toNamedType() {
   24.82 -        assert(kind() == TYPE);
   24.83 -        return reinterpret_cast<NamedType *>(this);
   24.84 -    }
   24.85 -    Type *type() const {
   24.86 -        return type_;
   24.87 -    }
   24.88 -    void setType(Handle<Type> type) {
   24.89 -        type_ = type;
   24.90 -    }
   24.91 -    void setUsed() {
   24.92 -        used_ = true;
   24.93 -    }
   24.94 -    bool used() const {
   24.95 -        return used_;
   24.96 -    }
   24.97 -    const SourcePosition &pos() {
   24.98 -        return pos_;
   24.99 -    }
  24.100 -};
  24.101 -
  24.102 -class NamedFunction : public BoundName
  24.103 -{
  24.104 -    unsigned slot_;
  24.105 -    TokenKind token_;
  24.106 -    ScopedRoot<Type> forwardType_;
  24.107 -    bool isVariadicNative_;
  24.108 -    Vector<BoundName *, PoolAllocationPolicy> globals_;
  24.109 -
  24.110 -  public:
  24.111 -    NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos, TokenKind token);
  24.112 -
  24.113 -    Kind kind() const {
  24.114 -        return FUNCTION;
  24.115 -    }
  24.116 -    void allocate(unsigned slot) {
  24.117 -        slot_ = slot;
  24.118 -    }
  24.119 -    bool isForward() const {
  24.120 -        return token_ == TOK_FORWARD;
  24.121 -    }
  24.122 -    bool isPublic() const {
  24.123 -        return token_ == TOK_PUBLIC;
  24.124 -    }
  24.125 -    bool isNative() const {
  24.126 -        return token_ == TOK_NATIVE;
  24.127 -    }
  24.128 -    TokenKind token() const {
  24.129 -        return token_;
  24.130 -    }
  24.131 -    void setForwardType(Handle<Type> type) {
  24.132 -        forwardType_ = type;
  24.133 -    }
  24.134 -    Type *forwardType() {
  24.135 -        return forwardType_;
  24.136 -    }
  24.137 -    void setImplemented(const SourcePosition &at) {
  24.138 -        token_ = TOK_PUBLIC;
  24.139 -        pos_ = at;
  24.140 -    }
  24.141 -    void markNativeVariadic() {
  24.142 -        assert(token_ == TOK_NATIVE);
  24.143 -        isVariadicNative_ = true;
  24.144 -    }
  24.145 -    bool isNativeVariadic() {
  24.146 -        assert(token_ == TOK_NATIVE);
  24.147 -        return isVariadicNative_;
  24.148 -    }
  24.149 -    unsigned slot() const {
  24.150 -        return slot_;
  24.151 -    }
  24.152 -    bool addUsedGlobal(BoundName *name) {
  24.153 -        return globals_.append(name);
  24.154 -    }
  24.155 -    Vector<BoundName *, PoolAllocationPolicy> *usedGlobals() {
  24.156 -        return &globals_;
  24.157 -    }
  24.158 -};
  24.159 -
  24.160 -class NamedConstant : public BoundName
  24.161 -{
  24.162 -    BoxedPrimitive value_;
  24.163 -
  24.164 -  public:
  24.165 -    NamedConstant(Scope *scope, Handle<String> name, const SourcePosition &pos)
  24.166 -      : BoundName(scope, name, pos)
  24.167 -    {
  24.168 -    }
  24.169 -
  24.170 -    Kind kind() const {
  24.171 -        return CONSTANT;
  24.172 -    }
  24.173 -    void set(Handle<Type> type, const BoxedPrimitive &value) {
  24.174 -        value_ = value;
  24.175 -        setType(type);
  24.176 -    }
  24.177 -    BoxedPrimitive value() const {
  24.178 -        return value_;
  24.179 -    }
  24.180 -};
  24.181 -
  24.182 -class NamedType : public BoundName
  24.183 -{
  24.184 -  public:
  24.185 -    NamedType(Scope *scope, Handle<String> name, Handle<Type> type)
  24.186 -      : BoundName(scope, name, SourcePosition())
  24.187 -    {
  24.188 -        setType(type);
  24.189 -    }
  24.190 -
  24.191 -    NamedType(Scope *scope, Handle<String> name, const SourcePosition &pos)
  24.192 -      : BoundName(scope, name, pos)
  24.193 -    {
  24.194 -    }
  24.195 -
  24.196 -    Kind kind() const {
  24.197 -        return TYPE;
  24.198 -    }
  24.199 -};
  24.200 -
  24.201 -class UnboundName : public BoundName
  24.202 -{
  24.203 -  public:
  24.204 -    UnboundName(Scope *scope, Handle<String> name)
  24.205 -      : BoundName(scope, name, SourcePosition())
  24.206 -    {
  24.207 -    }
  24.208 -
  24.209 -    Kind kind() const {
  24.210 -        return UNBOUND;
  24.211 -    }
  24.212 -};
  24.213 -
  24.214 -class Variable : public BoundName
  24.215 -{
  24.216 -  public:
  24.217 -    enum Location {
  24.218 -        UNALLOCATED,
  24.219 -        STACK,
  24.220 -        PARAMETER,
  24.221 -        ENVIRONMENT
  24.222 -    };
  24.223 -
  24.224 -    Variable(Scope *scope, Handle<String> name, const SourcePosition &pos);
  24.225 -
  24.226 -    Kind kind() const {
  24.227 -        return VARIABLE;
  24.228 -    }
  24.229 -    bool unallocated() const {
  24.230 -        return location() == UNALLOCATED;
  24.231 -    }
  24.232 -    void allocate(Location location, unsigned slot) {
  24.233 -        location_ = location;
  24.234 -        slot_ = slot;
  24.235 -    }
  24.236 -    Location location() const {
  24.237 -        return location_;
  24.238 -    }
  24.239 -    unsigned slot() const {
  24.240 -        assert(!unallocated());
  24.241 -        return slot_;
  24.242 -    }
  24.243 -    void setPublic() {
  24.244 -        assert(!public_);
  24.245 -        public_ = true;
  24.246 -    }
  24.247 -    bool isPublic() const {
  24.248 -        return public_;
  24.249 -    }
  24.250 -    bool needsHeapAllocation();
  24.251 -
  24.252 -  private:
  24.253 -    Location location_;
  24.254 -    unsigned slot_;
  24.255 -    bool public_;
  24.256 -};
  24.257 -
  24.258 -}
  24.259 -
  24.260 -#endif // _include_name_binding_h_
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/src/NativeTable.cpp	Sat Nov 17 18:41:01 2012 -0800
    25.3 @@ -0,0 +1,96 @@
    25.4 +/* vim: set ts=4 sw=4 tw=99 et:
    25.5 + *
    25.6 + * Copyright (C) 2012 David Anderson
    25.7 + *
    25.8 + * This file is part of SourcePawn.
    25.9 + *
   25.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   25.11 + * the terms of the GNU General Public License as published by the Free
   25.12 + * Software Foundation, either version 3 of the License, or (at your option)
   25.13 + * any later version.
   25.14 + * 
   25.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   25.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   25.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   25.18 + *
   25.19 + * You should have received a copy of the GNU General Public License along with
   25.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   25.21 + */
   25.22 +#include "Zone.h"
   25.23 +#include "NativeTable.h"
   25.24 +#include "StringPool.h"
   25.25 +
   25.26 +using namespace ke;
   25.27 +
   25.28 +NativeTable::NativeTable(Zone *zone)
   25.29 +  : zone_(zone),
   25.30 +    nativeMap_(ZoneAllocatorPolicy())
   25.31 +{
   25.32 +}
   25.33 +
   25.34 +NativeTable::~NativeTable()
   25.35 +{
   25.36 +    for (size_t i = 0; i < natives_.length(); i++)
   25.37 +        delete natives_[i];
   25.38 +}
   25.39 +
   25.40 +bool
   25.41 +NativeTable::initialize()
   25.42 +{
   25.43 +    return nativeMap_.init(16);
   25.44 +}
   25.45 +
   25.46 +bool
   25.47 +NativeTable::add(Handle<String> name, size_t *indexp)
   25.48 +{
   25.49 +    // :TODO: assert no GC
   25.50 +    CharsAndLength key(name->chars(), name->length());
   25.51 +    NativeMap::Insert p = nativeMap_.findForAdd(key);
   25.52 +    if (p.found()) {
   25.53 +        *indexp = (*p)->index;
   25.54 +        return true;
   25.55 +    }
   25.56 +
   25.57 +    NativeInfo *info = new NativeInfo(name, NULL, natives_.length());
   25.58 +    if (!info || !natives_.append(info))
   25.59 +        return false;
   25.60 +
   25.61 +    if (!nativeMap_.add(p, info))
   25.62 +        return false;
   25.63 +
   25.64 +    *indexp = info->index;
   25.65 +
   25.66 +    return true;
   25.67 +}
   25.68 +
   25.69 +bool
   25.70 +NativeTable::bind(const char *name, void *address)
   25.71 +{
   25.72 +    CharsAndLength key(name, strlen(name));
   25.73 +    NativeMap::Insert p = nativeMap_.findForAdd(key);
   25.74 +    if (p.found()) {
   25.75 +        (*p)->address = address;
   25.76 +        return true;
   25.77 +    }
   25.78 +
   25.79 +    Local<String> str(zone_, zone_->symbols()->add(key.str(), key.length()));
   25.80 +    if (!str)
   25.81 +        return false;
   25.82 +
   25.83 +    // :TODO: assert no GC
   25.84 +    NativeInfo *info = new NativeInfo(str, address, natives_.length());
   25.85 +    if (!info || !natives_.append(info))
   25.86 +        return false;
   25.87 +
   25.88 +    if (!nativeMap_.add(p, info))
   25.89 +        return false;
   25.90 +
   25.91 +    return true;
   25.92 +}
   25.93 +
   25.94 +void
   25.95 +NativeTable::accept(VirtualObjectVisitor *visitor)
   25.96 +{
   25.97 +    for (size_t i = 0; i < natives_.length(); i++)
   25.98 +        visitor->visit(natives_[i]->name.address());
   25.99 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/NativeTable.h	Sat Nov 17 18:41:01 2012 -0800
    26.3 @@ -0,0 +1,89 @@
    26.4 +/* vim: set ts=4 sw=4 tw=99 et:
    26.5 + *
    26.6 + * Copyright (C) 2012 David Anderson
    26.7 + *
    26.8 + * This file is part of SourcePawn.
    26.9 + *
   26.10 + * SourcePawn is free software: you can redistribute it and/or modify it under
   26.11 + * the terms of the GNU General Public License as published by the Free
   26.12 + * Software Foundation, either version 3 of the License, or (at your option)
   26.13 + * any later version.
   26.14 + * 
   26.15 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   26.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   26.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   26.18 + *
   26.19 + * You should have received a copy of the GNU General Public License along with
   26.20 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   26.21 + */
   26.22 +#ifndef _include_sp2_native_table_h_
   26.23 +#define _include_sp2_native_table_h_
   26.24 +
   26.25 +#include "AllocatorPolicies.h"
   26.26 +#include "Strings.h"
   26.27 +#include "HashTable.h"
   26.28 +#include "Vector.h"
   26.29 +#include "VirtualObjectVisitor.h"
   26.30 +
   26.31 +namespace ke {
   26.32 +
   26.33 +class NativeTable
   26.34 +{
   26.35 +  public:
   26.36 +    NativeTable(Zone *zone);
   26.37 +    ~NativeTable();
   26.38 +
   26.39 +  private:
   26.40 +    struct NativeInfo {
   26.41 +        Unbarriered<String> name;
   26.42 +        void *address;
   26.43 +        size_t index;
   26.44 +
   26.45 +        NativeInfo(String *name, void *address, size_t index)
   26.46 +          : address(address),
   26.47 +            index(index)
   26.48 +        {
   26.49 +            this->name = name;
   26.50 +        }
   26.51 +    };
   26.52 +
   26.53 +    struct Policy
   26.54 +    {
   26.55 +        typedef NativeInfo * Payload;
   26.56 +
   26.57 +        static uint32 hash(const CharsAndLength &key) {
   26.58 +            return HashCharSequence(key.str(), key.length());
   26.59 +        }
   26.60 +        
   26.61 +        static bool matches(const CharsAndLength &key, NativeInfo *info) {
   26.62 +            if (info->name->length() != key.length())
   26.63 +                return false;
   26.64 +            return memcmp(info->name->chars(), key.str(), key.length() * sizeof(char)) == 0;
   26.65 +        }
   26.66 +    };
   26.67 +
   26.68 +    typedef HashTable<Policy, ZoneAllocatorPolicy> NativeMap;
   26.69 +
   26.70 +  public:
   26.71 +    bool initialize();
   26.72 +
   26.73 +    bool bind(const char *name, void *address);
   26.74 +    bool add(Handle<String> name, size_t *indexp);
   26.75 +    String *name(size_t index) const {
   26.76 +        return natives_[index]->name;
   26.77 +    }
   26.78 +    void *address(size_t index) const {
   26.79 +        return natives_[index]->address;
   26.80 +    }
   26.81 +
   26.82 +    void accept(VirtualObjectVisitor *visitor);
   26.83 +
   26.84 +  private:
   26.85 +    Zone *zone_;
   26.86 +    NativeMap nativeMap_;
   26.87 +    Vector<NativeInfo *> natives_;
   26.88 +};
   26.89 +
   26.90 +}
   26.91 +
   26.92 +#endif // _include_sp2_native_table_h_
    27.1 --- a/src/ObjectVisitor.h	Mon Sep 17 00:10:01 2012 -0700
    27.2 +++ b/src/ObjectVisitor.h	Sat Nov 17 18:41:01 2012 -0800
    27.3 @@ -47,15 +47,27 @@
    27.4  
    27.5      size_t iterateType(Object *obj) {
    27.6          visitField(obj, Type::offsetOfContained());
    27.7 -        visitField(obj, Type::offsetOfReturnType());
    27.8 -        visitField(obj, Type::offsetOfParameters());
    27.9          visitField(obj, Type::offsetOfName());
   27.10 -        visitField(obj, Type::offsetOfFields());
   27.11 -        visitField(obj, Type::offsetOfDefaults());
   27.12 -        visitField(obj, Type::offsetOfNewMap());
   27.13          return sizeof(Type);
   27.14      }
   27.15  
   27.16 +    size_t iterateStructType(Object *obj) {
   27.17 +        visitField(obj, Type::offsetOfContained());
   27.18 +        visitField(obj, Type::offsetOfName());
   27.19 +        visitField(obj, StructType::offsetOfFields());
   27.20 +        visitField(obj, StructType::offsetOfNewMap());
   27.21 +        return sizeof(StructType);
   27.22 +    }
   27.23 +
   27.24 +    size_t iterateFunctionType(Object *obj) {
   27.25 +        visitField(obj, Type::offsetOfContained());
   27.26 +        visitField(obj, Type::offsetOfName());
   27.27 +        visitField(obj, FunctionType::offsetOfReturnType());
   27.28 +        visitField(obj, FunctionType::offsetOfParameters());      
   27.29 +        visitField(obj, FunctionType::offsetOfDefaults());
   27.30 +        return sizeof(FunctionType);
   27.31 +    }
   27.32 +
   27.33      size_t iterateFixedArray(FixedArray *array) {
   27.34          unsigned length = array->length();
   27.35          Object **ptr = reinterpret_cast<Object **>(array + 1);
   27.36 @@ -75,6 +87,7 @@
   27.37          visitField(obj, Code::offsetOfObjects());
   27.38          visitField(obj, Code::offsetOfSafepoints());
   27.39          visitField(obj, Code::offsetOfSourceMap());
   27.40 +        visitField(obj, Code::offsetOfStrings());
   27.41          return sizeof(Code);
   27.42      }
   27.43  
   27.44 @@ -84,11 +97,8 @@
   27.45      }
   27.46  
   27.47      size_t iterateModule(Object *obj) {
   27.48 -        visitField(obj, Module::offsetOfFunctions());
   27.49 -        visitField(obj, Module::offsetOfPublics());
   27.50 -        visitField(obj, Module::offsetOfNatives());
   27.51          visitField(obj, Module::offsetOfFile());
   27.52 -        visitField(obj, Module::offsetOfEnvironment());
   27.53 +        visitField(obj, Module::offsetOfGlobals());
   27.54          visitField(obj, Module::offsetOfCode());
   27.55          return sizeof(Module);
   27.56      }
   27.57 @@ -108,7 +118,6 @@
   27.58  
   27.59      size_t iterateNative(Object *obj) {
   27.60          visitField(obj, Native::offsetOfType());
   27.61 -        visitField(obj, Native::offsetOfName());
   27.62          return sizeof(Native);
   27.63      }
   27.64  
   27.65 @@ -182,6 +191,12 @@
   27.66            case MapKind_Type:
   27.67              return iterateType(obj);
   27.68  
   27.69 +          case MapKind_FunctionType:
   27.70 +            return iterateFunctionType(obj);
   27.71 +
   27.72 +          case MapKind_StructType:
   27.73 +            return iterateStructType(obj);
   27.74 +
   27.75            case MapKind_FixedArray:
   27.76              return iterateFixedArray(FixedArray::cast(obj));
   27.77  
   27.78 @@ -256,6 +271,12 @@
   27.79        case MapKind_Type:
   27.80          return sizeof(Type);
   27.81  
   27.82 +      case MapKind_FunctionType:
   27.83 +        return sizeof(FunctionType);
   27.84 +
   27.85 +      case MapKind_StructType:
   27.86 +        return sizeof(StructType);
   27.87 +
   27.88        case MapKind_FixedArray:
   27.89          return FixedArray::cast(obj)->objSize();
   27.90  
    28.1 --- a/src/Objects.h	Mon Sep 17 00:10:01 2012 -0700
    28.2 +++ b/src/Objects.h	Sat Nov 17 18:41:01 2012 -0800
    28.3 @@ -35,6 +35,8 @@
    28.4  {
    28.5      // Represents Type objects.
    28.6      MapKind_Type,
    28.7 +    MapKind_FunctionType,
    28.8 +    MapKind_StructType,
    28.9  
   28.10      // Represents basic data structures. When adding to this, don't forget
   28.11      // to update Zone::initialize(), or you'll get a NULL crash trying to
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/src/OldByCo.cpp	Sat Nov 17 18:41:01 2012 -0800
    29.3 @@ -0,0 +1,1585 @@
    29.4 +/* vim: set ts=4 sw=4 tw=99 et:
    29.5 + *
    29.6 + * Copyright (C) 2012 David Anderson
    29.7 + *
    29.8 + * This file is part of JITCraft.
    29.9 + *
   29.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   29.11 + * the terms of the GNU General Public License as published by the Free
   29.12 + * Software Foundation, either version 3 of the License, or (at your option)
   29.13 + * any later version.
   29.14 + * 
   29.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   29.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   29.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   29.18 + *
   29.19 + * You should have received a copy of the GNU General Public License along with
   29.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   29.21 + */
   29.22 +#include <string.h>
   29.23 +#include "../Modules.h"
   29.24 +#include "../Types.h"
   29.25 +#include "../Array.h"
   29.26 +#include "../Strings.h"
   29.27 +#include "../Zone.h"
   29.28 +#include "../Environments.h"
   29.29 +#include "../Box.h"
   29.30 +#include "../Heap-inl.h"
   29.31 +#include "BytecodeCompiler.h"
   29.32 +#include "Scopes.h"
   29.33 +
   29.34 +using namespace ke;
   29.35 +
   29.36 +typedef BytecodeEmitter::Label Label;
   29.37 +
   29.38 +#define __ emitter_.
   29.39 +
   29.40 +BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
   29.41 +  : zone_(zone),
   29.42 +    tree_(tree),
   29.43 +    emitter_(zone->pool()),
   29.44 +    locals_(NULL),
   29.45 +    scope_(NULL),
   29.46 +    moduleData_(module),
   29.47 +    loop_(NULL)
   29.48 +{
   29.49 +}
   29.50 +
   29.51 +static inline TokenKind
   29.52 +ToCompare(Expression *expr)
   29.53 +{
   29.54 +    if (expr->isBinaryExpression()) {
   29.55 +        BinaryExpression *b = expr->toBinaryExpression();
   29.56 +        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
   29.57 +            return b->token();
   29.58 +    } else if (expr->isUnaryExpression()) {
   29.59 +        UnaryExpression *u = expr->toUnaryExpression();
   29.60 +        if (u->token() == TOK_NOT)
   29.61 +            return TOK_NOT;
   29.62 +    }
   29.63 +    return TOK_EOF;
   29.64 +}
   29.65 +
   29.66 +static inline Opcode
   29.67 +CompareTokenToJump(TokenKind kind)
   29.68 +{
   29.69 +    switch (kind) {
   29.70 +      case TOK_EQUALS:
   29.71 +        return OP_JEQ;
   29.72 +      case TOK_NOTEQUALS:
   29.73 +        return OP_JNE;
   29.74 +      case TOK_GT:
   29.75 +        return OP_JG;
   29.76 +      case TOK_GE:
   29.77 +        return OP_JGE;
   29.78 +      case TOK_LT:
   29.79 +        return OP_JL;
   29.80 +      default:
   29.81 +        assert(kind == TOK_LE);
   29.82 +        return OP_JLE;
   29.83 +    }
   29.84 +}
   29.85 +
   29.86 +static inline Opcode
   29.87 +TokenToOpcode(TokenKind kind)
   29.88 +{
   29.89 +    switch (kind) {
   29.90 +      case TOK_PLUS:
   29.91 +        return OP_ADD;
   29.92 +      case TOK_MINUS:
   29.93 +        return OP_SUB;
   29.94 +      case TOK_STAR:
   29.95 +        return OP_MUL;
   29.96 +      case TOK_SLASH:
   29.97 +        return OP_DIV;
   29.98 +      case TOK_PERCENT:
   29.99 +        return OP_MOD;
  29.100 +      case TOK_SHR:
  29.101 +        return OP_SHR;
  29.102 +      case TOK_USHR:
  29.103 +        return OP_USHR;
  29.104 +      case TOK_SHL:
  29.105 +        return OP_SHL;
  29.106 +      case TOK_BITAND:
  29.107 +        return OP_BITAND;
  29.108 +      case TOK_BITOR:
  29.109 +        return OP_BITOR;
  29.110 +      case TOK_GT:
  29.111 +          return OP_GT;
  29.112 +      case TOK_GE:
  29.113 +          return OP_GE;
  29.114 +      case TOK_LT:
  29.115 +          return OP_LT;
  29.116 +      case TOK_LE:
  29.117 +          return OP_LE;
  29.118 +      case TOK_EQUALS:
  29.119 +          return OP_EQ;
  29.120 +      case TOK_NOTEQUALS:
  29.121 +          return OP_NE;
  29.122 +      default:
  29.123 +        assert(kind == TOK_BITXOR);
  29.124 +        return OP_BITXOR;
  29.125 +    }
  29.126 +}
  29.127 +
  29.128 +void
  29.129 +BytecodeCompiler::recordLifoSlot(Scope *scope)
  29.130 +{
  29.131 +    if (!scope)
  29.132 +        return;
  29.133 +
  29.134 +    if (Variable *var = scope->lifoSlot()) {
  29.135 +        locals_->set(zone_, var->slot(), var->type());
  29.136 +        __ savelifo(var->slot());
  29.137 +    }
  29.138 +}
  29.139 +
  29.140 +void
  29.141 +BytecodeCompiler::unwindTo(Scope *scope)
  29.142 +{
  29.143 +    // Note: we only need to unwind to the outermost scope's LIFO slot.
  29.144 +    Variable *var = NULL;
  29.145 +    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
  29.146 +        if (Variable *slot = current->lifoSlot())
  29.147 +            var = slot;
  29.148 +    }
  29.149 +
  29.150 +    if (var)
  29.151 +        __ unwindlifo(var->slot());
  29.152 +}
  29.153 +
  29.154 +void
  29.155 +BytecodeCompiler::visit(NameProxy *name)
  29.156 +{
  29.157 +    switch (name->binding()->kind()) {
  29.158 +      case BoundName::VARIABLE:
  29.159 +      {
  29.160 +        Variable *var = name->binding()->toVariable();
  29.161 +
  29.162 +        if (var->location() == Variable::STACK) {
  29.163 +            __ getlocal(var);
  29.164 +            assert(!name->type()->isReference());
  29.165 +        } else if (var->location() == Variable::ENVIRONMENT) {
  29.166 +            getEnvSlot(var);
  29.167 +        } else {
  29.168 +            assert(var->location() == Variable::PARAMETER);
  29.169 +            __ getarg(var);
  29.170 +
  29.171 +            // If this argument is actually a reference, dereference it now.
  29.172 +            if (var->type()->isReference())
  29.173 +                __ getref(var->type()->contained());
  29.174 +        }
  29.175 +        break;
  29.176 +      }
  29.177 +
  29.178 +      case BoundName::FUNCTION:
  29.179 +      {
  29.180 +        NamedFunction *fun = name->binding()->toNamedFunction();
  29.181 +        __ module();
  29.182 +        __ getmodule_fn(fun->slot());
  29.183 +        break;
  29.184 +      }
  29.185 +
  29.186 +      default:
  29.187 +      {
  29.188 +        NamedConstant *constant = name->binding()->toNamedConstant();
  29.189 +        __ int_(constant->value().toInt());
  29.190 +        break;
  29.191 +      }
  29.192 +    }
  29.193 +}
  29.194 +
  29.195 +void
  29.196 +BytecodeCompiler::visit(ExpressionStatement *node)
  29.197 +{
  29.198 +    // Expressions leave their value on the top of the stack, so we make sure
  29.199 +    // to balance the stack if they're used as a statement.
  29.200 +    node->expression()->accept(this);
  29.201 +    if (!node->expression()->type()->isVoid())
  29.202 +        __ pop();
  29.203 +}
  29.204 +
  29.205 +static inline bool
  29.206 +IsCompositeValueType(Type *type)
  29.207 +{
  29.208 +    return type->isStruct() ||
  29.209 +           (type->isArray() && type->isFixedLength());
  29.210 +}
  29.211 +
  29.212 +static inline Array *
  29.213 +StringLiteralToArray(Zone *zone, StringLiteral *node)
  29.214 +{
  29.215 +    Local<Type> type(zone, node->type());
  29.216 +    Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
  29.217 +    if (!map)
  29.218 +        return NULL;
  29.219 +
  29.220 +    return Array::NewString(zone,
  29.221 +                            map,
  29.222 +                            node->string()->raw(),
  29.223 +                            node->string()->length(),
  29.224 +                            Heap::Tenure_Old);
  29.225 +}
  29.226 +
  29.227 +void
  29.228 +BytecodeCompiler::visit(Assignment *node)
  29.229 +{
  29.230 +    Local<Type> left(zone_, node->type());
  29.231 +    Local<Type> right(zone_, node->expression()->type());
  29.232 +
  29.233 +    // The first step is three sub-steps:
  29.234 +    //
  29.235 +    //   (1) Bind the left-hand side.
  29.236 +    //   -- If a cumulative operation (+=, etc):
  29.237 +    //   (2) Save a copy of the binding on the stack.
  29.238 +    //   (3) Dereference the binding to get a value.
  29.239 +    //
  29.240 +    if (node->lvalue()->isNameProxy()) {
  29.241 +        NameProxy *proxy = node->lvalue()->toNameProxy();
  29.242 +        Variable *var = proxy->binding()->toVariable();
  29.243 +
  29.244 +        // We need to fetch the variable under the following circumstances:
  29.245 +        //  (1) The variable is a reference, since we'll store into the ref.
  29.246 +        //  (2) The variable is a fixed array, since we need to copy into it.
  29.247 +        //  (3) The variable is a struct, since we need to copy into it.
  29.248 +        if (var->type()->isReference() || IsCompositeValueType(var->type()))
  29.249 +            __ get(var);
  29.250 +
  29.251 +        // Get the value if needed.
  29.252 +        if (node->token() != TOK_ASSIGN) {
  29.253 +            // += etc is not allowed on arrays.
  29.254 +            assert(!var->type()->isArray());
  29.255 +
  29.256 +            if (var->location() == Variable::ENVIRONMENT)
  29.257 +                getEnvSlot(var);
  29.258 +
  29.259 +            if (var->type()->isReference()) {
  29.260 +                __ dup();
  29.261 +                __ getref(var->type()->contained());
  29.262 +            } else if (var->location() != Variable::ENVIRONMENT) {
  29.263 +                __ get(var);
  29.264 +            }
  29.265 +        }
  29.266 +    } else if (node->lvalue()->isFieldExpression()) {
  29.267 +        FieldExpression *expr = node->lvalue()->toFieldExpression();
  29.268 +        __ note_position(expr->pos());
  29.269 +
  29.270 +        expr->left()->accept(this);
  29.271 +
  29.272 +        if (node->token() != TOK_ASSIGN)
  29.273 +            __ dup();
  29.274 +
  29.275 +        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
  29.276 +            __ getfield(expr->fieldIndex(), left);
  29.277 +    } else {
  29.278 +        IndexExpression *index = node->lvalue()->toIndexExpression();
  29.279 +        __ note_position(index->pos());
  29.280 +
  29.281 +        index->left()->accept(this);
  29.282 +        index->right()->accept(this);
  29.283 +
  29.284 +        if (node->token() != TOK_ASSIGN)
  29.285 +            __ dup2();
  29.286 +
  29.287 +        if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
  29.288 +            __ getelem(left);
  29.289 +    }
  29.290 +
  29.291 +    if (node->token() == TOK_ASSIGN) {
  29.292 +        // Special case: if the left-hand side is a string literal, we must
  29.293 +        // spawn a new copy (:TODO: something about const?)
  29.294 +        if (node->expression()->isStringLiteral() && !left->isFixedLength()) {
  29.295 +            Local<Array> string(zone_,
  29.296 +                    StringLiteralToArray(zone_, node->expression()->toStringLiteral()));
  29.297 +            if (!string)
  29.298 +                return;
  29.299 +
  29.300 +            Local<ArrayMap> arrayMap(zone_, ArrayMap::cast(string->map()));
  29.301 +            __ note_position(node->expression()->pos());
  29.302 +            __ int_(string->length());
  29.303 +            __ newarray(OP_NEWSIZED, arrayMap, Heap::Tenure_Default);
  29.304 +            __ object(string);
  29.305 +            __ copyarray();
  29.306 +        } else {
  29.307 +            node->expression()->accept(this);
  29.308 +        }
  29.309 +    } else {
  29.310 +        visitForALU(left, node->expression());
  29.311 +
  29.312 +        TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
  29.313 +        __ note_position(node->pos());
  29.314 +        __ binary(TokenToOpcode(alu));
  29.315 +    }
  29.316 +
  29.317 +    // Emit the store.
  29.318 +    if (left->isArray() && left->isFixedLength()) {
  29.319 +        // (x = y) returns the left-hand side; if |x| is a fixed-length array,
  29.320 +        // then |y| is as well, and we perform a deep copy.
  29.321 +        assert(right->isFixedLength());
  29.322 +        __ note_position(node->pos());
  29.323 +        __ copyarray();
  29.324 +    } else if (left->isStruct()) {
  29.325 +        // Structs have value semantics, so emit a full copy. We don't break
  29.326 +        // this down into u-ops, to avoid unnecessary bytecode explosion.
  29.327 +        assert(right->isStruct());
  29.328 +        __ note_position(node->pos());
  29.329 +        __ copystruct();
  29.330 +    } else if (node->lvalue()->isNameProxy()) {
  29.331 +        NameProxy *proxy = node->lvalue()->toNameProxy();
  29.332 +        Variable *var = proxy->binding()->toVariable();
  29.333 +
  29.334 +        if (var->type()->isReference())
  29.335 +            __ setref(var->type()->contained());
  29.336 +        else if (var->location() == Variable::ENVIRONMENT)
  29.337 +            setEnvSlot(var);
  29.338 +        else
  29.339 +            __ set(var);
  29.340 +    } else if (node->lvalue()->isFieldExpression()) {
  29.341 +        FieldExpression *expr = node->lvalue()->toFieldExpression();
  29.342 +        __ setfield(expr->fieldIndex(), left);
  29.343 +    } else {
  29.344 +        __ setelem(left);
  29.345 +    }
  29.346 +}
  29.347 +
  29.348 +void
  29.349 +BytecodeCompiler::visit(IncDecExpression *node)
  29.350 +{
  29.351 +    // In the postfix case, the logic looks like:
  29.352 +    //      (1) Bind       -> REF
  29.353 +    //      (2) Dup        -> REF REF
  29.354 +    //      (3) Fetch      -> REF VAL
  29.355 +    //      (4) Swap       -> VAL REF
  29.356 +    //      (5) Pick       -> VAL REF VAL
  29.357 +    //      (6) Add        -> VAL REF VAL+1
  29.358 +    //      (7) Store      -> VAL VAL+1
  29.359 +    //      (8) Drop       -> VAL
  29.360 +    //
  29.361 +    // In the prefix case, the logic looks like:
  29.362 +    //      (1) Bind       -> REF
  29.363 +    //      (2) Dup        -> REF REF
  29.364 +    //      (3) Fetch      -> REF VAL
  29.365 +    //      --
  29.366 +    //      --
  29.367 +    //      (6) Add        -> REF VAL+1
  29.368 +    //      (7) Store      -> VAL+1
  29.369 +    //      --
  29.370 +    //
  29.371 +    // This is squirrely enough such that we don't bother sharing too much
  29.372 +    // with the above.
  29.373 +    // 
  29.374 +    // Note: We simulate a "Pick" operation with a dup2+pop.
  29.375 +
  29.376 +    // This is steps (1) to (5).
  29.377 +    Expression *expr = node->expression();
  29.378 +    if (expr->isNameProxy()) {
  29.379 +        NameProxy *proxy = expr->toNameProxy();
  29.380 +        Variable *var = proxy->binding()->toVariable();
  29.381 +
  29.382 +        // Bind.
  29.383 +        if (var->location() == Variable::ENVIRONMENT)
  29.384 +            getEnvSlot(var);
  29.385 +        else if (var->type()->isReference() || var->type()->isArray())
  29.386 +            __ get(var);
  29.387 +
  29.388 +        // Dup and fetch.
  29.389 +        if (var->type()->isReference()) {
  29.390 +            __ dup();
  29.391 +            __ getref(node->type());
  29.392 +            if (node->postfix()) {
  29.393 +                __ swap();
  29.394 +                __ pick2();
  29.395 +            }
  29.396 +        } else {
  29.397 +            assert(!var->type()->isArray());
  29.398 +            if (var->location() != Variable::ENVIRONMENT)
  29.399 +                __ get(var);
  29.400 +            if (node->postfix())
  29.401 +                __ dup();
  29.402 +        }
  29.403 +    } else if (expr->isFieldExpression()) {
  29.404 +        FieldExpression *field = expr->toFieldExpression();
  29.405 +
  29.406 +        field->left()->accept(this);
  29.407 +        __ dup();
  29.408 +        __ getfield(field->fieldIndex(), field->type());
  29.409 +
  29.410 +        if (node->postfix()) {
  29.411 +            // The stack looks like this now:
  29.412 +            // OBJECT VALUE
  29.413 +            __ swap();          // VALUE OBJECT
  29.414 +            __ pick2();         // VALUE OBJECT VALUE
  29.415 +        }
  29.416 +    } else {
  29.417 +        IndexExpression *index = expr->toIndexExpression();
  29.418 +        __ note_position(index->pos());
  29.419 +
  29.420 +        index->left()->accept(this);
  29.421 +        index->right()->accept(this);
  29.422 +
  29.423 +        assert(!node->type()->isArray());
  29.424 +        __ dup2();
  29.425 +        __ getelem(node->type());
  29.426 +
  29.427 +        if (node->postfix()) {
  29.428 +            // The stack looks like this now:
  29.429 +            // ARRAY INDEX VALUE
  29.430 +            //
  29.431 +            // So we must use a PICK operation to rotate the stack into position.
  29.432 +            __ roll3();         // INDEX VALUE ARRAY
  29.433 +            __ roll3();         // VALUE ARRAY INDEX
  29.434 +            __ pick3();         // VALUE ARRAY INDEX VALUE
  29.435 +        }
  29.436 +    }
  29.437 +
  29.438 +    // Perform step (6).
  29.439 +    if (node->type()->isFloat()) {
  29.440 +        __ float_(1.0);
  29.441 +    } else {
  29.442 +        assert(node->type()->isInt32());
  29.443 +        __ int_(1);
  29.444 +    }
  29.445 +
  29.446 +    __ note_position(node->pos());
  29.447 +    if (node->token() == TOK_INCREMENT)
  29.448 +        __ binary(OP_ADD);
  29.449 +    else
  29.450 +        __ binary(OP_SUB);
  29.451 +
  29.452 +    // Perform step (7).
  29.453 +    if (expr->isNameProxy()) {
  29.454 +        NameProxy *proxy = expr->toNameProxy();
  29.455 +        Variable *var = proxy->binding()->toVariable();
  29.456 +
  29.457 +        if (var->type()->isReference())
  29.458 +            __ setref(node->type());
  29.459 +        else if (var->location() == Variable::ENVIRONMENT)
  29.460 +            setEnvSlot(var);
  29.461 +        else
  29.462 +            __ set(var);
  29.463 +    } else if (expr->isFieldExpression()) {
  29.464 +        FieldExpression *field = expr->toFieldExpression();
  29.465 +        __ setfield(field->fieldIndex(), field->type());
  29.466 +    } else {
  29.467 +        assert(expr->isIndexExpression());
  29.468 +        __ setelem(node->type());
  29.469 +    }
  29.470 +
  29.471 +    // Perform step (8).
  29.472 +    if (node->postfix())
  29.473 +        __ pop();
  29.474 +}
  29.475 +
  29.476 +void
  29.477 +BytecodeCompiler::visitForALU(Type *needed, Expression *node)
  29.478 +{
  29.479 +    node->accept(this);
  29.480 +    if (needed->isFloat() && !node->type()->isFloat())
  29.481 +        __ cvt_i2f();
  29.482 +    else
  29.483 +        assert(needed->primitive() == node->type()->primitive());
  29.484 +}
  29.485 +
  29.486 +static inline Type *
  29.487 +GetCoercionType(TokenKind tok, Type *left, Type *right)
  29.488 +{
  29.489 +    if (left->isFloat())
  29.490 +        return left;
  29.491 +    return right;
  29.492 +}
  29.493 +
  29.494 +void
  29.495 +BytecodeCompiler::visit(UnaryExpression *node)
  29.496 +{
  29.497 +    Local<Type> out(zone_, ((Expression *)node)->type());
  29.498 +
  29.499 +    switch (node->token()) {
  29.500 +      case TOK_MINUS:
  29.501 +      {
  29.502 +        Local<Type> type(zone_, node->expression()->type());
  29.503 +        node->expression()->accept(this);
  29.504 +        
  29.505 +        if (out->isFloat())
  29.506 +            __ neg_f();
  29.507 +        else
  29.508 +            __ neg();
  29.509 +        break;
  29.510 +      }
  29.511 +
  29.512 +      case TOK_NOT:
  29.513 +      {
  29.514 +        Local<Type> type(zone_, node->expression()->type());
  29.515 +        node->expression()->accept(this);
  29.516 +        
  29.517 +        if (out->isFloat())
  29.518 +            __ not_f();
  29.519 +        else
  29.520 +            __ not_();
  29.521 +        break;
  29.522 +      }
  29.523 +
  29.524 +      case TOK_LABEL:
  29.525 +      {
  29.526 +        Local<Type> from(zone_, node->expression()->type());
  29.527 +
  29.528 +        node->expression()->accept(this);
  29.529 +        if (!from->isFloat() && out->isFloat())
  29.530 +            __ bits_f2i();
  29.531 +        else if (from->isFloat() && !out->isFloat())
  29.532 +            __ bits_i2f();
  29.533 +        break;
  29.534 +      }
  29.535 +
  29.536 +      case TOK_SIZEOF:
  29.537 +      {
  29.538 +        Local<Type> type(zone_, node->expression()->type());
  29.539 +        if (type->isFixedLength()) {
  29.540 +            __ int_(type->fixedLength());
  29.541 +        } else {
  29.542 +            node->expression()->accept(this);
  29.543 +            __ sizeof_();
  29.544 +        }
  29.545 +        break;
  29.546 +      }
  29.547 +
  29.548 +      default:
  29.549 +        assert(node->token() == TOK_TILDE);
  29.550 +        node->expression()->accept(this);
  29.551 +        __ bitnot();
  29.552 +        break;
  29.553 +    }
  29.554 +}
  29.555 +
  29.556 +void
  29.557 +BytecodeCompiler::visit(BinaryExpression *node)
  29.558 +{
  29.559 +    if (node->token() == TOK_AND || node->token() == TOK_OR) {
  29.560 +        Label success, failure, done;
  29.561 +        visitForTest(node, &success, &failure, &success);
  29.562 +        __ bind(&success);
  29.563 +        __ int_(1);
  29.564 +        __ drop(1);         // Otherwise, the stack depth will be +1 too much.
  29.565 +        __ jump(&done);
  29.566 +        __ bind(&failure);
  29.567 +        __ int_(0);
  29.568 +        __ bind(&done);
  29.569 +        return;
  29.570 +    }
  29.571 +
  29.572 +    Local<Type> leftType(zone_, node->left()->type());
  29.573 +    Local<Type> rightType(zone_, node->right()->type());
  29.574 +    Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
  29.575 +
  29.576 +    visitForALU(coerce, node->left());
  29.577 +    visitForALU(coerce, node->right());
  29.578 +
  29.579 +    Opcode op = TokenToOpcode(node->token());
  29.580 +    if (node->type()->isFloat())
  29.581 +        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
  29.582 +
  29.583 +    __ note_position(node->pos());
  29.584 +    __ binary(op);
  29.585 +}
  29.586 +
  29.587 +void
  29.588 +BytecodeCompiler::visit(IndexExpression *node)
  29.589 +{
  29.590 +    node->left()->accept(this);
  29.591 +    node->right()->accept(this);
  29.592 +    __ note_position(node->pos());
  29.593 +    __ getelem(node->type());
  29.594 +}
  29.595 +
  29.596 +void
  29.597 +BytecodeCompiler::visit(FieldExpression *node)
  29.598 +{
  29.599 +    node->left()->accept(this);
  29.600 +    __ getfield(node->fieldIndex(), node->type());
  29.601 +}
  29.602 +
  29.603 +void
  29.604 +BytecodeCompiler::visit(ReturnStatement *node)
  29.605 +{
  29.606 +    if (node->expression()) {
  29.607 +        node->expression()->accept(this);
  29.608 +        __ return_();
  29.609 +    } else {
  29.610 +        __ returnvoid();
  29.611 +    }
  29.612 +}
  29.613 +
  29.614 +void
  29.615 +BytecodeCompiler::visitForTest(Expression *expression,
  29.616 +                               Label *trueBranch,
  29.617 +                               Label *falseBranch,
  29.618 +                               Label *fallthrough)
  29.619 +{
  29.620 +    TokenKind token = ToCompare(expression);
  29.621 +    if (token == TOK_EOF || token == TOK_NOT) {
  29.622 +        if (token == TOK_EOF)
  29.623 +            expression->accept(this);
  29.624 +        else
  29.625 +            expression->toUnaryExpression()->expression()->accept(this);
  29.626 +        
  29.627 +        bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
  29.628 +
  29.629 +        Opcode op = jumpOnTrue ? OP_JT : OP_JF;
  29.630 +        if (expression->type()->isFloat())
  29.631 +            op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
  29.632 +
  29.633 +        if (fallthrough == falseBranch)
  29.634 +            __ j(op, trueBranch);
  29.635 +        else
  29.636 +            __ j(op, falseBranch); 
  29.637 +        return;
  29.638 +    }
  29.639 +
  29.640 +    BinaryExpression *binary = expression->toBinaryExpression();
  29.641 +
  29.642 +    if (token == TOK_AND || token == TOK_OR) {
  29.643 +        Label next;
  29.644 +        if (token == TOK_AND)
  29.645 +            visitForTest(binary->left(), &next, falseBranch, &next);
  29.646 +        else
  29.647 +            visitForTest(binary->left(), trueBranch, &next, &next);
  29.648 +        __ bind(&next);
  29.649 +        visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
  29.650 +        return;
  29.651 +    }
  29.652 +
  29.653 +    Opcode op = CompareTokenToJump(token);
  29.654 +    if (fallthrough == trueBranch)
  29.655 +        op = Invert(op);
  29.656 +
  29.657 +    Local<Type> leftType(zone_, binary->left()->type());
  29.658 +    Local<Type> rightType(zone_, binary->right()->type());
  29.659 +    Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
  29.660 +
  29.661 +    visitForALU(coerce, binary->left());
  29.662 +    visitForALU(coerce, binary->right());
  29.663 +    if (coerce->isFloat())
  29.664 +        op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
  29.665 +
  29.666 +    if (fallthrough == trueBranch)
  29.667 +        __ j(op, falseBranch);
  29.668 +    else
  29.669 +        __ j(op, trueBranch);
  29.670 +}
  29.671 +
  29.672 +void
  29.673 +BytecodeCompiler::visit(ForStatement *node)
  29.674 +{
  29.675 +    AutoEnterScope forScope(this, node->scope());
  29.676 +
  29.677 +    recordLifoSlot(node->scope());
  29.678 +
  29.679 +    Label join, update;
  29.680 +    LoopScope loop(scope_, &join, &update, &loop_);
  29.681 +
  29.682 +    if (node->initialization())
  29.683 +        node->initialization()->accept(this);
  29.684 +
  29.685 +    Label header, test;
  29.686 +    if (node->condition())
  29.687 +        __ jump(&test);
  29.688 +
  29.689 +    __ bind(&header);
  29.690 +    node->body()->accept(this);
  29.691 +
  29.692 +    __ bind(&update);
  29.693 +    if (node->update())
  29.694 +        node->update()->accept(this);
  29.695 +
  29.696 +    if (node->condition()) {
  29.697 +        __ bind(&test);
  29.698 +        visitForTest(node->condition(), &header, &join, &join);
  29.699 +    } else {
  29.700 +        __ jump(&header);
  29.701 +    }
  29.702 +
  29.703 +    __ bind(&join);
  29.704 +
  29.705 +    if (node->scope())
  29.706 +        unwindTo(node->scope()->enclosing());
  29.707 +    assert(__ stackDepth() == 0);
  29.708 +}
  29.709 +
  29.710 +void
  29.711 +BytecodeCompiler::visit(WhileStatement *node)
  29.712 +{
  29.713 +    Label header, join;
  29.714 +
  29.715 +    __ bind(&header);
  29.716 +
  29.717 +    LoopScope loop(scope_, &join, &header, &loop_);
  29.718 +
  29.719 +    if (node->token() == TOK_WHILE) {
  29.720 +        Label body;
  29.721 +
  29.722 +        visitForTest(node->condition(), &body, &join, &body);
  29.723 +        __ bind(&body);
  29.724 +        node->body()->accept(this);
  29.725 +        __ jump(&header);
  29.726 +    } else {
  29.727 +        node->body()->accept(this);
  29.728 +        visitForTest(node->condition(), &header, &join, &join);
  29.729 +    }
  29.730 +
  29.731 +    __ bind(&join);
  29.732 +}
  29.733 +
  29.734 +void
  29.735 +BytecodeCompiler::visit(BreakStatement *node)
  29.736 +{
  29.737 +    unwindTo(loop_->scope());
  29.738 +    __ jump(loop_->break_());
  29.739 +}
  29.740 +
  29.741 +void
  29.742 +BytecodeCompiler::visit(ContinueStatement *node)
  29.743 +{
  29.744 +    unwindTo(loop_->scope());
  29.745 +    __ jump(loop_->continue_());
  29.746 +}
  29.747 +
  29.748 +void
  29.749 +BytecodeCompiler::visit(BlockStatement *node)
  29.750 +{
  29.751 +    AutoEnterScope blockScope(this, node->scope());
  29.752 +
  29.753 +    recordLifoSlot(node->scope());
  29.754 +
  29.755 +    for (size_t i = 0; i < node->statements()->length(); i++) {
  29.756 +        Statement *statement = node->statements()->at(i);
  29.757 +        statement->accept(this);
  29.758 +        assert(__ stackDepth() == 0);
  29.759 +    }
  29.760 +
  29.761 +    // We don't bother emitting an "unwind" instruction for function scopes,
  29.762 +    // since this is taken care of by the calling convention.
  29.763 +    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
  29.764 +        unwindTo(node->scope()->enclosing());
  29.765 +}
  29.766 +
  29.767 +void
  29.768 +BytecodeCompiler::visit(IntegerLiteral *node)
  29.769 +{
  29.770 +    __ int_(node->value());
  29.771 +}
  29.772 +
  29.773 +void
  29.774 +BytecodeCompiler::visit(BooleanLiteral *node)
  29.775 +{
  29.776 +    if (node->token() == TOK_TRUE)
  29.777 +        __ true_();
  29.778 +    else
  29.779 +        __ false_();
  29.780 +}
  29.781 +
  29.782 +void
  29.783 +BytecodeCompiler::visit(FloatLiteral *node)
  29.784 +{
  29.785 +    __ float_((float)node->value());
  29.786 +}
  29.787 +
  29.788 +void
  29.789 +BytecodeCompiler::visit(StringLiteral *node)
  29.790 +{
  29.791 +    Local<Array> array(zone_, StringLiteralToArray(zone_, node));
  29.792 +    if (!array)
  29.793 +        return;
  29.794 +
  29.795 +    __ note_position(node->pos());
  29.796 +    __ object(array);
  29.797 +}
  29.798 +
  29.799 +void
  29.800 +BytecodeCompiler::getEnvSlot(Variable *var)
  29.801 +{
  29.802 +    assert(var->scope()->kind() == Scope::GLOBAL);
  29.803 +    __ getglobal(var);
  29.804 +}
  29.805 +
  29.806 +void
  29.807 +BytecodeCompiler::setEnvSlot(Variable *var)
  29.808 +{
  29.809 +    assert(var->scope()->kind() == Scope::GLOBAL);
  29.810 +    __ setglobal(var);
  29.811 +}
  29.812 +
  29.813 +static bool
  29.814 +FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
  29.815 +{
  29.816 +    Local<Array> string(zone);
  29.817 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
  29.818 +        Expression *expr = literal->expressions()->at(i);
  29.819 +        StringLiteral *lit = expr->toStringLiteral();
  29.820 +        if ((string = StringLiteralToArray(zone, lit)) == NULL)
  29.821 +            return false;
  29.822 +
  29.823 +        array->writeObject(zone, i, string);
  29.824 +
  29.825 +        if (string->length() > *maxsize)
  29.826 +            *maxsize = string->length();
  29.827 +
  29.828 +        assert(!array->type()->contained()->isFixedLength() ||
  29.829 +                array->type()->contained()->fixedLength() >= string->length());
  29.830 +    }
  29.831 +
  29.832 +    return true;
  29.833 +}
  29.834 +
  29.835 +static bool
  29.836 +FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
  29.837 +{
  29.838 +    assert(array->type()->fixedLength() == literal->expressions()->length());
  29.839 +
  29.840 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
  29.841 +        Expression *expr = literal->expressions()->at(i);
  29.842 +        if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
  29.843 +            array->writeInt32(i, lit->value());
  29.844 +            continue;
  29.845 +        }
  29.846 +        if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
  29.847 +            if (lit->token() == TOK_TRUE)
  29.848 +                array->writeInt32(i, 1);
  29.849 +            else
  29.850 +                array->writeInt32(i, 0);
  29.851 +            continue;
  29.852 +        }
  29.853 +        if (FloatLiteral *lit = expr->asFloatLiteral()) {
  29.854 +            array->writeFloat(i, (float)lit->value());
  29.855 +            continue;
  29.856 +        }
  29.857 +
  29.858 +        // Unrecognized literal type.
  29.859 +        assert(false);
  29.860 +    }
  29.861 +
  29.862 +    return true;
  29.863 +}
  29.864 +
  29.865 +static bool
  29.866 +TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
  29.867 +                     unsigned *maxsize)
  29.868 +{
  29.869 +    assert(type->fixedLength() == literal->expressions()->length());
  29.870 +
  29.871 +    Local<Type> contained(zone, type->contained());
  29.872 +    if (contained->isCharArray())
  29.873 +        return FillArrayLiteral_String(zone, array, literal, maxsize);
  29.874 +
  29.875 +    if (!contained->isArray())
  29.876 +        return FillArrayLiteral_Primitive(zone, array, literal);
  29.877 +
  29.878 +    Local<Array> subarray(zone);
  29.879 +    for (size_t i = 0; i < literal->expressions()->length(); i++) {
  29.880 +        Expression *expr = literal->expressions()->at(i);
  29.881 +        subarray = Array::cast(array->readObject(i));
  29.882 +        if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
  29.883 +            return false;
  29.884 +    }
  29.885 +
  29.886 +    return true;
  29.887 +}
  29.888 +
  29.889 +static Array *
  29.890 +BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
  29.891 +{
  29.892 +    Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
  29.893 +    if (!root)
  29.894 +        return NULL;
  29.895 +
  29.896 +    // This should have allocated everything in the array, so all we need to
  29.897 +    // do is traverse down to the lowest levels and copy things.
  29.898 +    Local<Type> type(zone, map->type());
  29.899 +    if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
  29.900 +        return NULL;
  29.901 +
  29.902 +    return root;
  29.903 +}
  29.904 +
  29.905 +static inline bool
  29.906 +ArrayContainsCharBuffers(Type *type)
  29.907 +{
  29.908 +    if (type->contained()->isArray())
  29.909 +        return ArrayContainsCharBuffers(type->contained());
  29.910 +    return type->isCharArray();
  29.911 +}
  29.912 +
  29.913 +void
  29.914 +BytecodeCompiler::visit(VariableDeclaration *node)
  29.915 +{
  29.916 +    Variable *var = node->variable();
  29.917 +    
  29.918 +    Local<Type> type(zone_, var->type());
  29.919 +    if (type->isArray()) {
  29.920 +        Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
  29.921 +        __ note_position(node->pos());
  29.922 +
  29.923 +        Local<Type> right(zone_);
  29.924 +        if (node->initialization())
  29.925 +            right = node->initialization()->type();
  29.926 +
  29.927 +        // There are a few methods for allocating, here:
  29.928 +        // (1) If the array is fixed,
  29.929 +        //    (a) Initializer not present,
  29.930 +        //              NEWFIXED
  29.931 +        //    (b) Left is const non-string:
  29.932 +        //              <nothing>
  29.933 +        //    (b) Otherwise:
  29.934 +        //              NEWFIXED
  29.935 +        //              COPYARRAY
  29.936 +        // (2) If the array is not fixed,
  29.937 +        //    (a) Initializer is not present,
  29.938 +        //              NEWEMPTY
  29.939 +        //    (b) Initializer is not a string literal,
  29.940 +        //        or left is const:
  29.941 +        //              <nothing>
  29.942 +        //    (c) Initializer is a string literal,
  29.943 +        //              NEWSIZED
  29.944 +        //              COPYARRAY
  29.945 +        //
  29.946 +
  29.947 +        Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
  29.948 +                              ? Heap::Tenure_Old
  29.949 +                              : Heap::Tenure_Default;
  29.950 +
  29.951 +        if (Expression *init = node->initialization()) {
  29.952 +            if (init->isArrayLiteral()) {
  29.953 +                unsigned maxsize = 0;
  29.954 +                Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
  29.955 +                if (!array)
  29.956 +                    return;
  29.957 +
  29.958 +                assert(type->isFixedLength());
  29.959 +
  29.960 +                if (type->isConst()) {
  29.961 +                    __ object(array);
  29.962 +                } else if (ArrayContainsCharBuffers(type)) {
  29.963 +                    // This array contains mutable char buffers, so
  29.964 +                    // unfortunately this gets a little more complicated. We
  29.965 +                    // compute the maximum size needed for the innermost
  29.966 +                    // string, which is similar to SP1. This means we can use
  29.967 +                    // CopyArray rather than individually emit opcodes to clone
  29.968 +                    // every string.
  29.969 +                    Local<Type> child(zone_, type);
  29.970 +                    for (size_t i = 0; i < type->levels() - 1; i++) {
  29.971 +                        __ int_(child->fixedLength());
  29.972 +                        child = child->contained();
  29.973 +                    }
  29.974 +                    __ int_(maxsize);
  29.975 +                    __ newarray(OP_NEWSIZED, map, tenure);
  29.976 +                    __ object(array);
  29.977 +                    __ copyarray();
  29.978 +                } else {
  29.979 +                    __ newarray(OP_NEWFIXED, map, tenure);
  29.980 +                    __ object(array);
  29.981 +                    __ copyarray();
  29.982 +                }
  29.983 +            } else if (type->isFixedLength()) {
  29.984 +                // Note in the case of:
  29.985 +                // const String:buffer[50] = "hello";
  29.986 +                //
  29.987 +                // We want to preserve sizeof(buffer) == 50.
  29.988 +                if (type->isConst() && !type->isCharArray()) {
  29.989 +                    init->accept(this);
  29.990 +                } else {
  29.991 +                    __ newarray(OP_NEWFIXED, map, tenure);
  29.992 +                    init->accept(this);
  29.993 +                    __ copyarray();
  29.994 +                }
  29.995 +            } else if (!type->isConst() && init->isStringLiteral()) {
  29.996 +                // This is a degenerate case of ArrayLiteral.
  29.997 +                __ int_(right->fixedLength());
  29.998 +                __ newarray(OP_NEWSIZED, map, tenure);
  29.999 +                init->accept(this);
 29.1000 +                __ copyarray();
 29.1001 +            } else if (type->isConst()) {
 29.1002 +                init->accept(this);
 29.1003 +            }
 29.1004 +        } else if (type->isFixedLength()) {
 29.1005 +            __ newarray(OP_NEWFIXED, map, tenure);
 29.1006 +        } else {
 29.1007 +#if 0
 29.1008 +            if (node->postDimensions()) {
 29.1009 +                for (size_t i = 0; i < node->postDimensions()->length(); i++) {
 29.1010 +                    Expression *expr = node->postDimensions()->at(i);
 29.1011 +                    if (expr)
 29.1012 +                        expr->accept(this);
 29.1013 +                    else
 29.1014 +                        __ int_(0);
 29.1015 +                }
 29.1016 +                __ newarray(OP_NEWSIZED, map, tenure);
 29.1017 +            } else {
 29.1018 +                __ newarray(OP_NEWEMPTY, map, tenure);
 29.1019 +            }
 29.1020 +#endif
 29.1021 +        }
 29.1022 +    } else if (type->isStruct()) {
 29.1023 +        Local<StructMap> map(zone_, StructMap::cast(type->newMap()));
 29.1024 +
 29.1025 +        // Because structs can contain arrays, any sort of composition
 29.1026 +        // triggers non-LIFO allocation. This is just for correctness.
 29.1027 +        // We could do better by:
 29.1028 +        //  (1) Limiting to structs that just (recursively) contain arrays,
 29.1029 +        //  (2) Swap Stack for Default tenure in Struct::New
 29.1030 +        //  (3) JIT analysis
 29.1031 +        if (var->scope()->kind() == Scope::GLOBAL)
 29.1032 +            __ newstruct(map, Heap::Tenure_Old);
 29.1033 +        else if (var->needsHeapAllocation() || map->composed())
 29.1034 +            __ newstruct(map, Heap::Tenure_Default);
 29.1035 +        else
 29.1036 +            __ newstruct(map, Heap::Tenure_Stack);
 29.1037 +    } else {
 29.1038 +        if (node->initialization()) {
 29.1039 +            node->initialization()->accept(this);
 29.1040 +        } else {
 29.1041 +            if (type->isInt32OrEnum() || type->isBool()) {
 29.1042 +                __ int_(0);
 29.1043 +            } else {
 29.1044 +                assert(type->isFloat());
 29.1045 +                __ float_(0);
 29.1046 +            }
 29.1047 +        }
 29.1048 +    }
 29.1049 +
 29.1050 +    if (var->location() == Variable::STACK) {
 29.1051 +        __ setlocal(var);
 29.1052 +        locals_->set(zone_, var->slot(), var->type());
 29.1053 +    } else {
 29.1054 +        assert(var->location() == Variable::ENVIRONMENT);
 29.1055 +        setEnvSlot(var);
 29.1056 +    }
 29.1057 +
 29.1058 +    __ pop();
 29.1059 +}
 29.1060 +
 29.1061 +void
 29.1062 +BytecodeCompiler::visit(CallExpression *node)
 29.1063 +{
 29.1064 +#if 0
 29.1065 +    Local<Type> funType(zone_, node->callee()->type());
 29.1066 +
 29.1067 +    // Sniff out natives, which have a specific opcode and are guaranteed to
 29.1068 +    // be called via name proxy.
 29.1069 +    NamedFunction *native = NULL;
 29.1070 +    if (funType->isNative())
 29.1071 +        native = node->callee()->toNameProxy()->binding()->toNamedFunction();
 29.1072 +
 29.1073 +    Local<Type> given(zone_);
 29.1074 +    for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
 29.1075 +        Expression *arg = node->arguments()->at(i);
 29.1076 +
 29.1077 +        given = arg->type();
 29.1078 +
 29.1079 +        // We need to compute a reference if the parameter was in the form:
 29.1080 +        //  f(&a)
 29.1081 +        // Note this form does not allow: f({})
 29.1082 +        // 
 29.1083 +        // We also need to compute references for all variadic native
 29.1084 +        // arguments, but arrays and references are already in the
 29.1085 +        // appropriate form.
 29.1086 +        bool mustPushReference = false;
 29.1087 +        if (i >= funType->parameters()->length()) {
 29.1088 +            assert(funType->isNative() && funType->isNativeVariadic());
 29.1089 +            mustPushReference = !given->isArray() && !given->isReference();
 29.1090 +        } else if (funType->parameterAt(i)->isReference()) {
 29.1091 +            mustPushReference = !given->isReference();
 29.1092 +        }
 29.1093 +
 29.1094 +        // If a native is passed to a native, it must only be one level deep.
 29.1095 +        assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
 29.1096 +
 29.1097 +        if (mustPushReference) {
 29.1098 +            if (arg->isNameProxy()) {
 29.1099 +                // :TODO: test with functions and globals
 29.1100 +                // Compute a reference to the name.
 29.1101 +                Variable *var = arg->toNameProxy()->binding()->toVariable();
 29.1102 +                __ note_position(node->pos());
 29.1103 +                __ newref(var);
 29.1104 +            } else if (arg->isFieldExpression()) {
 29.1105 +                FieldExpression *expr = arg->toFieldExpression();
 29.1106 +                expr->left()->accept(this);
 29.1107 +                __ note_position(expr->pos());
 29.1108 +                __ fieldref_lifo(expr->fieldIndex());
 29.1109 +            } else {
 29.1110 +                // We don't know how to, or can't, build a direct reference to
 29.1111 +                // this type. Make an indirect one, by taking the top of the
 29.1112 +                // stack and boxing it up.
 29.1113 +                arg->accept(this);
 29.1114 +                __ note_position(node->pos());
 29.1115 +                __ slotref_lifo();
 29.1116 +            }
 29.1117 +        } else {
 29.1118 +            arg->accept(this);
 29.1119 +        }
 29.1120 +    }
 29.1121 +
 29.1122 +    unsigned argc = node->arguments()->length();
 29.1123 +
 29.1124 +    // If there are missing arguments, then we're not done and have to push
 29.1125 +    // default parameters.
 29.1126 +    Local<Box> box(zone_);
 29.1127 +    Local<Array> array(zone_);
 29.1128 +    Local<ArrayMap> map(zone_);
 29.1129 +    for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
 29.1130 +        box = Box::cast(funType->defaults()->at(i));
 29.1131 +
 29.1132 +        if (box->type()->isPod()) {
 29.1133 +            if (box->type()->pod() == PrimitiveType_Int32)
 29.1134 +                __ int_(box->toInt32());
 29.1135 +            else if (box->type()->pod() == PrimitiveType_Float)
 29.1136 +                __ float_(box->toFloat());
 29.1137 +            else
 29.1138 +                assert(false);
 29.1139 +
 29.1140 +            if (funType->parameterAt(i)->isReference()) {
 29.1141 +                __ note_position(node->pos());
 29.1142 +                __ slotref_lifo();
 29.1143 +            }
 29.1144 +        } else {
 29.1145 +            assert(box->type()->isArray());
 29.1146 +
 29.1147 +            array = Array::cast(box->toObject());
 29.1148 +            if (funType->parameterAt(i)->isConst()) {
 29.1149 +                __ object(array);
 29.1150 +            } else {
 29.1151 +                // We need to copy the array since it's mutable. Note that
 29.1152 +                // although COPYARRAY returns its left-hand side, this may
 29.1153 +                // change in the future, we do the same thing and dupe the
 29.1154 +                // newly allocated array.
 29.1155 +                map = ArrayMap::cast(array->map());
 29.1156 +                
 29.1157 +                // Natives cannot escape array references, so we can allocate
 29.1158 +                // them on the LIFO stack.
 29.1159 +                if (funType->isNative())
 29.1160 +                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack);
 29.1161 +                else
 29.1162 +                    __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default);
 29.1163 +                __ dup();
 29.1164 +                __ object(array);
 29.1165 +                __ copyarray();
 29.1166 +                __ pop();
 29.1167 +            }
 29.1168 +        }
 29.1169 +
 29.1170 +        argc++;
 29.1171 +    }
 29.1172 +
 29.1173 +    __ note_position(node->pos());
 29.1174 +    if (native) {
 29.1175 +        __ callnative(native->slot(), argc);
 29.1176 +        __ drop(argc);
 29.1177 +    } else {
 29.1178 +        node->callee()->accept(this);
 29.1179 +        __ call(funType);
 29.1180 +        __ drop(argc + 1);
 29.1181 +    }
 29.1182 +#endif
 29.1183 +}
 29.1184 +
 29.1185 +void
 29.1186 +BytecodeCompiler::visit(TernaryExpression *node)
 29.1187 +{
 29.1188 +    Label success, failure, join;
 29.1189 +
 29.1190 +    visitForTest(node->condition(), &success, &failure, &success);
 29.1191 +    __ bind(&success);
 29.1192 +    node->left()->accept(this);
 29.1193 +    __ drop(1);
 29.1194 +    __ jump(&join);
 29.1195 +    __ bind(&failure);
 29.1196 +    node->right()->accept(this);
 29.1197 +    __ bind(&join);
 29.1198 +}
 29.1199 +
 29.1200 +void
 29.1201 +BytecodeCompiler::visit(IfStatement *node)
 29.1202 +{
 29.1203 +    Label join;
 29.1204 +    if (!node->ifFalse()) {
 29.1205 +        Label success;
 29.1206 +
 29.1207 +        visitForTest(node->condition(), &success, &join, &success);
 29.1208 +        __ bind(&success);
 29.1209 +        node->ifTrue()->accept(this);
 29.1210 +    } else {
 29.1211 +        Label success, next;
 29.1212 +
 29.1213 +        visitForTest(node->condition(), &success, &next, &success);
 29.1214 +        __ bind(&success);
 29.1215 +        node->ifTrue()->accept(this);
 29.1216 +        __ jump(&join);
 29.1217 +        __ bind(&next);
 29.1218 +        node->ifFalse()->accept(this);
 29.1219 +    }
 29.1220 +
 29.1221 +    __ bind(&join);
 29.1222 +}
 29.1223 +
 29.1224 +bool
 29.1225 +BytecodeCompiler::tableswitch(SwitchStatement *node)
 29.1226 +{
 29.1227 +    CaseValueList *values = node->caseValueList();
 29.1228 +
 29.1229 +    if (values->length() < 3)
 29.1230 +        return false;
 29.1231 +
 29.1232 +    // Find the delta between the largest and smallest value.
 29.1233 +    int hi = values->at(values->length() - 1).box.toInt();
 29.1234 +    int lo = values->at(0).box.toInt();
 29.1235 +    assert(hi > lo);
 29.1236 +
 29.1237 +    unsigned tablesize = TableSwitchEntries(lo, hi);
 29.1238 +    if (tablesize > MAX_TABLESWITCH_ENTRIES)
 29.1239 +        return false;
 29.1240 +
 29.1241 +    Label def, join;
 29.1242 +
 29.1243 +    // Create the list of labels that each statement will bind to.
 29.1244 +    Label *labels = new Label[node->cases()->length()];
 29.1245 +
 29.1246 +    // Create the table of labels we'll use for each case.
 29.1247 +    Label **table = new Label *[tablesize];
 29.1248 +
 29.1249 +    // Link all cases, by default, to the default label.
 29.1250 +    for (size_t i = 0; i < tablesize; i++)
 29.1251 +        table[i] = &def;
 29.1252 +
 29.1253 +    // Now patch actual cases to their correct labels.
 29.1254 +    for (size_t i = 0; i < values->length(); i++) {
 29.1255 +        CaseValue &v = values->at(i);
 29.1256 +        assert(v.statement < node->cases()->length());
 29.1257 +
 29.1258 +        unsigned index = unsigned(v.box.toInt() - lo);
 29.1259 +        assert(index < tablesize);
 29.1260 +
 29.1261 +        table[index] = &labels[v.statement];
 29.1262 +    }
 29.1263 +
 29.1264 +    // Emit the tableswitch opcode and the jump table.
 29.1265 +    __ tableswitch(lo, hi, &def, table);
 29.1266 +
 29.1267 +    // We're done with the jump table now.
 29.1268 +    delete [] table;
 29.1269 +
 29.1270 +    // Emit each statement.
 29.1271 +    for (size_t i = 0; i < node->cases()->length(); i++) {
 29.1272 +        Statement *stmt = node->cases()->at(i)->statement();
 29.1273 +
 29.1274 +        __ bind(&labels[i]);
 29.1275 +        stmt->accept(this);
 29.1276 +        __ jump(&join);
 29.1277 +    }
 29.1278 +
 29.1279 +    // We're done with the statement labels.
 29.1280 +    delete [] labels;
 29.1281 +
 29.1282 +    // Emit the default case.
 29.1283 +    __ bind(&def);
 29.1284 +    if (node->defaultCase())
 29.1285 +        node->defaultCase()->accept(this);
 29.1286 +
 29.1287 +    __ bind(&join);
 29.1288 +
 29.1289 +    return true;
 29.1290 +}
 29.1291 +
 29.1292 +void
 29.1293 +BytecodeCompiler::visit(SwitchStatement *node)
 29.1294 +{
 29.1295 +    node->expression()->accept(this);
 29.1296 +
 29.1297 +    if (tableswitch(node))
 29.1298 +        return;
 29.1299 +
 29.1300 +    Label join;
 29.1301 +
 29.1302 +    for (size_t i = 0; i < node->cases()->length(); i++) {
 29.1303 +        Case *c = node->cases()->at(i);
 29.1304 +
 29.1305 +        Label success, fail;
 29.1306 +        if (c->others()) {
 29.1307 +            for (size_t j = 0; j < c->others()->length(); j++) {
 29.1308 +                Expression *expr = c->others()->at(j);
 29.1309 +
 29.1310 +                __ dup();
 29.1311 +                expr->accept(this);
 29.1312 +                __ j(OP_JEQ, &success);
 29.1313 +            }
 29.1314 +        }
 29.1315 +
 29.1316 +        // The final test.
 29.1317 +        __ dup();
 29.1318 +        c->expression()->accept(this);
 29.1319 +        __ j(OP_JNE, &fail);
 29.1320 +        __ bind(&success);
 29.1321 +        c->statement()->accept(this);
 29.1322 +        __ jump(&join);
 29.1323 +        __ bind(&fail);
 29.1324 +    }
 29.1325 +
 29.1326 +    if (node->defaultCase())
 29.1327 +        node->defaultCase()->accept(this);
 29.1328 +
 29.1329 +    __ pop();
 29.1330 +    __ bind(&join);
 29.1331 +}
 29.1332 +
 29.1333 +void
 29.1334 +BytecodeCompiler::visit(FunctionStatement *node)
 29.1335 +{
 29.1336 +    if (!node->fun()->used())
 29.1337 +        return;
 29.1338 +
 29.1339 +    if (node->fun()->isNative()) {
 29.1340 +        assert(!moduleData_->natives->at(node->fun()->slot()));
 29.1341 +
 29.1342 +        Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
 29.1343 +        Local<String> name(zone_, node->fun()->name());
 29.1344 +        Local<Native> native(zone_, Native::New(zone_, type, name));
 29.1345 +        if (!native)
 29.1346 +            return;
 29.1347 +
 29.1348 +        moduleData_->natives->set(zone_, node->fun()->slot(), native);
 29.1349 +        return;
 29.1350 +    }
 29.1351 +
 29.1352 +    // If the function has no body, then it's just a declaration.
 29.1353 +    if (!node->body()) {
 29.1354 +        assert(node->fun()->isForward() || node->fun()->isPublic());
 29.1355 +        return;
 29.1356 +    }
 29.1357 +
 29.1358 +    BytecodeCompiler child(zone_, tree_, moduleData_);
 29.1359 +    Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
 29.1360 +    if (!fun)
 29.1361 +        return;
 29.1362 +    
 29.1363 +    assert(!moduleData_->module->getFunction(node->fun()->slot()));
 29.1364 +    moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
 29.1365 +}
 29.1366 +
 29.1367 +void
 29.1368 +BytecodeCompiler::visit(FunctionTypeStatement *node)
 29.1369 +{
 29.1370 +}
 29.1371 +
 29.1372 +void
 29.1373 +BytecodeCompiler::visit(EnumStatement *node)
 29.1374 +{
 29.1375 +}
 29.1376 +
 29.1377 +void
 29.1378 +BytecodeCompiler::visit(StructureStatement *node)
 29.1379 +{
 29.1380 +}
 29.1381 +
 29.1382 +void
 29.1383 +BytecodeCompiler::visit(ArrayLiteral *node)
 29.1384 +{
 29.1385 +    // We shouldn't reach these; they're handled manually when initializing
 29.1386 +    // declared arrays.
 29.1387 +    assert(false);
 29.1388 +}
 29.1389 +
 29.1390 +void
 29.1391 +BytecodeCompiler::visit(ImportStatement *node)
 29.1392 +{
 29.1393 +}
 29.1394 +
 29.1395 +Code *
 29.1396 +BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
 29.1397 +{
 29.1398 +    // STOP doubles as RETURNVOID.
 29.1399 +    __ stop();
 29.1400 +
 29.1401 +    if (__ oom() || zone_->hasPendingException())
 29.1402 +        return NULL;
 29.1403 +
 29.1404 +    Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
 29.1405 +    if (!bytes)
 29.1406 +        return NULL;
 29.1407 +    memcpy(bytes->raw(), __ buffer(), __ length());
 29.1408 +
 29.1409 +    for (size_t i = 0; i < scope->maxContainedLocals(); i++)
 29.1410 +        assert(locals_->at(i));
 29.1411 +
 29.1412 +    Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
 29.1413 +    if (!objects)
 29.1414 +        return NULL;
 29.1415 +
 29.1416 +    for (size_t i = 0; i < __ objects()->length(); i++)
 29.1417 +        objects->set(zone_, i, *(__ objects()->at(i)));
 29.1418 +
 29.1419 +    Local<ByteArray> safepoints(zone_);
 29.1420 +
 29.1421 +    // If any stack slots hold gc pointers at potential failure points in the
 29.1422 +    // bytecode, record them now. We do this by building a list of tuples;
 29.1423 +    // each tuple contains the pc offset, and a bitset containing which stack
 29.1424 +    // slots must be scanned by the gc.
 29.1425 +    if (__ oopRecords()->length()) {
 29.1426 +        size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
 29.1427 +        size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
 29.1428 +        safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
 29.1429 +        if (!safepoints)
 29.1430 +            return NULL;
 29.1431 +
 29.1432 +        Address cursor = safepoints->raw();
 29.1433 +        for (size_t i = 0; i < __ oopRecords()->length(); i++) {
 29.1434 +            OopRecord *record = __ oopRecords()->at(i);
 29.1435 +            assert(record->depth <= __ maxStackDepth());
 29.1436 +
 29.1437 +            *reinterpret_cast<unsigned *>(cursor) = record->offset;
 29.1438 +
 29.1439 +            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
 29.1440 +            for (unsigned i = 0; i < record->depth; i++)
 29.1441 +                bits[i / 8] |= (1 << (i % 8));
 29.1442 +
 29.1443 +            cursor += bytesPerSafepoint;
 29.1444 +        }
 29.1445 +
 29.1446 +        assert(cursor == safepoints->raw() + gcmapSize);
 29.1447 +    }
 29.1448 +
 29.1449 +    Local<ByteArray> sourcemap(zone_);
 29.1450 +    if (__ sourcemapLength()) {
 29.1451 +        sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
 29.1452 +        if (!sourcemap)
 29.1453 +            return NULL;
 29.1454 +
 29.1455 +        memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
 29.1456 +    }
 29.1457 +
 29.1458 +    Local<Code> code(zone_);
 29.1459 +
 29.1460 +    code = Code::New(zone_,
 29.1461 +                     bytes,
 29.1462 +                     locals_,
 29.1463 +                     objects,
 29.1464 +                     __ maxStackDepth(),
 29.1465 +                     moduleData_->module,
 29.1466 +                     safepoints,
 29.1467 +                     sourcemap,
 29.1468 +                     lineno);
 29.1469 +    return code;
 29.1470 +}
 29.1471 +
 29.1472 +Function *
 29.1473 +BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
 29.1474 +{
 29.1475 +    // Note: No need to record a life slot here, since it's part of the Frame.
 29.1476 +    AutoEnterScope functionScope(this, node->scope());
 29.1477 +
 29.1478 +    // Set the initial line, because line mappings are deltas.
 29.1479 +    __ setFirstLine(node->pos().line);
 29.1480 +    locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
 29.1481 +
 29.1482 +    node->body()->accept(this);
 29.1483 +
 29.1484 +    unsigned nargs = node->scope()->numArguments();
 29.1485 +    Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
 29.1486 +    if (!args)
 29.1487 +        return NULL;
 29.1488 +
 29.1489 +    for (size_t i = 0; i < node->scope()->numArguments(); i++)
 29.1490 +        args->set(zone_, i, node->scope()->getArgument(i)->type());
 29.1491 +
 29.1492 +
 29.1493 +    Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
 29.1494 +    if (!code)
 29.1495 +        return NULL;
 29.1496 +
 29.1497 +    Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
 29.1498 +    Local<String> name(zone_, node->fun()->name());
 29.1499 +    Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
 29.1500 +    if (!fun)
 29.1501 +        return NULL;
 29.1502 +
 29.1503 +    // If this function had a forward, export it as a named public.
 29.1504 +    if (node->fun()->isPublic()) {
 29.1505 +        assert(node->fun()->isPublic());
 29.1506 +        ScopedRoot<Function> root(fun);
 29.1507 +        if (!root)
 29.1508 +            return NULL;
 29.1509 +        if (!moduleData_->publics.append(root))
 29.1510 +            return NULL;
 29.1511 +    }
 29.1512 +
 29.1513 +#ifndef NDEBUG
 29.1514 +    Disassemble(code, stdout);
 29.1515 +#endif
 29.1516 +    
 29.1517 +    return fun;
 29.1518 +}
 29.1519 +
 29.1520 +Module *
 29.1521 +BytecodeCompiler::compile()
 29.1522 +{
 29.1523 +    AutoEnterScope scope(this, tree_->globalScope());
 29.1524 +
 29.1525 +    ModuleData moduleData;
 29.1526 +
 29.1527 +    moduleData_ = &moduleData;
 29.1528 +    moduleData_->module = Module::New(zone_, tree_->globalScope()->numFunctions());
 29.1529 +
 29.1530 +    if (!moduleData_)
 29.1531 +        return NULL;
 29.1532 +    
 29.1533 +    moduleData_->natives = FixedArray::New(zone_, tree_->globalScope()->numNatives(), Heap::Tenure_Old);
 29.1534 +    if (!moduleData_->natives)
 29.1535 +        return NULL;
 29.1536 +
 29.1537 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
 29.1538 +        Statement *statement = tree_->statements()->at(i);
 29.1539 +        statement->accept(this);
 29.1540 +    }
 29.1541 +
 29.1542 +    if (zone_->hasPendingException())
 29.1543 +        return NULL;
 29.1544 +
 29.1545 +#ifndef NDEBUG
 29.1546 +    for (size_t i = 0; i < tree_->globalScope()->numFunctions(); i++)
 29.1547 +        assert(moduleData_->module->getFunction(i));
 29.1548 +    for (size_t i = 0; i < tree_->globalScope()->numNatives(); i++)
 29.1549 +        assert(moduleData_->natives->at(i));
 29.1550 +#endif
 29.1551 +
 29.1552 +    if (moduleData_->publics.length()) {
 29.1553 +        Local<Function> fun(zone_);
 29.1554 +        Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
 29.1555 +                               Heap::Tenure_Old));
 29.1556 +        if (!list)
 29.1557 +            return NULL;
 29.1558 +
 29.1559 +        for (size_t i = 0; i < moduleData_->publics.length(); i++)
 29.1560 +            list->set(zone_, i, moduleData_->publics[i]);
 29.1561 +
 29.1562 +        moduleData_->module->setPublics(list);
 29.1563 +    }
 29.1564 +
 29.1565 +    moduleData_->module->setNatives(moduleData_->natives);
 29.1566 +
 29.1567 +    if (scope_->numEnvironmentVars()) {
 29.1568 +        Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
 29.1569 +        if (!globalMap)
 29.1570 +            return NULL;
 29.1571 +
 29.1572 +        Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
 29.1573 +        if (!environment)
 29.1574 +            return NULL;
 29.1575 +
 29.1576 +        moduleData_->module->setEnvironment(environment);
 29.1577 +    }
 29.1578 +
 29.1579 +    Local<Code> code(zone_, compileCode(tree_->globalScope(), 1));
 29.1580 +    if (!code)
 29.1581 +        return NULL;
 29.1582 +
 29.1583 +    Disassemble(code, stdout);
 29.1584 +
 29.1585 +    moduleData_->module->setCode(code);
 29.1586 +
 29.1587 +    return moduleData_->module;
 29.1588 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/src/OldByCo.h	Sat Nov 17 18:41:01 2012 -0800
    30.3 @@ -0,0 +1,160 @@
    30.4 +/* vim: set ts=4 sw=4 tw=99 et:
    30.5 + *
    30.6 + * Copyright (C) 2012 David Anderson
    30.7 + *
    30.8 + * This file is part of JITCraft.
    30.9 + *
   30.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   30.11 + * the terms of the GNU General Public License as published by the Free
   30.12 + * Software Foundation, either version 3 of the License, or (at your option)
   30.13 + * any later version.
   30.14 + * 
   30.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   30.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   30.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   30.18 + *
   30.19 + * You should have received a copy of the GNU General Public License along with
   30.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   30.21 + */
   30.22 +#ifndef _include_bytecode_compiler_h_
   30.23 +#define _include_bytecode_compiler_h_
   30.24 +
   30.25 +#include "../Functions.h"
   30.26 +#include "AST.h"
   30.27 +#include "BytecodeEmitter.h"
   30.28 +
   30.29 +namespace ke {
   30.30 +
   30.31 +class Module;
   30.32 +class Array;
   30.33 +class ArrayMap;
   30.34 +
   30.35 +struct ModuleData
   30.36 +{
   30.37 +    ScopedRoot<Module> module;
   30.38 +    PoolList<ScopedRoot<Function> > publics;
   30.39 +    ScopedRoot<FixedArray> natives;
   30.40 +};
   30.41 +
   30.42 +class BytecodeCompiler : public AstVisitor
   30.43 +{
   30.44 +    Zone *zone_;
   30.45 +    ParseTree *tree_;
   30.46 +    BytecodeEmitter emitter_;
   30.47 +    ScopedRoot<FixedArray> locals_;
   30.48 +    Scope *scope_;
   30.49 +    ModuleData *moduleData_;
   30.50 +
   30.51 +    class LoopScope
   30.52 +    {
   30.53 +        Scope *scope_;
   30.54 +        BytecodeEmitter::Label *bk_;
   30.55 +        BytecodeEmitter::Label *ct_;
   30.56 +        LoopScope **prevp_;
   30.57 +        LoopScope *prev_;
   30.58 +
   30.59 +      public:
   30.60 +        LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
   30.61 +                  LoopScope **prevp)
   30.62 +          : scope_(scope),
   30.63 +            bk_(bk),
   30.64 +            ct_(ct),
   30.65 +            prevp_(prevp),
   30.66 +            prev_(*prevp)
   30.67 +        {
   30.68 +            *prevp_ = this;
   30.69 +        }
   30.70 +
   30.71 +        ~LoopScope()
   30.72 +        {
   30.73 +            *prevp_ = prev_;
   30.74 +        }
   30.75 +
   30.76 +        BytecodeEmitter::Label *break_() {
   30.77 +            return bk_;
   30.78 +        }
   30.79 +        BytecodeEmitter::Label *continue_() {
   30.80 +            return ct_;
   30.81 +        }
   30.82 +        Scope *scope() {
   30.83 +            return scope_;
   30.84 +        }
   30.85 +    };
   30.86 +
   30.87 +    LoopScope *loop_;
   30.88 +
   30.89 +  public:
   30.90 +    class AutoEnterScope
   30.91 +    {
   30.92 +        BytecodeCompiler *bc_;
   30.93 +        Scope *saved_;
   30.94 +
   30.95 +      public:
   30.96 +        AutoEnterScope(BytecodeCompiler *bc, Scope *scope)
   30.97 +          : bc_(bc),
   30.98 +            saved_(bc->scope_)
   30.99 +        {
  30.100 +            if (scope)
  30.101 +                bc->scope_ = scope;
  30.102 +        }
  30.103 +        ~AutoEnterScope() {
  30.104 +            bc_->scope_ = saved_;
  30.105 +        }
  30.106 +    };
  30.107 +
  30.108 +  private:
  30.109 +    void recordLifoSlot(Scope *scope);
  30.110 +    void unwindTo(Scope *scope);
  30.111 +    void visitForTest(Expression *expression,
  30.112 +                      BytecodeEmitter::Label *trueBranch,
  30.113 +                      BytecodeEmitter::Label *falseBranch,
  30.114 +                      BytecodeEmitter::Label *fallthrough);
  30.115 +    Code *compileCode(Scope *scope, unsigned lineno);
  30.116 +    Function *compileFunction(ModuleData *module, FunctionStatement *fun);
  30.117 +    void visitForALU(Type *needed, Expression *node);
  30.118 +
  30.119 +    void getEnvSlot(Variable *var);
  30.120 +    void setEnvSlot(Variable *var);
  30.121 +
  30.122 +    bool tableswitch(SwitchStatement *node);
  30.123 +
  30.124 +  public:
  30.125 +    BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
  30.126 +
  30.127 +    Module *compile();
  30.128 +
  30.129 +  public:
  30.130 +    void visit(NameProxy *name);
  30.131 +    void visit(Assignment *node);
  30.132 +    void visit(BinaryExpression *node);
  30.133 +    void visit(ReturnStatement *node);
  30.134 +    void visit(ForStatement *node);
  30.135 +    void visit(BlockStatement *node);
  30.136 +    void visit(VariableDeclaration *node);
  30.137 +    void visit(IntegerLiteral *node);
  30.138 +    void visit(BooleanLiteral *node);
  30.139 +    void visit(FloatLiteral *node);
  30.140 +    void visit(StringLiteral *node);
  30.141 +    void visit(ExpressionStatement *node);
  30.142 +    void visit(FunctionStatement *node);
  30.143 +    void visit(CallExpression *node);
  30.144 +    void visit(IfStatement *node);
  30.145 +    void visit(IndexExpression *node);
  30.146 +    void visit(EnumStatement *node);
  30.147 +    void visit(WhileStatement *node);
  30.148 +    void visit(BreakStatement *node);
  30.149 +    void visit(ContinueStatement *node);
  30.150 +    void visit(IncDecExpression *node);
  30.151 +    void visit(UnaryExpression *node);
  30.152 +    void visit(TernaryExpression *node);
  30.153 +    void visit(StructureStatement *node);
  30.154 +    void visit(FieldExpression *node);
  30.155 +    void visit(SwitchStatement *node);
  30.156 +    void visit(FunctionTypeStatement *node);
  30.157 +    void visit(ArrayLiteral *node);
  30.158 +    void visit(ImportStatement *node);
  30.159 +};
  30.160 +
  30.161 +}
  30.162 +
  30.163 +#endif // _include_bytecode_generator_h_
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/src/OldSema.cpp	Sat Nov 17 18:41:01 2012 -0800
    31.3 @@ -0,0 +1,1899 @@
    31.4 +/* vim: set ts=4 sw=4 tw=99 et:
    31.5 + *
    31.6 + * Copyright (C) 2012 David Anderson
    31.7 + *
    31.8 + * This file is part of JITCraft.
    31.9 + *
   31.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   31.11 + * the terms of the GNU General Public License as published by the Free
   31.12 + * Software Foundation, either version 3 of the License, or (at your option)
   31.13 + * any later version.
   31.14 + * 
   31.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   31.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   31.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   31.18 + *
   31.19 + * You should have received a copy of the GNU General Public License along with
   31.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   31.21 + */
   31.22 +#include <string.h>
   31.23 +#include "SemanticAnalysis.h"
   31.24 +#include "../Types.h"
   31.25 +#include "../Zone.h"
   31.26 +#include "../TypeManager.h"
   31.27 +#include "../Strings.h"
   31.28 +#include "../Box.h"
   31.29 +#include "../Array.h"
   31.30 +#include "../Heap-inl.h"
   31.31 +#include "Scopes.h"
   31.32 +#include "NameBinding.h"
   31.33 +
   31.34 +using namespace ke;
   31.35 +
   31.36 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
   31.37 +  : zone_(zone),
   31.38 +    cc_(cc),
   31.39 +    tree_(tree),
   31.40 +    scope_(NULL),
   31.41 +    loop_(NULL)
   31.42 +{
   31.43 +}
   31.44 +
   31.45 +bool
   31.46 +SemanticAnalysis::analyze()
   31.47 +{
   31.48 +    assert(false);
   31.49 +    return false;
   31.50 +}
   31.51 +
   31.52 +
   31.53 +#if 0
   31.54 +
   31.55 +static inline bool
   31.56 +IsPrimitiveType(Type *type, PrimitiveType primitive)
   31.57 +{
   31.58 +    if (!type)
   31.59 +        return false;
   31.60 +
   31.61 +    if (!type->isPrimitive())
   31.62 +        return false;
   31.63 +
   31.64 +    return primitive == type->primitive();
   31.65 +}
   31.66 +
   31.67 +static inline bool
   31.68 +EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
   31.69 +                        BoxedPrimitive *out)
   31.70 +{
   31.71 +    switch (kind) {
   31.72 +      case TOK_PLUS:
   31.73 +        *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
   31.74 +        return true;
   31.75 +
   31.76 +      case TOK_SHL:
   31.77 +        *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
   31.78 +        return true;
   31.79 +
   31.80 +      default:
   31.81 +        return false;
   31.82 +    }
   31.83 +}
   31.84 +
   31.85 +static inline bool
   31.86 +EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
   31.87 +{
   31.88 +  switch (kind) {
   31.89 +    case TOK_MINUS:
   31.90 +      *out = BoxedPrimitive::Int(-inner.toInt());
   31.91 +      return true;
   31.92 +
   31.93 +    default:
   31.94 +      return false;
   31.95 +  }
   31.96 +}
   31.97 +
   31.98 +static bool
   31.99 +EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
  31.100 +{
  31.101 +    switch (expression->kind()) {
  31.102 +      case AstNode::kBinaryExpression:
  31.103 +      {
  31.104 +        BoxedPrimitive left;
  31.105 +        BoxedPrimitive right;
  31.106 +        BinaryExpression *b = expression->toBinaryExpression();
  31.107 +        if (!EvaluateForConstant(b->left(), &left) ||
  31.108 +            !EvaluateForConstant(b->right(), &right))
  31.109 +        {
  31.110 +            return false;
  31.111 +        }
  31.112 +        return EvaluateBinaryOperation(b->token(), left, right, out);
  31.113 +      }
  31.114 +
  31.115 +      case AstNode::kUnaryExpression:
  31.116 +      {
  31.117 +        BoxedPrimitive inner;
  31.118 +        UnaryExpression *u = expression->toUnaryExpression();
  31.119 +        if (!EvaluateForConstant(u->expression(), &inner))
  31.120 +            return false;
  31.121 +        return EvaluateUnaryOperation(u->token(), inner, out);
  31.122 +      }
  31.123 +
  31.124 +      case AstNode::kNameProxy:
  31.125 +      {
  31.126 +        NameProxy *proxy = expression->toNameProxy();
  31.127 +        if (proxy->binding()->kind() != BoundName::CONSTANT)
  31.128 +            return false;
  31.129 +
  31.130 +        NamedConstant *c = proxy->binding()->toNamedConstant();
  31.131 +        if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
  31.132 +            return false;
  31.133 +
  31.134 +        *out = c->value();
  31.135 +        return true;
  31.136 +      }
  31.137 +
  31.138 +      case AstNode::kBooleanLiteral:
  31.139 +        *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
  31.140 +        return true;
  31.141 +
  31.142 +      case AstNode::kIntegerLiteral:
  31.143 +        *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
  31.144 +        return true;
  31.145 +
  31.146 +      default:
  31.147 +        return false;
  31.148 +    }
  31.149 +}
  31.150 +
  31.151 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
  31.152 +  : zone_(zone),
  31.153 +    cc_(cc),
  31.154 +    tree_(tree),
  31.155 +    scope_(NULL),
  31.156 +    loop_(NULL)
  31.157 +{
  31.158 +}
  31.159 +
  31.160 +bool
  31.161 +SemanticAnalysis::analyze()
  31.162 +{
  31.163 +    if (cc_.failures())
  31.164 +        return false;
  31.165 +
  31.166 +    scope_ = tree_->globalScope();
  31.167 +    assert(scope_->kind() == Scope::GLOBAL);
  31.168 +
  31.169 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  31.170 +        Statement *statement = tree_->statements()->at(i);
  31.171 +        if (statement->isFunctionStatement()) {
  31.172 +            FunctionStatement *funstmt = statement->toFunctionStatement();
  31.173 +            if (!preanalyze(funstmt))
  31.174 +                return false;
  31.175 +        } else if (statement->isEnumStatement()) {
  31.176 +            EnumStatement *enumstmt = statement->toEnumStatement();
  31.177 +
  31.178 +            // We pre-fill global enum types, since they may occur in function
  31.179 +            // signatures. This should probably be somewhere else...
  31.180 +            enumstmt->accept(this);
  31.181 +        } else if (statement->isStructureStatement()) {
  31.182 +            StructureStatement *node = statement->toStructureStatement();
  31.183 +            node->accept(this);
  31.184 +            if (!node->decl()->type())
  31.185 +                return false;
  31.186 +        } else if (statement->isFunctionTypeStatement()) {
  31.187 +            FunctionTypeStatement *node = statement->toFunctionTypeStatement();
  31.188 +            node->accept(this);
  31.189 +            if (!node->decl()->type())
  31.190 +                return false;
  31.191 +        }
  31.192 +    }
  31.193 +
  31.194 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  31.195 +        Statement *statement = tree_->statements()->at(i);
  31.196 +
  31.197 +        // We can't double-process these. Maybe put this check somewhere else.
  31.198 +        if (statement->isEnumStatement())
  31.199 +            continue;
  31.200 +
  31.201 +        statement->accept(this);
  31.202 +    }
  31.203 +
  31.204 +    if (!determineLiveFunctions())
  31.205 +        return false;
  31.206 +
  31.207 +    return !cc_.failures();
  31.208 +}
  31.209 +
  31.210 +bool
  31.211 +SemanticAnalysis::determineLiveFunctions()
  31.212 +{
  31.213 +    Vector<NamedFunction *> worklist;
  31.214 +
  31.215 +    // Add the root set.
  31.216 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  31.217 +        Statement *statement = tree_->statements()->at(i);
  31.218 +        if (!statement->isFunctionStatement())
  31.219 +            continue;
  31.220 +
  31.221 +        FunctionStatement *stmt = statement->toFunctionStatement();
  31.222 +        NamedFunction  *fun = stmt->fun();
  31.223 +        if (!fun->used())
  31.224 +            continue;
  31.225 +
  31.226 +        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
  31.227 +            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
  31.228 +
  31.229 +            // Names in these lists are always unused, however, we mark them
  31.230 +            // as used while inserting into the work queue, to avoid double-
  31.231 +            // insertion.
  31.232 +            if (name->used())
  31.233 +                continue;
  31.234 +
  31.235 +            if (!worklist.append(name))
  31.236 +                return false;
  31.237 +
  31.238 +            name->setUsed();
  31.239 +        }
  31.240 +    }
  31.241 +
  31.242 +    while (!worklist.empty()) {
  31.243 +        NamedFunction *fun = worklist.popCopy();
  31.244 +
  31.245 +        for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
  31.246 +            NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
  31.247 +            if (name->used())
  31.248 +                continue;
  31.249 +            if (!worklist.append(name))
  31.250 +                return false;
  31.251 +            name->setUsed();
  31.252 +        }
  31.253 +    }
  31.254 +
  31.255 +    return true;
  31.256 +}
  31.257 +
  31.258 +Type *
  31.259 +SemanticAnalysis::bindType(const SourcePosition &pos, BoundName *name)
  31.260 +{
  31.261 +    if (!name)
  31.262 +        return zone_->types()->getPrimitive(PrimitiveType_Int32);
  31.263 +
  31.264 +    if (name->kind() == BoundName::UNBOUND) {
  31.265 +        cc_.reportError(pos, Message_TypeNotFound, name->name()->chars());
  31.266 +        return NULL;
  31.267 +    }
  31.268 +
  31.269 +    if (name->kind() != BoundName::TYPE) {
  31.270 +        cc_.reportError(pos, Message_IdentifierIsNotAType, name->name()->chars());
  31.271 +        return NULL;
  31.272 +    }
  31.273 +
  31.274 +    if (!name->type())
  31.275 +        return NULL;
  31.276 +
  31.277 +    return name->type();
  31.278 +}
  31.279 +
  31.280 +Type *
  31.281 +SemanticAnalysis::visitAndApplyType(Expression *expression)
  31.282 +{
  31.283 +    expression->accept(this);
  31.284 +    return expression->type();
  31.285 +}
  31.286 +
  31.287 +Type *
  31.288 +SemanticAnalysis::visitForLoad(Expression *expression)
  31.289 +{
  31.290 +    Local<Type> type(zone_, visitAndApplyType(expression));
  31.291 +    if (!type)
  31.292 +        return NULL;
  31.293 +
  31.294 +    if (type->isReference()) {
  31.295 +        expression->setType(type->contained());
  31.296 +    } else if (expression->isCallExpression()) {
  31.297 +        if (type->isVoid()) {
  31.298 +            CallExpression *call = expression->toCallExpression();
  31.299 +            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
  31.300 +            return NULL;
  31.301 +        }
  31.302 +    }
  31.303 +
  31.304 +    return expression->type();
  31.305 +}
  31.306 +
  31.307 +void
  31.308 +SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type)
  31.309 +{
  31.310 +    const char *op = TokenNames[token];
  31.311 +    const char *name = GetTypeName(type);
  31.312 +
  31.313 +    cc_.reportError(node->pos(), Message_UnaryTypeError, op, name);
  31.314 +}
  31.315 +
  31.316 +void
  31.317 +SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
  31.318 +{
  31.319 +    const char *op = TokenNames[token];
  31.320 +    const char *leftName = GetTypeName(left);
  31.321 +    const char *rightName = GetTypeName(right);
  31.322 +
  31.323 +    cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName);
  31.324 +}
  31.325 +
  31.326 +Type *
  31.327 +SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
  31.328 +{
  31.329 +    if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
  31.330 +        (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
  31.331 +    {
  31.332 +        // If either side is a float, the other side must be a float or int.
  31.333 +        if (left->isFloat() || right->isFloat()) {
  31.334 +            Type *floatType = left->isFloat() ? left : right;
  31.335 +            Type *other = left->isFloat() ? right : left;
  31.336 +            if (other->isFloat() || other->isInt32())
  31.337 +                return floatType;
  31.338 +        }
  31.339 +    }
  31.340 +
  31.341 +    if (token == TOK_OR || token == TOK_AND) {
  31.342 +        if (!canTest(node, left) || !canTest(node, right))
  31.343 +            return NULL;
  31.344 +        return zone_->types()->getPrimitive(PrimitiveType_Bool);
  31.345 +    }
  31.346 +
  31.347 +    if (token >= TOK_EQUALS && token <= TOK_GE) {
  31.348 +        if ((left->isFloat() || left->isInt32()) &&
  31.349 +            (right->isFloat() || right->isInt32()))
  31.350 +        {
  31.351 +            return zone_->types()->getPrimitive(PrimitiveType_Bool);
  31.352 +        }
  31.353 +        binaryTypeError(node, token, left, right);
  31.354 +        return NULL;
  31.355 +    }
  31.356 +
  31.357 +    if (!left->isInt32() || !right->isInt32()) {
  31.358 +        binaryTypeError(node, token, left, right);
  31.359 +        return NULL;
  31.360 +    }
  31.361 +
  31.362 +    return left;
  31.363 +}
  31.364 +
  31.365 +bool
  31.366 +SemanticAnalysis::canTest(AstNode *node, Handle<Type> type)
  31.367 +{
  31.368 +    if (!type->isPrimitive() && !type->isEnum()) {
  31.369 +        cc_.reportError(node->pos(), Message_ArrayIsNotBoolean);
  31.370 +        return false;
  31.371 +    }
  31.372 +    return true;
  31.373 +}
  31.374 +
  31.375 +Type *
  31.376 +SemanticAnalysis::visitForLValue(Expression *expression)
  31.377 +{
  31.378 +    if (expression->isIndexExpression()) {
  31.379 +        Type *type = visitAndApplyType(expression);
  31.380 +        if (!type)
  31.381 +            return NULL;
  31.382 +
  31.383 +        // if (type->isConst()) {
  31.384 +        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  31.385 +        //     return NULL;
  31.386 +        // }
  31.387 +
  31.388 +        return type;
  31.389 +    }
  31.390 +
  31.391 +    if (expression->isFieldExpression()) {
  31.392 +        Type *type = visitAndApplyType(expression);
  31.393 +        if (!type)
  31.394 +            return NULL;
  31.395 +
  31.396 +        // if (expression->toFieldExpression()->left()->type()->isConst()) {
  31.397 +        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  31.398 +        //     return NULL;
  31.399 +        // }
  31.400 +
  31.401 +        return type;
  31.402 +    }
  31.403 +
  31.404 +    if (!expression->isNameProxy()) {
  31.405 +        cc_.reportError(expression->pos(), Message_ExpectedLValue);
  31.406 +        return NULL;
  31.407 +    }
  31.408 +
  31.409 +    NameProxy *proxy = expression->toNameProxy();
  31.410 +    if (!proxy->binding()->kind() == BoundName::VARIABLE) {
  31.411 +        cc_.reportError(expression->pos(), Message_ExpectedLValue);
  31.412 +        return NULL;
  31.413 +    }
  31.414 +
  31.415 +    Variable *var = proxy->binding()->toVariable();
  31.416 +    if (!var->type())
  31.417 +        return NULL;
  31.418 +
  31.419 +    if  (var->type()->isReference()) {
  31.420 +        if (var->type()->isConst()) {
  31.421 +            cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  31.422 +            return NULL;
  31.423 +        }
  31.424 +        return var->type()->contained();
  31.425 +    }
  31.426 +    return var->type();
  31.427 +}
  31.428 +
  31.429 +SemanticAnalysis::ControlStatus
  31.430 +SemanticAnalysis::visitForControl(Statement *statement)
  31.431 +{
  31.432 +    ControlScope scope(&control_);
  31.433 +    statement->accept(this);
  31.434 +    return scope.status();
  31.435 +}
  31.436 +
  31.437 +void
  31.438 +SemanticAnalysis::visit(NameProxy *name)
  31.439 +{
  31.440 +    BoundName *binding = name->binding();
  31.441 +
  31.442 +    if (binding->scope()->kind() == Scope::GLOBAL) {
  31.443 +        if (!function_ || function_->isPublic()) {
  31.444 +            // Whatever we're referencing must be kept alive no matter what.
  31.445 +            // As such, we simply mark it used, and don't do anything special.
  31.446 +            binding->setUsed();
  31.447 +        } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) {
  31.448 +            // Otherwise, we're inside a normal stock or function. Since we
  31.449 +            // don't really know if we've been used yet, we shouldn't
  31.450 +            // prematurely references as alive. Instead, we keep a list of
  31.451 +            // which names have been used, so we can mark them later if needed.
  31.452 +            //
  31.453 +            // Note that we skip this step if the binding is already in the
  31.454 +            // root set.
  31.455 +            if (!function_->addUsedGlobal(binding))
  31.456 +                return;
  31.457 +        }
  31.458 +    }
  31.459 +
  31.460 +    name->setType(binding->type());
  31.461 +}
  31.462 +
  31.463 +void
  31.464 +SemanticAnalysis::visit(Assignment *node)
  31.465 +{
  31.466 +    Local<Type> exprType(zone_, visitForLoad(node->expression()));
  31.467 +    if (!exprType)
  31.468 +        return ;
  31.469 +
  31.470 +    Local<Type> type(zone_, visitForLValue(node->lvalue()));
  31.471 +    if (!type)
  31.472 +        return;
  31.473 +
  31.474 +    if (node->token() != TOK_ASSIGN) {
  31.475 +        if (!typeCheckBinary(node, node->token(), type, exprType))
  31.476 +            return;
  31.477 +    }
  31.478 +
  31.479 +    if (!typeCheckAssignment(node->pos(), exprType, type, true))
  31.480 +        return;
  31.481 +
  31.482 +    node->setType(type);
  31.483 +}
  31.484 +
  31.485 +void
  31.486 +SemanticAnalysis::visit(IncDecExpression *node)
  31.487 +{
  31.488 +    Local<Type> type(zone_, visitForLValue(node->expression()));
  31.489 +    if (!type)
  31.490 +        return;
  31.491 +
  31.492 +    assert(!type->isReference());
  31.493 +
  31.494 +    if (!type->isInt32() && !type->isFloat()) {
  31.495 +        unaryTypeError(node, node->token(), type);
  31.496 +        return;
  31.497 +    }
  31.498 +
  31.499 +    node->setType(type);
  31.500 +}
  31.501 +
  31.502 +void
  31.503 +SemanticAnalysis::visit(UnaryExpression *node)
  31.504 +{
  31.505 +    Local<Type> type(zone_, visitForLoad(node->expression()));
  31.506 +    if (!type)
  31.507 +        return;
  31.508 +
  31.509 +    switch (node->token())
  31.510 +    {
  31.511 +      case TOK_NOT:
  31.512 +        if (!canTest(node->expression(), type))
  31.513 +            return;
  31.514 +        type = zone_->types()->getPrimitive(PrimitiveType_Int32);
  31.515 +        if (!type)
  31.516 +            return;
  31.517 +        node->setType(type);
  31.518 +        break;
  31.519 +
  31.520 +      case TOK_MINUS:
  31.521 +        if (!type->isFloat() && !type->isInt32()) {
  31.522 +            unaryTypeError(node, node->token(), type);
  31.523 +            return;
  31.524 +        }
  31.525 +        node->setType(type);
  31.526 +        break;
  31.527 +
  31.528 +      case TOK_LABEL:
  31.529 +      {
  31.530 +        Local<Type> to(zone_, bindType(node->pos(), node->type()));
  31.531 +        if (!to)
  31.532 +            return;
  31.533 +
  31.534 +        if ((!type->isFloat() && !type->isInt32OrEnum()) ||
  31.535 +            (!to->isFloat() && !to->isInt32OrEnum()))
  31.536 +        {
  31.537 +            unaryTypeError(node, node->token(), type);
  31.538 +            return;
  31.539 +        }
  31.540 +
  31.541 +        node->setType(to);
  31.542 +        break;
  31.543 +      }
  31.544 +
  31.545 +      case TOK_SIZEOF:
  31.546 +      {
  31.547 +        if (!type->isArray()) {
  31.548 +            cc_.reportError(node->pos(), Message_SizeofNeedsArray);
  31.549 +            return;
  31.550 +        }
  31.551 +        node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
  31.552 +        break;
  31.553 +      }
  31.554 +
  31.555 +      default:
  31.556 +        assert(node->token() == TOK_TILDE);
  31.557 +        if (!type->isInt32()) {
  31.558 +            unaryTypeError(node, node->token(), type);
  31.559 +            return;
  31.560 +        }
  31.561 +        node->setType(type);
  31.562 +        break;
  31.563 +    }
  31.564 +}
  31.565 +
  31.566 +void
  31.567 +SemanticAnalysis::visit(TernaryExpression *node)
  31.568 +{
  31.569 +    Local<Type> type(zone_, visitForLoad(node->condition()));
  31.570 +    if (!type)
  31.571 +        return;
  31.572 +
  31.573 +    if (!canTest(node->condition(), type))
  31.574 +        return;
  31.575 +
  31.576 +    Local<Type> left(zone_, visitForLoad(node->left()));
  31.577 +    Local<Type> right(zone_, visitForLoad(node->right()));
  31.578 +    if (!left || !right)
  31.579 +        return;
  31.580 +
  31.581 +    if (left != right) {
  31.582 +        binaryTypeError(node, TOK_QMARK, left, right);
  31.583 +        return;
  31.584 +    }
  31.585 +}
  31.586 +
  31.587 +void
  31.588 +SemanticAnalysis::visit(BinaryExpression *node)
  31.589 +{
  31.590 +    Local<Type> left(zone_, visitForLoad(node->left()));
  31.591 +    Local<Type> right(zone_, visitForLoad(node->right()));
  31.592 +    if (!left || !right)
  31.593 +        return;
  31.5