Renamed jitcraft/ to src/, fixed some /Wp64 warnings.
authorDavid Anderson <dvander@alliedmods.net>
Tue Jul 24 23:53:34 2012 -0700 (2012-07-24)
changeset 8632ad0523b309
parent 85 06a0015b6a5c
child 87 f8ac2633b4e3
Renamed jitcraft/ to src/, fixed some /Wp64 warnings.
src/API.cpp
src/AST.h
src/AllocatorPolicies.h
src/Array.cpp
src/Array.h
src/Barriers.h
src/BytecodeCompiler.cpp
src/BytecodeCompiler.h
src/BytecodeEmitter.cpp
src/BytecodeEmitter.h
src/Code.h
src/CompactBuffer.h
src/CompileContext.cpp
src/CompileContext.h
src/Environments.cpp
src/Environments.h
src/Exception.cpp
src/FixedArray.cpp
src/FixedArray.h
src/Functions.cpp
src/Functions.h
src/GlobalRoots.cpp
src/GlobalRoots.h
src/Handles-inl.h
src/Handles.h
src/HashTable.h
src/Heap-inl.h
src/Heap.cpp
src/Heap.h
src/InlineList.h
src/Interpreter.cpp
src/Interpreter.h
src/Makefile.in
src/Messages.h
src/Messages.tbl
src/Modules.cpp
src/Modules.h
src/NameBinding.cpp
src/NameBinding.h
src/ObjectVisitor.h
src/Objects.h
src/Opcodes.cpp
src/Opcodes.h
src/Opcodes.tbl
src/Parser.cpp
src/Parser.h
src/Platform-Posix.cpp
src/Platform-Windows.cpp
src/Platform.h
src/PoolAllocator.cpp
src/PoolAllocator.h
src/Reference.cpp
src/Reference.h
src/RootScopes.cpp
src/RootScopes.h
src/Scanner.cpp
src/Scanner.h
src/Scopes.cpp
src/Scopes.h
src/SemanticAnalysis.cpp
src/SemanticAnalysis.h
src/Spaces-inl.h
src/Spaces.cpp
src/Spaces.h
src/Stack.cpp
src/Stack.h
src/StringPool.cpp
src/StringPool.h
src/Strings.cpp
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/configure.in
src/jitcraft.vcxproj
src/main.cpp
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/API.cpp	Tue Jul 24 23:53:34 2012 -0700
     1.3 @@ -0,0 +1,483 @@
     1.4 +/* vim: set ts=4 sw=4 tw=99 et:
     1.5 + *
     1.6 + * Copyright (C) 2012 David Anderson
     1.7 + *
     1.8 + * This file is part of JITCraft.
     1.9 + *
    1.10 + * JITCraft is free software: you can redistribute it and/or modify it under
    1.11 + * the terms of the GNU General Public License as published by the Free
    1.12 + * Software Foundation, either version 3 of the License, or (at your option)
    1.13 + * any later version.
    1.14 + * 
    1.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    1.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    1.18 + *
    1.19 + * You should have received a copy of the GNU General Public License along with
    1.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
    1.21 + */
    1.22 +#include "../include/keima.h"
    1.23 +#include "Zone.h"
    1.24 +#include "RootScopes.h"
    1.25 +#include "CompileContext.h"
    1.26 +#include "Parser.h"
    1.27 +#include "Scopes.h"
    1.28 +#include "SemanticAnalysis.h"
    1.29 +#include "BytecodeCompiler.h"
    1.30 +#include "Modules.h"
    1.31 +#include "GlobalRoots.h"
    1.32 +#include "Reference.h"
    1.33 +#include "Array.h"
    1.34 +#include "Interpreter.h"
    1.35 +#include "Stack.h"
    1.36 +#include "Strings.h"
    1.37 +
    1.38 +using namespace ke;
    1.39 +
    1.40 +bool
    1.41 +Ke::Keima::Initialize()
    1.42 +{
    1.43 +    SingleThreadedZone = new Zone();
    1.44 +    if (!SingleThreadedZone || !SingleThreadedZone->initialize())
    1.45 +        return false;
    1.46 +    return true;
    1.47 +}
    1.48 +
    1.49 +void
    1.50 +Ke::Keima::Shutdown()
    1.51 +{
    1.52 +    delete SingleThreadedZone;
    1.53 +    SingleThreadedZone = NULL;
    1.54 +}
    1.55 +
    1.56 +Ke::HandleScope::HandleScope()
    1.57 +  : zone_(ke::ZONE()),
    1.58 +    position_(zone_->rootScopes().position()),
    1.59 +    prev_(*zone_->rootScopes().scope())
    1.60 +{
    1.61 +    *zone_->rootScopes().scope() = this;
    1.62 +}
    1.63 +
    1.64 +Ke::HandleScope::~HandleScope()
    1.65 +{
    1.66 +    zone_->rootScopes().unwind(position_);
    1.67 +    *zone_->rootScopes().scope() = prev_;
    1.68 +}
    1.69 +
    1.70 +ke::Object **
    1.71 +Ke::HandleScope::CreateHandle(ke::Object *obj)
    1.72 +{
    1.73 +    if (!obj)
    1.74 +        return NULL;
    1.75 +
    1.76 +    return ZONE()->rootScopes().make(obj);
    1.77 +}
    1.78 +
    1.79 +template <typename From, typename To> static inline To *
    1.80 +Open(Ke::Handle<From> from)
    1.81 +{
    1.82 +    return *reinterpret_cast<To **>(*from);
    1.83 +}
    1.84 +
    1.85 +template <typename From, typename To> static inline To *
    1.86 +Open(From *from)
    1.87 +{
    1.88 +    return *reinterpret_cast<To **>(from);
    1.89 +}
    1.90 +
    1.91 +template <typename From, typename To> static inline Ke::Local<To>
    1.92 +ToLocal(From *from)
    1.93 +{
    1.94 +    return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
    1.95 +}
    1.96 +
    1.97 +static ke::Module *
    1.98 +CompileFromSource(CompileContext &cc, const char *path, const char *stream, size_t length)
    1.99 +{
   1.100 +    Parser parser(ZONE(), cc, stream, length);
   1.101 +    ParseTree *tree = parser.parse();
   1.102 +    if (!tree)
   1.103 +        return NULL;
   1.104 +    tree->dump(stdout);
   1.105 +
   1.106 +    if (!Scope::Bind(cc, tree))
   1.107 +        return NULL;
   1.108 +
   1.109 +    SemanticAnalysis semantics(ZONE(), cc, tree);
   1.110 +    if (!semantics.analyze())
   1.111 +        return NULL;
   1.112 +
   1.113 +    Scope::Allocate(tree);
   1.114 +
   1.115 +    BytecodeCompiler compiler(ZONE(), tree, NULL);
   1.116 +    ke::Local<Module> module(ke::ZONE(), compiler.compile());
   1.117 +    if (!module)
   1.118 +        return NULL;
   1.119 +
   1.120 +    ke::InvokeArgs args;
   1.121 +    if (!ke::ZONE()->stack().pushModuleFrame(module, args))
   1.122 +        return NULL;
   1.123 +    if (!ke::Interpret(ke::ZONE(), NULL, NULL))
   1.124 +        return NULL;
   1.125 +
   1.126 +    return module;
   1.127 +}
   1.128 +
   1.129 +Ke::Local<Ke::Module>
   1.130 +Ke::Compile(const char *path)
   1.131 +{
   1.132 +    RootScope roots(ZONE());
   1.133 +    CompileContext cc(ZONE(), path);
   1.134 +
   1.135 +    char *bytes = NULL;
   1.136 +    size_t length;
   1.137 +    {
   1.138 +        FILE *fp = fopen(path, "rb");
   1.139 +        if (!fp) {
   1.140 +            cc.reportError(SourcePosition(), Message_CantOpenFile);
   1.141 +            return Ke::Local<Ke::Module>();
   1.142 +        }
   1.143 +
   1.144 +        if (fseek(fp, 0, SEEK_END)) {
   1.145 +            cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
   1.146 +            fclose(fp);
   1.147 +            return Ke::Local<Ke::Module>();;
   1.148 +        }
   1.149 +        long size = ftell(fp);
   1.150 +        if (size < 0) {
   1.151 +            cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
   1.152 +            fclose(fp);
   1.153 +            return Ke::Local<Ke::Module>();;
   1.154 +        }
   1.155 +        rewind(fp);
   1.156 +        length = size_t(size);
   1.157 +        bytes = new char[length + 1];
   1.158 +        if (fread(bytes, 1, length, fp) != length) {
   1.159 +            cc.reportError(SourcePosition(), Message_ErrorReadingFile);
   1.160 +            fclose(fp);
   1.161 +            delete [] bytes;
   1.162 +            return Ke::Local<Ke::Module>();;
   1.163 +        }
   1.164 +        fclose(fp);
   1.165 +    }
   1.166 +
   1.167 +    ke::Local<ke::Module> module(ZONE(),  CompileFromSource(cc, path, bytes, length));
   1.168 +    delete [] bytes;
   1.169 +    if (!module)
   1.170 +        return Ke::Local<Ke::Module>();
   1.171 +
   1.172 +    ke::Local<ke::String> pathstr(ZONE(), ke::String::New(ZONE(), path, Heap::Tenure_Old));
   1.173 +    if (!pathstr)
   1.174 +        return Ke::Local<Ke::Module>();
   1.175 +
   1.176 +    module->setPath(pathstr);
   1.177 +    return ToLocal<ke::Module, Ke::Module>(module);
   1.178 +}
   1.179 +
   1.180 +void
   1.181 +Ke::Keima::InstallMessageReporter(Ke::IMessageReporter *reporter)
   1.182 +{
   1.183 +    ZONE()->installErrorReporter(reporter);
   1.184 +}
   1.185 +
   1.186 +class StackFrameIterator : public Ke::IStackFrameIterator
   1.187 +{
   1.188 +    StackIter iter_;
   1.189 +
   1.190 +  public:
   1.191 +    StackFrameIterator()
   1.192 +      : iter_(ZONE())
   1.193 +    {
   1.194 +    }
   1.195 +
   1.196 +    virtual bool done() {
   1.197 +        return iter_.done();
   1.198 +    }
   1.199 +
   1.200 +    const char *function() {
   1.201 +        return iter_.function();
   1.202 +    }
   1.203 +
   1.204 +    const char *source() {
   1.205 +        return iter_.source();
   1.206 +    }
   1.207 +
   1.208 +    unsigned lineNumber() {
   1.209 +        return iter_.lineNumber();
   1.210 +    }
   1.211 +
   1.212 +    void prev() {
   1.213 +        iter_.prev();
   1.214 +    }
   1.215 +};
   1.216 +
   1.217 +Ke::IStackFrameIterator *
   1.218 +Ke::Keima::NewStackFrameIterator()
   1.219 +{
   1.220 +    return new StackFrameIterator();
   1.221 +}
   1.222 +
   1.223 +static inline ke::HeapRoot *
   1.224 +FromAPI(ke::HeapRoot *from)
   1.225 +{
   1.226 +    ke::Address address = reinterpret_cast<ke::Address>(from);
   1.227 +    address -= offsetof(ke::HeapRoot, obj);
   1.228 +    return reinterpret_cast<ke::HeapRoot *>(address);
   1.229 +}
   1.230 +
   1.231 +ke::HeapRoot *
   1.232 +Ke::Internals::NewHeapRoot(ke::Object **ptr)
   1.233 +{
   1.234 +    ke::Local<ke::Object> obj(ZONE(), *ptr);
   1.235 +    ke::HeapRoot *root = ke::ZONE()->globalRoots()->create(obj);
   1.236 +    if (!root)
   1.237 +        return NULL;
   1.238 +
   1.239 +    // Compute an interior pointer, so it looks like a Handle to an object.
   1.240 +    return reinterpret_cast<ke::HeapRoot *>(&root->obj);
   1.241 +}
   1.242 +
   1.243 +void
   1.244 +Ke::Internals::IncRef(ke::HeapRoot *root)
   1.245 +{
   1.246 +    ZONE()->globalRoots()->incref(FromAPI(root));
   1.247 +}
   1.248 +
   1.249 +void
   1.250 +Ke::Internals::DecRef(ke::HeapRoot *root)
   1.251 +{
   1.252 +    ZONE()->globalRoots()->decref(FromAPI(root));
   1.253 +}
   1.254 +
   1.255 +bool
   1.256 +Ke::Keima::IsInCallStack(Handle<Module> argModule)
   1.257 +{
   1.258 +    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(argModule));
   1.259 +    return ZONE()->stack().isInCallStack(module);
   1.260 +}
   1.261 +
   1.262 +void
   1.263 +Ke::Keima::CollectGarbage()
   1.264 +{
   1.265 +    ke::ZONE()->heap().reclaim();
   1.266 +}
   1.267 +
   1.268 +unsigned
   1.269 +Ke::Module::numPublics()
   1.270 +{
   1.271 +    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   1.272 +    if (!module->publics())
   1.273 +        return 0;
   1.274 +    return module->publics()->length();
   1.275 +}
   1.276 +
   1.277 +Ke::Local<Ke::Function>
   1.278 +Ke::Module::getPublic(unsigned index)
   1.279 +{
   1.280 +    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   1.281 +    ke::Local<ke::Function> fun(ke::ZONE(), ke::Function::cast(module->publics()->at(index)));
   1.282 +    return ToLocal<ke::Function, Ke::Function>(fun);
   1.283 +}
   1.284 +
   1.285 +unsigned
   1.286 +Ke::Module::numNatives()
   1.287 +{
   1.288 +    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   1.289 +    if (!module->natives())
   1.290 +        return 0;
   1.291 +    return module->natives()->length();
   1.292 +}
   1.293 +
   1.294 +Ke::Local<Ke::Native>
   1.295 +Ke::Module::getNative(unsigned index)
   1.296 +{
   1.297 +    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   1.298 +    ke::Local<ke::Native> fun(ke::ZONE(), ke::Native::cast(module->natives()->at(index)));
   1.299 +    return ToLocal<ke::Native, Ke::Native>(fun);
   1.300 +}
   1.301 +
   1.302 +void
   1.303 +Ke::Module::setNativeIdentity(void *identity)
   1.304 +{
   1.305 +    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   1.306 +    module->setNativeIdentity(identity);
   1.307 +}
   1.308 +
   1.309 +unsigned
   1.310 +Ke::String::length()
   1.311 +{
   1.312 +    ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
   1.313 +    return obj->length();
   1.314 +}
   1.315 +
   1.316 +const char *
   1.317 +Ke::String::chars()
   1.318 +{
   1.319 +    ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
   1.320 +    return obj->chars();
   1.321 +}
   1.322 +
   1.323 +Ke::Local<Ke::String>
   1.324 +Ke::Function::name()
   1.325 +{
   1.326 +    ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(this));
   1.327 +    return ToLocal<ke::String, Ke::String>(fun->name());
   1.328 +}
   1.329 +
   1.330 +Ke::Local<Ke::String>
   1.331 +Ke::Native::name()
   1.332 +{
   1.333 +    ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
   1.334 +    return ToLocal<ke::String, Ke::String>(native->name());
   1.335 +}
   1.336 +
   1.337 +void
   1.338 +Ke::Native::bind(void *function)
   1.339 +{
   1.340 +    ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
   1.341 +    native->bind(function);
   1.342 +}
   1.343 +
   1.344 +static inline bool
   1.345 +CheckInvokeType(const Ke::Parameter &param, Type *type)
   1.346 +{
   1.347 +    switch (param.type()) {
   1.348 +      case Ke::Parameter::Array:
   1.349 +        return type->isArray() &&
   1.350 +               type->levels() == 1 &&
   1.351 +               type->contained()->isPrimitive() &&
   1.352 +               (type->contained()->primitive() != PrimitiveType_Char);
   1.353 +      case Ke::Parameter::CharArray:
   1.354 +        return type->isCharArray();
   1.355 +      case Ke::Parameter::Float:
   1.356 +        return type->isFloat();
   1.357 +      case Ke::Parameter::FloatRef:
   1.358 +        return type->isReference() && type->contained()->isFloat();
   1.359 +      case Ke::Parameter::Int:
   1.360 +        return type->isInt32();
   1.361 +      case Ke::Parameter::IntRef:
   1.362 +       return type->isReference() && type->contained()->isInt32();
   1.363 +      default:
   1.364 +        return false;
   1.365 +    }
   1.366 +}
   1.367 +
   1.368 +bool
   1.369 +Ke::Keima::CheckInvokeTypes(Ke::Handle<Ke::Function> argFun, const Ke::Parameter *params, unsigned nparams)
   1.370 +{
   1.371 +    ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
   1.372 +
   1.373 +    if (fun->nargs() != nparams)
   1.374 +        return false;
   1.375 +
   1.376 +    for (unsigned i = 0; i < nparams; i++) {
   1.377 +        if (!CheckInvokeType(params[i], fun->argType(i)))
   1.378 +            return false;
   1.379 +    }
   1.380 +
   1.381 +    // Functions can only return tagged cells, for ISPE1-compatible Invoke().
   1.382 +    ke::Local<ke::Type> returnType(ke::ZONE(), fun->type()->returnType());
   1.383 +    if ((!returnType->isPrimitive() && !returnType->isVoid()) || returnType->isTraceable())
   1.384 +        return false;
   1.385 +
   1.386 +    return true;
   1.387 +}
   1.388 +
   1.389 +bool
   1.390 +Ke::Keima::Invoke(Handle<Function> argFun, const Parameter *params, unsigned nparams, int *retval)
   1.391 +{
   1.392 +    assert(CheckInvokeTypes(argFun, params, nparams));
   1.393 +
   1.394 +    ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
   1.395 +
   1.396 +    if (fun->nargs() != nparams) {
   1.397 +        // :TODO: report error
   1.398 +        assert(false);
   1.399 +        return false;
   1.400 +    }
   1.401 +
   1.402 +    ke::InvokeArgs args;
   1.403 +    if (!ke::ZONE()->stack().pushInvokeFrame(fun, args))
   1.404 +        return false;
   1.405 +
   1.406 +    for (unsigned i = 0; i < nparams; i++) {
   1.407 +        ke::LocalSlot &slot = args.arg(i);
   1.408 +        switch (params[i].type()) {
   1.409 +          case Ke::Parameter::Int:
   1.410 +            slot.i32 = params[i].i32();
   1.411 +            break;
   1.412 +
   1.413 +          case Ke::Parameter::Float:
   1.414 +            slot.f = params[i].f();
   1.415 +            break;
   1.416 +
   1.417 +          case Ke::Parameter::IntRef:
   1.418 +            if (params[i].writeback()) {
   1.419 +                slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack);
   1.420 +            } else {
   1.421 +                LocalSlot other;
   1.422 +                other.i32 = *params[i].i32p();
   1.423 +                slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
   1.424 +            }
   1.425 +            if (!slot.ref)
   1.426 +                return false;
   1.427 +            break;
   1.428 +
   1.429 +          case Ke::Parameter::FloatRef:
   1.430 +            if (params[i].writeback()) {
   1.431 +                slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack);
   1.432 +            } else {
   1.433 +                LocalSlot other;
   1.434 +                other.f = *params[i].fp();
   1.435 +                slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
   1.436 +            }
   1.437 +            if (!slot.ref)
   1.438 +                return false;
   1.439 +            break;
   1.440 +
   1.441 +          case Ke::Parameter::Array:
   1.442 +          {
   1.443 +            ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->genericArrayMap());
   1.444 +            if (params[i].writeback()) {
   1.445 +                slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
   1.446 +                                              params[i].buffer(), Heap::Tenure_Stack);
   1.447 +                if (!slot.obj)
   1.448 +                    return false;
   1.449 +            } else {
   1.450 +                Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
   1.451 +                if (!slot.obj)
   1.452 +                    return false;
   1.453 +                memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(int));
   1.454 +            }
   1.455 +            break;
   1.456 +          }
   1.457 +
   1.458 +          case Ke::Parameter::CharArray:
   1.459 +          {
   1.460 +            ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->charArrayMap());
   1.461 +            if (params[i].writeback()) {
   1.462 +                slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
   1.463 +                                              params[i].buffer(), Heap::Tenure_Stack);
   1.464 +                if (!slot.obj)
   1.465 +                    return false;
   1.466 +            } else {
   1.467 +                Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
   1.468 +                if (!slot.obj)
   1.469 +                    return false;
   1.470 +                memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(char));
   1.471 +            }
   1.472 +            break;
   1.473 +          }
   1.474 +        }
   1.475 +    }
   1.476 +
   1.477 +    LocalSlot result;
   1.478 +    if (!Interpret(ke::ZONE(), NULL, &result))
   1.479 +        return false;
   1.480 +
   1.481 +    if (fun->type()->returnType()->isVoid())
   1.482 +        result.i32 = 0;
   1.483 +
   1.484 +    *retval = result.i32;
   1.485 +    return true;
   1.486 +}
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/AST.h	Tue Jul 24 23:53:34 2012 -0700
     2.3 @@ -0,0 +1,873 @@
     2.4 +/*
     2.5 + * Copyright (C) 2012 David Anderson
     2.6 + *
     2.7 + * This file is part of JITCraft.
     2.8 + *
     2.9 + * JITCraft is free software: you can redistribute it and/or modify it under
    2.10 + * the terms of the GNU General Public License as published by the Free
    2.11 + * Software Foundation, either version 3 of the License, or (at your option)
    2.12 + * any later version.
    2.13 + * 
    2.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    2.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    2.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    2.17 + *
    2.18 + * You should have received a copy of the GNU General Public License along with
    2.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
    2.20 + */
    2.21 +#ifndef _include_jitcraft_ast_h_
    2.22 +#define _include_jitcraft_ast_h_
    2.23 +
    2.24 +#include "PoolAllocator.h"
    2.25 +#include "Token.h"
    2.26 +#include "NameBinding.h"
    2.27 +#include "Vector.h"
    2.28 +
    2.29 +namespace ke {
    2.30 +
    2.31 +#define ASTKINDS(_)             \
    2.32 +    _(VariableDeclaration)      \
    2.33 +    _(ForStatement)             \
    2.34 +    _(ReturnStatement)          \
    2.35 +    _(IntegerLiteral)           \
    2.36 +    _(FloatLiteral)             \
    2.37 +    _(StringLiteral)            \
    2.38 +    _(BinaryExpression)         \
    2.39 +    _(BlockStatement)           \
    2.40 +    _(Assignment)               \
    2.41 +    _(NameProxy)                \
    2.42 +    _(ExpressionStatement)      \
    2.43 +    _(FunctionStatement)        \
    2.44 +    _(CallExpression)           \
    2.45 +    _(IfStatement)              \
    2.46 +    _(IndexExpression)          \
    2.47 +    _(EnumStatement)            \
    2.48 +    _(WhileStatement)           \
    2.49 +    _(BreakStatement)           \
    2.50 +    _(ContinueStatement)        \
    2.51 +    _(IncDecExpression)         \
    2.52 +    _(UnaryExpression)          \
    2.53 +    _(TernaryExpression)
    2.54 +
    2.55 +// Forward declarations.
    2.56 +#define _(name) class name;
    2.57 +ASTKINDS(_)
    2.58 +#undef _
    2.59 +
    2.60 +class AstVisitor;
    2.61 +
    2.62 +// Interface for AST nodes.
    2.63 +class AstNode : public PoolObject
    2.64 +{
    2.65 +    SourcePosition pos_;
    2.66 +
    2.67 +  public:
    2.68 +    enum Kind {
    2.69 +#       define _(name) k##name,
    2.70 +        ASTKINDS(_)
    2.71 +#       undef _
    2.72 +        AstKind_Invalid
    2.73 +    };
    2.74 +
    2.75 +    AstNode(const SourcePosition &pos)
    2.76 +      : pos_(pos)
    2.77 +    {
    2.78 +    }
    2.79 +    
    2.80 +    virtual Kind kind() const = 0;
    2.81 +
    2.82 +#define _(name)     bool is##name() { return kind() == k##name; }                   \
    2.83 +                    name *to##name() { assert(is##name()); return (name *)this; }
    2.84 +    ASTKINDS(_)
    2.85 +#undef _
    2.86 +
    2.87 +    virtual void accept(AstVisitor *visitor) = 0;
    2.88 +
    2.89 +    const SourcePosition &pos() const {
    2.90 +        return pos_;
    2.91 +    }
    2.92 +};
    2.93 +
    2.94 +class AstVisitor
    2.95 +{
    2.96 +  public:
    2.97 +#define _(name) virtual void visit(name *node) = 0;
    2.98 +    ASTKINDS(_)
    2.99 +#undef _
   2.100 +};
   2.101 +
   2.102 +class NameLocation
   2.103 +{
   2.104 +  public:
   2.105 +    enum Kind {
   2.106 +        LOCAL
   2.107 +    };
   2.108 +
   2.109 +    static NameLocation Local(VariableDeclaration *decl) {
   2.110 +        NameLocation loc;
   2.111 +        loc.kind_ = LOCAL;
   2.112 +        loc.u_.decl = decl;
   2.113 +        return loc;
   2.114 +    }
   2.115 +
   2.116 +    Kind kind() const {
   2.117 +        return kind_;
   2.118 +    }
   2.119 +
   2.120 +    VariableDeclaration *local() const {
   2.121 +        assert(kind() == LOCAL);
   2.122 +        return u_.decl;
   2.123 +    }
   2.124 +
   2.125 +  private:
   2.126 +    Kind kind_;
   2.127 +    union {
   2.128 +        VariableDeclaration *decl;
   2.129 +    } u_;
   2.130 +};
   2.131 +
   2.132 +class Statement : public AstNode
   2.133 +{
   2.134 +  public:
   2.135 +    Statement(const SourcePosition &pos)
   2.136 +      : AstNode(pos)
   2.137 +    {
   2.138 +    }
   2.139 +};
   2.140 +
   2.141 +class Expression : public AstNode
   2.142 +{
   2.143 +    ScopedRoot<Type> type_;
   2.144 +
   2.145 +  public:
   2.146 +    Expression(const SourcePosition &pos)
   2.147 +      : AstNode(pos),
   2.148 +        type_(NULL)
   2.149 +    {
   2.150 +    }
   2.151 +
   2.152 +    void setType(Type *type) {
   2.153 +        type_ = type;
   2.154 +    }
   2.155 +    Type *type() const {
   2.156 +        return type_;
   2.157 +    }
   2.158 +};
   2.159 +
   2.160 +typedef PoolList<Statement *> StatementList;
   2.161 +typedef PoolList<Expression *> ExpressionList;
   2.162 +
   2.163 +class VariableDeclaration : public Statement
   2.164 +{
   2.165 +    Variable *variable_;
   2.166 +    Expression *initialization_;
   2.167 +    ExpressionList *postDimensions_;
   2.168 +    ScopedRoot<String> tag_;
   2.169 +
   2.170 +  public:
   2.171 +    VariableDeclaration(const SourcePosition &pos, Variable *var, Handle<String> tag,
   2.172 +                        ExpressionList *postDimensions, Expression *initialization)
   2.173 +      : Statement(pos),
   2.174 +        variable_(var),
   2.175 +        initialization_(initialization),
   2.176 +        postDimensions_(postDimensions),
   2.177 +        tag_(tag)
   2.178 +    {
   2.179 +    }
   2.180 +
   2.181 +    String *tag() const {
   2.182 +        return tag_;
   2.183 +    }
   2.184 +    Kind kind() const {
   2.185 +        return kVariableDeclaration;
   2.186 +    }
   2.187 +    Variable *variable() const {
   2.188 +        return variable_;
   2.189 +    }
   2.190 +    Expression *initialization() const {
   2.191 +        return initialization_;
   2.192 +    }
   2.193 +    ExpressionList *postDimensions() const {
   2.194 +        return postDimensions_;
   2.195 +    }
   2.196 +    void accept(AstVisitor *visitor) {
   2.197 +        visitor->visit(this);
   2.198 +    }
   2.199 +};
   2.200 +
   2.201 +class Parameter : public PoolObject
   2.202 +{
   2.203 +    Variable *variable_;
   2.204 +    ScopedRoot<String> tag_;
   2.205 +    bool reference_;
   2.206 +    bool const_;
   2.207 +    ExpressionList *dimensions_;
   2.208 +
   2.209 +  public:
   2.210 +    Parameter(Variable *var, Handle<String> tag, bool reference, bool isConst, ExpressionList *dimensions)
   2.211 +      : variable_(var),
   2.212 +        tag_(tag),
   2.213 +        reference_(reference),
   2.214 +        const_(isConst),
   2.215 +        dimensions_(dimensions)
   2.216 +    {
   2.217 +    }
   2.218 +
   2.219 +    String *tag() const {
   2.220 +        return tag_;
   2.221 +    }
   2.222 +    Variable *variable() const {
   2.223 +        return variable_;
   2.224 +    }
   2.225 +    bool reference() const {
   2.226 +        return reference_;
   2.227 +    }
   2.228 +    ExpressionList *dimensions() const {
   2.229 +        return dimensions_;
   2.230 +    }
   2.231 +    bool isConst() const {
   2.232 +        return const_;
   2.233 +    }
   2.234 +};
   2.235 +
   2.236 +class NameProxy : public Expression
   2.237 +{
   2.238 +    ScopedRoot<String> name_;
   2.239 +    BoundName *binding_;
   2.240 +
   2.241 +  public:
   2.242 +    NameProxy(const SourcePosition &pos, Handle<String> name, BoundName *binding)
   2.243 +      : Expression(pos),
   2.244 +        name_(name),
   2.245 +        binding_(binding)
   2.246 +    {
   2.247 +    }
   2.248 +
   2.249 +    Kind kind() const {
   2.250 +        return kNameProxy;
   2.251 +    }
   2.252 +    String *name() const {
   2.253 +        return name_;
   2.254 +    }
   2.255 +    void accept(AstVisitor *visitor) {
   2.256 +        visitor->visit(this);
   2.257 +    }
   2.258 +    BoundName *binding() const {
   2.259 +        return binding_;
   2.260 +    }
   2.261 +    void bind(BoundName *name) {
   2.262 +        assert(!binding());
   2.263 +        binding_ = name;
   2.264 +    }
   2.265 +};
   2.266 +
   2.267 +class IntegerLiteral : public Expression
   2.268 +{
   2.269 +    int value_;
   2.270 +
   2.271 +  public:
   2.272 +    IntegerLiteral(const SourcePosition &pos, int value)
   2.273 +      : Expression(pos),
   2.274 +        value_(value)
   2.275 +    {
   2.276 +    }
   2.277 +
   2.278 +    Kind kind() const {
   2.279 +        return kIntegerLiteral;
   2.280 +    }
   2.281 +    int value() const {
   2.282 +        return value_;
   2.283 +    }
   2.284 +    void accept(AstVisitor *visitor) {
   2.285 +        visitor->visit(this);
   2.286 +    }
   2.287 +};
   2.288 +
   2.289 +class FloatLiteral : public Expression
   2.290 +{
   2.291 +    double value_;
   2.292 +
   2.293 +  public:
   2.294 +    FloatLiteral(const SourcePosition &pos, double value)
   2.295 +      : Expression(pos),
   2.296 +        value_(value)
   2.297 +    {
   2.298 +    }
   2.299 +
   2.300 +    Kind kind() const {
   2.301 +        return kFloatLiteral;
   2.302 +    }
   2.303 +    double value() const {
   2.304 +        return value_;
   2.305 +    }
   2.306 +    void accept(AstVisitor *visitor) {
   2.307 +        visitor->visit(this);
   2.308 +    }
   2.309 +};
   2.310 +
   2.311 +class StringLiteral : public Expression
   2.312 +{
   2.313 +    ScopedRoot<ByteArray> string_;
   2.314 +
   2.315 +  public:
   2.316 +    StringLiteral(const SourcePosition &pos, ByteArray *array)
   2.317 +      : Expression(pos),
   2.318 +        string_(array)
   2.319 +    {
   2.320 +    }
   2.321 +
   2.322 +    Kind kind() const {
   2.323 +        return kStringLiteral;
   2.324 +    }
   2.325 +    ByteArray *string() const {
   2.326 +        return string_;
   2.327 +    }
   2.328 +    void accept(AstVisitor *visitor) {
   2.329 +        visitor->visit(this);
   2.330 +    }
   2.331 +};
   2.332 +
   2.333 +class UnaryExpression : public Expression
   2.334 +{
   2.335 +    Expression *expression_;
   2.336 +    TokenKind token_;
   2.337 +
   2.338 +  public:
   2.339 +    UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr)
   2.340 +      : Expression(pos),
   2.341 +        expression_(expr),
   2.342 +        token_(token)
   2.343 +    {
   2.344 +    }
   2.345 +
   2.346 +    Kind kind() const {
   2.347 +        return kUnaryExpression;
   2.348 +    }
   2.349 +    Expression *expression() const {
   2.350 +        return expression_;
   2.351 +    }
   2.352 +    TokenKind token() const {
   2.353 +        return token_;
   2.354 +    }
   2.355 +    void accept(AstVisitor *visitor) {
   2.356 +        visitor->visit(this);
   2.357 +    }
   2.358 +};
   2.359 +
   2.360 +class BinaryExpression : public Expression
   2.361 +{
   2.362 +    Expression *left_;
   2.363 +    Expression *right_;
   2.364 +    TokenKind token_;
   2.365 +
   2.366 +  public:
   2.367 +    BinaryExpression(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
   2.368 +      : Expression(pos),
   2.369 +        left_(left),
   2.370 +        right_(right),
   2.371 +        token_(token)
   2.372 +    {
   2.373 +    }
   2.374 +
   2.375 +    Kind kind() const {
   2.376 +        return kBinaryExpression;
   2.377 +    }
   2.378 +    Expression *left() const {
   2.379 +        return left_;
   2.380 +    }
   2.381 +    Expression *right() const {
   2.382 +        return right_;
   2.383 +    }
   2.384 +    TokenKind token() const {
   2.385 +        return token_;
   2.386 +    }
   2.387 +    void accept(AstVisitor *visitor) {
   2.388 +        visitor->visit(this);
   2.389 +    }
   2.390 +};
   2.391 +
   2.392 +class TernaryExpression : public Expression
   2.393 +{
   2.394 +    Expression *condition_;
   2.395 +    Expression *left_;
   2.396 +    Expression *right_;
   2.397 +
   2.398 +  public:
   2.399 +    TernaryExpression(const SourcePosition &pos, Expression *condition, Expression *left, Expression *right)
   2.400 +      : Expression(pos),
   2.401 +        condition_(condition),
   2.402 +        left_(left),
   2.403 +        right_(right)
   2.404 +    {
   2.405 +    }
   2.406 +
   2.407 +    Kind kind() const {
   2.408 +        return kTernaryExpression;
   2.409 +    }
   2.410 +    Expression *condition() const {
   2.411 +        return condition_;
   2.412 +    }
   2.413 +    Expression *left() const {
   2.414 +        return left_;
   2.415 +    }
   2.416 +    Expression *right() const {
   2.417 +        return right_;
   2.418 +    }
   2.419 +    void accept(AstVisitor *visitor) {
   2.420 +        visitor->visit(this);
   2.421 +    }
   2.422 +};
   2.423 +
   2.424 +class IndexExpression : public Expression
   2.425 +{
   2.426 +    Expression *left_;
   2.427 +    Expression *right_;
   2.428 +
   2.429 +  public:
   2.430 +    IndexExpression(const SourcePosition &pos, Expression *left, Expression *right)
   2.431 +      : Expression(pos),
   2.432 +        left_(left),
   2.433 +        right_(right)
   2.434 +    {
   2.435 +    }
   2.436 +
   2.437 +    Kind kind() const {
   2.438 +        return kIndexExpression;
   2.439 +    }
   2.440 +    Expression *left() const {
   2.441 +        return left_;
   2.442 +    }
   2.443 +    Expression *right() const {
   2.444 +        return right_;
   2.445 +    }
   2.446 +    void accept(AstVisitor *visitor) {
   2.447 +        visitor->visit(this);
   2.448 +    }
   2.449 +};
   2.450 +
   2.451 +class CallExpression : public Expression
   2.452 +{
   2.453 +    Expression *callee_;
   2.454 +    ExpressionList *arguments_;
   2.455 +
   2.456 +  public:
   2.457 +    CallExpression(const SourcePosition &pos, Expression *callee, ExpressionList *arguments)
   2.458 +      : Expression(pos),
   2.459 +        callee_(callee),
   2.460 +        arguments_(arguments)
   2.461 +    {
   2.462 +    }
   2.463 +
   2.464 +    Kind kind() const {
   2.465 +        return kCallExpression;
   2.466 +    }
   2.467 +    Expression *callee() const {
   2.468 +        return callee_;
   2.469 +    }
   2.470 +    ExpressionList *arguments() const {
   2.471 +        return arguments_;
   2.472 +    }
   2.473 +    void accept(AstVisitor *visitor) {
   2.474 +        visitor->visit(this);
   2.475 +    }
   2.476 +};
   2.477 +
   2.478 +class ForStatement : public Statement
   2.479 +{
   2.480 +    Scope *scope_;
   2.481 +    Statement *initialization_;
   2.482 +    Expression *condition_;
   2.483 +    Statement *update_;
   2.484 +    Statement *body_;
   2.485 +
   2.486 +  public:
   2.487 +    ForStatement(const SourcePosition &pos, Scope *scope, Statement *initialization,
   2.488 +                 Expression *condition, Statement *update, Statement *body)
   2.489 +      : Statement(pos),
   2.490 +        scope_(scope),
   2.491 +        initialization_(initialization),
   2.492 +        condition_(condition),
   2.493 +        update_(update),
   2.494 +        body_(body)
   2.495 +    {
   2.496 +    }
   2.497 +
   2.498 +    Kind kind() const {
   2.499 +        return kForStatement;
   2.500 +    }
   2.501 +    Statement *initialization() const {
   2.502 +        return initialization_;
   2.503 +    }
   2.504 +    Scope *scope() const {
   2.505 +        return scope_;
   2.506 +    }
   2.507 +    Expression *condition() const {
   2.508 +        return condition_;
   2.509 +    }
   2.510 +    Statement *update() const {
   2.511 +        return update_;
   2.512 +    }
   2.513 +    Statement *body() const {
   2.514 +        return body_;
   2.515 +    }
   2.516 +    void accept(AstVisitor *visitor) {
   2.517 +        visitor->visit(this);
   2.518 +    }
   2.519 +};
   2.520 +
   2.521 +class WhileStatement : public Statement
   2.522 +{
   2.523 +    TokenKind token_;
   2.524 +    Expression *condition_;
   2.525 +    Statement *body_;
   2.526 +
   2.527 +  public:
   2.528 +    WhileStatement(const SourcePosition &pos, TokenKind kind, Expression *condition, Statement *body)
   2.529 +      : Statement(pos),
   2.530 +        token_(kind),
   2.531 +        condition_(condition),
   2.532 +        body_(body)
   2.533 +    {
   2.534 +    }
   2.535 +    
   2.536 +    Kind kind() const {
   2.537 +        return kWhileStatement;
   2.538 +    }
   2.539 +    TokenKind token() const {
   2.540 +        return token_;
   2.541 +    }
   2.542 +    Expression *condition() const {
   2.543 +        return condition_;
   2.544 +    }
   2.545 +    Statement *body() const {
   2.546 +        return body_;
   2.547 +    }
   2.548 +    void accept(AstVisitor *visitor) {
   2.549 +        visitor->visit(this);
   2.550 +    }
   2.551 +};
   2.552 +
   2.553 +class ReturnStatement : public Statement
   2.554 +{
   2.555 +    Expression *expression_;
   2.556 +
   2.557 +  public:
   2.558 +    ReturnStatement(const SourcePosition &pos, Expression *expression)
   2.559 +      : Statement(pos),
   2.560 +        expression_(expression)
   2.561 +    {
   2.562 +    }
   2.563 +
   2.564 +    Kind kind() const {
   2.565 +        return kReturnStatement;
   2.566 +    }
   2.567 +    Expression *expression() const {
   2.568 +        return expression_;
   2.569 +    }
   2.570 +    void accept(AstVisitor *visitor) {
   2.571 +        visitor->visit(this);
   2.572 +    }
   2.573 +};
   2.574 +
   2.575 +class BreakStatement : public Statement
   2.576 +{
   2.577 +  public:
   2.578 +    BreakStatement(const SourcePosition &pos)
   2.579 +      : Statement(pos)
   2.580 +    {
   2.581 +    }
   2.582 +
   2.583 +    Kind kind() const {
   2.584 +        return kBreakStatement;
   2.585 +    }
   2.586 +    void accept(AstVisitor *visitor) {
   2.587 +        visitor->visit(this);
   2.588 +    }
   2.589 +};
   2.590 +
   2.591 +class ContinueStatement : public Statement
   2.592 +{
   2.593 +  public:
   2.594 +    ContinueStatement(const SourcePosition &pos)
   2.595 +      : Statement(pos)
   2.596 +    {
   2.597 +    }
   2.598 +
   2.599 +    Kind kind() const {
   2.600 +        return kContinueStatement;
   2.601 +    }
   2.602 +    void accept(AstVisitor *visitor) {
   2.603 +        visitor->visit(this);
   2.604 +    }
   2.605 +};
   2.606 +
   2.607 +class Assignment : public Expression
   2.608 +{
   2.609 +    TokenKind token_;
   2.610 +    Expression *lvalue_;
   2.611 +    Expression *expression_;
   2.612 +
   2.613 +  public:
   2.614 +    Assignment(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
   2.615 +      : Expression(pos),
   2.616 +        token_(token),
   2.617 +        lvalue_(left),
   2.618 +        expression_(right)
   2.619 +    {
   2.620 +    }
   2.621 +
   2.622 +    Kind kind() const {
   2.623 +        return kAssignment;
   2.624 +    }
   2.625 +    TokenKind token() const {
   2.626 +        return token_;
   2.627 +    }
   2.628 +    Expression *lvalue() const {
   2.629 +        return lvalue_;
   2.630 +    }
   2.631 +    Expression *expression() const {
   2.632 +        return expression_;
   2.633 +    }
   2.634 +    void accept(AstVisitor *visitor) {
   2.635 +        visitor->visit(this);
   2.636 +    }
   2.637 +};
   2.638 +
   2.639 +class ExpressionStatement : public Statement
   2.640 +{
   2.641 +    Expression *expression_;
   2.642 +
   2.643 +  public:
   2.644 +    ExpressionStatement(Expression *expression)
   2.645 +      : Statement(expression->pos()),
   2.646 +        expression_(expression)
   2.647 +    {
   2.648 +    }
   2.649 +
   2.650 +    Kind kind() const {
   2.651 +        return kExpressionStatement;
   2.652 +    }
   2.653 +    Expression *expression() const {
   2.654 +        return expression_;
   2.655 +    }
   2.656 +    void accept(AstVisitor *visitor) {
   2.657 +        visitor->visit(this);
   2.658 +    }
   2.659 +};
   2.660 +
   2.661 +class BlockStatement : public Statement
   2.662 +{
   2.663 +    Scope *scope_;
   2.664 +    StatementList *statements_;
   2.665 +
   2.666 +  public:
   2.667 +    BlockStatement(const SourcePosition &pos, Scope *scope, StatementList *statements)
   2.668 +      : Statement(pos),
   2.669 +        scope_(scope),
   2.670 +        statements_(statements)
   2.671 +    {
   2.672 +    }
   2.673 +
   2.674 +    Kind kind() const {
   2.675 +        return kBlockStatement;
   2.676 +    }
   2.677 +    Scope *scope() const {
   2.678 +        return scope_;
   2.679 +    }
   2.680 +    StatementList *statements() const {
   2.681 +        return statements_;
   2.682 +    }
   2.683 +    void accept(AstVisitor *visitor) {
   2.684 +        visitor->visit(this);
   2.685 +    }
   2.686 +};
   2.687 +
   2.688 +typedef PoolList<Parameter *> ParameterList;
   2.689 +
   2.690 +class FunctionStatement : public Statement
   2.691 +{
   2.692 +    Scope *scope_;
   2.693 +    NamedFunction *fun_;
   2.694 +    Statement *body_;
   2.695 +    ParameterList *parameters_;
   2.696 +    bool explicitReturn_;
   2.697 +
   2.698 +  public:
   2.699 +    FunctionStatement(const SourcePosition &pos, Scope *scope, NamedFunction *fun, Statement *body,
   2.700 +                      ParameterList *parameters, bool explicitReturn)
   2.701 +      : Statement(pos),
   2.702 +        scope_(scope),
   2.703 +        fun_(fun),
   2.704 +        body_(body),
   2.705 +        parameters_(parameters),
   2.706 +        explicitReturn_(explicitReturn)
   2.707 +    {
   2.708 +    }
   2.709 +
   2.710 +    Kind kind() const {
   2.711 +        return kFunctionStatement;
   2.712 +    }
   2.713 +    Scope *scope() const {
   2.714 +        return scope_;
   2.715 +    }
   2.716 +    NamedFunction *fun() const {
   2.717 +        return fun_;
   2.718 +    }
   2.719 +    Statement *body() const {
   2.720 +        return body_;
   2.721 +    }
   2.722 +    ParameterList *parameters() const {
   2.723 +        return parameters_;
   2.724 +    }
   2.725 +    void accept(AstVisitor *visitor) {
   2.726 +        visitor->visit(this);
   2.727 +    }
   2.728 +    bool hasExplicitReturn() const {
   2.729 +        return explicitReturn_;
   2.730 +    }
   2.731 +};
   2.732 +
   2.733 +class IfStatement : public Statement
   2.734 +{
   2.735 +    Expression *condition_;
   2.736 +    Statement *ifTrue_;
   2.737 +    Statement *ifFalse_;
   2.738 +
   2.739 +  public:
   2.740 +    IfStatement(const SourcePosition &pos, Expression *condition, Statement *ifTrue)
   2.741 +      : Statement(pos),
   2.742 +        condition_(condition),
   2.743 +        ifTrue_(ifTrue),
   2.744 +        ifFalse_(NULL)
   2.745 +    {
   2.746 +    }
   2.747 +
   2.748 +    Kind kind() const {
   2.749 +        return kIfStatement;
   2.750 +    }
   2.751 +    Expression *condition() const {
   2.752 +        return condition_;
   2.753 +    }
   2.754 +    Statement *ifTrue() const {
   2.755 +        return ifTrue_;
   2.756 +    }
   2.757 +    Statement *ifFalse() const {
   2.758 +        return ifFalse_;
   2.759 +    }
   2.760 +    void setIfFalse(Statement *ifFalse) {
   2.761 +        ifFalse_ = ifFalse;
   2.762 +    }
   2.763 +    void accept(AstVisitor *visitor) {
   2.764 +        visitor->visit(this);
   2.765 +    }
   2.766 +};
   2.767 +
   2.768 +class EnumStatement : public Statement
   2.769 +{
   2.770 +    ScopedRoot<String> name_;
   2.771 +
   2.772 +  public:
   2.773 +    struct Entry {
   2.774 +        NamedConstant *name;
   2.775 +        Expression *expr;
   2.776 +
   2.777 +        Entry(NamedConstant *name, Expression *expr)
   2.778 +          : name(name),
   2.779 +            expr(expr)
   2.780 +        {
   2.781 +        }
   2.782 +    };
   2.783 +
   2.784 +    typedef PoolList<Entry> EntryList;
   2.785 +
   2.786 +  public:
   2.787 +    EnumStatement(const SourcePosition &pos, Handle<String> name, EntryList *entries)
   2.788 +      : Statement(pos),
   2.789 +        name_(name),
   2.790 +        entries_(entries)
   2.791 +    {
   2.792 +    }
   2.793 +
   2.794 +    Kind kind() const {
   2.795 +        return kEnumStatement;
   2.796 +    }
   2.797 +    String *name() const {
   2.798 +        return name_;
   2.799 +    }
   2.800 +    EntryList *entries() const {
   2.801 +        return entries_;
   2.802 +    }
   2.803 +    void accept(AstVisitor *visitor) {
   2.804 +        visitor->visit(this);
   2.805 +    }
   2.806 +
   2.807 +  private:
   2.808 +    EntryList *entries_;
   2.809 +};
   2.810 +
   2.811 +class IncDecExpression : public Expression
   2.812 +{
   2.813 +    TokenKind token_;
   2.814 +    Expression *expression_;
   2.815 +    bool postfix_;
   2.816 +
   2.817 +  public:
   2.818 +    IncDecExpression(const SourcePosition &pos, TokenKind token, Expression *expression, bool postfix)
   2.819 +      : Expression(pos),
   2.820 +        token_(token),
   2.821 +        expression_(expression),
   2.822 +        postfix_(postfix)
   2.823 +    {
   2.824 +    }
   2.825 +
   2.826 +    Kind kind() const {
   2.827 +        return kIncDecExpression;
   2.828 +    }
   2.829 +    TokenKind token() const {
   2.830 +        return token_;
   2.831 +    }
   2.832 +    Expression *expression() const {
   2.833 +        return expression_;
   2.834 +    }
   2.835 +    bool postfix() const {
   2.836 +        return postfix_;
   2.837 +    }
   2.838 +    void accept(AstVisitor *visitor) {
   2.839 +        visitor->visit(this);
   2.840 +    }
   2.841 +};
   2.842 +
   2.843 +class Scope;
   2.844 +
   2.845 +typedef PoolList<NameProxy *> NameProxyList;
   2.846 +
   2.847 +class ParseTree : public PoolObject
   2.848 +{
   2.849 +    StatementList *statements_;
   2.850 +    Scope *scope_;
   2.851 +    NameProxyList *unbound_;
   2.852 +
   2.853 +  public:
   2.854 +    ParseTree(Scope *scope, StatementList *statements, NameProxyList *unbound)
   2.855 +      : statements_(statements),
   2.856 +        scope_(scope),
   2.857 +        unbound_(unbound)
   2.858 +    {
   2.859 +    }
   2.860 +
   2.861 +    void dump(FILE *fp);
   2.862 +
   2.863 +    StatementList *statements() const {
   2.864 +        return statements_;
   2.865 +    }
   2.866 +    Scope *scope() const {
   2.867 +        return scope_;
   2.868 +    }
   2.869 +    NameProxyList *unbound() const {
   2.870 +        return unbound_;
   2.871 +    }
   2.872 +};
   2.873 +
   2.874 +}
   2.875 +
   2.876 +#endif // _include_jitcraft_ast_h_
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/AllocatorPolicies.h	Tue Jul 24 23:53:34 2012 -0700
     3.3 @@ -0,0 +1,45 @@
     3.4 +/*
     3.5 + * Copyright (C) 2012 David Anderson
     3.6 + *
     3.7 + * This file is part of JITCraft.
     3.8 + *
     3.9 + * JITCraft is free software: you can redistribute it and/or modify it under
    3.10 + * the terms of the GNU General Public License as published by the Free
    3.11 + * Software Foundation, either version 3 of the License, or (at your option)
    3.12 + * any later version.
    3.13 + * 
    3.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    3.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    3.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    3.17 + *
    3.18 + * You should have received a copy of the GNU General Public License along with
    3.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
    3.20 + */
    3.21 +#ifndef _include_jc_allocators_h_
    3.22 +#define _include_jc_allocators_h_
    3.23 +
    3.24 +#include <stdlib.h>
    3.25 +
    3.26 +namespace ke {
    3.27 +
    3.28 +class ZoneAllocatorPolicy
    3.29 +{
    3.30 +  protected:
    3.31 +    void reportOutOfMemory();
    3.32 +    void reportAllocationOverflow();
    3.33 +
    3.34 +  public:
    3.35 +    void free(void *memory) {
    3.36 +        ::free(memory);
    3.37 +    }
    3.38 +    void *malloc(size_t bytes) {
    3.39 +        void *ptr = ::malloc(bytes);
    3.40 +        if (!ptr)
    3.41 +            reportOutOfMemory();
    3.42 +        return ptr;
    3.43 +    }
    3.44 +};
    3.45 +
    3.46 +}
    3.47 +
    3.48 +#endif // _include_jc_allocators_h_
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/Array.cpp	Tue Jul 24 23:53:34 2012 -0700
     4.3 @@ -0,0 +1,77 @@
     4.4 +/*
     4.5 + * Copyright (C) 2012 David Anderson
     4.6 + *
     4.7 + * This file is part of JITCraft.
     4.8 + *
     4.9 + * JITCraft is free software: you can redistribute it and/or modify it under
    4.10 + * the terms of the GNU General Public License as published by the Free
    4.11 + * Software Foundation, either version 3 of the License, or (at your option)
    4.12 + * any later version.
    4.13 + * 
    4.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    4.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    4.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    4.17 + *
    4.18 + * You should have received a copy of the GNU General Public License along with
    4.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
    4.20 + */
    4.21 +#include "Array.h"
    4.22 +#include "Heap.h"
    4.23 +#include "Zone.h"
    4.24 +#include "Heap-inl.h"
    4.25 +
    4.26 +using namespace ke;
    4.27 +
    4.28 +ArrayMap *
    4.29 +ArrayMap::New(Zone *zone, Handle<Type> type, Handle<ArrayMap> contained)
    4.30 +{
    4.31 +    Local<Map> obj(zone, zone->allocateMap(MapKind_Array, sizeof(ArrayMap), MapKind_MetaArray));
    4.32 +    if (!obj)
    4.33 +        return NULL;
    4.34 +
    4.35 +    Local<ArrayMap> map(zone, ArrayMap::cast(obj));
    4.36 +    map->type_ = type;
    4.37 +    map->contained_ = contained;
    4.38 +    return map;
    4.39 +}
    4.40 +
    4.41 +static inline size_t
    4.42 +SizeFor(Type *type, unsigned elements)
    4.43 +{
    4.44 +    if (type->levels() > 1)
    4.45 +        return sizeof(Array) + elements * sizeof(ke::Object *);
    4.46 +    if (type->contained()->isInt32())
    4.47 +        return sizeof(Array) + elements * sizeof(int);
    4.48 +    if (type->contained()->primitive() == PrimitiveType_Char)
    4.49 +        return sizeof(Array) + elements * sizeof(char);
    4.50 +    assert(type->contained()->isFloat());
    4.51 +    return elements * sizeof(float);
    4.52 +}
    4.53 +
    4.54 +Array *
    4.55 +Array::New(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure)
    4.56 +{
    4.57 +    size_t elementBytes = SizeFor(map->type(), elements);
    4.58 +    size_t bytes = sizeof(Array) + elementBytes;
    4.59 +    Local<Array> array(zone, Array::cast(zone->allocate(map, bytes, tenure)));
    4.60 +    if (!array)
    4.61 +        return NULL;
    4.62 +
    4.63 +    array->nelements_ = elements;
    4.64 +    array->elements_ = (Array *)array + 1;
    4.65 +    memset(array->elements_, 0, elementBytes);
    4.66 +    return array;
    4.67 +}
    4.68 +
    4.69 +Array *
    4.70 +Array::NewExternal(Zone *zone, Handle<ArrayMap> map, uint32 nelements, void *buffer,
    4.71 +                   Heap::Tenure tenure)
    4.72 +{
    4.73 +    Local<Array> array(zone, Array::cast(zone->allocate(map, sizeof(Array), tenure)));
    4.74 +    if (!array)
    4.75 +        return NULL;
    4.76 +
    4.77 +    array->nelements_ = nelements;
    4.78 +    array->elements_ = buffer;
    4.79 +    return array;
    4.80 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/Array.h	Tue Jul 24 23:53:34 2012 -0700
     5.3 @@ -0,0 +1,204 @@
     5.4 +/*
     5.5 + * Copyright (C) 2012 David Anderson
     5.6 + *
     5.7 + * This file is part of JITCraft.
     5.8 + *
     5.9 + * JITCraft is free software: you can redistribute it and/or modify it under
    5.10 + * the terms of the GNU General Public License as published by the Free
    5.11 + * Software Foundation, either version 3 of the License, or (at your option)
    5.12 + * any later version.
    5.13 + * 
    5.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    5.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    5.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    5.17 + *
    5.18 + * You should have received a copy of the GNU General Public License along with
    5.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
    5.20 + */
    5.21 +#ifndef _include_jitcraft_array_h_
    5.22 +#define _include_jitcraft_array_h_
    5.23 +
    5.24 +#include "Heap.h"
    5.25 +#include "Handles.h"
    5.26 +#include "Types.h"
    5.27 +
    5.28 +namespace ke {
    5.29 +
    5.30 +class ArrayMap;
    5.31 +
    5.32 +class Array : public Object
    5.33 +{
    5.34 +    friend class ArrayMap;
    5.35 +
    5.36 +    uint32 nelements_;
    5.37 +    void *elements_;
    5.38 +
    5.39 +  public:
    5.40 +    static Array *New(Zone *zone, Handle<ArrayMap> map, uint32 elements,
    5.41 +                      Heap::Tenure = Heap::Tenure_Default);
    5.42 +    static Array *NewExternal(Zone *zone, Handle<ArrayMap> map, uint32 nelements,
    5.43 +                              void *elements, Heap::Tenure = Heap::Tenure_Default);
    5.44 +
    5.45 +    uint32 nelements() {
    5.46 +        return nelements_;
    5.47 +    }
    5.48 +    void *vec() {
    5.49 +        return elements_;
    5.50 +    }
    5.51 +
    5.52 +    inline int *int32Vec();
    5.53 +    inline float *floatVec();
    5.54 +    inline Object **objVec();
    5.55 +    inline char *chars();
    5.56 +
    5.57 +    inline Type *type();
    5.58 +    inline size_t elementSize();
    5.59 +
    5.60 +    int readInt32(size_t index) {
    5.61 +        assert(index < nelements());
    5.62 +        return int32Vec()[index];
    5.63 +    }
    5.64 +    void writeInt32(size_t index, int i) {
    5.65 +        assert(index < nelements());
    5.66 +        int32Vec()[index] = i;
    5.67 +    }
    5.68 +    char readChar(size_t index) {
    5.69 +        assert(index < nelements());
    5.70 +        return chars()[index];
    5.71 +    }
    5.72 +    void writeChar(size_t index, char c) {
    5.73 +        assert(index < nelements());
    5.74 +        chars()[index] = c;
    5.75 +    }
    5.76 +    float readFloat(size_t index) {
    5.77 +        assert(index < nelements());
    5.78 +        return floatVec()[index];
    5.79 +    }
    5.80 +    void writeFloat(size_t index, float f) {
    5.81 +        assert(index < nelements());
    5.82 +        floatVec()[index] = f;
    5.83 +    }
    5.84 +    inline void *slotPtr(size_t index);
    5.85 +    Object *readObject(size_t index) {
    5.86 +        assert(index < nelements());
    5.87 +        return objVec()[index];
    5.88 +    }
    5.89 +    void writeObject(Zone *zone, size_t index, Object *ptr) {
    5.90 +        assert(index < nelements());
    5.91 +        write(zone, &objVec()[index], ptr);
    5.92 +    }
    5.93 +
    5.94 +    bool isExternal() {
    5.95 +        // Inline arrays always have their elements pointing at the next slot.
    5.96 +        Address buffer = reinterpret_cast<Address>(elements_);
    5.97 +        return buffer != reinterpret_cast<Address>(this + 1);
    5.98 +    }
    5.99 +
   5.100 +    static inline size_t SizeOf(Array *array) {
   5.101 +        if (array->isExternal())
   5.102 +            return sizeof(Array);
   5.103 +        return sizeof(Array) + array->nelements() * array->elementSize();
   5.104 +    }
   5.105 +
   5.106 +    static Array *cast(Object *obj) {
   5.107 +        assert(!obj || obj->is(MapKind_Array));
   5.108 +        return reinterpret_cast<Array *>(obj);
   5.109 +    }
   5.110 +};
   5.111 +
   5.112 +class ArrayMap : public Map
   5.113 +{
   5.114 +    Barriered<Type> type_;
   5.115 +    Barriered<ArrayMap> contained_;
   5.116 +
   5.117 +  public:
   5.118 +    static ArrayMap *New(Zone *zone, Handle<Type> type, Handle<ArrayMap> contained);
   5.119 +
   5.120 +    Type *type() {
   5.121 +        return type_;
   5.122 +    }
   5.123 +    ArrayMap *contained() {
   5.124 +        return contained_;
   5.125 +    }
   5.126 +
   5.127 +    // GC Descriptor.
   5.128 +    static inline size_t offsetOfType() {
   5.129 +        return offsetof(ArrayMap, type_);
   5.130 +    }
   5.131 +    static inline size_t offsetOfContained() {
   5.132 +        return offsetof(ArrayMap, contained_);
   5.133 +    }
   5.134 +    // End GC Descriptor.
   5.135 +    
   5.136 +    static ArrayMap *cast(Object *obj) {
   5.137 +        assert(!obj || obj->is(MapKind_MetaArray));
   5.138 +        return reinterpret_cast<ArrayMap *>(obj);
   5.139 +    }
   5.140 +};
   5.141 +
   5.142 +inline int *
   5.143 +Array::int32Vec()
   5.144 +{
   5.145 +    assert(type()->levels() == 1);
   5.146 +    assert(type()->contained()->isInt32());
   5.147 +    return reinterpret_cast<int *>(vec());
   5.148 +}
   5.149 +
   5.150 +inline float *
   5.151 +Array::floatVec()
   5.152 +{
   5.153 +    assert(type()->levels() == 1);
   5.154 +    assert(type()->contained()->isFloat());
   5.155 +    return reinterpret_cast<float *>(vec());
   5.156 +}
   5.157 +
   5.158 +inline Object **
   5.159 +Array::objVec()
   5.160 +{
   5.161 +    assert(type()->levels() > 1);
   5.162 +    return reinterpret_cast<Object **>(vec());
   5.163 +}
   5.164 +
   5.165 +inline void *
   5.166 +Array::slotPtr(size_t index)
   5.167 +{
   5.168 +    assert(type()->contained()->primitive() == PrimitiveType_Int32 ||
   5.169 +           type()->contained()->primitive() == PrimitiveType_Float);
   5.170 +    assert(index < nelements());
   5.171 +    return reinterpret_cast<int *>(vec()) + index;
   5.172 +}
   5.173 +
   5.174 +inline char *
   5.175 +Array::chars()
   5.176 +{
   5.177 +    assert(type()->levels() == 1);
   5.178 +    assert(type()->contained()->primitive() == PrimitiveType_Char);
   5.179 +    return reinterpret_cast<char *>(vec());
   5.180 +}
   5.181 +
   5.182 +inline Type *
   5.183 +Array::type()
   5.184 +{
   5.185 +    return ArrayMap::cast(map())->type();
   5.186 +}
   5.187 +
   5.188 +inline size_t
   5.189 +Array::elementSize()
   5.190 +{
   5.191 +    assert(type()->isArray());
   5.192 +    if (type()->contained()->isArray())
   5.193 +        return sizeof(Object *);
   5.194 +    switch (type()->contained()->primitive()) {
   5.195 +      case PrimitiveType_Float:
   5.196 +        return sizeof(float);
   5.197 +      case PrimitiveType_Int32:
   5.198 +        return sizeof(int);
   5.199 +      default:
   5.200 +        assert(type()->contained()->primitive() == PrimitiveType_Char);
   5.201 +        return sizeof(char);
   5.202 +    }
   5.203 +}
   5.204 +
   5.205 +}
   5.206 +
   5.207 +#endif // _include_jitcraft_array_h_
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/Barriers.h	Tue Jul 24 23:53:34 2012 -0700
     6.3 @@ -0,0 +1,93 @@
     6.4 +/*
     6.5 + * Copyright (C) 2012 David Anderson
     6.6 + *
     6.7 + * This file is part of JITCraft.
     6.8 + *
     6.9 + * JITCraft is free software: you can redistribute it and/or modify it under
    6.10 + * the terms of the GNU General Public License as published by the Free
    6.11 + * Software Foundation, either version 3 of the License, or (at your option)
    6.12 + * any later version.
    6.13 + * 
    6.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    6.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    6.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    6.17 + *
    6.18 + * You should have received a copy of the GNU General Public License along with
    6.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
    6.20 + */
    6.21 +#ifndef _include_jitcraft_barriers_h_
    6.22 +#define _include_jitcraft_barriers_h_
    6.23 +
    6.24 +namespace ke {
    6.25 +
    6.26 +class Object;
    6.27 +
    6.28 +// Used to store unbarriered heap locations.
    6.29 +template <typename T>
    6.30 +class Unbarriered
    6.31 +{
    6.32 +    T *obj_;
    6.33 +
    6.34 +  public:
    6.35 +    Unbarriered()
    6.36 +      : obj_(NULL)
    6.37 +    {
    6.38 +    }
    6.39 +
    6.40 +    T *operator ->() const {
    6.41 +        return operator *();
    6.42 +    }
    6.43 +    T *operator *() const {
    6.44 +        return static_cast<T *>(obj_);
    6.45 +    }
    6.46 +    Unbarriered &operator =(T *obj) {
    6.47 +        obj_ = obj;
    6.48 +        return *this;
    6.49 +    }
    6.50 +    Object **address() {
    6.51 +        return reinterpret_cast<Object **>(&obj_);
    6.52 +    }
    6.53 +    operator bool () const {
    6.54 +        return !!obj_;
    6.55 +    }
    6.56 +    operator T*() const {
    6.57 +        return static_cast<T *>(obj_);
    6.58 +    }
    6.59 +};
    6.60 +
    6.61 +// Used to store unbarriered heap locations.
    6.62 +template <typename T>
    6.63 +class Barriered
    6.64 +{
    6.65 +    T *obj_;
    6.66 +
    6.67 +  public:
    6.68 +    Barriered()
    6.69 +      : obj_(NULL)
    6.70 +    {
    6.71 +    }
    6.72 +
    6.73 +    T *operator ->() const {
    6.74 +        return operator *();
    6.75 +    }
    6.76 +    T *operator *() const {
    6.77 +        return static_cast<T *>(obj_);
    6.78 +    }
    6.79 +    Barriered &operator =(T *obj) {
    6.80 +        obj_ = obj;
    6.81 +        return *this;
    6.82 +    }
    6.83 +    Object **addr() {
    6.84 +        return reinterpret_cast<Object **>(&obj_);
    6.85 +    }
    6.86 +    operator bool () const {
    6.87 +        return !!obj_;
    6.88 +    }
    6.89 +    operator T*() const {
    6.90 +        return static_cast<T *>(obj_);
    6.91 +    }
    6.92 +};
    6.93 +
    6.94 +}
    6.95 +
    6.96 +#endif // _include_jitcraft_barriers_h_
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/BytecodeCompiler.cpp	Tue Jul 24 23:53:34 2012 -0700
     7.3 @@ -0,0 +1,1096 @@
     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 "BytecodeCompiler.h"
    7.23 +#include "Scopes.h"
    7.24 +#include "Modules.h"
    7.25 +#include "Types.h"
    7.26 +#include "Array.h"
    7.27 +#include "Strings.h"
    7.28 +#include "Zone.h"
    7.29 +#include "Environments.h"
    7.30 +#include "Heap-inl.h"
    7.31 +
    7.32 +using namespace ke;
    7.33 +
    7.34 +typedef BytecodeEmitter::Label Label;
    7.35 +
    7.36 +#define __ emitter_.
    7.37 +
    7.38 +BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
    7.39 +  : zone_(zone),
    7.40 +    tree_(tree),
    7.41 +    emitter_(zone->pool()),
    7.42 +    moduleData_(module),
    7.43 +    locals_(NULL),
    7.44 +    scope_(NULL),
    7.45 +    loop_(NULL)
    7.46 +{
    7.47 +}
    7.48 +
    7.49 +static inline TokenKind
    7.50 +ToCompare(Expression *expr)
    7.51 +{
    7.52 +    if (expr->isBinaryExpression()) {
    7.53 +        BinaryExpression *b = expr->toBinaryExpression();
    7.54 +        if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
    7.55 +            return b->token();
    7.56 +    } else if (expr->isUnaryExpression()) {
    7.57 +        UnaryExpression *u = expr->toUnaryExpression();
    7.58 +        if (u->token() == TOK_NOT)
    7.59 +            return TOK_NOT;
    7.60 +    }
    7.61 +    return TOK_EOF;
    7.62 +}
    7.63 +
    7.64 +static inline Opcode
    7.65 +CompareTokenToJump(TokenKind kind)
    7.66 +{
    7.67 +    switch (kind) {
    7.68 +      case TOK_EQUALS:
    7.69 +        return OP_JEQ;
    7.70 +      case TOK_NOTEQUALS:
    7.71 +        return OP_JNE;
    7.72 +      case TOK_GT:
    7.73 +        return OP_JG;
    7.74 +      case TOK_GE:
    7.75 +        return OP_JGE;
    7.76 +      case TOK_LT:
    7.77 +        return OP_JL;
    7.78 +      default:
    7.79 +        assert(kind == TOK_LE);
    7.80 +        return OP_JLE;
    7.81 +    }
    7.82 +}
    7.83 +
    7.84 +static inline Opcode
    7.85 +TokenToOpcode(TokenKind kind)
    7.86 +{
    7.87 +    switch (kind) {
    7.88 +      case TOK_PLUS:
    7.89 +        return OP_ADD;
    7.90 +      case TOK_MINUS:
    7.91 +        return OP_SUB;
    7.92 +      case TOK_STAR:
    7.93 +        return OP_MUL;
    7.94 +      case TOK_SLASH:
    7.95 +        return OP_DIV;
    7.96 +      case TOK_PERCENT:
    7.97 +        return OP_MOD;
    7.98 +      case TOK_SHR:
    7.99 +        return OP_SHR;
   7.100 +      case TOK_USHR:
   7.101 +        return OP_USHR;
   7.102 +      case TOK_SHL:
   7.103 +        return OP_SHL;
   7.104 +      case TOK_BITAND:
   7.105 +        return OP_BITAND;
   7.106 +      case TOK_BITOR:
   7.107 +        return OP_BITOR;
   7.108 +      case TOK_GT:
   7.109 +          return OP_GT;
   7.110 +      case TOK_GE:
   7.111 +          return OP_GE;
   7.112 +      case TOK_LT:
   7.113 +          return OP_LT;
   7.114 +      case TOK_LE:
   7.115 +          return OP_LE;
   7.116 +      case TOK_EQUALS:
   7.117 +          return OP_EQ;
   7.118 +      case TOK_NOTEQUALS:
   7.119 +          return OP_NE;
   7.120 +      default:
   7.121 +        assert(kind == TOK_BITXOR);
   7.122 +        return OP_BITXOR;
   7.123 +    }
   7.124 +}
   7.125 +
   7.126 +void
   7.127 +BytecodeCompiler::recordLifoSlot(Scope *scope)
   7.128 +{
   7.129 +    if (!scope)
   7.130 +        return;
   7.131 +
   7.132 +    if (Variable *var = scope->lifoSlot()) {
   7.133 +        locals_->set(zone_, var->slot(), var->type());
   7.134 +        __ savelifo(var->slot());
   7.135 +    }
   7.136 +}
   7.137 +
   7.138 +void
   7.139 +BytecodeCompiler::unwindTo(Scope *scope)
   7.140 +{
   7.141 +    // Note: we only need to unwind to the outermost scope's LIFO slot.
   7.142 +    Variable *var = NULL;
   7.143 +    for (Scope *current = scope_; current != scope; current = current->enclosing()) {
   7.144 +        if (Variable *slot = current->lifoSlot())
   7.145 +            var = slot;
   7.146 +    }
   7.147 +
   7.148 +    if (var)
   7.149 +        __ unwindlifo(var->slot());
   7.150 +}
   7.151 +
   7.152 +void
   7.153 +BytecodeCompiler::visit(NameProxy *name)
   7.154 +{
   7.155 +    switch (name->binding()->kind()) {
   7.156 +      case BoundName::VARIABLE:
   7.157 +      {
   7.158 +        Variable *var = name->binding()->toVariable();
   7.159 +
   7.160 +        if (var->location() == Variable::STACK) {
   7.161 +            __ getlocal(var);
   7.162 +            assert(!name->type()->isReference());
   7.163 +        } else if (var->location() == Variable::ENVIRONMENT) {
   7.164 +            getEnvSlot(var);
   7.165 +        } else {
   7.166 +            assert(var->location() == Variable::PARAMETER);
   7.167 +            __ getarg(var);
   7.168 +
   7.169 +            // If this argument is actually a reference, dereference it now.
   7.170 +            if (var->type()->isReference())
   7.171 +                __ getref(var->type()->contained()->primitive());
   7.172 +        }
   7.173 +        break;
   7.174 +      }
   7.175 +
   7.176 +      case BoundName::FUNCTION:
   7.177 +      {
   7.178 +        NamedFunction *fun = name->binding()->toNamedFunction();
   7.179 +        __ module();
   7.180 +        __ getmodule_fn(fun->slot());
   7.181 +        break;
   7.182 +      }
   7.183 +
   7.184 +      default:
   7.185 +      {
   7.186 +        NamedConstant *constant = name->binding()->toNamedConstant();
   7.187 +        __ int_(constant->value().toInt());
   7.188 +        break;
   7.189 +      }
   7.190 +    }
   7.191 +}
   7.192 +
   7.193 +void
   7.194 +BytecodeCompiler::visit(ExpressionStatement *node)
   7.195 +{
   7.196 +    // Expressions leave their value on the top of the stack, so we make sure
   7.197 +    // to balance the stack if they're used as a statement.
   7.198 +    node->expression()->accept(this);
   7.199 +    if (!node->expression()->type()->isVoid())
   7.200 +        __ pop();
   7.201 +}
   7.202 +
   7.203 +void
   7.204 +BytecodeCompiler::visit(Assignment *node)
   7.205 +{
   7.206 +    // The first step is three sub-steps:
   7.207 +    //
   7.208 +    //   (1) Bind the left-hand side.
   7.209 +    //   -- If a cumulative operation (+=, etc):
   7.210 +    //   (2) Save a copy of the binding on the stack.
   7.211 +    //   (3) Dereference the binding to get a value.
   7.212 +    //
   7.213 +    if (node->lvalue()->isNameProxy()) {
   7.214 +        NameProxy *proxy = node->lvalue()->toNameProxy();
   7.215 +        Variable *var = proxy->binding()->toVariable();
   7.216 +
   7.217 +        // Bind.
   7.218 +        if (var->type()->isReference() || var->type()->isArray())
   7.219 +            __ get(var);
   7.220 +
   7.221 +        // Get the value if needed.
   7.222 +        if (node->token() != TOK_ASSIGN) {
   7.223 +            // += etc is not allowed on arrays.
   7.224 +            assert(!var->type()->isArray());
   7.225 +
   7.226 +            if (var->type()->isReference()) {
   7.227 +                __ dup();
   7.228 +                __ getref(var->type()->contained()->primitive());
   7.229 +            } else {
   7.230 +                __ get(var);
   7.231 +            }
   7.232 +        }
   7.233 +    } else {
   7.234 +        IndexExpression *index = node->lvalue()->toIndexExpression();
   7.235 +        __ note_position(index->pos());
   7.236 +
   7.237 +        // Note: Eventually, watch out for a whole here. An expression like:
   7.238 +        //
   7.239 +        //   (a[4] = (5, a = []))
   7.240 +        //
   7.241 +        // Could shrink array, so we need to either bind a[i] to a Reference,
   7.242 +        // or keep the bounds check near the set. This is just a semantic
   7.243 +        // decision.
   7.244 +        index->left()->accept(this);
   7.245 +        index->right()->accept(this);
   7.246 +
   7.247 +        if (node->token() != TOK_ASSIGN) {
   7.248 +            __ dup2();
   7.249 +            __ bounds();
   7.250 +            if (node->type()->isArray())
   7.251 +                __ getarray_o();
   7.252 +            else
   7.253 +                __ getarray(node->type()->primitive());
   7.254 +        }
   7.255 +    }
   7.256 +
   7.257 +    if (node->token() == TOK_ASSIGN) {
   7.258 +        node->expression()->accept(this);
   7.259 +    } else {
   7.260 +        visitForALU(node->type(), node->expression());
   7.261 +
   7.262 +        TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
   7.263 +        __ note_position(node->pos());
   7.264 +        __ binary(TokenToOpcode(alu));
   7.265 +    }
   7.266 +
   7.267 +    // Emit the store.
   7.268 +    if (node->expression()->type()->isArray()) {
   7.269 +        // Unlike references, which can only be computed from a NamePRoxy,
   7.270 +        // arrays can be computed from multiple lvalue types.
   7.271 +        __ note_position(node->pos());
   7.272 +        __ arraycopy();
   7.273 +    } else if (node->lvalue()->isNameProxy()) {
   7.274 +        NameProxy *proxy = node->lvalue()->toNameProxy();
   7.275 +        Variable *var = proxy->binding()->toVariable();
   7.276 +
   7.277 +        if (var->type()->isReference())
   7.278 +            __ setref(var->type()->contained()->primitive());
   7.279 +        else
   7.280 +            __ set(var);
   7.281 +    } else {
   7.282 +        IndexExpression *index = node->lvalue()->toIndexExpression();
   7.283 +        // :TODO: get rid of the BOUNDS instruction, embed it in g/setarray*?
   7.284 +        // We can't emit it here because the stack is slightly out of position.
   7.285 +        // __ bounds();
   7.286 +        __ setarray(index->left()->type()->contained()->primitive());
   7.287 +    }
   7.288 +}
   7.289 +
   7.290 +void
   7.291 +BytecodeCompiler::visit(IncDecExpression *node)
   7.292 +{
   7.293 +    // In the postfix case, the logic looks like:
   7.294 +    //      (1) Bind       -> REF
   7.295 +    //      (2) Dup        -> REF REF
   7.296 +    //      (3) Fetch      -> REF VAL
   7.297 +    //      (4) Swap       -> VAL REF
   7.298 +    //      (5) Pick       -> VAL REF VAL
   7.299 +    //      (6) Add        -> VAL REF VAL+1
   7.300 +    //      (7) Store      -> VAL VAL+1
   7.301 +    //      (8) Drop       -> VAL
   7.302 +    //
   7.303 +    // In the prefix case, the logic looks like:
   7.304 +    //      (1) Bind       -> REF
   7.305 +    //      (2) Dup        -> REF REF
   7.306 +    //      (3) Fetch      -> REF VAL
   7.307 +    //      --
   7.308 +    //      --
   7.309 +    //      (6) Add        -> REF VAL+1
   7.310 +    //      (7) Store      -> VAL+1
   7.311 +    //      --
   7.312 +    //
   7.313 +    // This is squirrely enough such that we don't bother sharing too much
   7.314 +    // with the above.
   7.315 +    // 
   7.316 +    // Note: We simulate a "Pick" operation with a dup2+pop.
   7.317 +
   7.318 +    // This is steps (1) to (5).
   7.319 +    Expression *expr = node->expression();
   7.320 +    if (expr->isNameProxy()) {
   7.321 +        NameProxy *proxy = expr->toNameProxy();
   7.322 +        Variable *var = proxy->binding()->toVariable();
   7.323 +
   7.324 +        // Bind.
   7.325 +        if (var->type()->isReference() || var->type()->isArray())
   7.326 +            __ get(var);
   7.327 +
   7.328 +        // Dup and fetch.
   7.329 +        if (var->type()->isReference()) {
   7.330 +            __ dup();
   7.331 +            __ getref(node->type()->primitive());
   7.332 +            if (node->postfix()) {
   7.333 +                __ swap();
   7.334 +                __ pick2();
   7.335 +            }
   7.336 +        } else {
   7.337 +            assert(!var->type()->isArray());
   7.338 +            __ get(var);
   7.339 +            if (node->postfix())
   7.340 +                __ dup();
   7.341 +        }
   7.342 +    } else {
   7.343 +        IndexExpression *index = expr->toIndexExpression();
   7.344 +        __ note_position(index->pos());
   7.345 +
   7.346 +        index->left()->accept(this);
   7.347 +        index->right()->accept(this);
   7.348 +
   7.349 +        assert(!node->type()->isArray());
   7.350 +        __ bounds();
   7.351 +        __ dup2();
   7.352 +        __ getarray(node->type()->primitive());
   7.353 +
   7.354 +        if (node->postfix()) {
   7.355 +            // The stack looks like this now:
   7.356 +            // ARRAY INDEX VALUE
   7.357 +            //
   7.358 +            // So we must use a PICK operation to rotate the stack into position.
   7.359 +            __ roll3();         // INDEX VALUE ARRAY
   7.360 +            __ roll3();         // VALUE ARRAY INDEX
   7.361 +            __ pick3();         // VALUE ARRAY INDEX VALUE
   7.362 +        }
   7.363 +    }
   7.364 +
   7.365 +    // Perform step (6).
   7.366 +    if (node->type()->isFloat()) {
   7.367 +        __ float_(1.0);
   7.368 +    } else {
   7.369 +        assert(node->type()->isInt32());
   7.370 +        __ int_(1);
   7.371 +    }
   7.372 +
   7.373 +    __ note_position(node->pos());
   7.374 +    if (node->token() == TOK_INCREMENT)
   7.375 +        __ binary(OP_ADD);
   7.376 +    else
   7.377 +        __ binary(OP_SUB);
   7.378 +
   7.379 +    // Perform step (7).
   7.380 +    if (expr->isNameProxy()) {
   7.381 +        NameProxy *proxy = expr->toNameProxy();
   7.382 +        Variable *var = proxy->binding()->toVariable();
   7.383 +
   7.384 +        if (var->type()->isReference())
   7.385 +            __ setref(node->type()->primitive());
   7.386 +        else
   7.387 +            __ set(var);
   7.388 +    } else {
   7.389 +        __ setarray(node->type()->primitive());
   7.390 +    }
   7.391 +
   7.392 +    // Perform step (8).
   7.393 +    if (node->postfix())
   7.394 +        __ pop();
   7.395 +}
   7.396 +
   7.397 +void
   7.398 +BytecodeCompiler::visitForALU(Type *needed, Expression *node)
   7.399 +{
   7.400 +    node->accept(this);
   7.401 +    if (needed->isFloat() && !node->type()->isFloat())
   7.402 +        __ cvt_i2f();
   7.403 +    else
   7.404 +        assert(needed->primitive() == node->type()->primitive());
   7.405 +}
   7.406 +
   7.407 +static inline Type *
   7.408 +GetCoercionType(TokenKind tok, Type *left, Type *right)
   7.409 +{
   7.410 +    if (left->isFloat())
   7.411 +        return left;
   7.412 +    return right;
   7.413 +}
   7.414 +
   7.415 +void
   7.416 +BytecodeCompiler::visit(UnaryExpression *node)
   7.417 +{
   7.418 +    switch (node->token()) {
   7.419 +      case TOK_MINUS:
   7.420 +      {
   7.421 +        Local<Type> type(zone_, node->expression()->type());
   7.422 +        node->expression()->accept(this);
   7.423 +        
   7.424 +        if (node->type()->isFloat())
   7.425 +            __ neg_f();
   7.426 +        else
   7.427 +            __ neg();
   7.428 +        break;
   7.429 +      }
   7.430 +
   7.431 +      case TOK_NOT:
   7.432 +      {
   7.433 +        Local<Type> type(zone_, node->expression()->type());
   7.434 +        node->expression()->accept(this);
   7.435 +        
   7.436 +        if (node->type()->isFloat())
   7.437 +            __ not_f();
   7.438 +        else
   7.439 +            __ not_();
   7.440 +        break;
   7.441 +      }
   7.442 +
   7.443 +      default:
   7.444 +        assert(node->token() == TOK_TILDE);
   7.445 +        node->expression()->accept(this);
   7.446 +        __ bitnot();
   7.447 +        break;
   7.448 +    }
   7.449 +}
   7.450 +
   7.451 +void
   7.452 +BytecodeCompiler::visit(BinaryExpression *node)
   7.453 +{
   7.454 +    if (node->token() == TOK_AND || node->token() == TOK_OR) {
   7.455 +        Label success, failure, done;
   7.456 +        visitForTest(node, &success, &failure, &success);
   7.457 +        __ bind(&success);
   7.458 +        __ int_(1);
   7.459 +        __ drop(1);         // Otherwise, the stack depth will be +1 too much.
   7.460 +        __ jump(&done);
   7.461 +        __ bind(&failure);
   7.462 +        __ int_(0);
   7.463 +        __ bind(&done);
   7.464 +        return;
   7.465 +    }
   7.466 +
   7.467 +    Local<Type> leftType(zone_, node->left()->type());
   7.468 +    Local<Type> rightType(zone_, node->right()->type());
   7.469 +    Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
   7.470 +
   7.471 +    visitForALU(coerce, node->left());
   7.472 +    visitForALU(coerce, node->right());
   7.473 +
   7.474 +    Opcode op = TokenToOpcode(node->token());
   7.475 +    if (node->type()->isFloat())
   7.476 +        op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
   7.477 +
   7.478 +    __ note_position(node->pos());
   7.479 +    __ binary(op);
   7.480 +}
   7.481 +
   7.482 +void
   7.483 +BytecodeCompiler::visit(IndexExpression *node)
   7.484 +{
   7.485 +    node->left()->accept(this);
   7.486 +    node->right()->accept(this);
   7.487 +    __ note_position(node->pos());
   7.488 +    __ bounds();
   7.489 +
   7.490 +    if (node->type()->isArray())
   7.491 +        __ getarray_o();
   7.492 +    else
   7.493 +        __ getarray(node->type()->primitive());
   7.494 +}
   7.495 +
   7.496 +void
   7.497 +BytecodeCompiler::visit(ReturnStatement *node)
   7.498 +{
   7.499 +    if (node->expression()) {
   7.500 +        node->expression()->accept(this);
   7.501 +        __ return_();
   7.502 +    } else {
   7.503 +        __ returnvoid();
   7.504 +    }
   7.505 +}
   7.506 +
   7.507 +void
   7.508 +BytecodeCompiler::visitForTest(Expression *expression,
   7.509 +                               Label *trueBranch,
   7.510 +                               Label *falseBranch,
   7.511 +                               Label *fallthrough)
   7.512 +{
   7.513 +    TokenKind token = ToCompare(expression);
   7.514 +    if (token == TOK_EOF || token == TOK_NOT) {
   7.515 +        if (token == TOK_EOF)
   7.516 +            expression->accept(this);
   7.517 +        else
   7.518 +            expression->toUnaryExpression()->expression()->accept(this);
   7.519 +        
   7.520 +        bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
   7.521 +
   7.522 +        Opcode op = jumpOnTrue ? OP_JT : OP_JF;
   7.523 +        if (expression->type()->isFloat())
   7.524 +            op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
   7.525 +
   7.526 +        if (fallthrough == falseBranch)
   7.527 +            __ j(op, trueBranch);
   7.528 +        else
   7.529 +            __ j(op, falseBranch); 
   7.530 +        return;
   7.531 +    }
   7.532 +
   7.533 +    BinaryExpression *binary = expression->toBinaryExpression();
   7.534 +
   7.535 +    if (token == TOK_AND || token == TOK_OR) {
   7.536 +        Label next;
   7.537 +        if (token == TOK_AND)
   7.538 +            visitForTest(binary->left(), &next, falseBranch, &next);
   7.539 +        else
   7.540 +            visitForTest(binary->left(), trueBranch, &next, &next);
   7.541 +        __ bind(&next);
   7.542 +        visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
   7.543 +        return;
   7.544 +    }
   7.545 +
   7.546 +    Opcode op = CompareTokenToJump(token);
   7.547 +    if (fallthrough == trueBranch)
   7.548 +        op = Invert(op);
   7.549 +
   7.550 +    Local<Type> leftType(zone_, binary->left()->type());
   7.551 +    Local<Type> rightType(zone_, binary->right()->type());
   7.552 +    Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
   7.553 +
   7.554 +    visitForALU(coerce, binary->left());
   7.555 +    visitForALU(coerce, binary->right());
   7.556 +    if (coerce->isFloat())
   7.557 +        op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
   7.558 +
   7.559 +    if (fallthrough == trueBranch)
   7.560 +        __ j(op, falseBranch);
   7.561 +    else
   7.562 +        __ j(op, trueBranch);
   7.563 +}
   7.564 +
   7.565 +void
   7.566 +BytecodeCompiler::visit(ForStatement *node)
   7.567 +{
   7.568 +    AutoEnterScope forScope(this, node->scope());
   7.569 +
   7.570 +    recordLifoSlot(node->scope());
   7.571 +
   7.572 +    Label join, update;
   7.573 +    LoopScope loop(scope_, &join, &update, &loop_);
   7.574 +
   7.575 +    if (node->initialization())
   7.576 +        node->initialization()->accept(this);
   7.577 +
   7.578 +    Label header, test;
   7.579 +    if (node->condition())
   7.580 +        __ jump(&test);
   7.581 +
   7.582 +    __ bind(&header);
   7.583 +    node->body()->accept(this);
   7.584 +
   7.585 +    __ bind(&update);
   7.586 +    if (node->update())
   7.587 +        node->update()->accept(this);
   7.588 +
   7.589 +    if (node->condition()) {
   7.590 +        __ bind(&test);
   7.591 +        visitForTest(node->condition(), &header, &join, &join);
   7.592 +    } else {
   7.593 +        __ jump(&header);
   7.594 +    }
   7.595 +
   7.596 +    __ bind(&join);
   7.597 +
   7.598 +    if (node->scope())
   7.599 +        unwindTo(node->scope()->enclosing());
   7.600 +    assert(__ stackDepth() == 0);
   7.601 +}
   7.602 +
   7.603 +void
   7.604 +BytecodeCompiler::visit(WhileStatement *node)
   7.605 +{
   7.606 +    Label header, join;
   7.607 +
   7.608 +    __ bind(&header);
   7.609 +
   7.610 +    LoopScope loop(scope_, &join, &header, &loop_);
   7.611 +
   7.612 +    if (node->token() == TOK_WHILE) {
   7.613 +        Label body;
   7.614 +
   7.615 +        visitForTest(node->condition(), &body, &join, &body);
   7.616 +        __ bind(&body);
   7.617 +        node->body()->accept(this);
   7.618 +        __ jump(&header);
   7.619 +    } else {
   7.620 +        node->body()->accept(this);
   7.621 +        visitForTest(node->condition(), &header, &join, &join);
   7.622 +    }
   7.623 +
   7.624 +    __ bind(&join);
   7.625 +}
   7.626 +
   7.627 +void
   7.628 +BytecodeCompiler::visit(BreakStatement *node)
   7.629 +{
   7.630 +    unwindTo(loop_->scope());
   7.631 +    __ jump(loop_->break_());
   7.632 +}
   7.633 +
   7.634 +void
   7.635 +BytecodeCompiler::visit(ContinueStatement *node)
   7.636 +{
   7.637 +    unwindTo(loop_->scope());
   7.638 +    __ jump(loop_->continue_());
   7.639 +}
   7.640 +
   7.641 +void
   7.642 +BytecodeCompiler::visit(BlockStatement *node)
   7.643 +{
   7.644 +    AutoEnterScope blockScope(this, node->scope());
   7.645 +
   7.646 +    recordLifoSlot(node->scope());
   7.647 +
   7.648 +    for (size_t i = 0; i < node->statements()->length(); i++) {
   7.649 +        Statement *statement = node->statements()->at(i);
   7.650 +        statement->accept(this);
   7.651 +        assert(__ stackDepth() == 0);
   7.652 +    }
   7.653 +
   7.654 +    // We don't bother emitting an "unwind" instruction for function scopes,
   7.655 +    // since this is taken care of by the calling convention.
   7.656 +    if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
   7.657 +        unwindTo(node->scope()->enclosing());
   7.658 +}
   7.659 +
   7.660 +void
   7.661 +BytecodeCompiler::visit(IntegerLiteral *node)
   7.662 +{
   7.663 +    __ int_(node->value());
   7.664 +}
   7.665 +
   7.666 +void
   7.667 +BytecodeCompiler::visit(FloatLiteral *node)
   7.668 +{
   7.669 +    __ float_((float)node->value());
   7.670 +}
   7.671 +
   7.672 +static inline ArrayMap *
   7.673 +BuildArrayMap(Zone *zone, Handle<Type> type)
   7.674 +{
   7.675 +    Local<ArrayMap> contained(zone);
   7.676 +    if (type->levels() > 1) {
   7.677 +        Local<Type> containedType(zone, type->contained());
   7.678 +        contained = BuildArrayMap(zone, containedType);
   7.679 +        if (!contained)
   7.680 +            return NULL;
   7.681 +    }
   7.682 +
   7.683 +    return ArrayMap::New(zone, type, contained);
   7.684 +}
   7.685 +
   7.686 +void
   7.687 +BytecodeCompiler::visit(StringLiteral *node)
   7.688 +{
   7.689 +    Local<Type> type(zone_, node->type());
   7.690 +    Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
   7.691 +    if (!map)
   7.692 +        return;
   7.693 +
   7.694 +    Local<Array> array(zone_, Array::New(zone_, map, node->string()->length(), Heap::Tenure_Old));
   7.695 +    if (!array)
   7.696 +        return;
   7.697 +
   7.698 +    assert(array->nelements() >= node->string()->length());
   7.699 +    memcpy(array->chars(), node->string()->raw(), node->string()->length() * sizeof(char));
   7.700 +
   7.701 +    __ note_position(node->pos());
   7.702 +    __ object(array);
   7.703 +}
   7.704 +
   7.705 +void
   7.706 +BytecodeCompiler::getEnvSlot(Variable *var)
   7.707 +{
   7.708 +    assert(var->scope()->kind() == Scope::GLOBAL);
   7.709 +    __ getglobal(var);
   7.710 +}
   7.711 +
   7.712 +void
   7.713 +BytecodeCompiler::setEnvSlot(Variable *var)
   7.714 +{
   7.715 +    assert(var->scope()->kind() == Scope::GLOBAL);
   7.716 +    __ setglobal(var);
   7.717 +}
   7.718 +
   7.719 +void
   7.720 +BytecodeCompiler::visit(VariableDeclaration *node)
   7.721 +{
   7.722 +    Variable *var = node->variable();
   7.723 +    
   7.724 +    Local<Type> type(zone_, var->type());
   7.725 +    if (type->isArray()) {
   7.726 +        Local<ArrayMap> map(zone_, BuildArrayMap(zone_, type));
   7.727 +        __ note_position(node->pos());
   7.728 +        if (var->scope()->kind() == Scope::GLOBAL)
   7.729 +            __ newarray(map, Heap::Tenure_Old);
   7.730 +        else if (var->needsHeapAllocation())
   7.731 +            __ newarray(map, Heap::Tenure_Default);
   7.732 +        else
   7.733 +            __ newarray(map, Heap::Tenure_Stack);
   7.734 +
   7.735 +        if (node->initialization()) {
   7.736 +            node->initialization()->accept(this);
   7.737 +            __ note_position(node->pos());
   7.738 +            __ arraycopy();
   7.739 +        }
   7.740 +    } else {
   7.741 +        if (node->initialization()) {
   7.742 +            node->initialization()->accept(this);
   7.743 +        } else {
   7.744 +            if (!node->postDimensions())
   7.745 +                __ int_(0);
   7.746 +        }
   7.747 +    }
   7.748 +
   7.749 +    if (var->location() == Variable::STACK) {
   7.750 +        __ setlocal(var);
   7.751 +        locals_->set(zone_, var->slot(), var->type());
   7.752 +    } else {
   7.753 +        assert(var->location() == Variable::ENVIRONMENT);
   7.754 +        setEnvSlot(var);
   7.755 +    }
   7.756 +
   7.757 +    __ pop();
   7.758 +}
   7.759 +
   7.760 +void
   7.761 +BytecodeCompiler::visit(CallExpression *node)
   7.762 +{
   7.763 +    Local<Type> funType(zone_, node->callee()->type());
   7.764 +
   7.765 +    // Sniff out natives, which have a specific opcode and are guaranteed to
   7.766 +    // be called via name proxy.
   7.767 +    NamedFunction *native = NULL;
   7.768 +    if (funType->isNative()) {
   7.769 +        native = node->callee()->toNameProxy()->binding()->toNamedFunction();
   7.770 +    }
   7.771 +
   7.772 +    for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
   7.773 +        Expression *arg = node->arguments()->at(i);
   7.774 +
   7.775 +        // We need to compute a reference if the parameter was in the form:
   7.776 +        //  f(&a)
   7.777 +        // Note this form does not allow: f({})
   7.778 +        // 
   7.779 +        // We also need to compute references for all variadic native
   7.780 +        // arguments, but arrays and references are already in the
   7.781 +        // appropriate form.
   7.782 +        Local<Type> given(zone_, arg->type());
   7.783 +        bool mustPushReference = false;
   7.784 +        if (i >= funType->parameters()->length()) {
   7.785 +            assert(funType->isNative() && funType->isNativeVariadic());
   7.786 +            mustPushReference = !given->isArray() && !given->isReference();
   7.787 +        } else if (funType->parameterAt(i)->isReference()) {
   7.788 +            mustPushReference = !given->isReference();
   7.789 +        }
   7.790 +
   7.791 +        // If a native is passed to a native, it must only be one level deep.
   7.792 +        assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
   7.793 +
   7.794 +        if (mustPushReference) {
   7.795 +            if (arg->isNameProxy()) {
   7.796 +                // :TODO: test with functions and globals
   7.797 +                // Compute a reference to the name.
   7.798 +                Variable *var = arg->toNameProxy()->binding()->toVariable();
   7.799 +                __ note_position(node->pos());
   7.800 +                __ newref(var);
   7.801 +            } else if (arg->isIndexExpression()) {
   7.802 +                IndexExpression *expr = arg->toIndexExpression();
   7.803 +                expr->left()->accept(this);
   7.804 +                expr->right()->accept(this);
   7.805 +                __ note_position(expr->pos());
   7.806 +                __ bounds();
   7.807 +                __ arrayref_lifo();
   7.808 +            } else {
   7.809 +                // We don't know how to, or can't, build a direct reference to
   7.810 +                // this type. Make an indirect one, by taking the top of the
   7.811 +                // stack and boxing it up.
   7.812 +                arg->accept(this);
   7.813 +                __ note_position(node->pos());
   7.814 +                __ slotref_lifo();
   7.815 +            }
   7.816 +        } else {
   7.817 +            arg->accept(this);
   7.818 +        }
   7.819 +    }
   7.820 +
   7.821 +    __ note_position(node->pos());
   7.822 +    if (native) {
   7.823 +        __ callnative(native->slot(), node->arguments()->length());
   7.824 +        __ drop(node->arguments()->length());
   7.825 +    } else {
   7.826 +        node->callee()->accept(this);
   7.827 +        __ call(funType);
   7.828 +        __ drop(node->arguments()->length() + 1);
   7.829 +    }
   7.830 +}
   7.831 +
   7.832 +void
   7.833 +BytecodeCompiler::visit(TernaryExpression *node)
   7.834 +{
   7.835 +    Label success, failure, join;
   7.836 +
   7.837 +    visitForTest(node->condition(), &success, &failure, &success);
   7.838 +    __ bind(&success);
   7.839 +    node->left()->accept(this);
   7.840 +    __ drop(1);
   7.841 +    __ jump(&join);
   7.842 +    __ bind(&failure);
   7.843 +    node->right()->accept(this);
   7.844 +    __ bind(&join);
   7.845 +}
   7.846 +
   7.847 +void
   7.848 +BytecodeCompiler::visit(IfStatement *node)
   7.849 +{
   7.850 +    Label join;
   7.851 +    if (!node->ifFalse()) {
   7.852 +        Label success;
   7.853 +
   7.854 +        visitForTest(node->condition(), &success, &join, &success);
   7.855 +        __ bind(&success);
   7.856 +        node->ifTrue()->accept(this);
   7.857 +    } else {
   7.858 +        Label success, next;
   7.859 +
   7.860 +        visitForTest(node->condition(), &success, &next, &success);
   7.861 +        __ bind(&success);
   7.862 +        node->ifTrue()->accept(this);
   7.863 +        __ jump(&join);
   7.864 +        __ bind(&next);
   7.865 +        node->ifFalse()->accept(this);
   7.866 +    }
   7.867 +
   7.868 +    __ bind(&join);
   7.869 +}
   7.870 +
   7.871 +void
   7.872 +BytecodeCompiler::visit(FunctionStatement *node)
   7.873 +{
   7.874 +    if (node->fun()->isNative()) {
   7.875 +        assert(!moduleData_->natives->at(node->fun()->slot()));
   7.876 +
   7.877 +        Local<Type> type(zone_, node->fun()->type());
   7.878 +        Local<String> name(zone_, node->fun()->name());
   7.879 +        Local<Native> native(zone_, Native::New(zone_, type, name));
   7.880 +        if (!native)
   7.881 +            return;
   7.882 +
   7.883 +        moduleData_->natives->set(zone_, node->fun()->slot(), native);
   7.884 +        return;
   7.885 +    }
   7.886 +
   7.887 +    // If the function has no body, then it's just a declaration.
   7.888 +    if (!node->body()) {
   7.889 +        assert(node->fun()->isForward() || node->fun()->isPublic());
   7.890 +        return;
   7.891 +    }
   7.892 +
   7.893 +    BytecodeCompiler child(zone_, tree_, moduleData_);
   7.894 +    Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
   7.895 +    if (!fun)
   7.896 +        return;
   7.897 +    
   7.898 +    assert(!moduleData_->module->getFunction(node->fun()->slot()));
   7.899 +    moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
   7.900 +}
   7.901 +
   7.902 +void
   7.903 +BytecodeCompiler::visit(EnumStatement *node)
   7.904 +{
   7.905 +    // :TODO: eventually, we'll export these.
   7.906 +}
   7.907 +
   7.908 +Code *
   7.909 +BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
   7.910 +{
   7.911 +    // STOP doubles as RETURNVOID.
   7.912 +    __ stop();
   7.913 +
   7.914 +    if (__ oom() || zone_->hasPendingException())
   7.915 +        return NULL;
   7.916 +
   7.917 +    Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
   7.918 +    if (!bytes)
   7.919 +        return NULL;
   7.920 +    memcpy(bytes->raw(), __ buffer(), __ length());
   7.921 +
   7.922 +    for (size_t i = 0; i < scope->maxContainedLocals(); i++)
   7.923 +        assert(locals_->at(i));
   7.924 +
   7.925 +    Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
   7.926 +    if (!objects)
   7.927 +        return NULL;
   7.928 +
   7.929 +    for (size_t i = 0; i < __ objects()->length(); i++)
   7.930 +        objects->set(zone_, i, *(__ objects()->at(i)));
   7.931 +
   7.932 +    Local<ByteArray> safepoints(zone_);
   7.933 +
   7.934 +    // If any stack slots hold gc pointers at potential failure points in the
   7.935 +    // bytecode, record them now. We do this by building a list of tuples;
   7.936 +    // each tuple contains the pc offset, and a bitset containing which stack
   7.937 +    // slots must be scanned by the gc.
   7.938 +    if (__ oopRecords()->length()) {
   7.939 +        size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
   7.940 +        size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
   7.941 +        safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
   7.942 +        if (!safepoints)
   7.943 +            return NULL;
   7.944 +
   7.945 +        Address cursor = safepoints->raw();
   7.946 +        for (size_t i = 0; i < __ oopRecords()->length(); i++) {
   7.947 +            OopRecord *record = __ oopRecords()->at(i);
   7.948 +            assert(record->depth <= __ maxStackDepth());
   7.949 +
   7.950 +            *reinterpret_cast<unsigned *>(cursor) = record->offset;
   7.951 +
   7.952 +            unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
   7.953 +            for (unsigned i = 0; i < record->depth; i++)
   7.954 +                bits[i / 8] |= (1 << (i % 8));
   7.955 +
   7.956 +            cursor += bytesPerSafepoint;
   7.957 +        }
   7.958 +
   7.959 +        assert(cursor == safepoints->raw() + gcmapSize);
   7.960 +    }
   7.961 +
   7.962 +    Local<ByteArray> sourcemap(zone_);
   7.963 +    if (__ sourcemapLength()) {
   7.964 +        sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
   7.965 +        if (!sourcemap)
   7.966 +            return NULL;
   7.967 +
   7.968 +        memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
   7.969 +    }
   7.970 +
   7.971 +    Local<Code> code(zone_);
   7.972 +
   7.973 +    code = Code::New(zone_,
   7.974 +                     bytes,
   7.975 +                     locals_,
   7.976 +                     objects,
   7.977 +                     __ maxStackDepth(),
   7.978 +                     moduleData_->module,
   7.979 +                     safepoints,
   7.980 +                     sourcemap,
   7.981 +                     lineno);
   7.982 +    return code;
   7.983 +}
   7.984 +
   7.985 +Function *
   7.986 +BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
   7.987 +{
   7.988 +    // Note: No need to record a life slot here, since it's part of the Frame.
   7.989 +    AutoEnterScope functionScope(this, node->scope());
   7.990 +
   7.991 +    // Set the initial line, because line mappings are deltas.
   7.992 +    __ setFirstLine(node->pos().line);
   7.993 +    locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
   7.994 +
   7.995 +    node->body()->accept(this);
   7.996 +
   7.997 +    unsigned nargs = node->scope()->numArguments();
   7.998 +    Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
   7.999 +    if (!args)
  7.1000 +        return NULL;
  7.1001 +
  7.1002 +    for (size_t i = 0; i < node->scope()->numArguments(); i++)
  7.1003 +        args->set(zone_, i, node->scope()->getArgument(i)->type());
  7.1004 +
  7.1005 +
  7.1006 +    Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
  7.1007 +    if (!code)
  7.1008 +        return NULL;
  7.1009 +
  7.1010 +    Local<Type> type(zone_, node->fun()->type());
  7.1011 +    Local<String> name(zone_, node->fun()->name());
  7.1012 +    Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
  7.1013 +    if (!fun)
  7.1014 +        return NULL;
  7.1015 +
  7.1016 +    // If this function had a forward, export it as a named public.
  7.1017 +    if (node->fun()->isPublic()) {
  7.1018 +        assert(node->fun()->isPublic());
  7.1019 +        ScopedRoot<Function> root(fun);
  7.1020 +        if (!root)
  7.1021 +            return NULL;
  7.1022 +        if (!moduleData_->publics.append(root))
  7.1023 +            return NULL;
  7.1024 +    }
  7.1025 +
  7.1026 +    Disassemble(code, stdout);
  7.1027 +    
  7.1028 +    return fun;
  7.1029 +}
  7.1030 +
  7.1031 +Module *
  7.1032 +BytecodeCompiler::compile()
  7.1033 +{
  7.1034 +    AutoEnterScope scope(this, tree_->scope());
  7.1035 +
  7.1036 +    ModuleData moduleData;
  7.1037 +
  7.1038 +    moduleData_ = &moduleData;
  7.1039 +    moduleData_->module = Module::New(zone_, tree_->scope()->numFunctions());
  7.1040 +
  7.1041 +    if (!moduleData_)
  7.1042 +        return NULL;
  7.1043 +    
  7.1044 +    moduleData_->natives = FixedArray::New(zone_, tree_->scope()->numNatives(), Heap::Tenure_Old);
  7.1045 +    if (!moduleData_->natives)
  7.1046 +        return NULL;
  7.1047 +
  7.1048 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  7.1049 +        Statement *statement = tree_->statements()->at(i);
  7.1050 +        statement->accept(this);
  7.1051 +    }
  7.1052 +
  7.1053 +    if (zone_->hasPendingException())
  7.1054 +        return NULL;
  7.1055 +
  7.1056 +#ifndef NDEBUG
  7.1057 +    for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
  7.1058 +        assert(moduleData_->module->getFunction(i));
  7.1059 +    for (size_t i = 0; i < tree_->scope()->numNatives(); i++)
  7.1060 +        assert(moduleData_->natives->at(i));
  7.1061 +#endif
  7.1062 +
  7.1063 +    if (moduleData_->publics.length()) {
  7.1064 +        Local<Function> fun(zone_);
  7.1065 +        Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
  7.1066 +                               Heap::Tenure_Old));
  7.1067 +        if (!list)
  7.1068 +            return NULL;
  7.1069 +
  7.1070 +        for (size_t i = 0; i < moduleData_->publics.length(); i++)
  7.1071 +            list->set(zone_, i, moduleData_->publics[i]);
  7.1072 +
  7.1073 +        moduleData_->module->setPublics(list);
  7.1074 +    }
  7.1075 +
  7.1076 +    moduleData_->module->setNatives(moduleData_->natives);
  7.1077 +
  7.1078 +    if (scope_->numEnvironmentVars()) {
  7.1079 +        Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
  7.1080 +        if (!globalMap)
  7.1081 +            return NULL;
  7.1082 +
  7.1083 +        Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
  7.1084 +        if (!environment)
  7.1085 +            return NULL;
  7.1086 +
  7.1087 +        moduleData_->module->setEnvironment(environment);
  7.1088 +    }
  7.1089 +
  7.1090 +    Local<Code> code(zone_, compileCode(tree_->scope(), 1));
  7.1091 +    if (!code)
  7.1092 +        return NULL;
  7.1093 +
  7.1094 +    Disassemble(code, stdout);
  7.1095 +
  7.1096 +    moduleData_->module->setCode(code);
  7.1097 +
  7.1098 +    return moduleData_->module;
  7.1099 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/BytecodeCompiler.h	Tue Jul 24 23:53:34 2012 -0700
     8.3 @@ -0,0 +1,149 @@
     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_compiler_h_
    8.23 +#define _include_bytecode_compiler_h_
    8.24 +
    8.25 +#include "AST.h"
    8.26 +#include "BytecodeEmitter.h"
    8.27 +#include "Functions.h"
    8.28 +
    8.29 +namespace ke {
    8.30 +
    8.31 +class Module;
    8.32 +
    8.33 +struct ModuleData
    8.34 +{
    8.35 +    ScopedRoot<Module> module;
    8.36 +    PoolList<ScopedRoot<Function> > publics;
    8.37 +    ScopedRoot<FixedArray> natives;
    8.38 +};
    8.39 +
    8.40 +class BytecodeCompiler : public AstVisitor
    8.41 +{
    8.42 +    Zone *zone_;
    8.43 +    ParseTree *tree_;
    8.44 +    BytecodeEmitter emitter_;
    8.45 +    ScopedRoot<FixedArray> locals_;
    8.46 +    Scope *scope_;
    8.47 +    ModuleData *moduleData_;
    8.48 +
    8.49 +    class LoopScope
    8.50 +    {
    8.51 +        Scope *scope_;
    8.52 +        BytecodeEmitter::Label *bk_;
    8.53 +        BytecodeEmitter::Label *ct_;
    8.54 +        LoopScope **prevp_;
    8.55 +        LoopScope *prev_;
    8.56 +
    8.57 +      public:
    8.58 +        LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
    8.59 +                  LoopScope **prevp)
    8.60 +          : scope_(scope),
    8.61 +            bk_(bk),
    8.62 +            ct_(ct),
    8.63 +            prevp_(prevp),
    8.64 +            prev_(*prevp)
    8.65 +        {
    8.66 +            *prevp_ = this;
    8.67 +        }
    8.68 +
    8.69 +        ~LoopScope()
    8.70 +        {
    8.71 +            *prevp_ = prev_;
    8.72 +        }
    8.73 +
    8.74 +        BytecodeEmitter::Label *break_() {
    8.75 +            return bk_;
    8.76 +        }
    8.77 +        BytecodeEmitter::Label *continue_() {
    8.78 +            return ct_;
    8.79 +        }
    8.80 +        Scope *scope() {
    8.81 +            return scope_;
    8.82 +        }
    8.83 +    };
    8.84 +
    8.85 +    LoopScope *loop_;
    8.86 +
    8.87 +  public:
    8.88 +    class AutoEnterScope
    8.89 +    {
    8.90 +        BytecodeCompiler *bc_;
    8.91 +        Scope *saved_;
    8.92 +
    8.93 +      public:
    8.94 +        AutoEnterScope(BytecodeCompiler *bc, Scope *scope)
    8.95 +          : bc_(bc),
    8.96 +            saved_(bc->scope_)
    8.97 +        {
    8.98 +            if (scope)
    8.99 +                bc->scope_ = scope;
   8.100 +        }
   8.101 +        ~AutoEnterScope() {
   8.102 +            bc_->scope_ = saved_;
   8.103 +        }
   8.104 +    };
   8.105 +
   8.106 +  private:
   8.107 +    void recordLifoSlot(Scope *scope);
   8.108 +    void unwindTo(Scope *scope);
   8.109 +    void visitForTest(Expression *expression,
   8.110 +                      BytecodeEmitter::Label *trueBranch,
   8.111 +                      BytecodeEmitter::Label *falseBranch,
   8.112 +                      BytecodeEmitter::Label *fallthrough);
   8.113 +    Code *compileCode(Scope *scope, unsigned lineno);
   8.114 +    Function *compileFunction(ModuleData *module, FunctionStatement *fun);
   8.115 +    void visitForALU(Type *needed, Expression *node);
   8.116 +
   8.117 +    void getEnvSlot(Variable *var);
   8.118 +    void setEnvSlot(Variable *var);
   8.119 +
   8.120 +  public:
   8.121 +    BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
   8.122 +
   8.123 +    Module *compile();
   8.124 +
   8.125 +  public:
   8.126 +    void visit(NameProxy *name);
   8.127 +    void visit(Assignment *node);
   8.128 +    void visit(BinaryExpression *node);
   8.129 +    void visit(ReturnStatement *node);
   8.130 +    void visit(ForStatement *node);
   8.131 +    void visit(BlockStatement *node);
   8.132 +    void visit(VariableDeclaration *node);
   8.133 +    void visit(IntegerLiteral *node);
   8.134 +    void visit(FloatLiteral *node);
   8.135 +    void visit(StringLiteral *node);
   8.136 +    void visit(ExpressionStatement *node);
   8.137 +    void visit(FunctionStatement *node);
   8.138 +    void visit(CallExpression *node);
   8.139 +    void visit(IfStatement *node);
   8.140 +    void visit(IndexExpression *node);
   8.141 +    void visit(EnumStatement *node);
   8.142 +    void visit(WhileStatement *node);
   8.143 +    void visit(BreakStatement *node);
   8.144 +    void visit(ContinueStatement *node);
   8.145 +    void visit(IncDecExpression *node);
   8.146 +    void visit(UnaryExpression *node);
   8.147 +    void visit(TernaryExpression *node);
   8.148 +};
   8.149 +
   8.150 +}
   8.151 +
   8.152 +#endif // _include_bytecode_generator_h_
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/BytecodeEmitter.cpp	Tue Jul 24 23:53:34 2012 -0700
     9.3 @@ -0,0 +1,114 @@
     9.4 +/* vim: set ts=4 sw=4 tw=99 et:
     9.5 + *
     9.6 + * Copyright (C) 2012 David Anderson
     9.7 + *
     9.8 + * This file is part of JITCraft.
     9.9 + *
    9.10 + * JITCraft is free software: you can redistribute it and/or modify it under
    9.11 + * the terms of the GNU General Public License as published by the Free
    9.12 + * Software Foundation, either version 3 of the License, or (at your option)
    9.13 + * any later version.
    9.14 + * 
    9.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    9.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    9.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    9.18 + *
    9.19 + * You should have received a copy of the GNU General Public License along with
    9.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
    9.21 + */
    9.22 +#include <stdlib.h>
    9.23 +#include "BytecodeEmitter.h"
    9.24 +#include "Utility.h"
    9.25 +#include "Types.h"
    9.26 +#include "Zone.h"
    9.27 +
    9.28 +using namespace ke;
    9.29 +
    9.30 +BytecodeEmitter::BytecodeEmitter(PoolAllocator &pool)
    9.31 +  : pool_(pool),
    9.32 +    buffer_(inline_buffer_),
    9.33 +    buffer_pos_(buffer_),
    9.34 +    buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
    9.35 +    oom_(false),
    9.36 +    maxStackDepth_(0)
    9.37 +{
    9.38 +    lastCodePosition_ = 0;
    9.39 +    firstLine_ = 1;
    9.40 +}
    9.41 +
    9.42 +bool
    9.43 +BytecodeEmitter::growBuffer(size_t nbytes)
    9.44 +{
    9.45 +    if (oom_) {
    9.46 +        buffer_pos_ = buffer_;
    9.47 +        return false;
    9.48 +    }
    9.49 +
    9.50 +    size_t newSize = size_t((buffer_end_ - buffer_) * 2);
    9.51 +    if (newSize >= MAX_LENGTH) {
    9.52 +        oom_ = true;
    9.53 +        buffer_pos_ = buffer_;
    9.54 +        ZONE()->reportOutOfMemory();
    9.55 +        return false;
    9.56 +    }
    9.57 +
    9.58 +    bytecode *newBuffer;
    9.59 +    if (buffer_ == inline_buffer_)
    9.60 +        newBuffer = (bytecode *)malloc(nbytes);
    9.61 +    else
    9.62 +        newBuffer = (bytecode *)realloc(buffer_, newSize);
    9.63 +
    9.64 +    // If we can't allocate a buffer, reset the buffer to the start and set
    9.65 +    // a flag to indicate out-of-memory.
    9.66 +    if (!newBuffer) {
    9.67 +        oom_ = true;
    9.68 +        buffer_pos_ = buffer_;
    9.69 +        ZONE()->reportOutOfMemory();
    9.70 +        return false;
    9.71 +    }
    9.72 +
    9.73 +    buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
    9.74 +    buffer_ = newBuffer;
    9.75 +    buffer_end_ = buffer_ + newSize;
    9.76 +    return true;
    9.77 +}
    9.78 +
    9.79 +void
    9.80 +BytecodeEmitter::recordOops()
    9.81 +{
    9.82 +    OopRecord *record = new (pool_) OopRecord(oopMap_.length(), position());
    9.83 +
    9.84 +    record->slots = (bool *)pool_.allocate(record->depth);
    9.85 +    if (!record->slots) {
    9.86 +        oom_ = true;
    9.87 +        return;
    9.88 +    }
    9.89 +
    9.90 +    bool hadOops = false;
    9.91 +    for (size_t i = 0; i < oopMap_.length(); i++) {
    9.92 +        bool bit = oopMap_[i];
    9.93 +        record->slots[i] = bit;
    9.94 +        hadOops |= bit;
    9.95 +    }
    9.96 +
    9.97 +    if (!hadOops)
    9.98 +        return;
    9.99 +
   9.100 +    oom_ &= oopRecords_.append(record);
   9.101 +}
   9.102 +
   9.103 +void
   9.104 +BytecodeEmitter::note_position(const SourcePosition &pos)
   9.105 +{
   9.106 +    assert(pos.line > 0);
   9.107 +    assert(unsigned(pos.line) >= firstLine_);
   9.108 +
   9.109 +    unsigned lineDelta = unsigned(pos.line) - firstLine_;
   9.110 +    unsigned pcDelta = unsigned(position()) - lastCodePosition_;
   9.111 +
   9.112 +    sourcemap_.writeUint32(pcDelta);
   9.113 +    sourcemap_.writeUint32(lineDelta);
   9.114 +    sourcemap_.writeUint32(pos.col);
   9.115 +
   9.116 +    lastCodePosition_ = unsigned(position());
   9.117 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/BytecodeEmitter.h	Tue Jul 24 23:53:34 2012 -0700
    10.3 @@ -0,0 +1,626 @@
    10.4 +/* vim: set ts=4 sw=4 tw=99 et:
    10.5 + *
    10.6 + * Copyright (C) 2012 David Anderson
    10.7 + *
    10.8 + * This file is part of JITCraft.
    10.9 + *
   10.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   10.11 + * the terms of the GNU General Public License as published by the Free
   10.12 + * Software Foundation, either version 3 of the License, or (at your option)
   10.13 + * any later version.
   10.14 + * 
   10.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   10.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   10.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   10.18 + *
   10.19 + * You should have received a copy of the GNU General Public License along with
   10.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   10.21 + */
   10.22 +#ifndef _include_bytecode_emitter_h_
   10.23 +#define _include_bytecode_emitter_h_
   10.24 +
   10.25 +#include <assert.h>
   10.26 +#include <limits.h>
   10.27 +#include "Opcodes.h"
   10.28 +#include "NameBinding.h"
   10.29 +#include "Handles.h"
   10.30 +#include "CompactBuffer.h"
   10.31 +
   10.32 +namespace ke {
   10.33 +
   10.34 +class Type;
   10.35 +class Map;
   10.36 +
   10.37 +typedef PoolList<ScopedRoot<Object>> ObjectList;
   10.38 +
   10.39 +struct OopRecord : public PoolObject
   10.40 +{
   10.41 +    unsigned depth;
   10.42 +    unsigned offset;
   10.43 +    bool *slots;
   10.44 +
   10.45 +    OopRecord(unsigned length, unsigned offset)
   10.46 +      : depth(length),
   10.47 +        offset(offset),
   10.48 +        slots(NULL)
   10.49 +    {
   10.50 +    }
   10.51 +};
   10.52 +
   10.53 +class BytecodeEmitter
   10.54 +{
   10.55 +  private:
   10.56 +    PoolAllocator &pool_;
   10.57 +
   10.58 +    bytecode *buffer_;
   10.59 +    bytecode *buffer_pos_;
   10.60 +    bytecode *buffer_end_;
   10.61 +    bytecode inline_buffer_[512];
   10.62 +    bool oom_;
   10.63 +    unsigned maxStackDepth_;
   10.64 +    ObjectList objects_;
   10.65 +    PoolList<bool> oopMap_;
   10.66 +    PoolList<OopRecord *> oopRecords_;
   10.67 +    CompactBufferWriter sourcemap_;
   10.68 +    unsigned lastCodePosition_;
   10.69 +    unsigned firstLine_;
   10.70 +
   10.71 +  private:
   10.72 +    // The maximum size of a code object must be such that the distance between
   10.73 +    // two instructions fits into a signed, 31-bit integer. This ensures that
   10.74 +    // all code-bounded buffers (like the number of object literals or
   10.75 +    // safepoints) does not need to be bounds checked. It also means we can add
   10.76 +    // any two offsets and be guaranteed that they don't overflow.
   10.77 +    static const size_t MAX_LENGTH = INT_MAX / 2;
   10.78 +
   10.79 +  private:
   10.80 +    bool growBuffer(size_t bytes);
   10.81 +
   10.82 +    // Checking the return value is not necessary, since the inline buffer is
   10.83 +    // used as a ballast.
   10.84 +    bool ensure(size_t bytes) {
   10.85 +        if (buffer_pos_ + bytes > buffer_end_)
   10.86 +            return growBuffer(bytes);
   10.87 +        return true;
   10.88 +    }
   10.89 +
   10.90 +    void writeUint8(unsigned value) {
   10.91 +        assert(value <= UCHAR_MAX);
   10.92 +        *buffer_pos_++ = value;
   10.93 +    }
   10.94 +    void writeFloat(float value) {
   10.95 +        *(float *)buffer_pos_ = value;
   10.96 +        buffer_pos_ += sizeof(float);
   10.97 +    }
   10.98 +    void writeInt32(int value) {
   10.99 +        *(int *)buffer_pos_ = value;
  10.100 +        buffer_pos_ += sizeof(int);
  10.101 +    }
  10.102 +    void writeUint32(unsigned value) {
  10.103 +        *(unsigned *)buffer_pos_ = value;
  10.104 +        buffer_pos_ += sizeof(unsigned);
  10.105 +    }
  10.106 +    void writeOp(Opcode op) {
  10.107 +        if (oom_)
  10.108 +            return;
  10.109 +
  10.110 +        writeUint8(op);
  10.111 +        for (int i = 0; i < OpcodeInfo[op].nuses; i++)
  10.112 +            oopMap_.pop();
  10.113 +        for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
  10.114 +            oopMap_.append(false);
  10.115 +        if (oopMap_.length() > maxStackDepth_)
  10.116 +            maxStackDepth_ = oopMap_.length();
  10.117 +    }
  10.118 +    void writeObject(Object *obj) {
  10.119 +        writeUint32(objects_.length());
  10.120 +        ScopedRoot<Object> root(obj);
  10.121 +        if (!objects_.append(root))
  10.122 +            oom_ = true;
  10.123 +    }
  10.124 +
  10.125 +    int position() const {
  10.126 +        assert(buffer_pos_ - buffer_ < INT_MAX / 2);
  10.127 +        return int(buffer_pos_ - buffer_);
  10.128 +    }
  10.129 +
  10.130 +  public:
  10.131 +    BytecodeEmitter(PoolAllocator &pool);
  10.132 +
  10.133 +    bytecode *buffer() const {
  10.134 +        return buffer_;
  10.135 +    }
  10.136 +    unsigned length() const {
  10.137 +        return unsigned(buffer_pos_ - buffer_);
  10.138 +    }
  10.139 +    bool oom() const {
  10.140 +        return oom_ || sourcemap_.oom();
  10.141 +    }
  10.142 +    unsigned stackDepth() const {
  10.143 +        return oopMap_.length();
  10.144 +    }
  10.145 +    unsigned maxStackDepth() const {
  10.146 +        return maxStackDepth_;
  10.147 +    }
  10.148 +    const ObjectList *objects() const {
  10.149 +        return &objects_;
  10.150 +    }
  10.151 +    PoolList<OopRecord *> *oopRecords() {
  10.152 +        return &oopRecords_;
  10.153 +    }
  10.154 +
  10.155 +    void drop(unsigned amt) {
  10.156 +        assert(amt <= stackDepth());
  10.157 +        for (unsigned i = 0; i < amt; i++)
  10.158 +            oopMap_.pop();
  10.159 +    }
  10.160 +
  10.161 +    void note_position(const SourcePosition &pos);
  10.162 +    uint8 *sourcemap() const {
  10.163 +        return sourcemap_.buffer();
  10.164 +    }
  10.165 +    size_t sourcemapLength() const {
  10.166 +        return sourcemap_.length();
  10.167 +    }
  10.168 +    void setFirstLine(unsigned line) {
  10.169 +        assert(!sourcemap_.length());
  10.170 +        firstLine_ = line;
  10.171 +    }
  10.172 +
  10.173 +  public:
  10.174 +    // A label represents a local control-flow target in the bytecode. A label
  10.175 +    // may be in three states:
  10.176 +    //
  10.177 +    // (1) Empty - the label is not used yet.
  10.178 +    // (2) Pending - the label has incoming jumps, but the actual location of
  10.179 +    //               is not yet known. The list of jumps is threaded through
  10.180 +    //               the four bytes reserved for each emitted jump target. In
  10.181 +    //               this case, the offset field is the location of the most
  10.182 +    //               recently emitted incoming jump.
  10.183 +    // (3) Bound   - the label's position has been pinned.
  10.184 +    //
  10.185 +    // A jump can be emitted to a label in any state. Binding a label
  10.186 +    // immediately backpatches all pending incoming jumps. A label must be
  10.187 +    // bound if it is used.
  10.188 +    class Label
  10.189 +    {
  10.190 +        int offset_ : 31;
  10.191 +        bool bound_ : 1;
  10.192 +
  10.193 +        void setOffset(int offset) {
  10.194 +            offset_ = offset;
  10.195 +            assert(offset_ == offset);
  10.196 +        }
  10.197 +
  10.198 +      public:
  10.199 +        static const int INVALID_OFFSET = -1;
  10.200 +
  10.201 +      public:
  10.202 +        Label()
  10.203 +          : offset_(INVALID_OFFSET),
  10.204 +            bound_(false)
  10.205 +        {
  10.206 +        }
  10.207 +        ~Label()
  10.208 +        {
  10.209 +            assert(bound_ || offset_ == INVALID_OFFSET);
  10.210 +        }
  10.211 +        
  10.212 +        bool bound() const {
  10.213 +            return bound_;
  10.214 +        }
  10.215 +        int offset() const {
  10.216 +            return offset_;
  10.217 +        }
  10.218 +        void bind(int offset) {
  10.219 +            assert(!bound_);
  10.220 +            setOffset(offset);
  10.221 +            bound_ = true;
  10.222 +        }
  10.223 +        int link(int offset) {
  10.224 +            assert(!bound_);
  10.225 +            int old = offset_;
  10.226 +            setOffset(offset);
  10.227 +            return old;
  10.228 +        }
  10.229 +    };
  10.230 +
  10.231 +  private:
  10.232 +    int patchJumpAt(int at, int to) {
  10.233 +        assert(at >= 0 && at < position());
  10.234 +        int old = *(int *)(buffer_ + at + 1);
  10.235 +        *(int *)(buffer_ + at + 1) = (to - at);
  10.236 +        return old;
  10.237 +    }
  10.238 +
  10.239 +    void singleByteOp(Opcode op) {
  10.240 +        assert(OpcodeInfo[op].length == 1);
  10.241 +        ensure(OpcodeInfo[op].length);
  10.242 +        writeOp(op);
  10.243 +    }
  10.244 +
  10.245 +    // Mark a stack slot as having an object pointer.
  10.246 +    void markOop(unsigned depth, bool oop = true) {
  10.247 +        if (oom_)
  10.248 +            return;
  10.249 +        oopMap_[oopMap_.length() - depth] = oop;
  10.250 +    }
  10.251 +    bool getOop(unsigned depth) {
  10.252 +        if (oom_)
  10.253 +            return false;
  10.254 +        return oopMap_[oopMap_.length() - depth];
  10.255 +    }
  10.256 +
  10.257 +    // Mark the current bytecode position as either re-entrant (meaning, it
  10.258 +    // can leave the interpreter or call to another function), or causing GC.
  10.259 +    // This will record which stack slots have objects and associate that
  10.260 +    // information with the current pc.
  10.261 +    void recordOops();
  10.262 +
  10.263 +  public:
  10.264 +    void int_(int value) {
  10.265 +        ensure(OP_INT);
  10.266 +        writeOp(OP_INT);
  10.267 +        writeInt32(value);
  10.268 +    }
  10.269 +    void return_() {
  10.270 +        ensure(OP_RETURN);
  10.271 +        writeOp(OP_RETURN);
  10.272 +    }
  10.273 +    void getlocal(Variable *var) {
  10.274 +        ensure(OP_GETLOCAL_LENGTH);
  10.275 +        writeOp(OP_GETLOCAL);
  10.276 +        writeUint32(var->slot());
  10.277 +
  10.278 +        if (var->type()->isTraceable())
  10.279 +            markOop(1);
  10.280 +    }
  10.281 +    void setlocal(Variable *var) {
  10.282 +        ensure(OP_SETLOCAL_LENGTH);
  10.283 +        writeOp(OP_SETLOCAL);
  10.284 +        writeUint32(var->slot());
  10.285 +
  10.286 +        if (var->type()->isTraceable())
  10.287 +            markOop(1);
  10.288 +    }
  10.289 +    void getarg(Variable *var) {
  10.290 +        ensure(OP_GETARG_LENGTH);
  10.291 +        writeOp(OP_GETARG);
  10.292 +        writeUint32(var->slot());
  10.293 +
  10.294 +        if (var->type()->isTraceable())
  10.295 +            markOop(1);
  10.296 +    }
  10.297 +    void setarg(Variable *var) {
  10.298 +        ensure(OP_SETARG_LENGTH);
  10.299 +        writeOp(OP_SETARG);
  10.300 +        writeUint32(var->slot());
  10.301 +
  10.302 +        if (var->type()->isTraceable())
  10.303 +            markOop(1);
  10.304 +    }
  10.305 +
  10.306 +    void j(Opcode op, Label *label) {
  10.307 +        // Since jumps can skip around the stream, do not try to do anything
  10.308 +        // in a potentially truncated state.
  10.309 +        if (oom())
  10.310 +            return;
  10.311 +
  10.312 +        assert(op >= OP_JL && op <= OP_JUMP);
  10.313 +        ensure(OP_JUMP_LENGTH);
  10.314 +
  10.315 +        if (label->bound()) {
  10.316 +            // We can immediately emit this jump.
  10.317 +            int distance = label->offset() - position();
  10.318 +            writeOp(op);
  10.319 +            writeInt32(distance);
  10.320 +        } else {
  10.321 +            // We can't emit this jump yet. Add a placeholder.
  10.322 +            int old = label->link(position());
  10.323 +            writeOp(op);
  10.324 +            writeInt32(old);
  10.325 +        }
  10.326 +    }
  10.327 +    void bind(Label *label) {
  10.328 +        if (oom())
  10.329 +            return;
  10.330 +
  10.331 +        assert(!label->bound());
  10.332 +
  10.333 +        int offset = label->offset();
  10.334 +        while (offset != Label::INVALID_OFFSET)
  10.335 +            offset = patchJumpAt(offset, position());
  10.336 +
  10.337 +        label->bind(position());
  10.338 +    }
  10.339 +    void jump(Label *label) {
  10.340 +        j(OP_JUMP, label);
  10.341 +    }
  10.342 +
  10.343 +    void binary(Opcode op) {
  10.344 +        singleByteOp(op);
  10.345 +    }
  10.346 +
  10.347 +    void pop() {
  10.348 +        singleByteOp(OP_POP);
  10.349 +    }
  10.350 +    void stop() {
  10.351 +        singleByteOp(OP_STOP);
  10.352 +    }
  10.353 +    void call(Handle<Type> fun) {
  10.354 +        recordOops();
  10.355 +        ensure(OP_CALL_LENGTH);
  10.356 +        writeOp(OP_CALL);
  10.357 +
  10.358 +        if (fun->returnType()->isVoid())
  10.359 +            drop(1);
  10.360 +        else if (fun->returnType()->isTraceable())
  10.361 +            markOop(1);
  10.362 +    }
  10.363 +    void callnative(unsigned index, unsigned argc) {
  10.364 +        recordOops();
  10.365 +        ensure(OP_CALLNATIVE_LENGTH);
  10.366 +        writeOp(OP_CALLNATIVE);
  10.367 +        writeUint32(index);
  10.368 +        writeUint32(argc);
  10.369 +    }
  10.370 +
  10.371 +    void getarray(PrimitiveType type) {
  10.372 +        switch (type) {
  10.373 +          case PrimitiveType_Float:
  10.374 +            singleByteOp(OP_GETARRAY_F);
  10.375 +            break;
  10.376 +          case PrimitiveType_Int32:
  10.377 +            singleByteOp(OP_GETARRAY_I);
  10.378 +            break;
  10.379 +          default:
  10.380 +            assert(type == PrimitiveType_Char);
  10.381 +            singleByteOp(OP_GETARRAY_C);
  10.382 +            break;
  10.383 +        }
  10.384 +    }
  10.385 +    void setarray(PrimitiveType type) {
  10.386 +        switch (type) {
  10.387 +          case PrimitiveType_Float:
  10.388 +            singleByteOp(OP_SETARRAY_F);
  10.389 +            break;
  10.390 +          case PrimitiveType_Int32:
  10.391 +            singleByteOp(OP_SETARRAY_I);
  10.392 +            break;
  10.393 +          default:
  10.394 +            assert(type == PrimitiveType_Char);
  10.395 +            singleByteOp(OP_SETARRAY_C);
  10.396 +            break;
  10.397 +        }
  10.398 +    }
  10.399 +
  10.400 +    void getglobal(Variable *var) {
  10.401 +        ensure(OP_GETGLOBAL_F_LENGTH);
  10.402 +        if (var->type()->isPrimitive()) {
  10.403 +            switch (var->type()->primitive()) {
  10.404 +              case PrimitiveType_Float:
  10.405 +                writeOp(OP_GETGLOBAL_F);
  10.406 +                break;
  10.407 +              default:
  10.408 +                assert(var->type()->primitive() == PrimitiveType_Int32);
  10.409 +                writeOp(OP_GETGLOBAL_I);
  10.410 +                break;
  10.411 +            }
  10.412 +        } else {
  10.413 +            writeOp(OP_GETGLOBAL_O);
  10.414 +            markOop(1);
  10.415 +        }
  10.416 +        writeUint32(var->slot());
  10.417 +    }
  10.418 +    void setglobal(Variable *var) {
  10.419 +        ensure(OP_SETGLOBAL_F_LENGTH);
  10.420 +        if (var->type()->isPrimitive()) {
  10.421 +            switch (var->type()->primitive()) {
  10.422 +              case PrimitiveType_Float:
  10.423 +                writeOp(OP_SETGLOBAL_F);
  10.424 +                break;
  10.425 +              default:
  10.426 +                assert(var->type()->primitive() == PrimitiveType_Int32);
  10.427 +                writeOp(OP_SETGLOBAL_I);
  10.428 +                break;
  10.429 +            }
  10.430 +        } else {
  10.431 +            writeOp(OP_SETGLOBAL_O);
  10.432 +        }
  10.433 +        writeUint32(var->slot());
  10.434 +    }
  10.435 +
  10.436 +    void getarray_o() {
  10.437 +        singleByteOp(OP_GETARRAY_O);
  10.438 +        markOop(1);
  10.439 +    }
  10.440 +    void bounds() {
  10.441 +        singleByteOp(OP_BOUNDS);
  10.442 +        markOop(2);
  10.443 +    }
  10.444 +    void float_(float value) {
  10.445 +        ensure(OP_FLOAT_LENGTH);
  10.446 +        writeOp(OP_FLOAT);
  10.447 +        writeFloat(value);
  10.448 +    }
  10.449 +    void cvt_i2f() {
  10.450 +        singleByteOp(OP_CVT_I2F);
  10.451 +    }
  10.452 +    void newarray(Handle<Map> map, Heap::Tenure tenure) {
  10.453 +        recordOops();
  10.454 +        ensure(OP_NEWARRAY_LENGTH);
  10.455 +        writeOp(OP_NEWARRAY);
  10.456 +        writeUint8(tenure);
  10.457 +        writeObject(map);
  10.458 +        markOop(1);
  10.459 +    }
  10.460 +    void savelifo(unsigned slot) {
  10.461 +        ensure(OP_SAVELIFO_LENGTH);
  10.462 +        writeOp(OP_SAVELIFO);
  10.463 +        writeUint32(slot);
  10.464 +    }
  10.465 +    void unwindlifo(unsigned slot) {
  10.466 +        ensure(OP_UNWINDLIFO_LENGTH);
  10.467 +        writeOp(OP_UNWINDLIFO);
  10.468 +        writeUint32(slot);
  10.469 +    }
  10.470 +    void newref(Variable *var) {
  10.471 +        recordOops();
  10.472 +        if (var->location() == Variable::STACK) {
  10.473 +            ensure(OP_VARREF_LIFO_LENGTH);
  10.474 +            writeOp(OP_VARREF_LIFO);
  10.475 +        } else {
  10.476 +            assert(var->location() == Variable::PARAMETER);
  10.477 +            ensure(OP_ARGREF_LIFO_LENGTH);
  10.478 +            writeOp(OP_ARGREF_LIFO);
  10.479 +        }
  10.480 +        writeUint32(var->slot());
  10.481 +        markOop(1);
  10.482 +    }
  10.483 +
  10.484 +    void slotref_lifo() {
  10.485 +        recordOops();
  10.486 +        singleByteOp(OP_SLOTREF_LIFO);
  10.487 +        markOop(1);
  10.488 +    }
  10.489 +    void arrayref_lifo() {
  10.490 +        recordOops();
  10.491 +        singleByteOp(OP_ARRAYREF_LIFO);
  10.492 +        markOop(1);
  10.493 +    }
  10.494 +    void getref(PrimitiveType type) {
  10.495 +        if (type == PrimitiveType_Int32) {
  10.496 +            singleByteOp(OP_GETREF_I);
  10.497 +        } else {
  10.498 +            assert(type == PrimitiveType_Float);
  10.499 +            singleByteOp(OP_GETREF_F);
  10.500 +        }
  10.501 +    }
  10.502 +    void setref(PrimitiveType type) {
  10.503 +        if (type == PrimitiveType_Int32) {
  10.504 +            singleByteOp(OP_SETREF_I);
  10.505 +        } else {
  10.506 +            assert(type == PrimitiveType_Float);
  10.507 +            singleByteOp(OP_SETREF_F);
  10.508 +        }
  10.509 +    }
  10.510 +    void object(Handle<Object> obj) {
  10.511 +        ensure(OP_OBJECT_LENGTH);
  10.512 +        writeOp(OP_OBJECT);
  10.513 +        writeObject(obj);
  10.514 +        markOop(1);
  10.515 +    }
  10.516 +    void arraycopy() {
  10.517 +        singleByteOp(OP_ARRAYCOPY);
  10.518 +        markOop(1);
  10.519 +    }
  10.520 +
  10.521 +    void dup() {
  10.522 +        bool oop = getOop(1);
  10.523 +        singleByteOp(OP_DUP);
  10.524 +        markOop(1, oop);
  10.525 +    }
  10.526 +    void dup2() {
  10.527 +        bool oop2 = getOop(2);
  10.528 +        bool oop1 = getOop(1);
  10.529 +
  10.530 +        singleByteOp(OP_DUP2);
  10.531 +
  10.532 +        markOop(2, oop2);
  10.533 +        markOop(1, oop1);
  10.534 +    }
  10.535 +    void swap() {
  10.536 +        bool oop2 = getOop(2);
  10.537 +        bool oop1 = getOop(1);
  10.538 +
  10.539 +        singleByteOp(OP_SWAP);
  10.540 +
  10.541 +        markOop(2, oop1);
  10.542 +        markOop(1, oop2);
  10.543 +    }
  10.544 +    void roll3() {
  10.545 +        bool oop3 = getOop(3);
  10.546 +        bool oop2 = getOop(2);
  10.547 +        bool oop1 = getOop(1);
  10.548 +
  10.549 +        singleByteOp(OP_ROLL3);
  10.550 +
  10.551 +        markOop(3, oop2);
  10.552 +        markOop(2, oop1);
  10.553 +        markOop(1, oop3);
  10.554 +    }
  10.555 +    void pick2() {
  10.556 +        bool oop2 = getOop(2);
  10.557 +        bool oop1 = getOop(1);
  10.558 +
  10.559 +        singleByteOp(OP_PICK2);
  10.560 +
  10.561 +        markOop(3, oop2);
  10.562 +        markOop(2, oop1);
  10.563 +        markOop(1, oop2);
  10.564 +    }
  10.565 +    void pick3() {
  10.566 +        bool oop3 = getOop(3);
  10.567 +        bool oop2 = getOop(2);
  10.568 +        bool oop1 = getOop(1);
  10.569 +
  10.570 +        singleByteOp(OP_PICK3);
  10.571 +
  10.572 +        markOop(4, oop3);
  10.573 +        markOop(3, oop2);
  10.574 +        markOop(2, oop1);
  10.575 +        markOop(1, oop3);
  10.576 +    }
  10.577 +
  10.578 +    void returnvoid() {
  10.579 +        singleByteOp(OP_RETURNVOID);
  10.580 +    }
  10.581 +    void module() {
  10.582 +        singleByteOp(OP_MODULE);
  10.583 +        markOop(1);
  10.584 +    }
  10.585 +    void getmodule_fn(unsigned index) {
  10.586 +        ensure(OP_GETMODULE_FN_LENGTH);
  10.587 +        writeOp(OP_GETMODULE_FN);
  10.588 +        writeUint32(index);
  10.589 +        markOop(1);
  10.590 +    }
  10.591 +    void bitnot() {
  10.592 +        singleByteOp(OP_BITNOT);
  10.593 +    }
  10.594 +    void not_() {
  10.595 +        singleByteOp(OP_NOT);
  10.596 +    }
  10.597 +    void not_f() {
  10.598 +        singleByteOp(OP_NOT_F);
  10.599 +    }
  10.600 +    void neg() {
  10.601 +        singleByteOp(OP_NEG);
  10.602 +    }
  10.603 +    void neg_f() {
  10.604 +        singleByteOp(OP_NEG_F);
  10.605 +    }
  10.606 +
  10.607 +    // Helpers.
  10.608 +    void get(Variable *var) {
  10.609 +        if (var->location() == Variable::STACK) {
  10.610 +            getlocal(var);
  10.611 +        } else {
  10.612 +            assert(var->location() == Variable::PARAMETER);
  10.613 +            getarg(var);
  10.614 +        }
  10.615 +    }
  10.616 +    void set(Variable *var) {
  10.617 +        assert(!var->type()->isReference());
  10.618 +        if (var->location() == Variable::STACK) {
  10.619 +            setlocal(var);
  10.620 +        } else {
  10.621 +            assert(var->location() == Variable::PARAMETER);
  10.622 +            setarg(var);
  10.623 +        }
  10.624 +    }
  10.625 +};
  10.626 +
  10.627 +}
  10.628 +
  10.629 +#endif // _include_bytecode_emitter_h_
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/Code.h	Tue Jul 24 23:53:34 2012 -0700
    11.3 @@ -0,0 +1,127 @@
    11.4 +/* vim: set ts=4 sw=4 tw=99 et:
    11.5 + *
    11.6 + * Copyright (C) 2012 David Anderson
    11.7 + *
    11.8 + * This file is part of JITCraft.
    11.9 + *
   11.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   11.11 + * the terms of the GNU General Public License as published by the Free
   11.12 + * Software Foundation, either version 3 of the License, or (at your option)
   11.13 + * any later version.
   11.14 + * 
   11.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   11.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   11.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   11.18 + *
   11.19 + * You should have received a copy of the GNU General Public License along with
   11.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   11.21 + */
   11.22 +#ifndef _include_jc_code_h_
   11.23 +#define _include_jc_code_h_
   11.24 +
   11.25 +#include "Opcodes.h"
   11.26 +#include "Barriers.h"
   11.27 +#include "Heap.h"
   11.28 +#include "Types.h"
   11.29 +#include "FixedArray.h"
   11.30 +#include "Token.h"
   11.31 +
   11.32 +namespace ke {
   11.33 +
   11.34 +class Module;
   11.35 +class Type;
   11.36 +
   11.37 +// A code object contains the bytecode compiled from a function (or global
   11.38 +// script), as well as all information needed to interpret or JIT-compile
   11.39 +// the bytecode.
   11.40 +class Code : public Object
   11.41 +{
   11.42 +    Barriered<Module> module_;
   11.43 +    Barriered<ByteArray> bytecode_;
   11.44 +    Barriered<FixedArray> locals_;
   11.45 +    Barriered<FixedArray> objects_;
   11.46 +    Barriered<ByteArray> safepoints_;
   11.47 +    Barriered<ByteArray> sourcemap_;
   11.48 +    unsigned maxStackDepth_;
   11.49 +    unsigned lineNumber_;
   11.50 +
   11.51 +  public:
   11.52 +    static inline size_t BytesPerSafepoint(size_t stackDepth) {
   11.53 +        return (Align(stackDepth, 8) / 8) + sizeof(unsigned);
   11.54 +    }
   11.55 +
   11.56 +  public:
   11.57 +    static Code *New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
   11.58 +                     Handle<FixedArray> objects, unsigned maxStackDepth, Handle<Module> module,
   11.59 +                     Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap,
   11.60 +                     unsigned lineNumber);
   11.61 +
   11.62 +    Module *module() {
   11.63 +        return module_;
   11.64 +    }
   11.65 +    bytecode *start() {
   11.66 +        return bytecode_->raw();
   11.67 +    }
   11.68 +    unsigned length() {
   11.69 +        return bytecode_->length();
   11.70 +    }
   11.71 +    Type *localType(size_t index) {
   11.72 +        return Type::cast(locals_->at(index));
   11.73 +    }
   11.74 +    unsigned nlocals() {
   11.75 +        return locals_ ? locals_->length() : 0;
   11.76 +    }
   11.77 +    unsigned maxStackDepth() {
   11.78 +        return maxStackDepth_;
   11.79 +    }
   11.80 +    Map *map(size_t index) {
   11.81 +        return Map::cast(objects_->at(index));
   11.82 +    }
   11.83 +    Object *object(size_t index) {
   11.84 +        return objects_->at(index);
   11.85 +    }
   11.86 +    ByteArray *safepoints() {
   11.87 +        return safepoints_;
   11.88 +    }
   11.89 +    uint8 *safepointAt(unsigned pcOffset);
   11.90 +
   11.91 +    unsigned pcToOffset(bytecode *pc) {
   11.92 +        assert(pc >= start() && pc < start() + length());
   11.93 +        return unsigned(pc - start());
   11.94 +    }
   11.95 +
   11.96 +    SourcePosition pcToSource(unsigned pc);
   11.97 +    unsigned lineNumber() {
   11.98 +        return lineNumber_;
   11.99 +    }
  11.100 +
  11.101 +    // GC Descriptor.
  11.102 +    static inline size_t offsetOfModule() {
  11.103 +        return offsetof(Code, module_);
  11.104 +    }
  11.105 +    static inline size_t offsetOfBytecode() {
  11.106 +        return offsetof(Code, bytecode_);
  11.107 +    }
  11.108 +    static inline size_t offsetOfLocals() {
  11.109 +        return offsetof(Code, locals_);
  11.110 +    }
  11.111 +    static inline size_t offsetOfObjects() {
  11.112 +        return offsetof(Code, objects_);
  11.113 +    }
  11.114 +    static inline size_t offsetOfSafepoints() {
  11.115 +        return offsetof(Code, safepoints_);
  11.116 +    }
  11.117 +    static inline size_t offsetOfSourceMap() {
  11.118 +        return offsetof(Code, sourcemap_);
  11.119 +    }
  11.120 +    // End GC Descriptor.
  11.121 +
  11.122 +    static Code *cast(Object *obj) {
  11.123 +        assert(!obj || obj->is(MapKind_Code));
  11.124 +        return reinterpret_cast<Code *>(obj);
  11.125 +    }
  11.126 +};
  11.127 +
  11.128 +}
  11.129 +
  11.130 +#endif // _include_jc_code_h_
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/CompactBuffer.h	Tue Jul 24 23:53:34 2012 -0700
    12.3 @@ -0,0 +1,100 @@
    12.4 +/* vim: set ts=4 sw=4 tw=99 et:
    12.5 + *
    12.6 + * Copyright (C) 2012 David Anderson
    12.7 + *
    12.8 + * This file is part of JITCraft.
    12.9 + *
   12.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   12.11 + * the terms of the GNU General Public License as published by the Free
   12.12 + * Software Foundation, either version 3 of the License, or (at your option)
   12.13 + * any later version.
   12.14 + * 
   12.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   12.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   12.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   12.18 + *
   12.19 + * You should have received a copy of the GNU General Public License along with
   12.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   12.21 + */
   12.22 +#ifndef _include_jc_compact_buffer_h_
   12.23 +#define _include_jc_compact_buffer_h_
   12.24 +
   12.25 +#include "AllocatorPolicies.h"
   12.26 +#include "Utility.h"
   12.27 +#include "Vector.h"
   12.28 +
   12.29 +namespace ke {
   12.30 +
   12.31 +class CompactBufferReader
   12.32 +{
   12.33 +    const uint8 *pos_;
   12.34 +    const uint8 *end_;
   12.35 +
   12.36 +  public:
   12.37 +    CompactBufferReader(const uint8 *start, const uint8 *end)
   12.38 +      : pos_(start),
   12.39 +        end_(end)
   12.40 +    {
   12.41 +    }
   12.42 +
   12.43 +    uint8 readUint8() {
   12.44 +        assert(pos_ < end_);
   12.45 +        return *pos_++;
   12.46 +    }
   12.47 +
   12.48 +    uint32 readUint32() {
   12.49 +        uint32 value = 0;
   12.50 +        uint32 shift = 0;
   12.51 +
   12.52 +        uint8 byte;
   12.53 +        do {
   12.54 +            byte = readUint8();
   12.55 +            value |= (byte >> 1) << shift;
   12.56 +            shift += 7;
   12.57 +        } while (byte & 1);
   12.58 +
   12.59 +        assert(shift < 32);
   12.60 +        return value;
   12.61 +    }
   12.62 +
   12.63 +    bool done() const {
   12.64 +        return pos_ == end_;
   12.65 +    }
   12.66 +};
   12.67 +
   12.68 +class CompactBufferWriter
   12.69 +{
   12.70 +    Vector<uint8, ZoneAllocatorPolicy> buffer_;
   12.71 +    bool enoughMemory_;
   12.72 +
   12.73 +  public:
   12.74 +    CompactBufferWriter()
   12.75 +      : enoughMemory_(true)
   12.76 +    {
   12.77 +    }
   12.78 +
   12.79 +    void writeUint8(unsigned value) {
   12.80 +        enoughMemory_ &= buffer_.append(value);
   12.81 +    }
   12.82 +    void writeUint32(unsigned value) {
   12.83 +        do {
   12.84 +            writeUint8(((value & 0x7F) << 1) | (value > 0x7F));
   12.85 +            value >>= 7;
   12.86 +        } while (value);
   12.87 +    }
   12.88 +
   12.89 +    uint8 *buffer() const {
   12.90 +        return buffer_.buffer();
   12.91 +    }
   12.92 +    size_t length() const {
   12.93 +        return buffer_.length();
   12.94 +    }
   12.95 +
   12.96 +    bool oom() const {
   12.97 +        return !enoughMemory_;
   12.98 +    }
   12.99 +};
  12.100 +
  12.101 +}
  12.102 +
  12.103 +#endif // _include_jc_compact_buffer_h_
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/CompileContext.cpp	Tue Jul 24 23:53:34 2012 -0700
    13.3 @@ -0,0 +1,56 @@
    13.4 +/*
    13.5 + * Copyright (C) 2012 David Anderson
    13.6 + *
    13.7 + * This file is part of JITCraft.
    13.8 + *
    13.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   13.10 + * the terms of the GNU General Public License as published by the Free
   13.11 + * Software Foundation, either version 3 of the License, or (at your option)
   13.12 + * any later version.
   13.13 + * 
   13.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   13.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   13.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   13.17 + *
   13.18 + * You should have received a copy of the GNU General Public License along with
   13.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   13.20 + */
   13.21 +#include <stdio.h>
   13.22 +#include "Scanner.h"
   13.23 +#include "CompileContext.h"
   13.24 +#include "Zone.h"
   13.25 +
   13.26 +using namespace ke;
   13.27 +
   13.28 +CompileContext::CompileContext(Zone *zone, const char *file)
   13.29 +  : zone_(zone),
   13.30 +    failures_(0),
   13.31 +    file_(file)
   13.32 +{
   13.33 +}
   13.34 +
   13.35 +CompileContext::~CompileContext()
   13.36 +{
   13.37 +    if (failures_)
   13.38 +        zone_->endCompilationErrors();
   13.39 +}
   13.40 +
   13.41 +void
   13.42 +CompileContext::reportErrorVa(const SourcePosition &pos, Message msg, va_list ap)
   13.43 +{
   13.44 +    if (!failures_)
   13.45 +        zone_->beginCompilationErrors(file_);
   13.46 +
   13.47 +    zone_->reportCompilationError(msg, pos.line, pos.col, ap);
   13.48 +
   13.49 +    failures_++;
   13.50 +}
   13.51 +
   13.52 +void
   13.53 +CompileContext::reportError(const SourcePosition &pos, Message msg, ...)
   13.54 +{
   13.55 +    va_list ap;
   13.56 +    va_start(ap, msg);
   13.57 +    reportErrorVa(pos, msg, ap);
   13.58 +    va_end(ap);
   13.59 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/CompileContext.h	Tue Jul 24 23:53:34 2012 -0700
    14.3 @@ -0,0 +1,49 @@
    14.4 +/*
    14.5 + * Copyright (C) 2012 David Anderson
    14.6 + *
    14.7 + * This file is part of JITCraft.
    14.8 + *
    14.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   14.10 + * the terms of the GNU General Public License as published by the Free
   14.11 + * Software Foundation, either version 3 of the License, or (at your option)
   14.12 + * any later version.
   14.13 + * 
   14.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   14.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   14.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   14.17 + *
   14.18 + * You should have received a copy of the GNU General Public License along with
   14.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   14.20 + */
   14.21 +#ifndef _include_jitcraft_compile_context_h_
   14.22 +#define _include_jitcraft_compile_context_h_
   14.23 +
   14.24 +#include <stdarg.h>
   14.25 +#include "Messages.h"
   14.26 +
   14.27 +namespace ke {
   14.28 +
   14.29 +class Zone;
   14.30 +struct SourcePosition;
   14.31 +
   14.32 +class CompileContext
   14.33 +{
   14.34 +    Zone *zone_;
   14.35 +    unsigned failures_;
   14.36 +    const char *file_;
   14.37 +
   14.38 +  public:
   14.39 +    CompileContext(Zone *zone, const char *file);
   14.40 +    ~CompileContext();
   14.41 +
   14.42 +    void reportErrorVa(const SourcePosition &pos, Message msg, va_list ap);
   14.43 +    void reportError(const SourcePosition &pos, Message msg, ...);
   14.44 +
   14.45 +    unsigned failures() const {
   14.46 +        return failures_;
   14.47 +    }
   14.48 +};
   14.49 +
   14.50 +}
   14.51 +
   14.52 +#endif // _include_jitcraft_compile_context_h_
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/Environments.cpp	Tue Jul 24 23:53:34 2012 -0700
    15.3 @@ -0,0 +1,97 @@
    15.4 +/*
    15.5 + * Copyright (C) 2012 David Anderson
    15.6 + *
    15.7 + * This file is part of JITCraft.
    15.8 + *
    15.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   15.10 + * the terms of the GNU General Public License as published by the Free
   15.11 + * Software Foundation, either version 3 of the License, or (at your option)
   15.12 + * any later version.
   15.13 + * 
   15.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   15.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   15.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   15.17 + *
   15.18 + * You should have received a copy of the GNU General Public License along with
   15.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   15.20 + */
   15.21 +#include "Utility.h"
   15.22 +#include "Environments.h"
   15.23 +#include "Structures.h"
   15.24 +#include "FixedArray.h"
   15.25 +#include "Zone.h"
   15.26 +#include "NameBinding.h"
   15.27 +
   15.28 +using namespace ke;
   15.29 +
   15.30 +EnvironmentSlotDescriptorArray *
   15.31 +EnvironmentSlotDescriptorArray::New(Zone *zone, unsigned nslots)
   15.32 +{
   15.33 +    size_t bytesNeeded = sizeof(EnvironmentSlotDescriptorArray) +
   15.34 +                         sizeof(EnvironmentSlotDescriptor) * nslots;
   15.35 +
   15.36 +    Local<EnvironmentSlotDescriptorArray> array(zone);
   15.37 +    Local<Map> map(zone, zone->getMap(MapKind_EnvironmentSlotDescriptorArray));
   15.38 +
   15.39 +    array = EnvironmentSlotDescriptorArray::cast(zone->allocate(map, bytesNeeded, Heap::Tenure_Old));
   15.40 +    if (!array)
   15.41 +        return NULL;
   15.42 +
   15.43 +    // We zero the array for safety, since we could GC or fail before initialization.
   15.44 +    array->length_ = nslots;
   15.45 +    memset(array->slots(), 0, sizeof(EnvironmentSlotDescriptor) * nslots);
   15.46 +    return array;
   15.47 +}
   15.48 +
   15.49 +Environment *
   15.50 +Environment::New(Zone *zone, Handle<EnvironmentMap> map, Heap::Tenure tenure)
   15.51 +{
   15.52 +    size_t bytesNeeded = sizeof(Environment) + map->structureSize();
   15.53 +    Local<Environment> env(zone, Environment::cast(zone->allocate(map, bytesNeeded, tenure)));
   15.54 +    if (!env)
   15.55 +        return NULL;
   15.56 +
   15.57 +    // Initialize when called from C++, to make sure object slots are NULL.
   15.58 +    memset((Object *)env + 1, 0, map->structureSize());
   15.59 +    return env;
   15.60 +}
   15.61 +
   15.62 +EnvironmentMap *
   15.63 +EnvironmentMap::New(Zone *zone, unsigned nvars, Variable **vars)
   15.64 +{
   15.65 +    StructureBufferBuilder structure;
   15.66 +
   15.67 +    Local<EnvironmentSlotDescriptorArray> slots(zone);
   15.68 +    slots = EnvironmentSlotDescriptorArray::New(zone, nvars);
   15.69 +    if (!slots)
   15.70 +        return NULL;
   15.71 +
   15.72 +    // Build the descriptor table, mapping each slot to an offset and type.
   15.73 +    Local<Type> type(zone);
   15.74 +    for (unsigned i = 0; i < nvars; i++) {
   15.75 +        assert(vars[i]->slot() == i);
   15.76 +        type = vars[i]->type();
   15.77 +
   15.78 +        EnvironmentSlotDescriptor &desc = slots->slots()[i];
   15.79 +        if (!structure.add(type, &desc.offset))
   15.80 +            return NULL;
   15.81 +
   15.82 +        desc.type = type;
   15.83 +    }
   15.84 +
   15.85 +    // Allocate the actual map now.
   15.86 +    size_t bytesNeeded = sizeof(EnvironmentMap) + structure.traceableOffsetCount() * sizeof(unsigned);
   15.87 +    Local<EnvironmentMap> map(zone);
   15.88 +    
   15.89 +    map = EnvironmentMap::cast(zone->allocateMap(MapKind_Environment, bytesNeeded, MapKind_MetaEnvironment));
   15.90 +    if (!map)
   15.91 +        return NULL;
   15.92 +    
   15.93 +    // Fill in the map fields, and copy the traceable offsets structure.
   15.94 +    map->structureSize_ = structure.structureSize();
   15.95 +    map->traceOffsetCount_ = structure.traceableOffsetCount();
   15.96 +    map->slots_ = slots;
   15.97 +    memcpy(const_cast<unsigned *>(map->traceOffsets()), structure.offsets(), sizeof(unsigned) * structure.traceableOffsetCount());
   15.98 +
   15.99 +    return map;
  15.100 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/Environments.h	Tue Jul 24 23:53:34 2012 -0700
    16.3 @@ -0,0 +1,168 @@
    16.4 +/*
    16.5 + * Copyright (C) 2012 David Anderson
    16.6 + *
    16.7 + * This file is part of JITCraft.
    16.8 + *
    16.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   16.10 + * the terms of the GNU General Public License as published by the Free
   16.11 + * Software Foundation, either version 3 of the License, or (at your option)
   16.12 + * any later version.
   16.13 + * 
   16.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   16.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   16.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   16.17 + *
   16.18 + * You should have received a copy of the GNU General Public License along with
   16.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   16.20 + */
   16.21 +#ifndef _include_ke_environment_h_
   16.22 +#define _include_ke_environment_h_
   16.23 +
   16.24 +#include "Objects.h"
   16.25 +#include "Handles.h"
   16.26 +#include "Heap.h"
   16.27 +#include "FixedArray.h"
   16.28 +
   16.29 +namespace ke {
   16.30 +
   16.31 +class EnvironmentMap;
   16.32 +class Variable;
   16.33 +class ByteArray;
   16.34 +class Type;
   16.35 +
   16.36 +// An environment represents the lexical environment of a code or function
   16.37 +// object. It used for variables which may be accessed outside a function's
   16.38 +// normal activation (i.e., upvars).
   16.39 +//
   16.40 +// A module uses an Environment to store its global variables.
   16.41 +class Environment : public Object
   16.42 +{
   16.43 +    template <typename T>
   16.44 +    inline T *pointerToSlot(unsigned slot);
   16.45 +
   16.46 +  public:
   16.47 +    static Environment *New(Zone *zone, Handle<EnvironmentMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
   16.48 +
   16.49 +    inline EnvironmentMap *map();
   16.50 +    inline size_t size();
   16.51 +
   16.52 +    float getFloat(unsigned slot) {
   16.53 +        return *pointerToSlot<float>(slot);
   16.54 +    }
   16.55 +    int getInt32(unsigned slot) {
   16.56 +        return *pointerToSlot<int>(slot);
   16.57 +    }
   16.58 +    Object *getObject(unsigned slot) {
   16.59 +        return *pointerToSlot<Object *>(slot);
   16.60 +    }
   16.61 +    void setFloat(unsigned slot, float f) {
   16.62 +        *pointerToSlot<float>(slot) = f;
   16.63 +    }
   16.64 +    void setInt32(unsigned slot, int i) {
   16.65 +        *pointerToSlot<int>(slot) = i;
   16.66 +    }
   16.67 +    void setObject(unsigned slot, Object *obj) {
   16.68 +        // :TODO: write barrier
   16.69 +        *pointerToSlot<Object *>(slot) = obj;
   16.70 +    }
   16.71 +
   16.72 +    static inline size_t offsetOfSlotOffset(unsigned offset) {
   16.73 +        return sizeof(Environment) + offset;
   16.74 +    }
   16.75 +
   16.76 +    static inline Environment *cast(Object *obj) {
   16.77 +        assert(!obj || obj->is(MapKind_Environment));
   16.78 +        return reinterpret_cast<Environment *>(obj);
   16.79 +    }
   16.80 +};
   16.81 +
   16.82 +struct EnvironmentSlotDescriptor
   16.83 +{
   16.84 +    Barriered<Type> type;
   16.85 +    unsigned offset;
   16.86 +};
   16.87 +
   16.88 +class EnvironmentSlotDescriptorArray : public Object
   16.89 +{
   16.90 +    unsigned length_;
   16.91 +
   16.92 +  public:
   16.93 +    static EnvironmentSlotDescriptorArray *New(Zone *zone, unsigned length);
   16.94 +
   16.95 +    EnvironmentSlotDescriptor *slots() {
   16.96 +        return reinterpret_cast<EnvironmentSlotDescriptor *>(this + 1);
   16.97 +    }
   16.98 +    EnvironmentSlotDescriptor &at(unsigned slot) {
   16.99 +        assert(slot < length_);
  16.100 +        return slots()[slot];
  16.101 +    }
  16.102 +    unsigned length() {
  16.103 +        return length_;
  16.104 +    }
  16.105 +    unsigned size() {
  16.106 +        return Align(sizeof(*this) + length() * sizeof(EnvironmentSlotDescriptorArray),
  16.107 +                     kObjectAlignment);
  16.108 +    }
  16.109 +
  16.110 +    static inline EnvironmentSlotDescriptorArray *cast(Object *obj) {
  16.111 +        assert(!obj || obj->is(MapKind_EnvironmentSlotDescriptorArray));
  16.112 +        return reinterpret_cast<EnvironmentSlotDescriptorArray *>(obj);
  16.113 +    }
  16.114 +};
  16.115 +
  16.116 +class EnvironmentMap : public Map
  16.117 +{
  16.118 +    unsigned structureSize_;
  16.119 +    unsigned traceOffsetCount_;
  16.120 +    Barriered<EnvironmentSlotDescriptorArray> slots_;
  16.121 +
  16.122 +  public:
  16.123 +    static EnvironmentMap *New(Zone *zone, unsigned nvars, Variable **vars);
  16.124 +
  16.125 +    unsigned structureSize() {
  16.126 +        return structureSize_;
  16.127 +    }
  16.128 +    unsigned traceOffsetCount() {
  16.129 +        return traceOffsetCount_;
  16.130 +    }
  16.131 +    const unsigned *traceOffsets() {
  16.132 +        return reinterpret_cast<unsigned *>(this + 1);
  16.133 +    }
  16.134 +    size_t size() {
  16.135 +        return Align(sizeof(EnvironmentMap) + sizeof(unsigned) * traceOffsetCount(), kObjectAlignment);
  16.136 +    }
  16.137 +    EnvironmentSlotDescriptor &slotDescriptor(unsigned slot) {
  16.138 +        return slots_->at(slot);
  16.139 +    }
  16.140 +
  16.141 +    static inline size_t offsetOfSlots() {
  16.142 +        return offsetof(EnvironmentMap, slots_);
  16.143 +    }
  16.144 +
  16.145 +    static inline EnvironmentMap *cast(Object *obj) {
  16.146 +        assert(!obj || obj->is(MapKind_MetaEnvironment));
  16.147 +        return reinterpret_cast<EnvironmentMap *>(obj);
  16.148 +    }
  16.149 +};
  16.150 +
  16.151 +size_t
  16.152 +Environment::size()
  16.153 +{
  16.154 +    return Align(sizeof(Environment) + map()->structureSize(), kObjectAlignment);
  16.155 +}
  16.156 +
  16.157 +EnvironmentMap *
  16.158 +Environment::map()
  16.159 +{
  16.160 +    return EnvironmentMap::cast(Object::map());
  16.161 +}
  16.162 +
  16.163 +template <typename T> T *
  16.164 +Environment::pointerToSlot(unsigned slot)
  16.165 +{
  16.166 +    return reinterpret_cast<T *>(reinterpret_cast<char *>(this + 1) + map()->slotDescriptor(slot).offset);
  16.167 +}
  16.168 +
  16.169 +}
  16.170 +
  16.171 +#endif // _include_ke_environment_h_
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/Exception.cpp	Tue Jul 24 23:53:34 2012 -0700
    17.3 @@ -0,0 +1,31 @@
    17.4 +
    17.5 +/*
    17.6 + * Copyright (C) 2012 David Anderson
    17.7 + *
    17.8 + * This file is part of JITCraft.
    17.9 + *
   17.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   17.11 + * the terms of the GNU General Public License as published by the Free
   17.12 + * Software Foundation, either version 3 of the License, or (at your option)
   17.13 + * any later version.
   17.14 + * 
   17.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   17.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   17.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   17.18 + *
   17.19 + * You should have received a copy of the GNU General Public License along with
   17.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   17.21 + */
   17.22 +#include "Utility.h"
   17.23 +#include "Messages.h"
   17.24 +
   17.25 +using namespace ke;
   17.26 +
   17.27 +const MessageInfo ke::Messages[] =
   17.28 +{
   17.29 +#define MSG(Name, Type, String) \
   17.30 +    { MessageType_##Type, String },
   17.31 +# include "Messages.tbl"
   17.32 +#undef MSG
   17.33 +    { MessageType_SyntaxError, NULL }
   17.34 +};
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/FixedArray.cpp	Tue Jul 24 23:53:34 2012 -0700
    18.3 @@ -0,0 +1,76 @@
    18.4 +/*
    18.5 + * Copyright (C) 2012 David Anderson
    18.6 + *
    18.7 + * This file is part of JITCraft.
    18.8 + *
    18.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   18.10 + * the terms of the GNU General Public License as published by the Free
   18.11 + * Software Foundation, either version 3 of the License, or (at your option)
   18.12 + * any later version.
   18.13 + * 
   18.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   18.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   18.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   18.17 + *
   18.18 + * You should have received a copy of the GNU General Public License along with
   18.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   18.20 + */
   18.21 +#include <limits.h>
   18.22 +#include "FixedArray.h"
   18.23 +#include "Zone.h"
   18.24 +#include "Heap-inl.h"
   18.25 +
   18.26 +using namespace ke;
   18.27 +
   18.28 +static const unsigned kMaxFixedArrayLength = ((INT_MAX - sizeof(FixedArray)) / sizeof(ke::Object *));
   18.29 +
   18.30 +FixedArray *
   18.31 +FixedArray::New(Zone *zone, unsigned length, Heap::Tenure tenure)
   18.32 +{
   18.33 +    if (length >= kMaxFixedArrayLength) {
   18.34 +        zone->reportError(Message_ArrayTooBig);
   18.35 +        return NULL;
   18.36 +    }
   18.37 +
   18.38 +    Local<FixedArray> array(zone, FixedArray::cast(zone->allocate(MapKind_FixedArray, SizeFor(length), tenure)));
   18.39 +    if (!array)
   18.40 +        return NULL;
   18.41 +
   18.42 +    array->length_ = length;
   18.43 +    memset(array->vec(), 0, length * sizeof(Object *));
   18.44 +    return array;
   18.45 +}
   18.46 +
   18.47 +ByteArray *
   18.48 +ByteArray::New(Zone *zone, unsigned length, Heap::Tenure tenure)
   18.49 +{
   18.50 +    if (length >= kMaxFixedArrayLength) {
   18.51 +        zone->reportError(Message_ArrayTooBig);
   18.52 +        return NULL;
   18.53 +    }
   18.54 +
   18.55 +    Local<ByteArray> array(zone, ByteArray::cast(zone->allocate(MapKind_ByteArray, SizeFor(length), tenure)));
   18.56 +    if (!array)
   18.57 +        return NULL;
   18.58 +
   18.59 +    array->length_ = length;
   18.60 +    memset(array->raw(), 0, length);
   18.61 +    return array;
   18.62 +}
   18.63 +
   18.64 +ByteArray *
   18.65 +ByteArray::New(Zone *zone, Handle<Map> map, unsigned length, Heap::Tenure tenure)
   18.66 +{
   18.67 +    if (length >= kMaxFixedArrayLength) {
   18.68 +        zone->reportError(Message_ArrayTooBig);
   18.69 +        return NULL;
   18.70 +    }
   18.71 +
   18.72 +    Local<ByteArray> array(zone, ByteArray::cast(zone->allocate(map, SizeFor(length), tenure)));
   18.73 +    if (!array)
   18.74 +        return NULL;
   18.75 +
   18.76 +    array->length_ = length;
   18.77 +    memset(array->raw(), 0, length);
   18.78 +    return array;
   18.79 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/src/FixedArray.h	Tue Jul 24 23:53:34 2012 -0700
    19.3 @@ -0,0 +1,89 @@
    19.4 +/* vim: set ts=4 sw=4 tw=99 et
    19.5 + *
    19.6 + * Copyright (C) 2012 David Anderson
    19.7 + *
    19.8 + * This file is part of JITCraft.
    19.9 + *
   19.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   19.11 + * the terms of the GNU General Public License as published by the Free
   19.12 + * Software Foundation, either version 3 of the License, or (at your option)
   19.13 + * any later version.
   19.14 + * 
   19.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   19.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   19.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   19.18 + *
   19.19 + * You should have received a copy of the GNU General Public License along with
   19.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   19.21 + */
   19.22 +#ifndef _include_jitcraft_fixedarray_h_
   19.23 +#define _include_jitcraft_fixedarray_h_
   19.24 +
   19.25 +#include "Heap.h"
   19.26 +
   19.27 +namespace ke {
   19.28 +
   19.29 +// A fixed-length array that contains Object * slots.
   19.30 +class FixedArray : public Object
   19.31 +{
   19.32 +    uint32 length_;
   19.33 +
   19.34 +  private:
   19.35 +    Object **vec() {
   19.36 +        return reinterpret_cast<Object **>(this + 1);
   19.37 +    }
   19.38 +
   19.39 +  public:
   19.40 +    static FixedArray *New(Zone *zone, unsigned length, Heap::Tenure tenure);
   19.41 +
   19.42 +    unsigned length() {
   19.43 +        return length_;
   19.44 +    }
   19.45 +    Object *at(size_t i) {
   19.46 +        assert(i < length());
   19.47 +        return vec()[i];
   19.48 +    }
   19.49 +    void set(Zone *zone, size_t i, Object *obj) {
   19.50 +        assert(i < length());
   19.51 +        write(zone, &vec()[i], obj);
   19.52 +    }
   19.53 +
   19.54 +    static size_t SizeFor(unsigned length) {
   19.55 +        return sizeof(FixedArray) + sizeof(Object *) * length;
   19.56 +    }
   19.57 +
   19.58 +    static inline FixedArray *cast(Object *obj) {
   19.59 +        assert(!obj || obj->is(MapKind_FixedArray));
   19.60 +        return reinterpret_cast<FixedArray *>(obj);
   19.61 +    }
   19.62 +};
   19.63 +
   19.64 +// A fixed-length array containing raw bytes.
   19.65 +class ByteArray : public Object
   19.66 +{
   19.67 +    uint32 length_;
   19.68 +
   19.69 +  public:
   19.70 +    static ByteArray *New(Zone *zone, unsigned length, Heap::Tenure tenure = Heap::Tenure_Default);
   19.71 +    static ByteArray *New(Zone *zone, Handle<Map> map, unsigned length, Heap::Tenure tenure = Heap::Tenure_Default);
   19.72 +
   19.73 +    unsigned length() {
   19.74 +        return length_;
   19.75 +    }
   19.76 +    Address raw() {
   19.77 +        return reinterpret_cast<uint8 *>(this + 1);
   19.78 +    }
   19.79 +
   19.80 +    static size_t SizeFor(unsigned length) {
   19.81 +        return Align(sizeof(ByteArray) + sizeof(uint8) * length, kObjectAlignment);
   19.82 +    }
   19.83 +
   19.84 +    static inline ByteArray *cast(Object *obj) {
   19.85 +        assert(!obj || obj->is(MapKind_ByteArray));
   19.86 +        return reinterpret_cast<ByteArray *>(obj);
   19.87 +    }
   19.88 +};
   19.89 +
   19.90 +}
   19.91 +
   19.92 +#endif // _include_jitcraft_fixedarray_h_
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/src/Functions.cpp	Tue Jul 24 23:53:34 2012 -0700
    20.3 @@ -0,0 +1,51 @@
    20.4 +/*
    20.5 + * Copyright (C) 2012 David Anderson
    20.6 + *
    20.7 + * This file is part of JITCraft.
    20.8 + *
    20.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   20.10 + * the terms of the GNU General Public License as published by the Free
   20.11 + * Software Foundation, either version 3 of the License, or (at your option)
   20.12 + * any later version.
   20.13 + * 
   20.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   20.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   20.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   20.17 + *
   20.18 + * You should have received a copy of the GNU General Public License along with
   20.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   20.20 + */
   20.21 +#include "Functions.h"
   20.22 +#include "Modules.h"
   20.23 +#include "Zone.h"
   20.24 +#include "Heap-inl.h"
   20.25 +
   20.26 +using namespace ke;
   20.27 +
   20.28 +Function *
   20.29 +Function::New(Zone *zone, Handle<Code> code, Handle<Type> type, Handle<String> name,
   20.30 +              const SourcePosition &pos)
   20.31 +{
   20.32 +    Function *fun = Function::cast(zone->allocate(MapKind_Function, sizeof(Function), Heap::Tenure_Old));
   20.33 +    if (!fun)
   20.34 +        return NULL;
   20.35 +
   20.36 +    fun->code_ = code;
   20.37 +    fun->pos_ = pos;
   20.38 +    fun->type_ = type;
   20.39 +    fun->name_ = name;
   20.40 +    return fun;
   20.41 +}
   20.42 +
   20.43 +Native *
   20.44 +Native::New(Zone *zone, Handle<Type> type, Handle<String> name)
   20.45 +{
   20.46 +    Native *fun = Native::cast(zone->allocate(MapKind_Native, sizeof(Native), Heap::Tenure_Old));
   20.47 +    if (!fun)
   20.48 +        return NULL;
   20.49 +
   20.50 +    fun->type_ = type;
   20.51 +    fun->name_ = name;
   20.52 +    fun->function_ = NULL;
   20.53 +    return fun;
   20.54 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/src/Functions.h	Tue Jul 24 23:53:34 2012 -0700
    21.3 @@ -0,0 +1,122 @@
    21.4 +/*
    21.5 + * Copyright (C) 2012 David Anderson
    21.6 + *
    21.7 + * This file is part of JITCraft.
    21.8 + *
    21.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   21.10 + * the terms of the GNU General Public License as published by the Free
   21.11 + * Software Foundation, either version 3 of the License, or (at your option)
   21.12 + * any later version.
   21.13 + * 
   21.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   21.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   21.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   21.17 + *
   21.18 + * You should have received a copy of the GNU General Public License along with
   21.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   21.20 + */
   21.21 +#ifndef _include_jitcraft_function_h_
   21.22 +#define _include_jitcraft_function_h_
   21.23 +
   21.24 +#include "Heap.h"
   21.25 +#include "Barriers.h"
   21.26 +#include "Token.h"
   21.27 +#include "Types.h"
   21.28 +
   21.29 +namespace ke {
   21.30 +
   21.31 +class Code;
   21.32 +class Module;
   21.33 +class Type;
   21.34 +class String;
   21.35 +
   21.36 +class Function : public Object
   21.37 +{
   21.38 +    Barriered<Code> code_;
   21.39 +    Barriered<Type> type_;
   21.40 +    Barriered<String> name_;
   21.41 +    SourcePosition pos_;
   21.42 +
   21.43 + public:
   21.44 +    static Function *New(Zone *zone, Handle<Code> code, Handle<Type> type, Handle<String> name,
   21.45 +                         const SourcePosition &pos);
   21.46 +
   21.47 +    Code *code() const {
   21.48 +        return code_;
   21.49 +    }
   21.50 +    Type *type() const {
   21.51 +        return type_;
   21.52 +    }
   21.53 +    String *name() const {
   21.54 +        return name_;
   21.55 +    }
   21.56 +    const SourcePosition &pos() {
   21.57 +        return pos_;
   21.58 +    }
   21.59 +    unsigned nargs() {
   21.60 +        return type()->parameters()->length();
   21.61 +    }
   21.62 +    Type *argType(size_t index) {
   21.63 +        return type()->parameterAt(index);
   21.64 +    }
   21.65 +
   21.66 +    // Begin GC Descriptor.
   21.67 +    static inline size_t offsetOfCode() {
   21.68 +        return offsetof(Function, code_);
   21.69 +    }
   21.70 +    static inline size_t offsetOfType() {
   21.71 +        return offsetof(Function, type_);
   21.72 +    }
   21.73 +    static inline size_t offsetOfName() {
   21.74 +        return offsetof(Function, name_);
   21.75 +    }
   21.76 +    // End GC Descriptor.
   21.77 +
   21.78 +    static inline Function *cast(Object *obj) {
   21.79 +        assert(!obj || obj->is(MapKind_Function));
   21.80 +        return reinterpret_cast<Function *>(obj);
   21.81 +    }
   21.82 +};
   21.83 +
   21.84 +// A Native is a function with a very specialized calling convention, intended
   21.85 +// for earlier ISourcePawnEngine API compatibility.
   21.86 +class Native : public Object
   21.87 +{
   21.88 +    Barriered<Type> type_;
   21.89 +    Barriered<String> name_;
   21.90 +    void *function_;
   21.91 +
   21.92 +  public:
   21.93 +    static Native *New(Zone *zone, Handle<Type> type, Handle<String> name);
   21.94 +
   21.95 +    void *function() {
   21.96 +        return function_;
   21.97 +    }
   21.98 +    Type *type() {
   21.99 +        return type_;
  21.100 +    }
  21.101 +    String *name() {
  21.102 +        return name_;
  21.103 +    }
  21.104 +    void bind(void *function) {
  21.105 +        function_ = function;
  21.106 +    }
  21.107 +
  21.108 +    // Begin GC Descriptor.
  21.109 +    static inline size_t offsetOfType() {
  21.110 +        return offsetof(Native, type_);
  21.111 +    }
  21.112 +    static inline size_t offsetOfName() {
  21.113 +        return offsetof(Native, name_);
  21.114 +    }
  21.115 +    // End GC Descriptor.
  21.116 +
  21.117 +    static inline Native *cast(Object *obj) {
  21.118 +        assert(!obj || obj->is(MapKind_Native));
  21.119 +        return reinterpret_cast<Native *>(obj);
  21.120 +    }
  21.121 +};
  21.122 +
  21.123 +}
  21.124 +
  21.125 +#endif // _include_jitcraft_function_h_
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/src/GlobalRoots.cpp	Tue Jul 24 23:53:34 2012 -0700
    22.3 @@ -0,0 +1,81 @@
    22.4 +/*
    22.5 + * Copyright (C) 2004-2012 David Anderson
    22.6 + *
    22.7 + * This file is part of SourcePawn.
    22.8 + *
    22.9 + * SourcePawn is free software: you can redistribute it and/or modify it under
   22.10 + * the terms of the GNU General Public License as published by the Free
   22.11 + * Software Foundation, either version 3 of the License, or (at your option)
   22.12 + * any later version.
   22.13 + * 
   22.14 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   22.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   22.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   22.17 + *
   22.18 + * You should have received a copy of the GNU General Public License along with
   22.19 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   22.20 + */
   22.21 +#include "GlobalRoots.h"
   22.22 +#include "Zone.h"
   22.23 +
   22.24 +using namespace ke;
   22.25 +
   22.26 +GlobalRoots::GlobalRoots(Zone *zone)
   22.27 +  : zone_(zone)
   22.28 +{
   22.29 +}
   22.30 +
   22.31 +GlobalRoots::~GlobalRoots()
   22.32 +{
   22.33 +    InlineList<HeapRoot>::iterator iter = roots_.begin();
   22.34 +    while (iter != roots_.end()) {
   22.35 +		HeapRoot *root = *iter;
   22.36 +        iter = roots_.erase(iter);
   22.37 +		delete root;
   22.38 +    }
   22.39 +}
   22.40 +
   22.41 +bool
   22.42 +GlobalRoots::initialize()
   22.43 +{
   22.44 +    return true;
   22.45 +}
   22.46 +
   22.47 +void
   22.48 +GlobalRoots::accept(VirtualObjectVisitor *visitor)
   22.49 +{
   22.50 +    for (InlineList<HeapRoot>::iterator iter = roots_.begin(); iter != roots_.end(); iter++)
   22.51 +        visitor->visit(&iter->obj);
   22.52 +}
   22.53 +
   22.54 +HeapRoot *
   22.55 +GlobalRoots::create(Handle<Object> obj)
   22.56 +{
   22.57 +    HeapRoot *root = new HeapRoot();
   22.58 +    if (!root) {
   22.59 +        ZONE()->reportOutOfMemory();
   22.60 +        return NULL;
   22.61 +    }
   22.62 +
   22.63 +    root->obj = obj;
   22.64 +    root->refcount = 1;
   22.65 +
   22.66 +    roots_.append(root);
   22.67 +    return root;
   22.68 +}
   22.69 +
   22.70 +void
   22.71 +GlobalRoots::incref(HeapRoot *root)
   22.72 +{
   22.73 +    root->refcount++;
   22.74 +}
   22.75 +
   22.76 +void
   22.77 +GlobalRoots::decref(HeapRoot *root)
   22.78 +{
   22.79 +    assert(root->refcount > 0);
   22.80 +    if (--root->refcount == 0) {
   22.81 +        roots_.remove(root);
   22.82 +        delete root;
   22.83 +    }
   22.84 +}
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/src/GlobalRoots.h	Tue Jul 24 23:53:34 2012 -0700
    23.3 @@ -0,0 +1,61 @@
    23.4 +/*
    23.5 + * Copyright (C) 2004-2012 David Anderson
    23.6 + *
    23.7 + * This file is part of SourcePawn.
    23.8 + *
    23.9 + * SourcePawn is free software: you can redistribute it and/or modify it under
   23.10 + * the terms of the GNU General Public License as published by the Free
   23.11 + * Software Foundation, either version 3 of the License, or (at your option)
   23.12 + * any later version.
   23.13 + * 
   23.14 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   23.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   23.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   23.17 + *
   23.18 + * You should have received a copy of the GNU General Public License along with
   23.19 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   23.20 + */
   23.21 +#ifndef _include_ke_global_roots_h_
   23.22 +#define _include_ke_global_roots_h_
   23.23 +
   23.24 +#include "Handles.h"
   23.25 +#include "InlineList.h"
   23.26 +#include "VirtualObjectVisitor.h"
   23.27 +
   23.28 +namespace ke {
   23.29 +
   23.30 +class Zone;
   23.31 +class Object;
   23.32 +
   23.33 +class HeapRoot : public InlineListNode<HeapRoot>
   23.34 +{
   23.35 +  public:
   23.36 +    Object *obj;
   23.37 +    intptr_t refcount;
   23.38 +};
   23.39 +
   23.40 +class GlobalRoots
   23.41 +{
   23.42 +    Zone *zone_;
   23.43 +
   23.44 +  public:
   23.45 +    GlobalRoots(Zone *zone);
   23.46 +    ~GlobalRoots();
   23.47 +
   23.48 +    bool initialize();
   23.49 +
   23.50 +    // The caller must immediately incref this.
   23.51 +    HeapRoot *create(Handle<Object> ptr);
   23.52 +
   23.53 +    void incref(HeapRoot *root);
   23.54 +    void decref(HeapRoot *root);
   23.55 +
   23.56 +    void accept(VirtualObjectVisitor *visitor);
   23.57 +
   23.58 +  private:
   23.59 +    InlineList<HeapRoot> roots_;
   23.60 +};
   23.61 +
   23.62 +}
   23.63 +
   23.64 +#endif // _include_ke_global_roots_h_
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/src/Handles-inl.h	Tue Jul 24 23:53:34 2012 -0700
    24.3 @@ -0,0 +1,62 @@
    24.4 +/*
    24.5 + * Copyright (C) 2012 David Anderson
    24.6 + *
    24.7 + * This file is part of JITCraft.
    24.8 + *
    24.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   24.10 + * the terms of the GNU General Public License as published by the Free
   24.11 + * Software Foundation, either version 3 of the License, or (at your option)
   24.12 + * any later version.
   24.13 + * 
   24.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   24.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   24.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   24.17 + *
   24.18 + * You should have received a copy of the GNU General Public License along with
   24.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   24.20 + */
   24.21 +#ifndef _include_jitcraft_rooting_inl_h_
   24.22 +#define _include_jitcraft_rooting_inl_h_
   24.23 +
   24.24 +#include "Heap.h"
   24.25 +
   24.26 +namespace ke {
   24.27 +
   24.28 +template <typename T>
   24.29 +Local<T>::Local(Environment *env)
   24.30 +  : zone_(env->zone()), thing_(NULL)
   24.31 +{
   24.32 +    prev_ = zone_->registerThingLocal(toRaw());
   24.33 +}
   24.34 +
   24.35 +template <typename T>
   24.36 +Local<T>::Local(Environment *env, T *thing)
   24.37 +  : zone_(env->zone()), thing_(thing)
   24.38 +{
   24.39 +    prev_ = zone_->registerThingLocal(toRaw());
   24.40 +}
   24.41 +
   24.42 +template <typename T>
   24.43 +Local<T>::Local(Zone *zone)
   24.44 +  : zone_(zone), thing_(NULL)
   24.45 +{
   24.46 +    prev_ = zone_->registerThingLocal(toRaw());
   24.47 +}
   24.48 +
   24.49 +template <typename T>
   24.50 +Local<T>::Local(Zone *zone, T *thing)
   24.51 +  : zone_(zone), thing_(thing)
   24.52 +{
   24.53 +    prev_ = zone_->registerThingLocal(toRaw());
   24.54 +}
   24.55 +
   24.56 +
   24.57 +template <typename T>
   24.58 +Local<T>::~Local()
   24.59 +{
   24.60 +    zone_->deregisterThingLocal(toRaw(), prev_);
   24.61 +}
   24.62 +
   24.63 +}
   24.64 +
   24.65 +#endif // _include_jitcraft_rooting_inl_h_
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/src/Handles.h	Tue Jul 24 23:53:34 2012 -0700
    25.3 @@ -0,0 +1,204 @@
    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 JITCraft.
    25.9 + *
   25.10 + * JITCraft 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 + * Foobar 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 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   25.21 + */
   25.22 +#ifndef _include_jitcraft_rooting_h_
   25.23 +#define _include_jitcraft_rooting_h_
   25.24 +
   25.25 +#include <stdlib.h>
   25.26 +
   25.27 +namespace ke {
   25.28 +
   25.29 +class Zone;
   25.30 +class Object;
   25.31 +
   25.32 +template <typename T> class Local;
   25.33 +template <typename T> class ScopedRoot;
   25.34 +
   25.35 +/*
   25.36 + * Internal handles work differently from API handles. An API handle is a
   25.37 + * root, whereas as an internal handle points to a rooted location. This
   25.38 + * subtle difference makes handles easy for embedders, but somewhat
   25.39 + * cumbersome internally.
   25.40 + */
   25.41 +template <typename T>
   25.42 +class Handle
   25.43 +{
   25.44 +    T * const *thingp_;
   25.45 +
   25.46 +  public:
   25.47 +    Handle(const Handle &other) {
   25.48 +        thingp_ = other.address();
   25.49 +    }
   25.50 +    template <typename S> Handle(const Handle<S> &handle) {
   25.51 +        typeCheck<S>();
   25.52 +        thingp_ = reinterpret_cast<T * const *>(handle.address());
   25.53 +    }
   25.54 +    template <typename S> inline Handle(const Local<S> &local);
   25.55 +    template <typename S> inline Handle(const ScopedRoot<S> &root);
   25.56 +
   25.57 +  public:
   25.58 +    T *operator ->() {
   25.59 +        return *thingp_;
   25.60 +    }
   25.61 +    T *operator *() {
   25.62 +        return *thingp_;
   25.63 +    }
   25.64 +    operator T *() { return *thingp_; }
   25.65 +    operator bool() const {
   25.66 +        return thingp_ && *thingp_;
   25.67 +    }
   25.68 +    T * const *address() const {
   25.69 +        return thingp_;
   25.70 +    }
   25.71 +
   25.72 +  private:
   25.73 +    template <typename S>
   25.74 +    void typeCheck() {
   25.75 +#ifndef NDEBUG
   25.76 +        T *v1 = NULL;
   25.77 +        S *v2 = NULL;
   25.78 +        v1 = v2;
   25.79 +        (void)v1;
   25.80 +#endif
   25.81 +    }
   25.82 +};
   25.83 +
   25.84 +template <typename T>
   25.85 +class Local
   25.86 +{
   25.87 +    friend class Zone;
   25.88 +
   25.89 +    Zone *zone_;
   25.90 +    T *thing_;
   25.91 +    Local<Object> *prev_;
   25.92 +
   25.93 +    Local<Object> *prev() {
   25.94 +        return prev_;
   25.95 +    }
   25.96 +    Local<Object> *toRaw() {
   25.97 +        return reinterpret_cast<Local<Object>*>(this);
   25.98 +    }
   25.99 +
  25.100 +  public:
  25.101 +    // These are implemented in Zone.h.
  25.102 +    inline explicit Local(Zone *zone, T *thing = NULL);
  25.103 +    inline ~Local();
  25.104 +
  25.105 +    const Local &operator =(T *thing) {
  25.106 +        thing_ = thing;
  25.107 +        return *this;
  25.108 +    }
  25.109 +    T *operator ->() const {
  25.110 +        return operator *();
  25.111 +    }
  25.112 +    T *operator *() const {
  25.113 +        return thing_;
  25.114 +    }
  25.115 +    operator bool () const {
  25.116 +        return !!thing_;
  25.117 +    }
  25.118 +    bool operator !=(const Local &other) {
  25.119 +        return thing_ != other.thing_;
  25.120 +    }
  25.121 +
  25.122 +    Object **address() {
  25.123 +        return (Object **)&thing_;
  25.124 +    }
  25.125 +    Object * const *address() const {
  25.126 +        return (Object * const *)&thing_;
  25.127 +    }
  25.128 +    T **ref() {
  25.129 +        return &thing_;
  25.130 +    }
  25.131 +    operator T *() {
  25.132 +        return thing_;
  25.133 +    }
  25.134 +
  25.135 +  private:
  25.136 +    // Disallow heap allocation.
  25.137 +    void *operator new(size_t size);
  25.138 +    void *operator new[](size_t size);
  25.139 +
  25.140 +    // Disallow copy construction.
  25.141 +    Local(const Local<T> &other);
  25.142 +    Local &operator =(const Local &other);
  25.143 +};
  25.144 +
  25.145 +// A ScopedRoot is a special kind of handle for storing references on the
  25.146 +// heap in bulk.
  25.147 +template <typename T>
  25.148 +class ScopedRoot
  25.149 +{
  25.150 +    T **thingp_;
  25.151 +
  25.152 +  private:
  25.153 +    // This is implemented in Zone.h.
  25.154 +    inline T **make(T *other);
  25.155 +
  25.156 +    void assign(T *other) {
  25.157 +        *thingp_ = other;
  25.158 +    }
  25.159 +
  25.160 +  public:
  25.161 +    ScopedRoot();
  25.162 +
  25.163 +    // This is implemented in Zone.h.
  25.164 +    inline ScopedRoot(T *thing);
  25.165 +
  25.166 +    ScopedRoot &operator =(const ScopedRoot<T> &other) {
  25.167 +        assign(*other);
  25.168 +        return *this;
  25.169 +    }
  25.170 +    ScopedRoot &operator =(T *other) {
  25.171 +        assign(other);
  25.172 +        return *this;
  25.173 +    }
  25.174 +    T *operator ->() const {
  25.175 +        return operator *();
  25.176 +    }
  25.177 +    T *operator *() const {
  25.178 +        return *thingp_;
  25.179 +    }
  25.180 +    operator T *() const {
  25.181 +        return *thingp_;
  25.182 +    }
  25.183 +    operator bool () const {
  25.184 +        return !!*thingp_;
  25.185 +    }
  25.186 +    T **address() const {
  25.187 +        return thingp_;
  25.188 +    }
  25.189 +};
  25.190 +
  25.191 +template <typename T> template <typename S> inline
  25.192 +Handle<T>::Handle(const Local<S> &local)
  25.193 +{
  25.194 +    typeCheck<S>();
  25.195 +    thingp_ = reinterpret_cast<T * const *>(local.address());
  25.196 +}
  25.197 +
  25.198 +template <typename T> template <typename S> inline
  25.199 +Handle<T>::Handle(const ScopedRoot<S> &root)
  25.200 +{
  25.201 +    typeCheck<S>();
  25.202 +    thingp_ = reinterpret_cast<T * const *>(root.address());
  25.203 +}
  25.204 +
  25.205 +}
  25.206 +
  25.207 +#endif // _include_jitcraft_rooting_h_
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/HashTable.h	Tue Jul 24 23:53:34 2012 -0700
    26.3 @@ -0,0 +1,424 @@
    26.4 +/*
    26.5 + * Copyright (C) 2012 David Anderson
    26.6 + *
    26.7 + * This file is part of JITCraft.
    26.8 + *
    26.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   26.10 + * the terms of the GNU General Public License as published by the Free
   26.11 + * Software Foundation, either version 3 of the License, or (at your option)
   26.12 + * any later version.
   26.13 + * 
   26.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   26.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   26.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   26.17 + *
   26.18 + * You should have received a copy of the GNU General Public License along with
   26.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   26.20 + */
   26.21 +#ifndef _INCLUDE_KEIMA_HASHTABLE_H_
   26.22 +#define _INCLUDE_KEIMA_HASHTABLE_H_
   26.23 +
   26.24 +#include <new>
   26.25 +#include <limits.h>
   26.26 +#include "Utility.h"
   26.27 +
   26.28 +namespace ke {
   26.29 +
   26.30 +template <typename T>
   26.31 +class HashTableEntry
   26.32 +{
   26.33 +    uint32 hash_;
   26.34 +    T t_;
   26.35 +
   26.36 +  public:
   26.37 +    static const uint32 kFreeHash = 0;
   26.38 +    static const uint32 kRemovedHash = 1;
   26.39 +
   26.40 +  public:
   26.41 +    void setHash(uint32 hash) {
   26.42 +        hash_ = hash;
   26.43 +    }
   26.44 +    uint32 hash() const {
   26.45 +        return hash_;
   26.46 +    }
   26.47 +    void setRemoved() {
   26.48 +        hash_ = kRemovedHash;
   26.49 +        t_ = T();
   26.50 +    }
   26.51 +    void construct() {
   26.52 +        hash_ = kFreeHash;
   26.53 +        new (&t_) T();
   26.54 +    }
   26.55 +    void destruct() {
   26.56 +        t_.~T();
   26.57 +    }
   26.58 +    bool removed() const {
   26.59 +        return hash_ == kRemovedHash;
   26.60 +    }
   26.61 +    bool free() const {
   26.62 +        return hash_ == kFreeHash;
   26.63 +    }
   26.64 +    bool isLive() const {
   26.65 +        return hash_ > kRemovedHash;
   26.66 +    }
   26.67 +    T &payload() {
   26.68 +        return t_;
   26.69 +    }
   26.70 +    bool sameHash(uint32 hash) const {
   26.71 +        return hash_ == hash;
   26.72 +    }
   26.73 +};
   26.74 +
   26.75 +template <typename HashPolicy, typename AllocPolicy>
   26.76 +class HashTable : public AllocPolicy
   26.77 +{
   26.78 +    friend class iterator;
   26.79 +
   26.80 +    typedef typename HashPolicy::Payload Payload;
   26.81 +    typedef HashTableEntry<Payload> Entry;
   26.82 +
   26.83 +    uint32 capacity_;
   26.84 +    uint32 nelements_;
   26.85 +    uint32 ndeleted_;
   26.86 +    Entry *table_;
   26.87 +    uint32 minCapacity_;
   26.88 +
   26.89 +  private:
   26.90 +    static const uint32 kMinCapacity = 16;
   26.91 +    static const uint32 kMaxCapacity = INT_MAX / sizeof(Entry);
   26.92 +
   26.93 +    template <typename Key>
   26.94 +    uint32 computeHash(const Key &key) {
   26.95 +        // Multiply by golden ratio.
   26.96 +        uint32 hash = HashPolicy::hash(key) * 0x9E3779B9;
   26.97 +        if (hash == Entry::kFreeHash || hash == Entry::kRemovedHash)
   26.98 +            hash += 2;
   26.99 +        return hash;
  26.100 +    }
  26.101 +
  26.102 +    Entry *createTable(uint32 capacity) {
  26.103 +        assert(capacity <= kMaxCapacity);
  26.104 +
  26.105 +        Entry *table = (Entry *)this->malloc(capacity * sizeof(Entry));
  26.106 +        if (!table)
  26.107 +            return NULL;
  26.108 +
  26.109 +        for (size_t i = 0; i < capacity; i++)
  26.110 +            table[i].construct();
  26.111 +
  26.112 +        return table;
  26.113 +    }
  26.114 +
  26.115 +  public:
  26.116 +    class Result
  26.117 +    {
  26.118 +        friend class HashTable;
  26.119 +
  26.120 +        Entry *entry_;
  26.121 +
  26.122 +        Entry &entry() {
  26.123 +            return *entry_;
  26.124 +        }
  26.125 +
  26.126 +      public:
  26.127 +        Result(Entry *entry)
  26.128 +          : entry_(entry)
  26.129 +        { }
  26.130 +
  26.131 +        Payload * operator ->() {
  26.132 +            return entry_->payload();
  26.133 +        }
  26.134 +        Payload & operator *() {
  26.135 +            return entry_->payload();
  26.136 +        }
  26.137 +
  26.138 +        bool found() const {
  26.139 +            return entry_->isLive();
  26.140 +        }
  26.141 +    };
  26.142 +
  26.143 +    class Insert : public Result
  26.144 +    {
  26.145 +        uint32 hash_;
  26.146 +
  26.147 +      public:
  26.148 +        Insert(Entry *entry, uint32 hash)
  26.149 +          : Result(entry),
  26.150 +            hash_(hash)
  26.151 +        {
  26.152 +        }
  26.153 +
  26.154 +        uint32 hash() const {
  26.155 +            return hash_;
  26.156 +        }
  26.157 +    };
  26.158 +
  26.159 +  private:
  26.160 +    class Probulator {
  26.161 +        uint32 hash_;
  26.162 +        uint32 capacity_;
  26.163 +
  26.164 +      public:
  26.165 +        Probulator(uint32 hash, uint32 capacity)
  26.166 +          : hash_(hash),
  26.167 +            capacity_(capacity)
  26.168 +        {
  26.169 +            assert(IsPowerOfTwo(capacity_)); 
  26.170 +        }
  26.171 +
  26.172 +        uint32 entry() const {
  26.173 +            return hash_ & (capacity_ - 1);
  26.174 +        }
  26.175 +        uint32 next() {
  26.176 +            hash_++;
  26.177 +            return entry();
  26.178 +        }
  26.179 +    };
  26.180 +
  26.181 +    bool underloaded() const {
  26.182 +        // Check if the table is underloaded: < 25% entries used.
  26.183 +        return (capacity_ > kMinCapacity) && (nelements_ + ndeleted_ < capacity_ / 4);
  26.184 +    }
  26.185 +    bool overloaded() const {
  26.186 +        // Grow if the table is overloaded: > 75% entries used.
  26.187 +        return (nelements_ + ndeleted_) > ((capacity_ / 2) + (capacity_ / 4));
  26.188 +    }
  26.189 +
  26.190 +    bool shrink() {
  26.191 +        if ((capacity_ >> 1) < minCapacity_)
  26.192 +            return true;
  26.193 +        return changeCapacity(capacity_ >> 1);
  26.194 +    }
  26.195 +    
  26.196 +    bool grow() {
  26.197 +        assert(IsPowerOfTwo(kMaxCapacity));
  26.198 +        if (capacity_ >= kMaxCapacity) {
  26.199 +            this->reportAllocationOverflow();
  26.200 +            return false;
  26.201 +        }
  26.202 +        return changeCapacity(capacity_ << 1);
  26.203 +    }
  26.204 +
  26.205 +    bool changeCapacity(uint32 newCapacity) {
  26.206 +        assert(newCapacity <= kMaxCapacity);
  26.207 +
  26.208 +        Entry *newTable = createTable(newCapacity);
  26.209 +        if (!newTable)
  26.210 +            return false;
  26.211 +
  26.212 +        Entry *oldTable = table_;
  26.213 +        uint32 oldCapacity = capacity_;
  26.214 +
  26.215 +        table_ = newTable;
  26.216 +        capacity_ = newCapacity;
  26.217 +        ndeleted_ = 0;
  26.218 +
  26.219 +        for (uint32 i = 0; i < oldCapacity; i++) {
  26.220 +            Entry &oldEntry = oldTable[i];
  26.221 +            if (oldEntry.isLive()) {
  26.222 +                Insert p = insertUnique(oldEntry.hash());
  26.223 +                p.entry().setHash(p.hash());
  26.224 +                p.entry().payload() = oldEntry.payload();
  26.225 +            }
  26.226 +            oldEntry.destruct();
  26.227 +        }
  26.228 +        this->free(oldTable);
  26.229 +
  26.230 +        return true;
  26.231 +    }
  26.232 +
  26.233 +    // For use when the key is known to be unique.
  26.234 +    Insert insertUnique(uint32 hash) {
  26.235 +        Probulator probulator(hash, capacity_);
  26.236 +
  26.237 +        Entry *e = &table_[probulator.entry()];
  26.238 +        for (;;) {
  26.239 +            if (e->free() || e->removed())
  26.240 +                break;
  26.241 +            e = &table_[probulator.next()];
  26.242 +        }
  26.243 +
  26.244 +        return Insert(e, hash);
  26.245 +    }
  26.246 +
  26.247 +    template <typename Key>
  26.248 +    Result lookup(const Key &key) {
  26.249 +        uint32 hash = computeHash(key);
  26.250 +        Probulator probulator(hash, capacity_);
  26.251 +
  26.252 +        Entry *e = &table_[probulator.entry()];
  26.253 +        for (;;) {
  26.254 +            if (e->free())
  26.255 +                break;
  26.256 +            if (e->isLive() &&
  26.257 +                e->sameHash(hash) &&
  26.258 +                HashPolicy::matches(key, e->payload()))
  26.259 +            {
  26.260 +                return Result(e);
  26.261 +            }
  26.262 +            e = &table_[probulator.next()];
  26.263 +        }
  26.264 +
  26.265 +        return Result(e);
  26.266 +    }
  26.267 +
  26.268 +    template <typename Key>
  26.269 +    Insert lookupForAdd(const Key &key) {
  26.270 +        uint32 hash = computeHash(key);
  26.271 +        Probulator probulator(hash, capacity_);
  26.272 +
  26.273 +        Entry *e = &table_[probulator.entry()];
  26.274 +        for (;;) {
  26.275 +            if (!e->isLive())
  26.276 +                break;
  26.277 +            if (e->sameHash(hash) && HashPolicy::matches(key, e->payload()))
  26.278 +                break;
  26.279 +            e = &table_[probulator.next()];
  26.280 +        }
  26.281 +
  26.282 +        return Insert(e, hash);
  26.283 +    }
  26.284 +
  26.285 +    bool add(Insert &i) {
  26.286 +        assert(!i.found());
  26.287 +
  26.288 +        // If the entry is deleted, just re-use the slot.
  26.289 +        if (i.entry().removed()) {
  26.290 +            ndeleted_--;
  26.291 +            return true;
  26.292 +        }
  26.293 +
  26.294 +        // Otherwise, see if we're at max capacity.
  26.295 +        if (nelements_ == kMaxCapacity) {
  26.296 +            this->reportAllocationOverflow();
  26.297 +            return false;
  26.298 +        }
  26.299 +
  26.300 +        // Check if the table is over or underloaded. The table is always at
  26.301 +        // least 25% free, so this check is enough to guarantee one free slot.
  26.302 +        // (Without one free slot, insertion search could infinite loop.)
  26.303 +        uint32 oldCapacity = capacity_;
  26.304 +        if (!checkDensity())
  26.305 +            return false;
  26.306 +
  26.307 +        // If the table changed size, we need to find a new insertion point.
  26.308 +        // Note that a removed entry is impossible: either we caught it above,
  26.309 +        // or we just resized and no entries are removed.
  26.310 +        if (capacity_ != oldCapacity)
  26.311 +            i = insertUnique(i.hash());
  26.312 +
  26.313 +        i.entry().setHash(i.hash());
  26.314 +        nelements_++;
  26.315 +
  26.316 +        return true;
  26.317 +    }
  26.318 +
  26.319 +    void remove(Entry &e) {
  26.320 +        assert(e.isLive());
  26.321 +        e.setRemoved();
  26.322 +        ndeleted_++;
  26.323 +        nelements_--;
  26.324 +    }
  26.325 +
  26.326 +  public:
  26.327 +    HashTable(AllocPolicy ap)
  26.328 +      : AllocPolicy(ap),
  26.329 +        capacity_(0),
  26.330 +        nelements_(0),
  26.331 +        ndeleted_(0),
  26.332 +        table_(NULL),
  26.333 +        minCapacity_(kMinCapacity)
  26.334 +    {
  26.335 +    }
  26.336 +
  26.337 +    ~HashTable()
  26.338 +    {
  26.339 +        for (uint32 i = 0; i < capacity_; i++)
  26.340 +            table_[i].destruct();
  26.341 +        this->free(table_);
  26.342 +    }
  26.343 +
  26.344 +    bool init(uint32 capacity = 0) {
  26.345 +        if (capacity < kMinCapacity)
  26.346 +            capacity = kMinCapacity;
  26.347 +        else if (capacity > kMaxCapacity)
  26.348 +            capacity = kMaxCapacity;
  26.349 +
  26.350 +        minCapacity_ = capacity;
  26.351 +
  26.352 +        assert(IsPowerOfTwo(capacity));
  26.353 +        capacity_ = capacity;
  26.354 +
  26.355 +        table_ = createTable(capacity_);
  26.356 +        if (!table_)
  26.357 +            return false;
  26.358 +
  26.359 +        return true;
  26.360 +    }
  26.361 +
  26.362 +    template <typename Key>
  26.363 +    Result find(const Key &key) {
  26.364 +        return lookup(key);
  26.365 +    }
  26.366 +
  26.367 +    template <typename Key>
  26.368 +    Insert findForAdd(const Key &key) {
  26.369 +        return lookupForAdd(key);
  26.370 +    }
  26.371 +
  26.372 +    bool add(Insert &i, const Payload &payload) {
  26.373 +        if (!add(i))
  26.374 +            return false;
  26.375 +        *i = payload;
  26.376 +        return true;
  26.377 +    }
  26.378 +
  26.379 +    bool checkDensity() {
  26.380 +        if (underloaded())
  26.381 +            return shrink(); 
  26.382 +        if (overloaded())
  26.383 +            return grow();
  26.384 +        return true;
  26.385 +    }
  26.386 +
  26.387 +  public:
  26.388 +    class iterator
  26.389 +    {
  26.390 +        HashTable *table_;
  26.391 +        Entry *i_;
  26.392 +        Entry *end_;
  26.393 +
  26.394 +      public:
  26.395 +        iterator(HashTable *table)
  26.396 +          : table_(table),
  26.397 +            i_(table->table_),
  26.398 +            end_(table->table_ + table->capacity_)
  26.399 +        {
  26.400 +            while (i_ < end_ && !i_->isLive())
  26.401 +                i_++;
  26.402 +        }
  26.403 +
  26.404 +        bool empty() const {
  26.405 +            return i_ == end_;
  26.406 +        }
  26.407 +
  26.408 +        void erase() {
  26.409 +            assert(!empty());
  26.410 +            table_->remove(*i_);
  26.411 +        }
  26.412 +
  26.413 +        const Payload &operator *() const {
  26.414 +            return i_->payload();
  26.415 +        }
  26.416 +
  26.417 +        void next() {
  26.418 +            do {
  26.419 +                i_++;
  26.420 +            } while (i_ < end_ && !i_->isLive());
  26.421 +        }
  26.422 +    };
  26.423 +};
  26.424 +
  26.425 +}
  26.426 +
  26.427 +#endif // _INCLUDE_KEIMA_HASHTABLE_H_
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/src/Heap-inl.h	Tue Jul 24 23:53:34 2012 -0700
    27.3 @@ -0,0 +1,118 @@
    27.4 +/* vim: set ts=4 sw=4 tw=99 et:
    27.5 + *
    27.6 + * Copyright (C) 2012 David Anderson
    27.7 + *
    27.8 + * This file is part of JITCraft.
    27.9 + *
   27.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   27.11 + * the terms of the GNU General Public License as published by the Free
   27.12 + * Software Foundation, either version 3 of the License, or (at your option)
   27.13 + * any later version.
   27.14 + * 
   27.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   27.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   27.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   27.18 + *
   27.19 + * You should have received a copy of the GNU General Public License along with
   27.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   27.21 + */
   27.22 +#ifndef _include_jitcraft_heap_inl_h_
   27.23 +#define _include_jitcraft_heap_inl_h_
   27.24 +
   27.25 +#include "Heap.h"
   27.26 +#include "Spaces-inl.h"
   27.27 +
   27.28 +namespace ke {
   27.29 +
   27.30 +static inline Object *
   27.31 +InitAddressIntoObject(Address address, Map *map)
   27.32 +{
   27.33 +    uintptr_t untagged = reinterpret_cast<uintptr_t>(address);
   27.34 +    assert(IsAligned(untagged, kObjectAlignment));
   27.35 +
   27.36 +    Object *obj = reinterpret_cast<Object *>(address);
   27.37 +    obj->init(map);
   27.38 +    return obj;
   27.39 +}
   27.40 +
   27.41 +inline Address
   27.42 +Heap::newObject(size_t bytes, Tenure age)
   27.43 +{
   27.44 +    if (bytes >= HeapChunk::kLargeObjectThreshold)
   27.45 +        return newLargeObject(bytes);
   27.46 +
   27.47 +    if (age == Tenure_Stack) {
   27.48 +        if (Address addr = newStackObject(bytes))
   27.49 +            return addr;
   27.50 +    }
   27.51 +
   27.52 +#if 0
   27.53 +    if (age == Tenure_Default) {
   27.54 +        if (Address addr = newSpace_.allocate(bytes))
   27.55 +            return addr;
   27.56 +
   27.57 +        scavenge();
   27.58 +        if (Address addr = newSpace_.allocate(bytes))
   27.59 +            return addr;
   27.60 +    }
   27.61 +#endif
   27.62 +
   27.63 +    // Try an old-space allocation.
   27.64 +    if (Address addr = newOldObject(bytes))
   27.65 +        return addr;
   27.66 +
   27.67 +    // Uh-oh - perform a last-ditch collection.
   27.68 +    reclaim();
   27.69 +
   27.70 +    return newOldObject(bytes);
   27.71 +}
   27.72 +
   27.73 +inline Object *
   27.74 +Heap::allocate(Handle<Map> map, size_t bytes, Tenure age)
   27.75 +{
   27.76 +    size_t actualBytes = Align(bytes, kObjectAlignment);
   27.77 +
   27.78 +    // All objects must be at least two words.
   27.79 +    assert(actualBytes >= sizeof(Object *) * 2);
   27.80 +
   27.81 +    Address address = newObject(actualBytes, age);
   27.82 +    if (!address) {
   27.83 +        reportOutOfMemory();
   27.84 +        return NULL;
   27.85 +    }
   27.86 +    return InitAddressIntoObject(address, map);
   27.87 +}
   27.88 +
   27.89 +inline Address
   27.90 +Heap::newStackObject(size_t bytes)
   27.91 +{
   27.92 +    return lifoSpace_.allocate(bytes);
   27.93 +}
   27.94 +
   27.95 +inline Address
   27.96 +Heap::newOldObject(size_t bytes)
   27.97 +{
   27.98 +    return oldSpace_.allocate(bytes);
   27.99 +}
  27.100 +
  27.101 +inline Address
  27.102 +Heap::newLargeObject(size_t bytes)
  27.103 +{
  27.104 +    if (Address address = largeSpace_.allocate(bytes))
  27.105 +        return address;
  27.106 +
  27.107 +    reclaim();
  27.108 +
  27.109 +    return largeSpace_.allocate(bytes);
  27.110 +}
  27.111 +
  27.112 +inline void
  27.113 +Object::write(Zone *zone, Object **ptr, Object *obj)
  27.114 +{
  27.115 +    *ptr = obj;
  27.116 +}
  27.117 +
  27.118 +}
  27.119 +
  27.120 +#endif // _include_jitcraft_heap_inl_h_
  27.121 +
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/src/Heap.cpp	Tue Jul 24 23:53:34 2012 -0700
    28.3 @@ -0,0 +1,372 @@
    28.4 +/* vim: set ts=4 sw=4 tw=99 et:
    28.5 + *
    28.6 + * Copyright (C) 2012 David Anderson
    28.7 + *
    28.8 + * This file is part of JITCraft.
    28.9 + *
   28.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   28.11 + * the terms of the GNU General Public License as published by the Free
   28.12 + * Software Foundation, either version 3 of the License, or (at your option)
   28.13 + * any later version.
   28.14 + * 
   28.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   28.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   28.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   28.18 + *
   28.19 + * You should have received a copy of the GNU General Public License along with
   28.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   28.21 + */
   28.22 +#include "Heap.h"
   28.23 +#include "Heap-inl.h"
   28.24 +#include "Spaces-inl.h"
   28.25 +#include "VirtualObjectVisitor.h"
   28.26 +#include "ObjectVisitor.h"
   28.27 +#include "Zone.h"
   28.28 +#include "StringPool.h"
   28.29 +
   28.30 +using namespace ke;
   28.31 +
   28.32 +static const size_t kMarkStackSize = 256 * kKB;
   28.33 +
   28.34 +Heap::Heap(Zone *zone)
   28.35 +  : zone_(zone),
   28.36 +    markStack_(NULL),
   28.37 +    oldSpace_(zone),
   28.38 +    mapSpace_(zone)
   28.39 +{
   28.40 +}
   28.41 +
   28.42 +bool
   28.43 +Heap::initialize()
   28.44 +{
   28.45 +    if (!lifoSpace_.initialize())
   28.46 +        return false;
   28.47 +    if (!oldSpace_.initialize())
   28.48 +        return false;
   28.49 +    if (!mapSpace_.initialize())
   28.50 +        return false;
   28.51 +    if (!largeSpace_.initialize())
   28.52 +        return false;
   28.53 +
   28.54 +    markStack_ = malloc(kMarkStackSize);
   28.55 +    if (!markStack_)
   28.56 +        return false;
   28.57 +
   28.58 +    if ((metaMap_ = allocateMap(MapKind_Meta, sizeof(Map))) == NULL)
   28.59 +        return false;
   28.60 +    metaMap_->init(metaMap_);
   28.61 +
   28.62 +    return true;
   28.63 +}
   28.64 +
   28.65 +Heap::~Heap()
   28.66 +{
   28.67 +    free(markStack_);
   28.68 +}
   28.69 +
   28.70 +Map *
   28.71 +Heap::allocateMap(MapKind kind, size_t bytes)
   28.72 +{
   28.73 +    size_t actualBytes = Align(bytes, kObjectAlignment);
   28.74 +
   28.75 +    Address addr = mapSpace_.allocate(actualBytes);
   28.76 +    if (!addr) {
   28.77 +        reportOutOfMemory();
   28.78 +        return NULL;
   28.79 +    }
   28.80 +
   28.81 +    // Note that we use a NULL type initially, and reinterpret-cast to get
   28.82 +    // the Type pointer, so we can allocate the self-referencing meta type.
   28.83 +    Object *obj = InitAddressIntoObject(addr, NULL);
   28.84 +    Map *map = reinterpret_cast<Map *>(obj);
   28.85 +    map->setKind(kind);
   28.86 +    return map;
   28.87 +}
   28.88 +
   28.89 +// To avoid marking recursively, we use a worklist to manage the marking
   28.90 +// process. Algorithm:
   28.91 +//
   28.92 +// (1) While the mark stack is not empty:
   28.93 +//  (a) Remove object |o| from the mark stack.
   28.94 +//  (b) For each reference |p| in object |o|,
   28.95 +//   (i)  Mark |p| as Black.
   28.96 +//   (ii) Push |p| onto the mark stack.
   28.97 +//   (iv) If the mark stack overflowde, mark |p| as Grey.
   28.98 +//
   28.99 +// We run this algorithm after pushing every root object onto the mark stack.
  28.100 +// After all roots have been processed, it may be that the mark stack
  28.101 +// overflowed. In this case, we use the following algorithm:
  28.102 +//
  28.103 +//  (1) while the mark stack has overflowed:
  28.104 +//   (a) Search the heap for grey objects, adding as many as possible to the
  28.105 +//       mark stack.
  28.106 +//   (b) Run the mark-stack-emptying algorithm above.
  28.107 +//
  28.108 +// This algorithm is guaranteed to terminate, because even if there are more
  28.109 +// grey objects than mark stack capacity, we eventually all objects will
  28.110 +// become grey, and grey objects are not re-pushed onto the mark stack. Thus,
  28.111 +// eventually, all objects will become black.
  28.112 +//
  28.113 +namespace ke {
  28.114 +class MarkStack
  28.115 +{
  28.116 +    Object **base_;
  28.117 +    Object **top_;
  28.118 +    Object **end_;
  28.119 +    bool overflowed_;
  28.120 +
  28.121 +  public:
  28.122 +    MarkStack(Object **base, Object **end)
  28.123 +      : base_(base),
  28.124 +        top_(base),
  28.125 +        end_(end),
  28.126 +        overflowed_(false)
  28.127 +    {
  28.128 +    }
  28.129 +
  28.130 +    void pushBlack(Object *ptr) {
  28.131 +        assert(HeapChunk::IsBlack(HeapChunk::GetMarkBit(ptr)));
  28.132 +        if (top_ >= end_) {
  28.133 +            MarkBit bit = HeapChunk::GetMarkBit(ptr);
  28.134 +            HeapChunk::BlackToGrey(bit);
  28.135 +            overflowed_ = true;
  28.136 +            return;
  28.137 +        }
  28.138 +        *top_++ = ptr;
  28.139 +    }
  28.140 +
  28.141 +    Object *pop() {
  28.142 +        assert(!empty());
  28.143 +        return *--top_;
  28.144 +    }
  28.145 +    bool overflowed() const {
  28.146 +        return overflowed_;
  28.147 +    }
  28.148 +    bool empty() const {
  28.149 +        return base_ == top_;
  28.150 +    }
  28.151 +    void reset() {
  28.152 +        assert(empty());
  28.153 +        overflowed_ = true;
  28.154 +    }
  28.155 +};
  28.156 +} // namespace ke
  28.157 +
  28.158 +// Iterates over an object's body, pushing its referenced objects onto the
  28.159 +// mark stack.
  28.160 +class MarkingVisitor : public ObjectVisitor<VirtualObjectVisitor>
  28.161 +{
  28.162 +    MarkStack &stack_;
  28.163 +
  28.164 +  public:
  28.165 +    MarkingVisitor(MarkStack &stack)
  28.166 +      : stack_(stack)
  28.167 +    {
  28.168 +    }
  28.169 +
  28.170 +    void visit(Object **ptr) {
  28.171 +        if (!*ptr)
  28.172 +            return;
  28.173 +
  28.174 +        Object *obj = *ptr;
  28.175 +
  28.176 +        // If the object is grey, we'll find it later when searching the heap.
  28.177 +        // If the object is black, it's already been scsanned.
  28.178 +        MarkBit bit = HeapChunk::GetMarkBit(obj);
  28.179 +        if (HeapChunk::IsBlackOrGrey(bit))
  28.180 +            return;
  28.181 +
  28.182 +        // Place the object in the stack and optimistically mark it black. If
  28.183 +        // the stack overflows, it'll become grey instead.
  28.184 +        HeapChunk::WhiteToBlack(bit);
  28.185 +        stack_.pushBlack(obj);
  28.186 +    }
  28.187 +};
  28.188 +
  28.189 +static void
  28.190 +ProcessMarkStack(MarkStack &stack)
  28.191 +{
  28.192 +    MarkingVisitor visitor(stack);
  28.193 +
  28.194 +    while (!stack.empty()) {
  28.195 +        Object *obj = stack.pop();
  28.196 +        assert(HeapChunk::IsBlack(HeapChunk::GetMarkBit(obj)));
  28.197 +
  28.198 +        visitor.iterate(obj);
  28.199 +    }
  28.200 +}
  28.201 +
  28.202 +class RootMarkingVisitor : public VirtualObjectVisitor
  28.203 +{
  28.204 +    MarkStack &stack_;
  28.205 +    MarkingVisitor visitor_;
  28.206 +
  28.207 +  public:
  28.208 +    RootMarkingVisitor(MarkStack &stack)
  28.209 +      : stack_(stack),
  28.210 +        visitor_(stack)
  28.211 +    {
  28.212 +    }
  28.213 +
  28.214 +    void visit(Object **ptr) {
  28.215 +        // Flush the stack after every new root. Note that the root gets pushed
  28.216 +        // as black; that's okay. If the mark stack overflows, its children are
  28.217 +        // guaranteed to be at least grey.
  28.218 +        visitor_.visit(ptr);
  28.219 +        ProcessMarkStack(stack_);
  28.220 +    }
  28.221 +};
  28.222 +
  28.223 +typedef ChunkObjectIteratorBase<ObjectSizeEvaluator> ChunkObjectIterator;
  28.224 +
  28.225 +static inline bool
  28.226 +EnqueueGreyObject(MarkStack &stack, Object *obj)
  28.227 +{
  28.228 +    assert(!stack.overflowed());
  28.229 +    MarkBit bit = HeapChunk::GetMarkBit(obj);
  28.230 +    if (HeapChunk::IsGrey(bit)) {
  28.231 +        HeapChunk::GreyToBlack(bit);
  28.232 +        stack.pushBlack(obj);
  28.233 +        return !stack.overflowed();
  28.234 +    }
  28.235 +    return true;
  28.236 +}
  28.237 +
  28.238 +static void
  28.239 +EnqueueGreyObjectsInChunks(MarkStack &stack, ChunkObjectIterator iter)
  28.240 +{
  28.241 +    for (Object *obj = iter.next(); obj; obj = iter.next()) {
  28.242 +        if (!EnqueueGreyObject(stack, obj))
  28.243 +            return;
  28.244 +    }
  28.245 +}
  28.246 +
  28.247 +static void
  28.248 +EnqueueGreyObjectsInLargeChunks(MarkStack &stack, HeapChunk *first)
  28.249 +{
  28.250 +    for (HeapChunk *chunk = first; chunk; chunk = chunk->next()) {
  28.251 +        Object *obj = reinterpret_cast<Object *>(chunk->first());
  28.252 +        if (!EnqueueGreyObject(stack, obj))
  28.253 +            return;
  28.254 +    }
  28.255 +}
  28.256 +
  28.257 +void
  28.258 +Heap::findGreyObjects(MarkStack &stack)
  28.259 +{
  28.260 +    EnqueueGreyObjectsInChunks(stack, lifoSpace_.begin(ObjectSizeEvaluator()));
  28.261 +    if (stack.overflowed())
  28.262 +        return;
  28.263 +
  28.264 +    EnqueueGreyObjectsInChunks(stack, mapSpace_.begin(ObjectSizeEvaluator()));
  28.265 +    if (stack.overflowed())
  28.266 +        return;
  28.267 +    
  28.268 +    EnqueueGreyObjectsInChunks(stack, oldSpace_.begin(ObjectSizeEvaluator()));
  28.269 +    if (stack.overflowed())
  28.270 +        return;
  28.271 +
  28.272 +    EnqueueGreyObjectsInLargeChunks(stack, largeSpace_.first());
  28.273 +    if (stack.overflowed())
  28.274 +        return;
  28.275 +}
  28.276 +
  28.277 +void
  28.278 +Heap::mark()
  28.279 +{
  28.280 +    Object **qbase = reinterpret_cast<Object **>(markStack_);
  28.281 +    Object **qend = qbase + (kMarkStackSize / sizeof(Object *));
  28.282 +    MarkStack stack(qbase, qend);
  28.283 +    RootMarkingVisitor visitor(stack);
  28.284 +
  28.285 +    // Attempt to mark all objects reachable from the root set.
  28.286 +    zone_->accept(&visitor);
  28.287 +    assert(stack.empty());
  28.288 +
  28.289 +    // If the stack overflowed, we need to look through the entire heap for
  28.290 +    // grey objects to rescan. We keep doing this until there are no grey
  28.291 +    // objects left.
  28.292 +    while (stack.overflowed()) {
  28.293 +        stack.reset();
  28.294 +        findGreyObjects(stack);
  28.295 +        ProcessMarkStack(stack);
  28.296 +    }
  28.297 +}
  28.298 +
  28.299 +// Use the mark bits to scan for live objects, and mark the regions in
  28.300 +// between them as free.
  28.301 +static void
  28.302 +SweepOldSpaceChunk(OldSpace *space, HeapChunk *chunk)
  28.303 +{
  28.304 +    uint32 *markbits = chunk->markBits();
  28.305 +    uint32 *markbitsEnd = markbits + HeapChunk::kMarkWords;
  28.306 +    Address freeStart = chunk->first();
  28.307 +
  28.308 +    // Scoot up to the first usable markword. Since memory is reserved for
  28.309 +    // mark bits, not all addresses are allocatable, so quite a few of the
  28.310 +    // initial mark bits are wasted. (1KB of mark bytes on x86.)
  28.311 +    markbits = HeapChunk::GetMarkBit(reinterpret_cast<Object *>(chunk->first())).word();
  28.312 +
  28.313 +    uint32 bits = *markbits;
  28.314 +    for (;;) {
  28.315 +        while (bits) {
  28.316 +            uint32 bit = FindRightmostBit(bits);
  28.317 +            Address object = HeapChunk::FromMarkBit(chunk, markbits, bit);
  28.318 +
  28.319 +            assert(object >= freeStart);
  28.320 +            if (freeStart != object)
  28.321 +                space->markRegionFree(freeStart, object - freeStart);
  28.322 +
  28.323 +            Object *obj = reinterpret_cast<Object *>(object);
  28.324 +            freeStart = object + SizeOfObject(obj, obj->map());
  28.325 +
  28.326 +            // Since black is 10, we never need to clear the next bit.
  28.327 +            bits &= ~(1 << bit);
  28.328 +        }
  28.329 +        markbits++;
  28.330 +        bits = *markbits;
  28.331 +        if (markbits >= markbitsEnd)
  28.332 +            break;
  28.333 +    }
  28.334 +
  28.335 +    if (freeStart == chunk->base())
  28.336 +        chunk->setEmpty();
  28.337 +    else if (freeStart != chunk->end())
  28.338 +        space->markRegionFree(freeStart, chunk->end() - freeStart);
  28.339 +}
  28.340 +
  28.341 +static void
  28.342 +SweepOldSpace(OldSpace *space)
  28.343 +{
  28.344 +    space->resetFreeList();
  28.345 +    for (HeapChunk *chunk = space->first(); chunk; chunk = chunk->next()) {
  28.346 +        SweepOldSpaceChunk(space, chunk);
  28.347 +        chunk->resetMarkBits();
  28.348 +    }
  28.349 +    space->freeUnusedPages();
  28.350 +}
  28.351 +
  28.352 +void
  28.353 +Heap::sweep()
  28.354 +{
  28.355 +    // Before destroying mark bits, sweep weak roots.
  28.356 +    zone_->symbols()->sweep();
  28.357 +
  28.358 +    // Note: we don't bother sweeping the LIFO space.
  28.359 +    SweepOldSpace(&mapSpace_);
  28.360 +    SweepOldSpace(&oldSpace_);
  28.361 +    largeSpace_.sweep();
  28.362 +}
  28.363 +
  28.364 +void
  28.365 +Heap::reclaim()
  28.366 +{
  28.367 +    mark();
  28.368 +    sweep();
  28.369 +}
  28.370 +
  28.371 +void
  28.372 +Heap::reportOutOfMemory()
  28.373 +{
  28.374 +    zone_->reportOutOfMemory();
  28.375 +}
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/src/Heap.h	Tue Jul 24 23:53:34 2012 -0700
    29.3 @@ -0,0 +1,143 @@
    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 +#ifndef _include_jitcraft_heap_h_
   29.23 +#define _include_jitcraft_heap_h_
   29.24 +
   29.25 +#include "Utility.h"
   29.26 +#include "Spaces.h"
   29.27 +#include "Barriers.h"
   29.28 +#include "Objects.h"
   29.29 +#include "Handles.h"
   29.30 +
   29.31 +namespace ke {
   29.32 +
   29.33 +class Zone;
   29.34 +class MarkStack;
   29.35 +
   29.36 +// Heap-allocated objects go here. Heaps are thread-local. The heap contains
   29.37 +// four spaces:
   29.38 +//
   29.39 +//    LIFO Space:  Used for objects that may be stack-allocated.
   29.40 +//    Old Space:   Used for objects that are expected to be long-lived, or that
   29.41 +//                 survive one collection.
   29.42 +//    Large Space: Used for objects that are so large they should never be
   29.43 +//                 moved between spaces.
   29.44 +//
   29.45 +// ALLOCATING AN OBJECT DOES NOT ZERO ITS MEMORY.
   29.46 +// ALLOCATING AN OBJECT DOES NOT ZERO ITS MEMORY!
   29.47 +//
   29.48 +// ---------------------------------------------------------------------------
   29.49 +//
   29.50 +// The following is a high-level overview of how garbage collection works in
   29.51 +// Keima. Detailed notes are present in Heap.cpp.
   29.52 +//
   29.53 +// THE TRI-COLOR INVARIANT: Via an object's mark bits, we maintain the
   29.54 +//   property that an object that has been fully marked may never reference a
   29.55 +//   dead object. Objects exist in three states during collection: unmarked
   29.56 +//   (white), scheduled for marking (grey), and fully marked (black).
   29.57 +//
   29.58 +//   When initiating collection, all objects are white. Objects in the root
   29.59 +//   set are made grey. The marking process takes grey objects and marks that
   29.60 +//   each child object is live: if the child is white, it becomes grey. Once
   29.61 +//   all children are grey or black, the parent grey object can become black,
   29.62 +//   as it has been fully traversed.
   29.63 +//
   29.64 +//   The result of this process is that when there are no more grey objects,
   29.65 +//   then we are guaranteed that all black objects are live, and all white
   29.66 +//   objects are dead.
   29.67 +//
   29.68 +// MAJOR COLLECTIONS are performed periodically, when either a given memory
   29.69 +//   threshold has been reached, or when requested by the host application.
   29.70 +//   They are also performed if no memory can be allocated.
   29.71 +//
   29.72 +//   Major collections are extremely slow; they require full heap traversal,
   29.73 +//   which can take more than a second on very large heaps. However, they
   29.74 +//   have the greatest chance at reclaiming all syntactically dead objects.
   29.75 +//
   29.76 +// SWEEPING is performed after major collections. The free space in between
   29.77 +//   live objects is added to a free list. Tenured allocations are then
   29.78 +//   performed in the free space, if possible.
   29.79 +//
   29.80 +class Heap
   29.81 +{
   29.82 +    Zone *zone_;
   29.83 +    HeapStack lifoSpace_;
   29.84 +    OldSpace mapSpace_;
   29.85 +    OldSpace oldSpace_;
   29.86 +    LargeObjectSpace largeSpace_;
   29.87 +
   29.88 +    Map *metaMap_;
   29.89 +
   29.90 +    // This is a big hunk o' memory used for marking iteratively. Eventually,
   29.91 +    // this will be replaced by the inactive semispace in the nursery.
   29.92 +    void *markStack_;
   29.93 +
   29.94 +  public:
   29.95 +    enum Tenure {
   29.96 +        // Default, objects go into the nursery.
   29.97 +        Tenure_Default,
   29.98 +        
   29.99 +        // If objects are proven to not escape the stack, they can go into
  29.100 +        // a LIFO arena. Allocation on the LIFO arena is not guaranteed to
  29.101 +        // succeed; thus, objects may still be allocated in other arenas.
  29.102 +        Tenure_Stack,
  29.103 +
  29.104 +        // Objects that should not go into the nursery (i.e. are expected
  29.105 +        // to be long-living) go here.
  29.106 +        Tenure_Old
  29.107 +    };
  29.108 +
  29.109 +  private:
  29.110 +    inline Address newLargeObject(size_t bytes);
  29.111 +    inline Address newOldObject(size_t bytes);
  29.112 +    inline Address newStackObject(size_t bytes);
  29.113 +    inline Address newObject(size_t bytes, Tenure pretenure);
  29.114 +
  29.115 +  private:
  29.116 +    void findGreyObjects(MarkStack &stack);
  29.117 +    void mark();
  29.118 +    void sweep();
  29.119 +
  29.120 +    void reportOutOfMemory();
  29.121 +
  29.122 +  public:
  29.123 +    Heap(Zone *zone);
  29.124 +    ~Heap();
  29.125 +    bool initialize();
  29.126 +
  29.127 +    inline Object *allocate(Handle<Map> map, size_t byes, Tenure pretenure);
  29.128 +    Map *allocateMap(MapKind kind, size_t bytes);
  29.129 +
  29.130 +    Map *metaMap() {
  29.131 +        return metaMap_;
  29.132 +    }
  29.133 +    inline Address lifoPosition() const {
  29.134 +        return lifoSpace_.position();
  29.135 +    }
  29.136 +    inline void unwindLifo(Address to) {
  29.137 +        lifoSpace_.unwind(to);
  29.138 +    }
  29.139 +
  29.140 +    // Perform a full garbage collection.
  29.141 +    void reclaim();
  29.142 +};
  29.143 +
  29.144 +}
  29.145 +
  29.146 +#endif //_include_jitcraft_heap_h_
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/src/InlineList.h	Tue Jul 24 23:53:34 2012 -0700
    30.3 @@ -0,0 +1,129 @@
    30.4 +/*
    30.5 + * Copyright (C) 2004-2012 David Anderson
    30.6 + *
    30.7 + * This file is part of SourcePawn.
    30.8 + *
    30.9 + * SourcePawn is free software: you can redistribute it and/or modify it under
   30.10 + * the terms of the GNU General Public License as published by the Free
   30.11 + * Software Foundation, either version 3 of the License, or (at your option)
   30.12 + * any later version.
   30.13 + * 
   30.14 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
   30.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   30.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   30.17 + *
   30.18 + * You should have received a copy of the GNU General Public License along with
   30.19 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
   30.20 + */
   30.21 +#ifndef _include_ke_inline_list_h_
   30.22 +#define _include_ke_inline_list_h_
   30.23 +
   30.24 +#include <stddef.h>
   30.25 +
   30.26 +namespace ke {
   30.27 +
   30.28 +template <typename T> class InlineList;
   30.29 +
   30.30 +template <typename T>
   30.31 +class InlineListNode
   30.32 +{
   30.33 +    friend class InlineList<T>;
   30.34 +
   30.35 +  public:
   30.36 +    InlineListNode()
   30.37 +      : next_(NULL),
   30.38 +        prev_(NULL)
   30.39 +    {
   30.40 +    }
   30.41 +
   30.42 +    InlineListNode(InlineListNode *next, InlineListNode *prev)
   30.43 +      : next_(next),
   30.44 +        prev_(prev)
   30.45 +    {
   30.46 +    }
   30.47 +
   30.48 +  protected:
   30.49 +    InlineListNode *next_;
   30.50 +    InlineListNode *prev_;
   30.51 +};
   30.52 +
   30.53 +template <typename T>
   30.54 +class InlineList
   30.55 +{
   30.56 +    typedef InlineListNode<T> Node;
   30.57 +
   30.58 +    Node head_;
   30.59 +
   30.60 +  public:
   30.61 +    InlineList()
   30.62 +      : head_(&head_, &head_)
   30.63 +    {
   30.64 +    }
   30.65 +
   30.66 +  public:
   30.67 +    class iterator
   30.68 +    {
   30.69 +        friend class InlineList;
   30.70 +        Node *iter_;
   30.71 +        
   30.72 +      public:
   30.73 +        iterator(Node *iter)
   30.74 +          : iter_(iter)
   30.75 +        {
   30.76 +        }
   30.77 +
   30.78 +        iterator & operator++() {
   30.79 +            iter_ = iter_->next_;
   30.80 +            return *this;
   30.81 +        }
   30.82 +        iterator operator ++(int) {
   30.83 +            iterator old(*this);
   30.84 +            iter_ = iter_->next_;
   30.85 +            return old;
   30.86 +        }
   30.87 +        T * operator *() {
   30.88 +            return static_cast<T *>(iter_);
   30.89 +        }
   30.90 +        T * operator ->() {
   30.91 +            return static_cast<T *>(iter_);
   30.92 +        }
   30.93 +        bool operator !=(const iterator &where) const {
   30.94 +            return iter_ != where.iter_;
   30.95 +        }
   30.96 +        bool operator ==(const iterator &where) const {
   30.97 +            return iter_ == where.iter_;
   30.98 +        }
   30.99 +        iterator prev() const {
  30.100 +            return iterator(iter_->prev_);
  30.101 +        }
  30.102 +        iterator next() const {
  30.103 +            return iterator(iter_->next_);
  30.104 +        }
  30.105 +    };
  30.106 +
  30.107 +    iterator begin() {
  30.108 +        return iterator(head_.next_);
  30.109 +    }
  30.110 +    iterator end() {
  30.111 +        return iterator(&head_);
  30.112 +    }
  30.113 +    void append(Node *t) {
  30.114 +        t->prev_ = head_.prev_;
  30.115 +        t->next_ = &head_;
  30.116 +        head_.prev_->next_ = t;
  30.117 +        head_.prev_ = t;
  30.118 +    }
  30.119 +    iterator erase(iterator i) {
  30.120 +        iterator next = ++i;
  30.121 +        remove(i.iter_);
  30.122 +        return next;
  30.123 +    }
  30.124 +    void remove(Node *t) {
  30.125 +        t->prev_->next_ = t->next_;
  30.126 +        t->next_->prev_ = t->prev_;
  30.127 +    }
  30.128 +};
  30.129 +
  30.130 +}
  30.131 +
  30.132 +#endif // _include_ke_inline_list_h_
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/src/Interpreter.cpp	Tue Jul 24 23:53:34 2012 -0700
    31.3 @@ -0,0 +1,937 @@
    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 "Interpreter.h"
   31.23 +#include "Modules.h"
   31.24 +#include "Zone.h"
   31.25 +#include "Types.h"
   31.26 +#include "Array.h"
   31.27 +#include "Reference.h"
   31.28 +#include "Strings.h"
   31.29 +#include "Environments.h"
   31.30 +#include "Heap-inl.h"
   31.31 +
   31.32 +using namespace ke;
   31.33 +
   31.34 +#define PUSH_I32(top, value)    \
   31.35 +    do {                        \
   31.36 +        top.sp->i32 = value;    \
   31.37 +        top.sp++;               \
   31.38 +   } while (0)
   31.39 +
   31.40 +#define PUSH_F(top, value)      \
   31.41 +    do {                        \
   31.42 +        top.sp->f = value;      \
   31.43 +        top.sp++;               \
   31.44 +   } while (0)
   31.45 +
   31.46 +static inline int
   31.47 +POP_I32(Top &top)
   31.48 +{
   31.49 +    int value = top.sp[-1].i32;
   31.50 +    top.sp--;
   31.51 +    return value;
   31.52 +}
   31.53 +
   31.54 +static inline float
   31.55 +POP_F(Top &top)
   31.56 +{
   31.57 +    float value = top.sp[-1].f;
   31.58 +    top.sp--;
   31.59 +    return value;
   31.60 +}
   31.61 +
   31.62 +// Pawn's original semantics specify some kind of floor operation, so
   31.63 +// (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
   31.64 +// the upstream algorithm when constant folding. However the SourcePawn 1 JIT
   31.65 +// does not. My guess is that Borja freaked out seeing the 13-instruction x86
   31.66 +// sequence necessary to get this functionality (I vaguely recall a thread
   31.67 +// where we discussed this with Mark Peter? But the ITB forums are gone...),
   31.68 +// and we just decided to break the damn thing. So SP1 was inconsistent, but
   31.69 +// we are not. And for completeness, we assert that the C compiler does the
   31.70 +// right thing, since C89 leaves it unspecified.
   31.71 +STATIC_ASSERT(8 / -3 == -2);
   31.72 +STATIC_ASSERT(-8 / 3 == -2);
   31.73 +
   31.74 +static inline bool
   31.75 +PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
   31.76 +{
   31.77 +    Reference *ref = Reference::NewStack(zone, location, tenure);
   31.78 +    if (!ref)
   31.79 +        return false;
   31.80 +    top.sp->ref = ref;
   31.81 +    top.sp++;
   31.82 +    return true;
   31.83 +}
   31.84 +
   31.85 +// Generate an array with completely static sizes.
   31.86 +static Array *
   31.87 +GenerateArray(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
   31.88 +{
   31.89 +    assert(map->type()->elements() != -1);
   31.90 +
   31.91 +    Local<Array> array(zone, Array::New(zone, map, map->type()->elements(), tenure));
   31.92 +    if (!array)
   31.93 +        return NULL;
   31.94 +
   31.95 +    if (map->type()->levels() == 1)
   31.96 +        return array;
   31.97 +
   31.98 +    Local<ArrayMap> contained(zone, map->contained());
   31.99 +    Local<Array> sub(zone);
  31.100 +    for (unsigned i = 0; i < unsigned(map->type()->elements()); i++) {
  31.101 +        sub = GenerateArray(zone, contained, tenure);
  31.102 +        if (!sub)
  31.103 +            return NULL;
  31.104 +        array->writeObject(zone, i, sub);
  31.105 +    }
  31.106 +
  31.107 +    return array;
  31.108 +}
  31.109 +
  31.110 +static bool
  31.111 +CopyArray(Zone *zone, Array *source, Array *dest)
  31.112 +{
  31.113 +    assert(source->type()->levels() == 1);
  31.114 +    assert(dest->type()->levels() == 1);
  31.115 +    assert(source->type()->contained()->primitive() ==
  31.116 +           dest->type()->contained()->primitive());
  31.117 +    assert(source->nelements() >= dest->nelements());
  31.118 +    assert(dest->elementSize() == source->elementSize());
  31.119 +
  31.120 +    memcpy(source->vec(), dest->vec(), dest->nelements() * dest->elementSize());
  31.121 +    return true;
  31.122 +}
  31.123 +
  31.124 +static bool
  31.125 +InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
  31.126 +             int *result)
  31.127 +{
  31.128 +    NativeArgs guard;
  31.129 +
  31.130 +    if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
  31.131 +        return false;
  31.132 +
  31.133 +    intptr_t *cells = guard.args();
  31.134 +
  31.135 +    // params[0] == argc, in ISPE
  31.136 +    cells[0] = argc;
  31.137 +
  31.138 +    // Pass the formal arguments.
  31.139 +    Local<Type> type(zone, native->type());
  31.140 +    Local<Type> param(zone);
  31.141 +    for (unsigned i = 0; i < type->parameters()->length(); i++) {
  31.142 +        param = type->parameterAt(i);
  31.143 +        
  31.144 +        // For floats, we rely on the aliasing of |i32| and |f|.
  31.145 +        LocalSlot &arg = args[-int(i) - 1];
  31.146 +        if (param->isInt32() || param->isFloat()) {
  31.147 +            cells[i + 1] = arg.i32;
  31.148 +        } else if (param->isReference()) {
  31.149 +            cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
  31.150 +        } else {
  31.151 +            assert(param->isArray());
  31.152 +            cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
  31.153 +        }
  31.154 +    }
  31.155 +
  31.156 +    // For variadic arguments, the compiler left either arrays or references.
  31.157 +    for (unsigned i = type->parameters()->length(); i < argc; i++) {
  31.158 +        LocalSlot &arg = args[-int(i) - 1];
  31.159 +
  31.160 +        if (arg.obj->is(MapKind_Reference)) {
  31.161 +            cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
  31.162 +        } else {
  31.163 +            assert(arg.obj->is(MapKind_Array));
  31.164 +            cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
  31.165 +        }
  31.166 +    }
  31.167 +
  31.168 +    typedef intptr_t (*INVOKE)(void *, intptr_t *);
  31.169 +    INVOKE invoke = (INVOKE)native->function();
  31.170 +    *result = invoke(identity, cells);
  31.171 +
  31.172 +    return !zone->hasPendingException();
  31.173 +}
  31.174 +
  31.175 +bool
  31.176 +ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
  31.177 +{
  31.178 +    Top &top = *zone->stack().top();
  31.179 +    if (!entryFrame)
  31.180 +        entryFrame = top.fp;
  31.181 +
  31.182 +    LocalSlot *locals = entryFrame->locals();
  31.183 +
  31.184 +    for (;;) {
  31.185 +        Opcode op = Opcode(*top.pc);
  31.186 +        switch (op) {
  31.187 +
  31.188 +case OP_NOP:
  31.189 +    break;
  31.190 +
  31.191 +case OP_INT:
  31.192 +    PUSH_I32(top, READ_INT32(top.pc));
  31.193 +    break;
  31.194 +
  31.195 +case OP_FLOAT:
  31.196 +    PUSH_F(top, READ_FLOAT(top.pc));
  31.197 +    break;
  31.198 +
  31.199 +case OP_RETURN:
  31.200 +case OP_RETURNVOID:
  31.201 +case OP_STOP:
  31.202 +{
  31.203 +    if (op == OP_RETURN)
  31.204 +        *result = *--top.sp;
  31.205 +
  31.206 +    if (top.fp == entryFrame)
  31.207 +        goto done;
  31.208 +
  31.209 +    // This must not GC.
  31.210 +    zone->stack().popInlineFrame();
  31.211 +    locals = top.fp->locals();
  31.212 +
  31.213 +    if (op == OP_RETURN)
  31.214 +        *top.sp++ = *result;
  31.215 +
  31.216 +    top.pc += OpcodeInfo[*top.pc].length;
  31.217 +    continue;
  31.218 +}
  31.219 +
  31.220 +case OP_POP:
  31.221 +{
  31.222 +    top.sp--;
  31.223 +    break;
  31.224 +}
  31.225 +
  31.226 +#define RELATIONAL_JUMP(op)                 \
  31.227 +    {                                       \
  31.228 +        int right = POP_I32(top);           \
  31.229 +        int left = POP_I32(top);            \
  31.230 +        if (left op right) {                \
  31.231 +            top.pc += READ_INT32(top.pc);   \
  31.232 +            continue;                       \
  31.233 +        }                                   \
  31.234 +    }
  31.235 +
  31.236 +case OP_JL:
  31.237 +    RELATIONAL_JUMP(<);
  31.238 +    break;
  31.239 +
  31.240 +case OP_JLE:
  31.241 +    RELATIONAL_JUMP(<=);
  31.242 +    break;
  31.243 +
  31.244 +case OP_JG:
  31.245 +    RELATIONAL_JUMP(>);
  31.246 +    break;
  31.247 +
  31.248 +case OP_JGE:
  31.249 +    RELATIONAL_JUMP(>=);
  31.250 +    break;
  31.251 +
  31.252 +case OP_JEQ:
  31.253 +    RELATIONAL_JUMP(==);
  31.254 +    break;
  31.255 +
  31.256 +case OP_JNE:
  31.257 +    RELATIONAL_JUMP(!=);
  31.258 +    break;
  31.259 +
  31.260 +#undef RELATIONAL_JUMP
  31.261 +
  31.262 +case OP_JT:
  31.263 +{
  31.264 +    int value = POP_I32(top);
  31.265 +    if (value) {
  31.266 +        top.pc += READ_INT32(top.pc);
  31.267 +        continue;
  31.268 +    }
  31.269 +    break;
  31.270 +}
  31.271 +
  31.272 +case OP_JF:
  31.273 +{
  31.274 +    int value = POP_I32(top);
  31.275 +    if (!value) {
  31.276 +        top.pc += READ_INT32(top.pc);
  31.277 +        continue;
  31.278 +    }
  31.279 +    break;
  31.280 +}
  31.281 +
  31.282 +#define RELATIONAL_JUMP_F(op)               \
  31.283 +    {                                       \
  31.284 +        float right = POP_F(top);           \
  31.285 +        float left = POP_F(top);            \
  31.286 +        if (left op right) {                \
  31.287 +            top.pc += READ_INT32(top.pc);   \
  31.288 +            continue;                       \
  31.289 +        }                                   \
  31.290 +    }
  31.291 +
  31.292 +case OP_JL_F:
  31.293 +    RELATIONAL_JUMP_F(<);
  31.294 +    break;
  31.295 +
  31.296 +case OP_JLE_F:
  31.297 +    RELATIONAL_JUMP_F(<=);
  31.298 +    break;
  31.299 +
  31.300 +case OP_JG_F:
  31.301 +    RELATIONAL_JUMP_F(>);
  31.302 +    break;
  31.303 +
  31.304 +case OP_JGE_F:
  31.305 +    RELATIONAL_JUMP_F(>=);
  31.306 +    break;
  31.307 +
  31.308 +case OP_JEQ_F:
  31.309 +    RELATIONAL_JUMP_F(==);
  31.310 +    break;
  31.311 +
  31.312 +case OP_JNE_F:
  31.313 +    RELATIONAL_JUMP_F(!=);
  31.314 +    break;
  31.315 +
  31.316 +case OP_JT_F:
  31.317 +{
  31.318 +    float value = POP_F(top);
  31.319 +    if (value) {
  31.320 +        top.pc += READ_INT32(top.pc);
  31.321 +        continue;
  31.322 +    }
  31.323 +    break;
  31.324 +}
  31.325 +
  31.326 +case OP_JF_F:
  31.327 +{
  31.328 +    float value = POP_F(top);
  31.329 +    if (!value) {
  31.330 +        top.pc += READ_INT32(top.pc);
  31.331 +        continue;
  31.332 +    }
  31.333 +    break;
  31.334 +}
  31.335 +
  31.336 +case OP_JUMP:
  31.337 +    top.pc += READ_INT32(top.pc);
  31.338 +    continue;
  31.339 +
  31.340 +case OP_GETLOCAL:
  31.341 +{
  31.342 +    int slot = READ_INT32(top.pc);
  31.343 +    *top.sp++ = locals[slot];
  31.344 +    break;
  31.345 +}
  31.346 +
  31.347 +case OP_SETLOCAL:
  31.348 +{
  31.349 +    int slot = READ_INT32(top.pc);
  31.350 +    locals[slot] = top.sp[-1];
  31.351 +    break;
  31.352 +}
  31.353 +
  31.354 +case OP_ADD:
  31.355 +{
  31.356 +    top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
  31.357 +    top.sp--;
  31.358 +    break;
  31.359 +}
  31.360 +
  31.361 +case OP_SUB:
  31.362 +{
  31.363 +    top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
  31.364 +    top.sp--;
  31.365 +    break;
  31.366 +}
  31.367 +
  31.368 +case OP_MUL:
  31.369 +{
  31.370 +    top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
  31.371 +    top.sp--;
  31.372 +    break;
  31.373 +}
  31.374 +
  31.375 +case OP_DIV:
  31.376 +{
  31.377 +    if (top.sp[-1].i32 == 0) {
  31.378 +        zone->reportError(Message_IntegerDivideByZero);
  31.379 +        goto error;
  31.380 +    }
  31.381 +    top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
  31.382 +    top.sp--;
  31.383 +    break;
  31.384 +}
  31.385 +
  31.386 +case OP_MOD:
  31.387 +{
  31.388 +    if (top.sp[-1].i32 == 0) {
  31.389 +        zone->reportError(Message_IntegerDivideByZero);
  31.390 +        goto error;
  31.391 +    }
  31.392 +    top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
  31.393 +    top.sp--;
  31.394 +    break;
  31.395 +}
  31.396 +
  31.397 +case OP_LT:
  31.398 +{
  31.399 +    top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
  31.400 +    top.sp--;
  31.401 +    break;
  31.402 +}
  31.403 +
  31.404 +case OP_LE:
  31.405 +{
  31.406 +    top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
  31.407 +    top.sp--;
  31.408 +    break;
  31.409 +}
  31.410 +
  31.411 +case OP_GT:
  31.412 +{
  31.413 +    top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
  31.414 +    top.sp--;
  31.415 +    break;
  31.416 +}
  31.417 +
  31.418 +case OP_GE:
  31.419 +{
  31.420 +    top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
  31.421 +    top.sp--;
  31.422 +    break;
  31.423 +}
  31.424 +
  31.425 +case OP_EQ:
  31.426 +{
  31.427 +    top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
  31.428 +    top.sp--;
  31.429 +    break;
  31.430 +}
  31.431 +
  31.432 +case OP_NE:
  31.433 +{
  31.434 +    top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
  31.435 +    top.sp--;
  31.436 +    break;
  31.437 +}
  31.438 +
  31.439 +case OP_ADD_F:
  31.440 +{
  31.441 +    top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
  31.442 +    top.sp--;
  31.443 +    break;
  31.444 +}
  31.445 +
  31.446 +case OP_SUB_F:
  31.447 +{
  31.448 +    top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
  31.449 +    top.sp--;
  31.450 +    break;
  31.451 +}
  31.452 +
  31.453 +case OP_MUL_F:
  31.454 +{
  31.455 +    top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
  31.456 +    top.sp--;
  31.457 +    break;
  31.458 +}
  31.459 +
  31.460 +case OP_DIV_F:
  31.461 +{
  31.462 +    top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
  31.463 +    top.sp--;
  31.464 +    break;
  31.465 +}
  31.466 +
  31.467 +case OP_LT_F:
  31.468 +{
  31.469 +    top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
  31.470 +    top.sp--;
  31.471 +    break;
  31.472 +}
  31.473 +
  31.474 +case OP_LE_F:
  31.475 +{
  31.476 +    top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
  31.477 +    top.sp--;
  31.478 +    break;
  31.479 +}
  31.480 +
  31.481 +case OP_GT_F:
  31.482 +{
  31.483 +    top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
  31.484 +    top.sp--;
  31.485 +    break;
  31.486 +}
  31.487 +
  31.488 +case OP_GE_F:
  31.489 +{
  31.490 +    top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
  31.491 +    top.sp--;
  31.492 +    break;
  31.493 +}
  31.494 +
  31.495 +case OP_EQ_F:
  31.496 +{
  31.497 +    top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
  31.498 +    top.sp--;
  31.499 +    break;
  31.500 +}
  31.501 +
  31.502 +case OP_NE_F:
  31.503 +{
  31.504 +    top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
  31.505 +    top.sp--;
  31.506 +    break;
  31.507 +}
  31.508 +
  31.509 +case OP_SHL:
  31.510 +{
  31.511 +    top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
  31.512 +    top.sp--;
  31.513 +    break;
  31.514 +}
  31.515 +
  31.516 +case OP_SHR:
  31.517 +{
  31.518 +    top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
  31.519 +    top.sp--;
  31.520 +    break;
  31.521 +}
  31.522 +
  31.523 +case OP_USHR:
  31.524 +{
  31.525 +    top.sp[-2].i32 = unsigned(top.sp[-2].i32) << unsigned(top.sp[-1].i32);
  31.526 +    top.sp--;
  31.527 +    break;
  31.528 +}
  31.529 +
  31.530 +case OP_BITAND:
  31.531 +{
  31.532 +    top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
  31.533 +    top.sp--;
  31.534 +    break;
  31.535 +}
  31.536 +
  31.537 +case OP_BITOR:
  31.538 +{
  31.539 +    top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
  31.540 +    top.sp--;
  31.541 +    break;
  31.542 +}
  31.543 +
  31.544 +case OP_BITXOR:
  31.545 +{
  31.546 +    top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
  31.547 +    top.sp--;
  31.548 +    break;
  31.549 +}
  31.550 +
  31.551 +case OP_BITNOT:
  31.552 +{
  31.553 +    top.sp[-1].i32 = ~top.sp[-1].i32;
  31.554 +    break;
  31.555 +}
  31.556 +
  31.557 +case OP_NOT:
  31.558 +{
  31.559 +    top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
  31.560 +    break;
  31.561 +}
  31.562 +
  31.563 +case OP_NOT_F:
  31.564 +{
  31.565 +    top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
  31.566 +    break;
  31.567 +}
  31.568 +
  31.569 +case OP_NEG:
  31.570 +{
  31.571 +    top.sp[-1].i32 = -top.sp[-1].i32;
  31.572 +    break;
  31.573 +}
  31.574 +
  31.575 +case OP_NEG_F:
  31.576 +{
  31.577 +    top.sp[-1].f = -top.sp[-1].f;
  31.578 +    break;
  31.579 +}
  31.580 +
  31.581 +case OP_CALL:
  31.582 +{
  31.583 +    Local<Function> newFun(zone, top.sp[-1].fun);
  31.584 +    top.sp--;
  31.585 +
  31.586 +    if (!zone->stack().pushInlineFrame(newFun))
  31.587 +        goto error;
  31.588 +
  31.589 +    locals = top.fp->locals();
  31.590 +    continue;
  31.591 +}
  31.592 +
  31.593 +case OP_GETARG:
  31.594 +{
  31.595 +    unsigned slot = READ_UINT32(top.pc);
  31.596 +    *top.sp++ = top.fp->arg(slot);
  31.597 +    break;
  31.598 +}
  31.599 +
  31.600 +case OP_SETARG:
  31.601 +{
  31.602 +    unsigned slot = READ_UINT32(top.pc);
  31.603 +    top.fp->arg(slot) = *--top.sp;
  31.604 +    break;
  31.605 +}
  31.606 +
  31.607 +case OP_BOUNDS:
  31.608 +{
  31.609 +    Array *array = top.sp[-2].array;
  31.610 +    int index = top.sp[-1].i32;
  31.611 +    if (index < 0 || unsigned(index) >= array->nelements()) {
  31.612 +        zone->reportError(Message_ArrayIndexOutOfBounds, index, array->nelements());
  31.613 +        goto error;
  31.614 +    }
  31.615 +    break;
  31.616 +}
  31.617 +
  31.618 +case OP_GETARRAY_I:
  31.619 +{
  31.620 +    Array *array = top.sp[-2].array;
  31.621 +    int index = top.sp[-1].i32;
  31.622 +    top.sp[-2].i32 = array->readInt32(index);
  31.623 +    top.sp--;
  31.624 +    break;
  31.625 +}
  31.626 +
  31.627 +case OP_GETARRAY_F:
  31.628 +{
  31.629 +    Array *array = top.sp[-2].array;
  31.630 +    int index = top.sp[-1].i32;
  31.631 +    top.sp[-2].f = array->readFloat(index);
  31.632 +    top.sp--;
  31.633 +    break;
  31.634 +}
  31.635 +
  31.636 +case OP_GETARRAY_C:
  31.637 +{
  31.638 +    Array *array = top.sp[-2].array;
  31.639 +    int index = top.sp[-1].i32;
  31.640 +    top.sp[-2].i32 = array->readChar(index);
  31.641 +    top.sp--;
  31.642 +    break;
  31.643 +}
  31.644 +
  31.645 +case OP_SETARRAY_I:
  31.646 +{
  31.647 +    Array *array = top.sp[-3].array;
  31.648 +    int index = top.sp[-2].i32;
  31.649 +    array->writeInt32(index, top.sp[-1].i32);
  31.650 +    top.sp[-3] = top.sp[-1];
  31.651 +    top.sp -= 2;
  31.652 +    break;
  31.653 +}
  31.654 +
  31.655 +case OP_SETARRAY_F:
  31.656 +{
  31.657 +    Array *array = top.sp[-3].array;
  31.658 +    int index = top.sp[-2].i32;
  31.659 +    array->writeFloat(index, top.sp[-1].f);
  31.660 +    top.sp[-3] = top.sp[-1];
  31.661 +    top.sp -= 2;
  31.662 +    break;
  31.663 +}
  31.664 +
  31.665 +case OP_SETARRAY_C:
  31.666 +{
  31.667 +    Array *array = top.sp[-3].array;
  31.668 +    int index = top.sp[-2].i32;
  31.669 +    array->writeChar(index, top.sp[-1].i32);
  31.670 +    top.sp[-3] = top.sp[-1];
  31.671 +    top.sp -= 2;
  31.672 +    break;
  31.673 +}
  31.674 +
  31.675 +case OP_GETARRAY_O:
  31.676 +{
  31.677 +    Array *array = top.sp[-2].array;
  31.678 +    int index = top.sp[-1].i32;
  31.679 +    top.sp[-2].array = Array::cast(array->readObject(index));
  31.680 +    top.sp--;
  31.681 +    break;
  31.682 +}
  31.683 +
  31.684 +case OP_CVT_I2F:
  31.685 +{
  31.686 +    int ival = POP_I32(top);
  31.687 +    float fval = (float)ival;
  31.688 +    PUSH_F(top, fval);
  31.689 +    break;
  31.690 +}
  31.691 +
  31.692 +case OP_NEWARRAY:
  31.693 +{
  31.694 +    Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
  31.695 +    Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
  31.696 +    Array *array = GenerateArray(zone, map, tenure);
  31.697 +    if (!array)
  31.698 +        goto error;
  31.699 +    top.sp->obj = array;
  31.700 +    top.sp++;
  31.701 +    break;
  31.702 +}
  31.703 +
  31.704 +case OP_SAVELIFO:
  31.705 +{
  31.706 +    unsigned slot = READ_UINT32(top.pc);
  31.707 +    locals[slot].address = zone->heap().lifoPosition();
  31.708 +    break;
  31.709 +}
  31.710 +
  31.711 +case OP_UNWINDLIFO:
  31.712 +{
  31.713 +    unsigned slot = READ_UINT32(top.pc);
  31.714 +    zone->heap().unwindLifo(locals[slot].address);
  31.715 +    break;
  31.716 +}
  31.717 +
  31.718 +case OP_VARREF_LIFO:
  31.719 +{
  31.720 +    unsigned slot = READ_UINT32(top.pc);
  31.721 +    if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
  31.722 +        goto error;
  31.723 +    break;
  31.724 +}
  31.725 +
  31.726 +case OP_ARGREF_LIFO:
  31.727 +{
  31.728 +    unsigned slot = READ_UINT32(top.pc);
  31.729 +    if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
  31.730 +        goto error;
  31.731 +    break;
  31.732 +}
  31.733 +
  31.734 +case OP_ARRAYREF_LIFO:
  31.735 +{
  31.736 +    Local<Array> array(zone, top.sp[-2].array);
  31.737 +    Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
  31.738 +    if (!ref)
  31.739 +        goto error;
  31.740 +    top.sp[-2].ref = ref;
  31.741 +    top.sp--;
  31.742 +    break;
  31.743 +}
  31.744 +
  31.745 +case OP_SLOTREF_LIFO:
  31.746 +{
  31.747 +    Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
  31.748 +    if (!ref)
  31.749 +        goto error;
  31.750 +    top.sp[-1].ref = ref;
  31.751 +    break;
  31.752 +}
  31.753 +
  31.754 +case OP_GETREF_I:
  31.755 +{
  31.756 +    top.sp[-1].i32 = top.sp[-1].ref->getInt();
  31.757 +    break;
  31.758 +}
  31.759 +
  31.760 +case OP_SETREF_I:
  31.761 +{
  31.762 +    top.sp[-2].ref->setInt(top.sp[-1].i32);
  31.763 +    top.sp[-2].i32 = top.sp[-1].i32;
  31.764 +    top.sp--;
  31.765 +    break;
  31.766 +}
  31.767 +
  31.768 +case OP_GETREF_F:
  31.769 +{
  31.770 +    top.sp[-1].f = top.sp[-1].ref->getFloat();
  31.771 +    break;
  31.772 +}
  31.773 +
  31.774 +case OP_SETREF_F:
  31.775 +{
  31.776 +    top.sp[-2].ref->setFloat(top.sp[-1].f);
  31.777 +    top.sp[-2].f = top.sp[-1].f;
  31.778 +    break;
  31.779 +}
  31.780 +
  31.781 +case OP_OBJECT:
  31.782 +{
  31.783 +    top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
  31.784 +    top.sp++;
  31.785 +    break;
  31.786 +}
  31.787 +
  31.788 +case OP_ARRAYCOPY:
  31.789 +{
  31.790 +    // Note for this assignment opcode, we return the left-hand side, not the
  31.791 +    // right, since in this case the result of the expression could be different.
  31.792 +    if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array))
  31.793 +        goto error;
  31.794 +    top.sp--;
  31.795 +    break;
  31.796 +}
  31.797 +
  31.798 +case OP_DUP:
  31.799 +{
  31.800 +    top.sp++;
  31.801 +    top.sp[-1] = top.sp[-2];
  31.802 +    break;
  31.803 +}
  31.804 +
  31.805 +case OP_DUP2:
  31.806 +{
  31.807 +    top.sp += 2;
  31.808 +    top.sp[-2] = top.sp[-4];
  31.809 +    top.sp[-1] = top.sp[-3];
  31.810 +    break;
  31.811 +}
  31.812 +
  31.813 +case OP_SWAP:
  31.814 +{
  31.815 +    LocalSlot slot = top.sp[-2];
  31.816 +    top.sp[-2] = top.sp[-1];
  31.817 +    top.sp[-1] = slot;
  31.818 +    break;
  31.819 +}
  31.820 +
  31.821 +case OP_ROLL3:
  31.822 +{
  31.823 +    LocalSlot slot = top.sp[-3];
  31.824 +    top.sp[-3] = top.sp[-2];
  31.825 +    top.sp[-2] = top.sp[-1];
  31.826 +    top.sp[-1] = slot;
  31.827 +    break;
  31.828 +}
  31.829 +
  31.830 +case OP_PICK2:
  31.831 +{
  31.832 +    top.sp++;
  31.833 +    top.sp[-1] = top.sp[-3];
  31.834 +    break;
  31.835 +}
  31.836 +
  31.837 +case OP_PICK3:
  31.838 +{
  31.839 +    top.sp++;
  31.840 +    top.sp[-1] = top.sp[-4];
  31.841 +    break;
  31.842 +}
  31.843 +
  31.844 +case OP_CALLNATIVE:
  31.845 +{
  31.846 +    unsigned index = READ_UINT32(top.pc);
  31.847 +    unsigned argc = READ_UINT32(top.pc + 4);
  31.848 +
  31.849 +    Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
  31.850 +    if (!native->function()) {
  31.851 +        zone->reportError(Message_NativeNotBound, native->name()->chars());
  31.852 +        goto error;
  31.853 +    }
  31.854 +
  31.855 +    int result;
  31.856 +    void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
  31.857 +    if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
  31.858 +        goto error;
  31.859 +
  31.860 +    top.sp -= argc;
  31.861 +    PUSH_I32(top, result);
  31.862 +    break;
  31.863 +}
  31.864 +
  31.865 +case OP_MODULE:
  31.866 +{
  31.867 +    top.sp++;
  31.868 +    top.sp[-1].module = top.fp->code()->module();
  31.869 +    break;
  31.870 +}
  31.871 +
  31.872 +case OP_GETMODULE_FN:
  31.873 +{
  31.874 +    top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
  31.875 +    break;
  31.876 +}
  31.877 +
  31.878 +case OP_GETGLOBAL_I:
  31.879 +{
  31.880 +    unsigned slot = READ_UINT32(top.pc);
  31.881 +    top.sp++;
  31.882 +    top.sp[-1].i32 = top.fp->code()->module()->environment()->getInt32(slot);
  31.883 +    break;
  31.884 +}
  31.885 +
  31.886 +case OP_GETGLOBAL_F:
  31.887 +{
  31.888 +    unsigned slot = READ_UINT32(top.pc);
  31.889 +    top.sp++;
  31.890 +    top.sp[-1].f = top.fp->code()->module()->environment()->getFloat(slot);
  31.891 +    break;
  31.892 +}
  31.893 +
  31.894 +case OP_GETGLOBAL_O:
  31.895 +{
  31.896 +    unsigned slot = READ_UINT32(top.pc);
  31.897 +    top.sp++;
  31.898 +    top.sp[-1].obj = top.fp->code()->module()->environment()->getObject(slot);
  31.899 +    break;
  31.900 +}
  31.901 +
  31.902 +case OP_SETGLOBAL_I:
  31.903 +{
  31.904 +    unsigned slot = READ_UINT32(top.pc);
  31.905 +    top.fp->code()->module()->environment()->setInt32(slot, top.sp[-1].i32);
  31.906 +    break;
  31.907 +}
  31.908 +
  31.909 +case OP_SETGLOBAL_F:
  31.910 +{
  31.911 +    unsigned slot = READ_UINT32(top.pc);
  31.912 +    top.fp->code()->module()->environment()->setFloat(slot, top.sp[-1].f);
  31.913 +    break;
  31.914 +}
  31.915 +
  31.916 +case OP_SETGLOBAL_O:
  31.917 +{
  31.918 +    unsigned slot = READ_UINT32(top.pc);
  31.919 +    top.fp->code()->module()->environment()->setObject(slot, top.sp[-1].obj);
  31.920 +    break;
  31.921 +}
  31.922 +
  31.923 +default:
  31.924 +    assert(false);
  31.925 +    return false;
  31.926 +
  31.927 +        }
  31.928 +
  31.929 +        top.pc += OpcodeInfo[op].length;
  31.930 +    }
  31.931 +
  31.932 +done:
  31.933 +    return true;
  31.934 +
  31.935 +error:
  31.936 +    // Unwind frames until we can continue.
  31.937 +    while (top.fp != entryFrame)
  31.938 +        zone->stack().popInlineFrame();
  31.939 +    return false;
  31.940 +}
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/src/Interpreter.h	Tue Jul 24 23:53:34 2012 -0700
    32.3 @@ -0,0 +1,29 @@
    32.4 +/*
    32.5 + * Copyright (C) 2012 David Anderson
    32.6 + *
    32.7 + * This file is part of JITCraft.
    32.8 + *
    32.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   32.10 + * the terms of the GNU General Public License as published by the Free
   32.11 + * Software Foundation, either version 3 of the License, or (at your option)
   32.12 + * any later version.
   32.13 + * 
   32.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   32.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   32.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   32.17 + *
   32.18 + * You should have received a copy of the GNU General Public License along with
   32.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   32.20 + */
   32.21 +#ifndef _include_jc_interpreter_h_
   32.22 +#define _include_jc_interpreter_h_
   32.23 +
   32.24 +#include "Stack.h"
   32.25 +
   32.26 +namespace ke {
   32.27 +
   32.28 +bool Interpret(Zone *zone, Frame *frame, LocalSlot *result);
   32.29 +
   32.30 +}
   32.31 +
   32.32 +#endif // _include_jc_interpreter_h_
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/src/Makefile.in	Tue Jul 24 23:53:34 2012 -0700
    33.3 @@ -0,0 +1,96 @@
    33.4 +#vim: set ft=make: 
    33.5 +
    33.6 +CXX=@CXX@
    33.7 +CXXFLAGS=@CXXFLAGS@
    33.8 +srcdir=@srcdir@
    33.9 +VPATH=${srcdir}
   33.10 +TOOLS=${srcdir}/../build
   33.11 +CXXVENDOR=@CXXVENDOR@
   33.12 +PLATFORM="@PLATFORM@"
   33.13 +NULL =
   33.14 +
   33.15 +INCLUDES += 
   33.16 +CXXFLAGS += $(INCLUDES)
   33.17 +BASECXXFLAGS = -Wall -Werror -Wno-null-arithmetic -Wno-invalid-offsetof -g3 -O0
   33.18 +
   33.19 +CPPSRCS = \
   33.20 +	Array.cpp                  \
   33.21 +	BytecodeCompiler.cpp       \
   33.22 +	BytecodeEmitter.cpp	   \
   33.23 +	CompileContext.cpp         \
   33.24 +        Exception.cpp              \
   33.25 +        FixedArray.cpp             \
   33.26 +        Functions.cpp              \
   33.27 +	Heap.cpp                   \
   33.28 +        Interpreter.cpp            \
   33.29 +	Modules.cpp                \
   33.30 +	NameBinding.cpp            \
   33.31 +	Parser.cpp                 \
   33.32 +	Opcodes.cpp                \
   33.33 +	PoolAllocator.cpp          \
   33.34 +	Reference.cpp              \
   33.35 +	RootScopes.cpp             \
   33.36 +	Scanner.cpp                \
   33.37 +	Scopes.cpp                 \
   33.38 +	SemanticAnalysis.cpp       \
   33.39 +	Spaces.cpp                 \
   33.40 +	Stack.cpp                  \
   33.41 +	TypeManager.cpp            \
   33.42 +	Types.cpp                  \
   33.43 +	Zone.cpp                   \
   33.44 +	main.cpp                   \
   33.45 +	$(NULL)
   33.46 +
   33.47 +ifeq ("darwin", $(PLATFORM))
   33.48 +CPPSRCS += \
   33.49 +	Platform-Posix.cpp         \
   33.50 +	$(NULL)
   33.51 +endif
   33.52 +ifeq ("linux", $(PLATFORM))
   33.53 +CPPSRCS += \
   33.54 +	Platform-Posix.cpp         \
   33.55 +	$(NULL)
   33.56 +endif
   33.57 +
   33.58 +default: all
   33.59 +
   33.60 +OBJECTS := $(CPPSRCS:%.cpp=%.o)
   33.61 +
   33.62 +ifeq ($(CXXVENDOR), microsoft)
   33.63 +
   33.64 +CXXFLAGS += /DWIN32 /D_WINDOWS
   33.65 +
   33.66 +%.o: %.cpp
   33.67 +	$(CXX) $(CXXFLAGS) /Fo$@ /c /TP /nologo $<
   33.68 +else
   33.69 +
   33.70 +%.o: %.cpp
   33.71 +	$(CXX) $(BASECXXFLAGS) $(CXXFLAGS) -c -o $@ -Wp,-MD,.deps/$(patsubst %.o,%.d,$@) $<
   33.72 +
   33.73 +endif
   33.74 +
   33.75 +#$(CXX) $(BASECXXFLAGS) $(CXXFLAGS) -c -o $@ -Wp,-MD,.deps/$(basename $(@F)).pp $<
   33.76 +
   33.77 +DEPEND_FILES := $(strip $(wildcard .deps/*.d))
   33.78 +
   33.79 +ifneq (,$(DEPEND_FILES))
   33.80 +DEPEND_RESULTS = $(shell $(TOOLS)/mddepend.pl - $(DEPEND_FILES))
   33.81 +$(eval $(DEPEND_RESULTS))
   33.82 +endif
   33.83 +
   33.84 +all: foobar
   33.85 +
   33.86 +foobar: libfoobar.a main.o
   33.87 +	$(CXX) main.o libfoobar.a -lpthread -o foobar
   33.88 +
   33.89 +libfoobar.a: $(OBJECTS)
   33.90 +	$(AR) -crs libfoobar.a $(OBJECTS)
   33.91 +
   33.92 +FORCE:
   33.93 +
   33.94 +clean:
   33.95 +	rm -f .deps/*.d
   33.96 +	rm -f *.o
   33.97 +	rm -f libfoobar.a
   33.98 +	rm -f foobar
   33.99 +
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/src/Messages.h	Tue Jul 24 23:53:34 2012 -0700
    34.3 @@ -0,0 +1,48 @@
    34.4 +/*
    34.5 + * Copyright (C) 2012 David Anderson
    34.6 + *
    34.7 + * This file is part of JITCraft.
    34.8 + *
    34.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   34.10 + * the terms of the GNU General Public License as published by the Free
   34.11 + * Software Foundation, either version 3 of the License, or (at your option)
   34.12 + * any later version.
   34.13 + * 
   34.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   34.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   34.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   34.17 + *
   34.18 + * You should have received a copy of the GNU General Public License along with
   34.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   34.20 + */
   34.21 +#ifndef _include_jitcraft_messages_h_
   34.22 +#define _include_jitcraft_messages_h_
   34.23 +
   34.24 +namespace ke {
   34.25 +
   34.26 +enum MessageType
   34.27 +{
   34.28 +    MessageType_SyntaxError,
   34.29 +    MessageType_TypeError,
   34.30 +    MessageType_SystemError
   34.31 +};
   34.32 +
   34.33 +enum Message
   34.34 +{
   34.35 +#define MSG(Name, Type, String)     Message_##Name,
   34.36 +# include "Messages.tbl"
   34.37 +#undef MSG
   34.38 +    MessageType_Total
   34.39 +};
   34.40 +
   34.41 +struct MessageInfo
   34.42 +{
   34.43 +    MessageType type;
   34.44 +    const char *format;
   34.45 +};
   34.46 +
   34.47 +extern const MessageInfo Messages[];
   34.48 +
   34.49 +}
   34.50 +
   34.51 +#endif // _include_jitcraft_messages_h_
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/src/Messages.tbl	Tue Jul 24 23:53:34 2012 -0700
    35.3 @@ -0,0 +1,62 @@
    35.4 +MSG(UnterminatedComment,            SyntaxError,            "unterminated comment")
    35.5 +MSG(UnexpectedCharacter,            SyntaxError,            "unexpected character '%c' (code %02X)")
    35.6 +MSG(UnterminatedString,             SyntaxError,            "unterminated string")
    35.7 +MSG(UnknownEscapeCode,              SyntaxError,            "unknown escape code '%c'")
    35.8 +MSG(ExpectedDigitForFloat,          SyntaxError,            "expected digit in float literal, got '%c'")
    35.9 +MSG(WrongToken,                     SyntaxError,            "expected token '%s', got '%s'")
   35.10 +MSG(ExpectedExpression,             SyntaxError,            "expected expression, got '%s'")
   35.11 +MSG(RedeclaredName,                 SyntaxError,            "name '%s' was redeclared (previous at line %d, col %d)")
   35.12 +MSG(ExpectedLValue,                 SyntaxError,            "impossible assignment, expected l-value")
   35.13 +MSG(MaximumArrayDepth,              SyntaxError,            "maximum array dimension depth exceeded")
   35.14 +MSG(ArrayInitializerDepth,          SyntaxError,            "array declaration and initializer have different dimension counts")
   35.15 +MSG(BadArraySize,                   SyntaxError,            "array size must be positive")
   35.16 +MSG(ArraySizeTooBig,                SyntaxError,            "array size is too big")
   35.17 +MSG(EnumFieldNotConstant,           SyntaxError,            "enum fields must be constant integers")
   35.18 +MSG(BreakOutsideLoop,               SyntaxError,            "break occurs outside any loop")
   35.19 +MSG(ContinueOutsideLoop,            SyntaxError,            "continue occurs outside any loop")
   35.20 +MSG(InvalidEnumName,                SyntaxError,            "invalid enumeration name")
   35.21 +MSG(IndexMustBeInteger,             SyntaxError,            "array index must be integer")
   35.22 +MSG(IndexBaseMustBeArray,           SyntaxError,            "cannot index into non-array")
   35.23 +MSG(ArrayIsNotBoolean,              SyntaxError,            "cannot convert an array to boolean")
   35.24 +MSG(CalleeNotFunction,              SyntaxError,            "callee is not a function")
   35.25 +MSG(ArgumentCountMismatch,          SyntaxError,            "argument counts do not match")
   35.26 +MSG(CannotAssignArrayToScalar,      SyntaxError,            "cannot coerce an array to a scalar")
   35.27 +MSG(UnsupportedType,                SyntaxError,            "unsupported type")
   35.28 +MSG(TagMismatch,                    SyntaxError,            "tag mismatch (expected '%s', got '%s')")
   35.29 +MSG(ArrayDimensionsMismatch,        SyntaxError,            "number of array dimensions does not match")
   35.30 +MSG(ExpectedArray,                  SyntaxError,            "expected array")
   35.31 +MSG(ArrayDimensionSizeMismatch,     SyntaxError,            "array dimension sizes do not match (level %d)")
   35.32 +MSG(ArrayDimensionNotInteger,       SyntaxError,            "array dimension size must be an integer expression")
   35.33 +MSG(ArrayNotSupported,              SyntaxError,            "array declaration not yet supported")
   35.34 +MSG(ArrayInitializerUnknown,        SyntaxError,            "array initialized size is not known")
   35.35 +MSG(DynamicArrayHasInitializer,     SyntaxError,            "dynamic arrays cannot have initializers")
   35.36 +MSG(ArraySizeNotSpecified,          SyntaxError,            "array size was not specified")
   35.37 +MSG(ArraySizeCannotBeDetermined,    SyntaxError,            "array size cannot be determined from initializer")
   35.38 +MSG(ArrayAssignmentTooBig,          SyntaxError,            "destination array is too small")
   35.39 +MSG(CannotDeclareStringCell,        SyntaxError,            "cannot declare a String cell")
   35.40 +MSG(BinaryTypeError,                SyntaxError,            "operator '%s' does not support types '%s' and '%s'")
   35.41 +MSG(ArraySizeNotKnown,              SyntaxError,            "array size is not known")
   35.42 +MSG(UnaryTypeError,                 SyntaxError,            "operator '%s' does not support type '%s'")
   35.43 +MSG(CantOpenFile,                   SyntaxError,            "cannot open file")
   35.44 +MSG(ErrorSeekingFile,               SyntaxError,            "error seeking file")
   35.45 +MSG(ErrorReadingFile,               SyntaxError,            "error reading file")
   35.46 +MSG(ExpectedGlobal,                 SyntaxError,            "expected global variable or function")
   35.47 +MSG(ForwardNotImplemented,          SyntaxError,            "forward '%s' not implemented")
   35.48 +MSG(ForwardDeclareMismatches,       SyntaxError,            "declaration does not match original forward signature")
   35.49 +MSG(ArrayCantBeReference,           SyntaxError,            "a parameter cannot be both an array and a reference")
   35.50 +MSG(ArraySizeMustBeConstant,        SyntaxError,            "array size must be a constant integer")
   35.51 +MSG(ReferenceIsConstant,            SyntaxError,            "cannot assign to a constant lvalue")
   35.52 +MSG(MultiArrayInNative,             SyntaxError,            "multidimensional arrays cannot be passed to natives")
   35.53 +MSG(InvalidVarArgs,                 SyntaxError,            "varargs cannot be const or ref")
   35.54 +MSG(VarArgsOutsideNative,           SyntaxError,            "variadic arguments can only be specified on natives")
   35.55 +MSG(ArrayTooBig,                    TypeError,              "array size is too large")
   35.56 +MSG(IntegerDivideByZero,            TypeError,              "integer divide by zero")
   35.57 +MSG(ArrayIndexOutOfBounds,          TypeError,              "array index %d is out of bounds [0, %d)")
   35.58 +MSG(NativeNotBound,                 TypeError,              "attempted to call unbound native \"%s\"")
   35.59 +MSG(AllocationOverflow,             SystemError,            "allocation request overflowed")
   35.60 +MSG(TooMuchRecursion,               SystemError,            "stack overflow: too much recursion")
   35.61 +MSG(MissingReturnValue,             SyntaxError,            "tagged function must return a value")
   35.62 +MSG(NotAllPathsReturnValue,         SyntaxError,            "not all paths through function return a value")
   35.63 +MSG(UsedVoidReturn,                 SyntaxError,            "return value expected, but function does not return a value")
   35.64 +MSG(FunctionDoesNotReturnValue,     SyntaxError,            "cannot use the result of a function with no return value")
   35.65 +MSG(IdentifierNotFound,             SyntaxError,            "identifier '%s' could not be found")
   35.66 \ No newline at end of file
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/src/Modules.cpp	Tue Jul 24 23:53:34 2012 -0700
    36.3 @@ -0,0 +1,43 @@
    36.4 +/*
    36.5 + * Copyright (C) 2012 David Anderson
    36.6 + *
    36.7 + * This file is part of JITCraft.
    36.8 + *
    36.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   36.10 + * the terms of the GNU General Public License as published by the Free
   36.11 + * Software Foundation, either version 3 of the License, or (at your option)
   36.12 + * any later version.
   36.13 + * 
   36.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   36.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   36.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   36.17 + *
   36.18 + * You should have received a copy of the GNU General Public License along with
   36.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   36.20 + */
   36.21 +#include "Modules.h"
   36.22 +#include "Zone.h"
   36.23 +#include "Heap.h"
   36.24 +#include "Heap-inl.h"
   36.25 +
   36.26 +using namespace ke;
   36.27 +
   36.28 +Module *
   36.29 +Module::New(Zone *zone, unsigned nfunctions)
   36.30 +{
   36.31 +    Local<Module> module(zone, Module::cast(zone->allocate(MapKind_Module, sizeof(Module), Heap::Tenure_Old)));
   36.32 +    if (!module)
   36.33 +        return NULL;
   36.34 +
   36.35 +    Local<FixedArray> functions(zone, FixedArray::New(zone, nfunctions, Heap::Tenure_Old));
   36.36 +    if (!functions)
   36.37 +        return NULL;
   36.38 +
   36.39 +    module->functions_ = functions;
   36.40 +    module->file_ = NULL;
   36.41 +    module->publics_ = NULL;
   36.42 +    module->natives_ = NULL;
   36.43 +    module->environment_ = NULL;
   36.44 +    module->nativeIdentity_ = NULL;
   36.45 +    return module;
   36.46 +}
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/src/Modules.h	Tue Jul 24 23:53:34 2012 -0700
    37.3 @@ -0,0 +1,119 @@
    37.4 +/*
    37.5 + * Copyright (C) 2012 David Anderson
    37.6 + *
    37.7 + * This file is part of JITCraft.
    37.8 + *
    37.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   37.10 + * the terms of the GNU General Public License as published by the Free
   37.11 + * Software Foundation, either version 3 of the License, or (at your option)
   37.12 + * any later version.
   37.13 + * 
   37.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   37.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   37.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   37.17 + *
   37.18 + * You should have received a copy of the GNU General Public License along with
   37.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   37.20 + */
   37.21 +#ifndef _include_jc_module_h_
   37.22 +#define _include_jc_module_h_
   37.23 +
   37.24 +#include "Heap.h"
   37.25 +#include "Code.h"
   37.26 +#include "Functions.h"
   37.27 +
   37.28 +namespace ke {
   37.29 +
   37.30 +class Environment;
   37.31 +
   37.32 +class Module : public Object
   37.33 +{
   37.34 +    Barriered<FixedArray> functions_;
   37.35 +    Barriered<FixedArray> publics_;
   37.36 +    Barriered<FixedArray> natives_;
   37.37 +    Barriered<String> file_;
   37.38 +    Barriered<Environment> environment_;
   37.39 +    Barriered<Code> code_;
   37.40 +    void *nativeIdentity_;
   37.41 +
   37.42 +  public:
   37.43 +    static Module *New(Zone *zone, unsigned nfunctions);
   37.44 +
   37.45 +    Function *getFunction(size_t i) {
   37.46 +        return Function::cast(functions_->at(i));
   37.47 +    }
   37.48 +    void setFunction(Zone *zone, size_t i, Function *fun) {
   37.49 +        assert(!functions_->at(i));
   37.50 +        assert(fun);
   37.51 +        functions_->set(zone, i, fun);
   37.52 +    }
   37.53 +
   37.54 +    FixedArray *publics() {
   37.55 +        return publics_;
   37.56 +    }
   37.57 +    FixedArray *natives() {
   37.58 +        return natives_;
   37.59 +    }
   37.60 +    String *file() {
   37.61 +        return file_;
   37.62 +    }
   37.63 +    Environment *environment() {
   37.64 +        return environment_;
   37.65 +    }
   37.66 +    Code *code() {
   37.67 +        return code_;
   37.68 +    }
   37.69 +
   37.70 +    void setPublics(Handle<FixedArray> publics) {
   37.71 +        publics_ = publics;
   37.72 +    }
   37.73 +    void setNatives(Handle<FixedArray> natives) {
   37.74 +        natives_ = natives;
   37.75 +    }
   37.76 +    void setPath(Handle<String> path) {
   37.77 +        file_ = path;
   37.78 +    }
   37.79 +    void setEnvironment(Handle<Environment> environment) {
   37.80 +        environment_ = environment;
   37.81 +    }
   37.82 +    void setCode(Handle<Code> code) {
   37.83 +        code_ = code;
   37.84 +    }
   37.85 +
   37.86 +    void *nativeIdentity() {
   37.87 +        return nativeIdentity_;
   37.88 +    }
   37.89 +    void setNativeIdentity(void *identity) {
   37.90 +        nativeIdentity_ = identity;
   37.91 +    }
   37.92 +
   37.93 +    // Begin GC Descriptor.
   37.94 +    static inline size_t offsetOfFunctions() {
   37.95 +        return offsetof(Module, functions_);
   37.96 +    }
   37.97 +    static inline size_t offsetOfPublics() {
   37.98 +        return offsetof(Module, publics_);
   37.99 +    }
  37.100 +    static inline size_t offsetOfNatives() {
  37.101 +        return offsetof(Module, natives_);
  37.102 +    }
  37.103 +    static inline size_t offsetOfFile() {
  37.104 +        return offsetof(Module, file_);
  37.105 +    }
  37.106 +    static inline size_t offsetOfEnvironment() {
  37.107 +        return offsetof(Module, environment_);
  37.108 +    }
  37.109 +    static inline size_t offsetOfCode() {
  37.110 +        return offsetof(Module, code_);
  37.111 +    }
  37.112 +    // End GC Descriptor.
  37.113 +
  37.114 +    static inline Module *cast(Object *obj) {
  37.115 +        assert(!obj || obj->is(MapKind_Module));
  37.116 +        return reinterpret_cast<Module *>(obj);
  37.117 +    }
  37.118 +};
  37.119 +
  37.120 +}
  37.121 +
  37.122 +#endif // _include_jc_module_h_
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/src/NameBinding.cpp	Tue Jul 24 23:53:34 2012 -0700
    38.3 @@ -0,0 +1,51 @@
    38.4 +/*
    38.5 + * Copyright (C) 2012 David Anderson
    38.6 + *
    38.7 + * This file is part of JITCraft.
    38.8 + *
    38.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   38.10 + * the terms of the GNU General Public License as published by the Free
   38.11 + * Software Foundation, either version 3 of the License, or (at your option)
   38.12 + * any later version.
   38.13 + * 
   38.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   38.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   38.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   38.17 + *
   38.18 + * You should have received a copy of the GNU General Public License along with
   38.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   38.20 + */
   38.21 +#include "NameBinding.h"
   38.22 +#include "Strings.h"
   38.23 +#include "Zone.h"
   38.24 +#include "Scopes.h"
   38.25 +
   38.26 +using namespace ke;
   38.27 +
   38.28 +BoundName::BoundName(Scope *scope, Handle<String> name, const SourcePosition &pos)
   38.29 +  : scope_(scope),
   38.30 +    name_(name),
   38.31 +    type_(NULL),
   38.32 +    pos_(pos)
   38.33 +{
   38.34 +}
   38.35 +
   38.36 +NamedFunction::NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos,
   38.37 +                             TokenKind token)
   38.38 +  : BoundName(scope, name, pos),
   38.39 +    token_(token),
   38.40 +    isVariadicNative_(false)
   38.41 +{
   38.42 +}
   38.43 +
   38.44 +Variable::Variable(Scope *scope, Handle<String> name, const SourcePosition &pos)
   38.45 +  : BoundName(scope, name, pos),
   38.46 +    location_(UNALLOCATED)
   38.47 +{
   38.48 +}
   38.49 +
   38.50 +bool
   38.51 +Variable::needsHeapAllocation()
   38.52 +{
   38.53 +    return scope()->kind() == Scope::GLOBAL;
   38.54 +}
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/src/NameBinding.h	Tue Jul 24 23:53:34 2012 -0700
    39.3 @@ -0,0 +1,211 @@
    39.4 +/*
    39.5 + * Copyright (C) 2012 David Anderson
    39.6 + *
    39.7 + * This file is part of JITCraft.
    39.8 + *
    39.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   39.10 + * the terms of the GNU General Public License as published by the Free
   39.11 + * Software Foundation, either version 3 of the License, or (at your option)
   39.12 + * any later version.
   39.13 + * 
   39.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   39.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   39.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   39.17 + *
   39.18 + * You should have received a copy of the GNU General Public License along with
   39.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   39.20 + */
   39.21 +#ifndef _include_name_binding_h_
   39.22 +#define _include_name_binding_h_
   39.23 +
   39.24 +#include "PoolAllocator.h"
   39.25 +#include "Types.h"
   39.26 +#include "Scanner.h"
   39.27 +
   39.28 +namespace ke {
   39.29 +
   39.30 +class Variable;
   39.31 +class NamedFunction;
   39.32 +class Scope;
   39.33 +class Type;
   39.34 +class NamedEnum;
   39.35 +class NamedConstant;
   39.36 +class String;
   39.37 +
   39.38 +class BoundName : public PoolObject
   39.39 +{
   39.40 +    Scope *scope_;
   39.41 +    ScopedRoot<String> name_;
   39.42 +    ScopedRoot<Type> type_;
   39.43 +
   39.44 +  protected:
   39.45 +    SourcePosition pos_;
   39.46 +
   39.47 +  public:
   39.48 +    enum Kind {
   39.49 +      VARIABLE,
   39.50 +      FUNCTION,
   39.51 +      ENUM,
   39.52 +      CONSTANT
   39.53 +    };
   39.54 +
   39.55 +    BoundName(Scope *scope, Handle<String> name, const SourcePosition &pos);
   39.56 +
   39.57 +    virtual Kind kind() const = 0;
   39.58 +
   39.59 +    String *name() const {
   39.60 +        return name_;
   39.61 +    }
   39.62 +    Scope *scope() const {
   39.63 +        return scope_;
   39.64 +    }
   39.65 +    Variable *toVariable() {
   39.66 +        assert(kind() == VARIABLE);
   39.67 +        return reinterpret_cast<Variable *>(this);
   39.68 +    }
   39.69 +    NamedFunction *toNamedFunction() {
   39.70 +        assert(kind() == FUNCTION);
   39.71 +        return reinterpret_cast<NamedFunction *>(this);
   39.72 +    }
   39.73 +    NamedConstant *toNamedConstant() {
   39.74 +        assert(kind() == CONSTANT);
   39.75 +        return reinterpret_cast<NamedConstant *>(this);
   39.76 +    }
   39.77 +    Type *type() const {
   39.78 +        return type_;
   39.79 +    }
   39.80 +    void setType(Handle<Type> type) {
   39.81 +        type_ = type;
   39.82 +    }
   39.83 +    const SourcePosition &pos() {
   39.84 +        return pos_;
   39.85 +    }
   39.86 +};
   39.87 +
   39.88 +class NamedFunction : public BoundName
   39.89 +{
   39.90 +    unsigned slot_;
   39.91 +    TokenKind token_;
   39.92 +    ScopedRoot<Type> forwardType_;
   39.93 +    bool isVariadicNative_;
   39.94 +
   39.95 +  public:
   39.96 +    NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos, TokenKind token);
   39.97 +
   39.98 +    Kind kind() const {
   39.99 +        return FUNCTION;
  39.100 +    }
  39.101 +    void allocate(unsigned slot) {
  39.102 +        slot_ = slot;
  39.103 +    }
  39.104 +    bool isForward() const {
  39.105 +        return token_ == TOK_FORWARD;
  39.106 +    }
  39.107 +    bool isPublic() const {
  39.108 +        return token_ == TOK_PUBLIC;
  39.109 +    }
  39.110 +    bool isNative() const {
  39.111 +        return token_ == TOK_NATIVE;
  39.112 +    }
  39.113 +    void setForwardType(Handle<Type> type) {
  39.114 +        forwardType_ = type;
  39.115 +    }
  39.116 +    Type *forwardType() {
  39.117 +        return forwardType_;
  39.118 +    }
  39.119 +    void setImplemented(const SourcePosition &at) {
  39.120 +        token_ = TOK_PUBLIC;
  39.121 +        pos_ = at;
  39.122 +    }
  39.123 +    void markNativeVariadic() {
  39.124 +        assert(token_ == TOK_NATIVE);
  39.125 +        isVariadicNative_ = true;
  39.126 +    }
  39.127 +    bool isNativeVariadic() {
  39.128 +        assert(token_ == TOK_NATIVE);
  39.129 +        return isVariadicNative_;
  39.130 +    }
  39.131 +    unsigned slot() const {
  39.132 +        return slot_;
  39.133 +    }
  39.134 +};
  39.135 +
  39.136 +class NamedEnum : public BoundName
  39.137 +{
  39.138 +  public:
  39.139 +    NamedEnum(Scope *scope, Handle<String> name, const SourcePosition &pos)
  39.140 +      : BoundName(scope, name, pos)
  39.141 +    {
  39.142 +    }
  39.143 +
  39.144 +    Kind kind() const {
  39.145 +        return ENUM;
  39.146 +    }
  39.147 +};
  39.148 +
  39.149 +class NamedConstant : public BoundName
  39.150 +{
  39.151 +    BoxedPrimitive value_;
  39.152 +    Type *type_;
  39.153 +
  39.154 +  public:
  39.155 +    NamedConstant(Scope *scope, Handle<String> name, const SourcePosition &pos)
  39.156 +      : BoundName(scope, name, pos),
  39.157 +        type_(NULL)
  39.158 +    {
  39.159 +    }
  39.160 +
  39.161 +    Kind kind() const {
  39.162 +        return CONSTANT;
  39.163 +    }
  39.164 +    void set(Type *type, const BoxedPrimitive &value) {
  39.165 +        value_ = value;
  39.166 +        type_ = type;
  39.167 +    }
  39.168 +    Type *type() const {
  39.169 +        return type_;
  39.170 +    }
  39.171 +    BoxedPrimitive value() const {
  39.172 +        return value_;
  39.173 +    }
  39.174 +};
  39.175 +
  39.176 +class Variable : public BoundName
  39.177 +{
  39.178 +  public:
  39.179 +    enum Location {
  39.180 +        UNALLOCATED,
  39.181 +        STACK,
  39.182 +        PARAMETER,
  39.183 +        ENVIRONMENT
  39.184 +    };
  39.185 +
  39.186 +    Variable(Scope *scope, Handle<String> name, const SourcePosition &pos);
  39.187 +
  39.188 +    Kind kind() const {
  39.189 +        return VARIABLE;
  39.190 +    }
  39.191 +    bool unallocated() const {
  39.192 +        return location() == UNALLOCATED;
  39.193 +    }
  39.194 +    void allocate(Location location, unsigned slot) {
  39.195 +        location_ = location;
  39.196 +        slot_ = slot;
  39.197 +    }
  39.198 +    Location location() const {
  39.199 +        return location_;
  39.200 +    }
  39.201 +    unsigned slot() const {
  39.202 +        assert(!unallocated());
  39.203 +        return slot_;
  39.204 +    }
  39.205 +    bool needsHeapAllocation();
  39.206 +
  39.207 +  private:
  39.208 +    Location location_;
  39.209 +    unsigned slot_;
  39.210 +};
  39.211 +
  39.212 +}
  39.213 +
  39.214 +#endif // _include_name_binding_h_
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/src/ObjectVisitor.h	Tue Jul 24 23:53:34 2012 -0700
    40.3 @@ -0,0 +1,269 @@
    40.4 +/* vim: set ts=4 sw=4 tw=99 et:
    40.5 + *
    40.6 + * Copyright (C) 2012 David Anderson
    40.7 + *
    40.8 + * This file is part of JITCraft.
    40.9 + *
   40.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   40.11 + * the terms of the GNU General Public License as published by the Free
   40.12 + * Software Foundation, either version 3 of the License, or (at your option)
   40.13 + * any later version.
   40.14 + * 
   40.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   40.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   40.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   40.18 + *
   40.19 + * You should have received a copy of the GNU General Public License along with
   40.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   40.21 + */
   40.22 +#ifndef _include_jc_object_visitor_h_
   40.23 +#define _include_jc_object_visitor_h_
   40.24 +
   40.25 +#include "Objects.h"
   40.26 +#include "Types.h"
   40.27 +#include "FixedArray.h"
   40.28 +#include "Code.h"
   40.29 +#include "Reference.h"
   40.30 +#include "Modules.h"
   40.31 +#include "Functions.h"
   40.32 +#include "Array.h"
   40.33 +#include "Strings.h"
   40.34 +#include "Environments.h"
   40.35 +
   40.36 +namespace ke {
   40.37 +
   40.38 +// An ObjectVisitor is used for traversing object references in the heap. Since
   40.39 +// this pattern must be lightning fast, we avoid virtual dispatch by forcing
   40.40 +// visitors to compose themselves with the visiting logic.
   40.41 +template <typename T>
   40.42 +class ObjectVisitor : public T
   40.43 +{
   40.44 +  private:
   40.45 +    void visitField(Object *obj, size_t offset) {
   40.46 +        this->visit(reinterpret_cast<Object **>(Address(obj) + offset));
   40.47 +    }
   40.48 +
   40.49 +    size_t iterateType(Object *obj) {
   40.50 +        visitField(obj, Type::offsetOfContained());
   40.51 +        visitField(obj, Type::offsetOfReturnType());
   40.52 +        visitField(obj, Type::offsetOfParameters());
   40.53 +        visitField(obj, Type::offsetOfTag());
   40.54 +        return sizeof(Type);
   40.55 +    }
   40.56 +
   40.57 +    size_t iterateFixedArray(FixedArray *array) {
   40.58 +        unsigned length = array->length();
   40.59 +        Object **ptr = reinterpret_cast<Object **>(array + 1);
   40.60 +        for (unsigned i = 0; i < length; i++)
   40.61 +            this->visit(ptr + i);
   40.62 +        return FixedArray::SizeFor(length);
   40.63 +    }
   40.64 +
   40.65 +    size_t iterateByteArray(ByteArray *array) {
   40.66 +        return ByteArray::SizeFor(array->length());
   40.67 +    }
   40.68 +
   40.69 +    size_t iterateCode(Object *obj) {
   40.70 +        visitField(obj, Code::offsetOfModule());
   40.71 +        visitField(obj, Code::offsetOfBytecode());
   40.72 +        visitField(obj, Code::offsetOfLocals());
   40.73 +        visitField(obj, Code::offsetOfObjects());
   40.74 +        visitField(obj, Code::offsetOfSafepoints());
   40.75 +        visitField(obj, Code::offsetOfSourceMap());
   40.76 +        return sizeof(Code);
   40.77 +    }
   40.78 +
   40.79 +    size_t iterateReference(Object *obj) {
   40.80 +        visitField(obj, Reference::offsetOfBase());
   40.81 +        return sizeof(Reference);
   40.82 +    }
   40.83 +
   40.84 +    size_t iterateModule(Object *obj) {
   40.85 +        visitField(obj, Module::offsetOfFunctions());
   40.86 +        visitField(obj, Module::offsetOfPublics());
   40.87 +        visitField(obj, Module::offsetOfNatives());
   40.88 +        visitField(obj, Module::offsetOfFile());
   40.89 +        visitField(obj, Module::offsetOfEnvironment());
   40.90 +        visitField(obj, Module::offsetOfCode());
   40.91 +        return sizeof(Module);
   40.92 +    }
   40.93 +
   40.94 +    size_t iterateFunction(Object *obj) {
   40.95 +        visitField(obj, Function::offsetOfCode());
   40.96 +        visitField(obj, Function::offsetOfType());
   40.97 +        visitField(obj, Function::offsetOfName());
   40.98 +        return sizeof(Function);
   40.99 +    }
  40.100 +
  40.101 +    size_t iterateNative(Object *obj) {
  40.102 +        visitField(obj, Native::offsetOfType());
  40.103 +        visitField(obj, Native::offsetOfName());
  40.104 +        return sizeof(Native);
  40.105 +    }
  40.106 +
  40.107 +    size_t iterateString(Object *obj) {
  40.108 +        return String::SizeFor(String::cast(obj)->length());
  40.109 +    }
  40.110 +
  40.111 +    size_t iterateArray(Array *array, ArrayMap *map) {
  40.112 +        assert(map->type()->isArray());
  40.113 +        if (map->contained()) {
  40.114 +            unsigned length = array->nelements();
  40.115 +            Object **vec = array->objVec();
  40.116 +            for (unsigned i = 0; i < length; i++)
  40.117 +                this->visit(vec + i);
  40.118 +        }
  40.119 +        return Array::SizeOf(array);
  40.120 +    }
  40.121 +
  40.122 +    size_t iterateArrayMap(ArrayMap *map) {
  40.123 +        visitField(map, ArrayMap::offsetOfType());
  40.124 +        visitField(map, ArrayMap::offsetOfContained());
  40.125 +        return sizeof(ArrayMap);
  40.126 +    }
  40.127 +
  40.128 +    size_t iterateEnvironmentSlotDescriptorArray(EnvironmentSlotDescriptorArray *env) {
  40.129 +        unsigned length = env->length();
  40.130 +        EnvironmentSlotDescriptor *desc = env->slots();
  40.131 +        for (unsigned i = 0; i < length; i++)
  40.132 +            this->visit(desc->type.addr());
  40.133 +        return env->size();
  40.134 +    }
  40.135 +
  40.136 +    size_t iterateEnvironmentMap(EnvironmentMap *map) {
  40.137 +        visitField(map, EnvironmentMap::offsetOfSlots());
  40.138 +        return map->size();
  40.139 +    }
  40.140 +
  40.141 +    size_t iterateEnvironment(Environment *env) {
  40.142 +        EnvironmentMap *map = env->map();
  40.143 +        const unsigned *offsets = map->traceOffsets();
  40.144 +        unsigned noffsets = map->traceOffsetCount();
  40.145 +        for (unsigned i = 0; i < noffsets; i++)
  40.146 +            visitField(env, Environment::offsetOfSlotOffset(offsets[i]));
  40.147 +        return env->size();
  40.148 +    }
  40.149 +
  40.150 +  public:
  40.151 +    size_t iterate(Object *obj) {
  40.152 +        visitField(obj, Object::offsetOfMap());
  40.153 +        return iterate(obj, obj->map());
  40.154 +    }
  40.155 +
  40.156 +    size_t iterate(Object *obj, Map *map) {
  40.157 +        switch (map->kind()) {
  40.158 +          case MapKind_Type:
  40.159 +            return iterateType(obj);
  40.160 +
  40.161 +          case MapKind_FixedArray:
  40.162 +            return iterateFixedArray(FixedArray::cast(obj));
  40.163 +
  40.164 +          case MapKind_ByteArray:
  40.165 +            return iterateByteArray(ByteArray::cast(obj));
  40.166 +
  40.167 +          case MapKind_Code:
  40.168 +            return iterateCode(obj);
  40.169 +
  40.170 +          case MapKind_Reference:
  40.171 +            return iterateReference(obj);
  40.172 +
  40.173 +          case MapKind_Module:
  40.174 +            return iterateModule(obj);
  40.175 +
  40.176 +          case MapKind_Function:
  40.177 +            return iterateFunction(obj);
  40.178 +
  40.179 +          case MapKind_String:
  40.180 +            return iterateString(obj);
  40.181 +
  40.182 +          case MapKind_Array:
  40.183 +            return Align(iterateArray(Array::cast(obj), ArrayMap::cast(map)), kObjectAlignment);
  40.184 +
  40.185 +          case MapKind_EnvironmentSlotDescriptorArray:
  40.186 +            return iterateEnvironmentSlotDescriptorArray(EnvironmentSlotDescriptorArray::cast(obj));
  40.187 +
  40.188 +          case MapKind_Environment:
  40.189 +            return iterateEnvironment(Environment::cast(obj));
  40.190 +
  40.191 +          case MapKind_Native:
  40.192 +            return iterateNative(obj);
  40.193 +
  40.194 +          case MapKind_MetaArray:
  40.195 +            return iterateArrayMap(ArrayMap::cast(obj));
  40.196 +
  40.197 +          case MapKind_MetaEnvironment:
  40.198 +            return iterateEnvironmentMap(EnvironmentMap::cast(obj));
  40.199 +
  40.200 +          default:
  40.201 +            assert(map->kind() == MapKind_Meta);
  40.202 +            return sizeof(Map);
  40.203 +        }
  40.204 +    }
  40.205 +};
  40.206 +
  40.207 +static inline size_t
  40.208 +SizeOfObject(Object *obj, Map *map)
  40.209 +{
  40.210 +    switch (map->kind()) {
  40.211 +      case MapKind_Type:
  40.212 +        return sizeof(Type);
  40.213 +
  40.214 +      case MapKind_FixedArray:
  40.215 +        return FixedArray::SizeFor(FixedArray::cast(obj)->length());
  40.216 +
  40.217 +      case MapKind_ByteArray:
  40.218 +        return ByteArray::SizeFor(ByteArray::cast(obj)->length());
  40.219 +
  40.220 +      case MapKind_Code:
  40.221 +        return sizeof(Code);
  40.222 +
  40.223 +      case MapKind_Reference:
  40.224 +        return sizeof(Reference);
  40.225 +
  40.226 +      case MapKind_Module:
  40.227 +        return sizeof(Module);
  40.228 +
  40.229 +      case MapKind_Function:
  40.230 +        return sizeof(Function);
  40.231 +
  40.232 +      case MapKind_String:
  40.233 +        return String::SizeFor(String::cast(obj)->length());
  40.234 +
  40.235 +      case MapKind_Native:
  40.236 +        return sizeof(Native);
  40.237 +
  40.238 +      case MapKind_Array:
  40.239 +        return Align(Array::SizeOf(Array::cast(obj)), kObjectAlignment);
  40.240 +
  40.241 +      case MapKind_EnvironmentSlotDescriptorArray:
  40.242 +        return EnvironmentSlotDescriptorArray::cast(obj)->size();
  40.243 +
  40.244 +      case MapKind_Environment:
  40.245 +        return Environment::cast(obj)->size();
  40.246 +
  40.247 +      case MapKind_MetaArray:
  40.248 +        return sizeof(ArrayMap);
  40.249 +
  40.250 +      case MapKind_MetaEnvironment:
  40.251 +        return EnvironmentMap::cast(obj)->size();
  40.252 +
  40.253 +      case MapKind_FreeRegion:
  40.254 +        return *reinterpret_cast<size_t *>(reinterpret_cast<Address>(obj + 1));
  40.255 +
  40.256 +      default:
  40.257 +        assert(map->kind() == MapKind_Meta);
  40.258 +        return sizeof(Map);
  40.259 +    }
  40.260 +}
  40.261 +
  40.262 +class ObjectSizeEvaluator
  40.263 +{
  40.264 +  public:
  40.265 +    size_t operator()(Object *obj, Map *map) {
  40.266 +        return SizeOfObject(obj, map);
  40.267 +    }
  40.268 +};
  40.269 +
  40.270 +}
  40.271 +
  40.272 +#endif // _include_jc_object_visitor_h_
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/src/Objects.h	Tue Jul 24 23:53:34 2012 -0700
    41.3 @@ -0,0 +1,119 @@
    41.4 +/* vim: set ts=4 sw=4 tw=99 et:
    41.5 + *
    41.6 + * Copyright (C) 2012 David Anderson
    41.7 + *
    41.8 + * This file is part of JITCraft.
    41.9 + *
   41.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   41.11 + * the terms of the GNU General Public License as published by the Free
   41.12 + * Software Foundation, either version 3 of the License, or (at your option)
   41.13 + * any later version.
   41.14 + * 
   41.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   41.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   41.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   41.18 + *
   41.19 + * You should have received a copy of the GNU General Public License along with
   41.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   41.21 + */
   41.22 +#ifndef _include_jitcraft_objects_h_
   41.23 +#define _include_jitcraft_objects_h_
   41.24 +
   41.25 +#include "Utility.h"
   41.26 +#include "Spaces.h"
   41.27 +#include "Barriers.h"
   41.28 +
   41.29 +namespace ke {
   41.30 +
   41.31 +class Zone;
   41.32 +
   41.33 +// Garbage-collection objects require a header to describe their layout. This
   41.34 +// header is called a "map". The different kinds of maps are enumerated below.
   41.35 +class Map;
   41.36 +
   41.37 +enum MapKind
   41.38 +{
   41.39 +    // Represents Type objects.
   41.40 +    MapKind_Type,
   41.41 +
   41.42 +    // Represents basic data structures. When adding to this, don't forget
   41.43 +    // to update Zone::initialize(), or you'll get a NULL crash trying to
   41.44 +    // allocate, since these maps are cached.
   41.45 +    MapKind_FixedArray,
   41.46 +    MapKind_ByteArray,
   41.47 +    MapKind_Code,
   41.48 +    MapKind_Reference,
   41.49 +    MapKind_Module,
   41.50 +    MapKind_Function,
   41.51 +    MapKind_String,
   41.52 +    MapKind_Native,
   41.53 +    MapKind_FreeRegion,     // Special map denoting freed space.
   41.54 +    MapKind_EnvironmentSlotDescriptorArray,
   41.55 +    MapKind_Environment,
   41.56 +
   41.57 +    // Used to represent Arrays. This does not have a canonical map.
   41.58 +    MapKind_Array,
   41.59 +
   41.60 +    // These represent special Map subclasses that require special tracing.
   41.61 +    MapKinds_Special,
   41.62 +    MapKind_Meta,               // (default map class)
   41.63 +    MapKind_MetaArray,          // ArrayMap instances
   41.64 +    MapKind_MetaEnvironment,    // EnvironmentMap instances
   41.65 +    MapKinds_EndSpecial,
   41.66 +
   41.67 +    MapKinds_Total
   41.68 +};
   41.69 +
   41.70 +// All garbage collected objects must inherit from GCObject. Note that using
   41.71 +// virtual functions is illegal, as the |map| field would be displaced.
   41.72 +class Object
   41.73 +{
   41.74 +    Barriered<Map> map_;
   41.75 +
   41.76 +  public:
   41.77 +    void init(Map *map) {
   41.78 +        map_ = map;
   41.79 +    }
   41.80 +
   41.81 +    Map *map() {
   41.82 +        return map_;
   41.83 +    }
   41.84 +    inline bool is(MapKind map);
   41.85 +
   41.86 +    inline void write(Zone *zone, Object **ptr, Object *value);
   41.87 +
   41.88 +    static inline size_t offsetOfMap() {
   41.89 +        return offsetof(Object, map_);
   41.90 +    }
   41.91 +};
   41.92 +
   41.93 +// Maps describe the layout of GCObjects. Every GCObject requires a map.
   41.94 +class Map : public Object
   41.95 +{
   41.96 +    MapKind kind_;
   41.97 +
   41.98 +  public:
   41.99 +    void setKind(MapKind kind) {
  41.100 +        kind_ = kind;
  41.101 +    }
  41.102 +    MapKind kind() {
  41.103 +        return kind_;
  41.104 +    }
  41.105 +
  41.106 +    static inline Map *cast(Object *obj) {
  41.107 +        // Note that ArrayMap is a map, but a special one: since it is non-
  41.108 +        assert(obj->map()->kind() > MapKinds_Special &&
  41.109 +               obj->map()->kind() < MapKinds_EndSpecial);
  41.110 +        return reinterpret_cast<Map *>(obj);
  41.111 +    }
  41.112 +};
  41.113 +
  41.114 +inline bool
  41.115 +Object::is(MapKind kind)
  41.116 +{
  41.117 +    return map()->kind() == kind;
  41.118 +}
  41.119 +
  41.120 +}
  41.121 +
  41.122 +#endif //_include_jitcraft_objects_h_
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/src/Opcodes.cpp	Tue Jul 24 23:53:34 2012 -0700
    42.3 @@ -0,0 +1,311 @@
    42.4 +/* vim: set ts=4 sw=4 tw=99 et:
    42.5 + *
    42.6 + * Copyright (C) 2012 David Anderson
    42.7 + *
    42.8 + * This file is part of JITCraft.
    42.9 + *
   42.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   42.11 + * the terms of the GNU General Public License as published by the Free
   42.12 + * Software Foundation, either version 3 of the License, or (at your option)
   42.13 + * any later version.
   42.14 + * 
   42.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   42.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   42.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   42.18 + *
   42.19 + * You should have received a copy of the GNU General Public License along with
   42.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   42.21 + */
   42.22 +#include <stdlib.h>
   42.23 +#include "Opcodes.h"
   42.24 +#include "Utility.h"
   42.25 +#include "Code.h"
   42.26 +#include "Zone.h"
   42.27 +#include "Array.h"
   42.28 +#include "Strings.h"
   42.29 +#include "CompactBuffer.h"
   42.30 +#include "Heap-inl.h"
   42.31 +
   42.32 +using namespace ke;
   42.33 +
   42.34 +OpInfo ke::OpcodeInfo[] =
   42.35 +{
   42.36 +#define OPDEF(name, number, text, length, uses, defs) \
   42.37 +    {text, length, uses, defs},
   42.38 +#include "Opcodes.tbl"
   42.39 +#undef OPDEF
   42.40 +};
   42.41 +
   42.42 +Code *
   42.43 +Code::New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
   42.44 +          Handle<FixedArray> objects, unsigned maxStackDepth, Handle<Module> module,
   42.45 +	      Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap,
   42.46 +          unsigned lineNumber)
   42.47 +{
   42.48 +    Local<Code> code(zone, Code::cast(zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old)));
   42.49 +    if (!code)
   42.50 +        return NULL;
   42.51 +
   42.52 +    code->bytecode_ = bytecode;
   42.53 +    code->locals_ = locals;
   42.54 +    code->objects_ = objects;
   42.55 +    code->maxStackDepth_ = maxStackDepth;
   42.56 +    code->module_ = module;
   42.57 +    code->safepoints_ = safepoints;
   42.58 +    code->sourcemap_ = sourcemap;
   42.59 +    code->lineNumber_ = lineNumber;
   42.60 +    return code;
   42.61 +}
   42.62 +
   42.63 +static int
   42.64 +CompareSafepoints(const void *a, const void *b)
   42.65 +{
   42.66 +    const unsigned *sa = reinterpret_cast<const unsigned *>(a);
   42.67 +    const unsigned *sb = reinterpret_cast<const unsigned *>(b);
   42.68 +    if (*sa > *sb)
   42.69 +        return 1;
   42.70 +    if (*sa == *sb)
   42.71 +        return 0;
   42.72 +    return -1;
   42.73 +}
   42.74 +
   42.75 +uint8 *
   42.76 +Code::safepointAt(unsigned pcOffset)
   42.77 +{
   42.78 +    // Only specific opcodes may have safepoints. Asking for a safepoint at
   42.79 +    // any other position indicates a failure to mark that position as a
   42.80 +    // safepoint, which is a bug.
   42.81 +    Opcode op = Opcode(*(start() + pcOffset));
   42.82 +    assert(op == OP_CALL || op == OP_NEWARRAY || op == OP_VARREF_LIFO ||
   42.83 +           op == OP_ARGREF_LIFO || op == OP_SLOTREF_LIFO || op == OP_ARRAYREF_LIFO ||
   42.84 +           op == OP_ARRAYCOPY);
   42.85 +
   42.86 +    if (!safepoints_)
   42.87 +        return NULL;
   42.88 +
   42.89 +    size_t bytesPerSafepoint = BytesPerSafepoint(maxStackDepth());
   42.90 +    assert(!(safepoints_->length() % bytesPerSafepoint));
   42.91 +
   42.92 +    size_t count = safepoints_->length() / bytesPerSafepoint;
   42.93 +
   42.94 +    void *result = bsearch(&pcOffset,
   42.95 +                           safepoints_->raw(),
   42.96 +                           count,
   42.97 +                           bytesPerSafepoint,
   42.98 +                           CompareSafepoints);
   42.99 +
  42.100 +    if (!result)
  42.101 +        return NULL;
  42.102 +
  42.103 +    assert(*reinterpret_cast<unsigned *>(result) == pcOffset);
  42.104 +
  42.105 +    return Address(result) + sizeof(unsigned);
  42.106 +}
  42.107 +
  42.108 +SourcePosition
  42.109 +Code::pcToSource(unsigned pc)
  42.110 +{
  42.111 +    assert(pc < bytecode_->length());
  42.112 +
  42.113 +    CompactBufferReader reader(sourcemap_->raw(), sourcemap_->raw() + sourcemap_->length());
  42.114 +
  42.115 +    unsigned line = 1;
  42.116 +    unsigned col = 0;
  42.117 +    unsigned curPc = 0;
  42.118 +    while (!reader.done()) {
  42.119 +        curPc += reader.readUint32();
  42.120 +        if (curPc > pc)
  42.121 +            break;
  42.122 +
  42.123 +        line = reader.readUint32();
  42.124 +        col = reader.readUint32();
  42.125 +    }
  42.126 +
  42.127 +    return SourcePosition(lineNumber_ + line, col);
  42.128 +}
  42.129 +
  42.130 +// All jumps must be the same length.
  42.131 +STATIC_ASSERT(OP_JL_LENGTH == OP_JUMP_LENGTH);
  42.132 +STATIC_ASSERT(OP_JLE_LENGTH == OP_JUMP_LENGTH);
  42.133 +STATIC_ASSERT(OP_JG_LENGTH == OP_JUMP_LENGTH);
  42.134 +STATIC_ASSERT(OP_JGE_LENGTH == OP_JUMP_LENGTH);
  42.135 +STATIC_ASSERT(OP_JEQ_LENGTH == OP_JUMP_LENGTH);
  42.136 +STATIC_ASSERT(OP_JNE_LENGTH == OP_JUMP_LENGTH);
  42.137 +STATIC_ASSERT(OP_JT_LENGTH == OP_JUMP_LENGTH);
  42.138 +STATIC_ASSERT(OP_JF_LENGTH == OP_JUMP_LENGTH);
  42.139 +
  42.140 +void
  42.141 +ke::Disassemble(Code *code, FILE *fp)
  42.142 +{
  42.143 +    bytecode *pc = code->start();
  42.144 +    for (;;) {
  42.145 +        Opcode op = Opcode(*pc);
  42.146 +
  42.147 +        fprintf(fp, "%-4d %s ", int(pc - code->start()), OpcodeInfo[op].name);
  42.148 +
  42.149 +        switch (op) {
  42.150 +          case OP_NOP:
  42.151 +          case OP_RETURN:
  42.152 +          case OP_RETURNVOID:
  42.153 +          case OP_ADD:
  42.154 +          case OP_SUB:
  42.155 +          case OP_MUL:
  42.156 +          case OP_DIV:
  42.157 +          case OP_ADD_F:
  42.158 +          case OP_SUB_F:
  42.159 +          case OP_MUL_F:
  42.160 +          case OP_DIV_F:
  42.161 +          case OP_CVT_I2F:
  42.162 +          case OP_POP:
  42.163 +          case OP_GETARRAY_I:
  42.164 +          case OP_SETARRAY_I:
  42.165 +          case OP_GETARRAY_F:
  42.166 +          case OP_SETARRAY_F:
  42.167 +          case OP_GETARRAY_C:
  42.168 +          case OP_SETARRAY_C:
  42.169 +          case OP_GETARRAY_O:
  42.170 +          case OP_BOUNDS:
  42.171 +          case OP_SHL:
  42.172 +          case OP_SHR:
  42.173 +          case OP_USHR:
  42.174 +          case OP_BITAND:
  42.175 +          case OP_BITOR:
  42.176 +          case OP_BITXOR:
  42.177 +          case OP_GETREF_I:
  42.178 +          case OP_SETREF_I:
  42.179 +          case OP_GETREF_F:
  42.180 +          case OP_SETREF_F:
  42.181 +          case OP_SLOTREF_LIFO:
  42.182 +          case OP_ARRAYREF_LIFO:
  42.183 +          case OP_ARRAYCOPY:
  42.184 +          case OP_DUP:
  42.185 +          case OP_DUP2:
  42.186 +          case OP_SWAP:
  42.187 +          case OP_ROLL3:
  42.188 +          case OP_PICK2:
  42.189 +          case OP_PICK3:
  42.190 +          case OP_CALL:
  42.191 +          case OP_MODULE:
  42.192 +          case OP_LT:
  42.193 +          case OP_LE:
  42.194 +          case OP_GE:
  42.195 +          case OP_GT:
  42.196 +          case OP_EQ:
  42.197 +          case OP_NE:
  42.198 +          case OP_LT_F:
  42.199 +          case OP_LE_F:
  42.200 +          case OP_GE_F:
  42.201 +          case OP_GT_F:
  42.202 +          case OP_EQ_F:
  42.203 +          case OP_NE_F:
  42.204 +          case OP_BITNOT:
  42.205 +          case OP_NOT:
  42.206 +          case OP_NOT_F:
  42.207 +          case OP_NEG:
  42.208 +          case OP_NEG_F:
  42.209 +          case OP_MOD:
  42.210 +            break;
  42.211 +
  42.212 +          case OP_STOP:
  42.213 +            fprintf(fp, "\n");
  42.214 +            break;
  42.215 +
  42.216 +          case OP_INT:
  42.217 +            fprintf(fp, "%d", READ_INT32(pc));
  42.218 +            break;
  42.219 +
  42.220 +          case OP_FLOAT:
  42.221 +            fprintf(fp, "%f", READ_FLOAT(pc));
  42.222 +            break;
  42.223 +
  42.224 +          case OP_JL:
  42.225 +          case OP_JLE:
  42.226 +          case OP_JG:
  42.227 +          case OP_JGE:
  42.228 +          case OP_JEQ:
  42.229 +          case OP_JNE:
  42.230 +          case OP_JT:
  42.231 +          case OP_JF:
  42.232 +          case OP_JL_F:
  42.233 +          case OP_JLE_F:
  42.234 +          case OP_JG_F:
  42.235 +          case OP_JGE_F:
  42.236 +          case OP_JEQ_F:
  42.237 +          case OP_JNE_F:
  42.238 +          case OP_JT_F:
  42.239 +          case OP_JF_F:
  42.240 +          case OP_JUMP:
  42.241 +            fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc));
  42.242 +            break;
  42.243 +
  42.244 +          case OP_NEWARRAY:
  42.245 +          {
  42.246 +            Heap::Tenure tenure = (Heap::Tenure)pc[1];
  42.247 +            ArrayMap *map = ArrayMap::cast(code->map(READ_UINT32(pc + 1)));
  42.248 +            fprintf(fp, "%s:", map->type()->innermost()->tag()
  42.249 +                               ? map->type()->innermost()->tag()->chars()
  42.250 +                               : "_");
  42.251 +            for (; map; map = map->contained()) {
  42.252 +                Type *type = map->type();
  42.253 +                fprintf(fp, "[%d]", type->elements());
  42.254 +            }
  42.255 +            if (tenure == Heap::Tenure_Stack)
  42.256 +                fprintf(fp, " ; lifo");
  42.257 +            else if (tenure == Heap::Tenure_Old)
  42.258 +                fprintf(fp, " ; pretenured");
  42.259 +            break;
  42.260 +          }
  42.261 +
  42.262 +          case OP_GETLOCAL:
  42.263 +          case OP_SETLOCAL:
  42.264 +          case OP_GETARG:
  42.265 +          case OP_SETARG:
  42.266 +          case OP_SAVELIFO:
  42.267 +          case OP_UNWINDLIFO:
  42.268 +          case OP_VARREF_LIFO:
  42.269 +          case OP_ARGREF_LIFO:
  42.270 +          case OP_OBJECT:
  42.271 +          case OP_GETMODULE_FN:
  42.272 +          case OP_GETGLOBAL_I:
  42.273 +          case OP_GETGLOBAL_F:
  42.274 +          case OP_GETGLOBAL_O:
  42.275 +          case OP_SETGLOBAL_I:
  42.276 +          case OP_SETGLOBAL_F:
  42.277 +          case OP_SETGLOBAL_O:
  42.278 +            fprintf(fp, "%u", READ_UINT32(pc));
  42.279 +            break;
  42.280 +
  42.281 +          case OP_CALLNATIVE:
  42.282 +            fprintf(fp, "%u %u", READ_UINT32(pc), READ_UINT32(pc + 4));
  42.283 +            break;
  42.284 +
  42.285 +          default:
  42.286 +            // Unknown opcode!
  42.287 +            assert(false);
  42.288 +            return;
  42.289 +        }
  42.290 +
  42.291 +        if (op == OP_STOP)
  42.292 +            break;
  42.293 +
  42.294 +        fprintf(fp, "\n");
  42.295 +        pc += OpcodeInfo[op].length;
  42.296 +        assert(pc < code->start() + code->length());
  42.297 +    }
  42.298 +
  42.299 +    fprintf(fp, "\nSafepoints:\n");
  42.300 +    ByteArray *safepoints = code->safepoints();
  42.301 +    if (safepoints) {
  42.302 +        size_t nsafepoints = safepoints->length() / Code::BytesPerSafepoint(code->maxStackDepth());
  42.303 +        for (size_t i = 0; i < nsafepoints; i++) {
  42.304 +            Address address = safepoints->raw() + Code::BytesPerSafepoint(code->maxStackDepth()) * i;
  42.305 +            fprintf(fp, "%4d: ", *reinterpret_cast<unsigned *>(address));
  42.306 +            unsigned char *bits = (unsigned char *)(address + sizeof(unsigned));
  42.307 +            for (unsigned j = 0; j < code->maxStackDepth(); j++) {
  42.308 +                if (bits[j / 8] & (1 << (j % 8)))
  42.309 +                    fprintf(fp, "%d ", j);
  42.310 +            }
  42.311 +            fprintf(fp, "\n");
  42.312 +        }
  42.313 +    }
  42.314 +}
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/src/Opcodes.h	Tue Jul 24 23:53:34 2012 -0700
    43.3 @@ -0,0 +1,94 @@
    43.4 +/*
    43.5 + * Copyright (C) 2012 David Anderson
    43.6 + *
    43.7 + * This file is part of JITCraft.
    43.8 + *
    43.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   43.10 + * the terms of the GNU General Public License as published by the Free
   43.11 + * Software Foundation, either version 3 of the License, or (at your option)
   43.12 + * any later version.
   43.13 + * 
   43.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   43.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   43.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   43.17 + *
   43.18 + * You should have received a copy of the GNU General Public License along with
   43.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   43.20 + */
   43.21 +#ifndef _include_opcodes_h_
   43.22 +#define _include_opcodes_h_
   43.23 +
   43.24 +#include <assert.h>
   43.25 +#include <stdio.h>
   43.26 +
   43.27 +namespace ke {
   43.28 +
   43.29 +enum Opcode
   43.30 +{
   43.31 +#define OPDEF(name, number, text, length, uses, defs)   \
   43.32 +    name = number,
   43.33 +#include "Opcodes.tbl"
   43.34 +#undef OPDEF
   43.35 +    OPCODES_TOTAL
   43.36 +};
   43.37 +
   43.38 +#define OPDEF(name, number, text, length, uses, defs)   \
   43.39 +static const unsigned name##_LENGTH = length;
   43.40 +#include "Opcodes.tbl"
   43.41 +#undef OPDEF
   43.42 +
   43.43 +struct OpInfo
   43.44 +{
   43.45 +    const char *name;
   43.46 +    int length;
   43.47 +    int nuses;
   43.48 +    int ndefs;
   43.49 +};
   43.50 +
   43.51 +typedef unsigned char bytecode;
   43.52 +
   43.53 +extern OpInfo OpcodeInfo[];
   43.54 +
   43.55 +static inline Opcode
   43.56 +Invert(Opcode op)
   43.57 +{
   43.58 +    switch (op) {
   43.59 +      case OP_JEQ:
   43.60 +        return OP_JNE;
   43.61 +      case OP_JNE:
   43.62 +        return OP_JEQ;
   43.63 +      case OP_JG:
   43.64 +        return OP_JLE;
   43.65 +      case OP_JGE:
   43.66 +        return OP_JL;
   43.67 +      case OP_JL:
   43.68 +        return OP_JGE;
   43.69 +      default:
   43.70 +        assert(op == OP_JLE);
   43.71 +        return OP_JG;
   43.72 +    }
   43.73 +}
   43.74 +
   43.75 +static inline int
   43.76 +READ_INT32(bytecode *pc)
   43.77 +{
   43.78 +    return *reinterpret_cast<int *>(pc + 1);
   43.79 +}
   43.80 +static inline unsigned
   43.81 +READ_UINT32(bytecode *pc)
   43.82 +{
   43.83 +    return *reinterpret_cast<unsigned *>(pc + 1);
   43.84 +}
   43.85 +static inline float
   43.86 +READ_FLOAT(bytecode *pc)
   43.87 +{
   43.88 +    return *reinterpret_cast<float *>(pc + 1);
   43.89 +}
   43.90 +
   43.91 +class Code;
   43.92 +
   43.93 +void Disassemble(Code *code, FILE *fp);
   43.94 +
   43.95 +}
   43.96 +
   43.97 +#endif // _include_opcodes_h_
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/src/Opcodes.tbl	Tue Jul 24 23:53:34 2012 -0700
    44.3 @@ -0,0 +1,246 @@
    44.4 +/* vim: set ts=4 sw=4 tw=99 et:
    44.5 + *
    44.6 + * Copyright (C) 2012 David Anderson
    44.7 + *
    44.8 + * This file is part of JITCraft.
    44.9 + *
   44.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   44.11 + * the terms of the GNU General Public License as published by the Free
   44.12 + * Software Foundation, either version 3 of the License, or (at your option)
   44.13 + * any later version.
   44.14 + * 
   44.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   44.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   44.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   44.18 + *
   44.19 + * You should have received a copy of the GNU General Public License along with
   44.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   44.21 + */
   44.22 +// Opcode macros:
   44.23 +//  NAME            NUMBER      TEXT                LENGTH  USES  DEFS   
   44.24 +//
   44.25 +// Type suffixes:
   44.26 +//  I = 32-bit integer
   44.27 +//  F = 32-bit IEEE-754 float
   44.28 +//  O = object reference
   44.29 +
   44.30 +// No operation.
   44.31 +OPDEF(OP_NOP,           0,          "nop",          1,      0,  0)
   44.32 +
   44.33 +// Pushes a signed integer immediate onto the stack.
   44.34 +OPDEF(OP_INT,           1,          "int",          5,      0,  1)    
   44.35 +
   44.36 +// Returns from the current routine, propagating the value at the top of the
   44.37 +// stack to the caller.
   44.38 +OPDEF(OP_RETURN,        2,          "return",       1,      1,  0)
   44.39 +
   44.40 +// Stack transitions for these comparison ops:
   44.41 +// rhs = pop()
   44.42 +// lhs = pop()
   44.43 +// if (lhs COMPARE rhs)
   44.44 +//    goto target (immediate, relative to the beginning of the jump instruction)
   44.45 +OPDEF(OP_JL,            3,          "jl",           5,      2,  0)
   44.46 +OPDEF(OP_JLE,           4,          "jle",          5,      2,  0)
   44.47 +OPDEF(OP_JG,            5,          "jg",           5,      2,  0)
   44.48 +OPDEF(OP_JGE,           6,          "jge",          5,      2,  0)
   44.49 +OPDEF(OP_JEQ,           7,          "jeq",          5,      2,  0)
   44.50 +OPDEF(OP_JNE,           8,          "jne",          5,      2,  0)
   44.51 +
   44.52 +// value = pop()
   44.53 +// if (value == [true, false])
   44.54 +//    goto target
   44.55 +OPDEF(OP_JT,            9,          "jt",           5,      1,  0)
   44.56 +OPDEF(OP_JF,            10,         "jf",           5,      1,  0)
   44.57 +
   44.58 +OPDEF(OP_JL_F,          11,         "jl.f",         5,      2,  0)
   44.59 +OPDEF(OP_JLE_F,         12,         "jle.f",        5,      2,  0)
   44.60 +OPDEF(OP_JG_F,          13,         "jg.f",         5,      2,  0)
   44.61 +OPDEF(OP_JGE_F,         14,         "jge.f",        5,      2,  0)
   44.62 +OPDEF(OP_JEQ_F,         15,         "jeq.f",        5,      2,  0)
   44.63 +OPDEF(OP_JNE_F,         16,         "jne.f",        5,      2,  0)
   44.64 +OPDEF(OP_JT_F,          17,         "jt.f",         5,      1,  0)
   44.65 +OPDEF(OP_JF_F,          18,         "jf.f",         5,      1,  0)
   44.66 +
   44.67 +// Unconditional jump.
   44.68 +OPDEF(OP_JUMP,          19,         "jump",         5,      0,  0)
   44.69 +
   44.70 +// Gets or sets the value of a local variable onto the stack. The local
   44.71 +// variable is given by an immediate index.
   44.72 +OPDEF(OP_GETLOCAL,      20,         "getlocal",     5,      0,  1)
   44.73 +OPDEF(OP_SETLOCAL,      21,         "setlocal",     5,      1,  1)
   44.74 +
   44.75 +// Stack transitions for these binary operators:
   44.76 +// rhs = pop()
   44.77 +// lhs = pop()
   44.78 +// push(lhs OP rhs)
   44.79 +OPDEF(OP_ADD,           22,         "add",          1,      2,  1)
   44.80 +OPDEF(OP_SUB,           23,         "sub",          1,      2,  1)
   44.81 +OPDEF(OP_MUL,           24,         "mul",          1,      2,  1)
   44.82 +OPDEF(OP_DIV,           25,         "div",          1,      2,  1)
   44.83 +OPDEF(OP_MOD,           26,         "mod",          1,      2,  1)
   44.84 +
   44.85 +OPDEF(OP_LT,            27,         "lt",           1,      2,  1)
   44.86 +OPDEF(OP_LE,            28,         "le",           1,      2,  1)
   44.87 +OPDEF(OP_GE,            29,         "ge",           1,      2,  1)
   44.88 +OPDEF(OP_GT,            30,         "gt",           1,      2,  1)
   44.89 +OPDEF(OP_EQ,            31,         "eq",           1,      2,  1)
   44.90 +OPDEF(OP_NE,            32,         "ne",           1,      2,  1)
   44.91 +
   44.92 +OPDEF(OP_NOT,           33,         "not",          1,      1,  1)
   44.93 +OPDEF(OP_NEG,           34,         "neg",          1,      1,  1)
   44.94 +
   44.95 +OPDEF(OP_POP,           35,         "pop",          1,      1,  0)
   44.96 +
   44.97 +// Unconditional terminator placed at the end of code. If a function returns
   44.98 +// void, this acts as a RETURNVOID. Otherwise, it must be unreachable.
   44.99 +OPDEF(OP_STOP,          36,         "stop",         1,      0,  0)
  44.100 +
  44.101 +// Call a function with N arguments. The target function must be the last item
  44.102 +// on the stack.
  44.103 +OPDEF(OP_CALL,          37,         "call",         1,      -1, 1)
  44.104 +
  44.105 +// Similar to GET/LOCAL, except for arguments.
  44.106 +OPDEF(OP_GETARG,        38,         "getarg",       5,      0,  1)
  44.107 +OPDEF(OP_SETARG,        39,         "setarg",       5,      1,  1)
  44.108 +
  44.109 +// Reads or writes an integer element to an unsafe array.
  44.110 +//  index = pop()
  44.111 +//  ref = pop()
  44.112 +//  ref[index]
  44.113 +//
  44.114 +OPDEF(OP_GETARRAY_I,    40,         "getarray.i",   1,      2,  1)
  44.115 +OPDEF(OP_SETARRAY_I,    41,         "setarray.i",   1,      3,  1)
  44.116 +OPDEF(OP_GETARRAY_F,    42,         "getarray.f",   1,      2,  1)
  44.117 +OPDEF(OP_SETARRAY_F,    43,         "setarray.f",   1,      3,  1)
  44.118 +OPDEF(OP_GETARRAY_C,    44,         "getarray.c",   1,      2,  1)
  44.119 +OPDEF(OP_SETARRAY_C,    45,         "setarray.c",   1,      3,  1)
  44.120 +OPDEF(OP_GETARRAY_O,    46,         "getarray.o",   1,      2,  1)
  44.121 +
  44.122 +// Allocate an array. The HeapTenure is stored as a byte following pc. The
  44.123 +// ArrayMap to use is specified as an index into the script's Map table.
  44.124 +//
  44.125 +// Format:
  44.126 +//  [u8 op] [u32 index]
  44.127 +OPDEF(OP_NEWARRAY,      47,         "newarray",     6,      0,  1)
  44.128 +
  44.129 +// Performs a bounds check on an unsafe array.
  44.130 +//
  44.131 +// index = pop()
  44.132 +// array = pop()
  44.133 +// push(array)
  44.134 +// push(index)
  44.135 +OPDEF(OP_BOUNDS,        48,         "bounds",       1,      2,  2)
  44.136 +
  44.137 +// Pushes a 32-bit IEEE-754 floating point immediate onto the stack.
  44.138 +OPDEF(OP_FLOAT,         49,         "float",        5,      0,  1)
  44.139 +
  44.140 +// Converts an integer to a 32-bit IEEE-754 floating point immediate.
  44.141 +OPDEF(OP_CVT_I2F,       50,         "cvt.i2f",      1,      1,  1)
  44.142 +
  44.143 +// Stack transitions for these binary operators:
  44.144 +// rhs = pop()
  44.145 +// lhs = pop()
  44.146 +// push(lhs OP rhs)
  44.147 +OPDEF(OP_ADD_F,         51,         "add.f",        1,      2,  1)
  44.148 +OPDEF(OP_SUB_F,         52,         "sub.f",        1,      2,  1)
  44.149 +OPDEF(OP_MUL_F,         53,         "mul.f",        1,      2,  1)
  44.150 +OPDEF(OP_DIV_F,         54,         "div.f",        1,      2,  1)
  44.151 +OPDEF(OP_UNUSED1,       55,         "unused0",      1,      0,  0)
  44.152 +
  44.153 +OPDEF(OP_LT_F,          56,         "lt.f",         1,      2,  1)
  44.154 +OPDEF(OP_LE_F,          57,         "le.f",         1,      2,  1)
  44.155 +OPDEF(OP_GE_F,          58,         "ge.f",         1,      2,  1)
  44.156 +OPDEF(OP_GT_F,          59,         "gt.f",         1,      2,  1)
  44.157 +OPDEF(OP_EQ_F,          60,         "eq.f",         1,      2,  1)
  44.158 +OPDEF(OP_NE_F,          61,         "ne.f",         1,      2,  1)
  44.159 +
  44.160 +OPDEF(OP_NOT_F,         62,         "not.f",        1,      1,  1)
  44.161 +OPDEF(OP_NEG_F,         63,         "neg.f",        1,      1,  1)
  44.162 +
  44.163 +// Bitwise operators.
  44.164 +OPDEF(OP_SHL,           64,         "shl",          1,      2,  1)
  44.165 +OPDEF(OP_SHR,           65,         "shr",          1,      2,  1)
  44.166 +OPDEF(OP_USHR,          66,         "ushr",         1,      2,  1)
  44.167 +OPDEF(OP_BITAND,        67,         "bitand",       1,      2,  1)
  44.168 +OPDEF(OP_BITOR,         68,         "bitor",        1,      2,  1)
  44.169 +OPDEF(OP_BITXOR,        69,         "bitxor",       1,      2,  1)
  44.170 +OPDEF(OP_BITNOT,        70,         "bitnot",       1,      1,  1)
  44.171 +
  44.172 +// Saves or restores the position of the LIFO heap to/from a local slot.
  44.173 +OPDEF(OP_SAVELIFO,      71,         "savelifo",     5,      0,  0)
  44.174 +OPDEF(OP_UNWINDLIFO,    72,         "unwindlifo",   5,      0,  0)
  44.175 +
  44.176 +// Composes a variable reference to a stack slot or argument.
  44.177 +OPDEF(OP_VARREF_LIFO,   73,         "varref.lifo",  5,      0,  1)
  44.178 +OPDEF(OP_ARGREF_LIFO,   74,         "argref.lifo",  5,      0,  1)
  44.179 +OPDEF(OP_SLOTREF_LIFO,  75,         "slotref.lifo", 1,      1,  1)
  44.180 +OPDEF(OP_ARRAYREF_LIFO, 76,         "arrayref.lifo",1,      2,  1)
  44.181 +OPDEF(OP_GETREF_I,      77,         "getref.i",     1,      1,  1)
  44.182 +OPDEF(OP_SETREF_I,      78,         "setref.i",     1,      2,  1)
  44.183 +OPDEF(OP_GETREF_F,      79,         "getref.f",     1,      1,  1)
  44.184 +OPDEF(OP_SETREF_F,      80,         "setref.f",     1,      2,  1)
  44.185 +
  44.186 +// Pushes an object reference onto the stack.
  44.187 +OPDEF(OP_OBJECT,        81,         "object",       5,      0,  1)
  44.188 +
  44.189 +// Performs an array-to-array assignment.
  44.190 +//   Left = pop()
  44.191 +//   Right = pop()
  44.192 +//   copy(Left, Right)
  44.193 +//   push(Left)
  44.194 +OPDEF(OP_ARRAYCOPY,     82,         "arraycopy",    1,      2,  1)
  44.195 +
  44.196 +// Duplicates the top item on the stack.
  44.197 +OPDEF(OP_DUP,           83,         "dup",          1,      1,  2)
  44.198 +
  44.199 +// Duplicates the top two items on the stack.
  44.200 +OPDEF(OP_DUP2,          84,         "dup2",         1,      2,  4)
  44.201 +
  44.202 +// Swaps the two items at the top of the stack.
  44.203 +OPDEF(OP_SWAP,          85,         "swap",         1,      2,  2)
  44.204 +
  44.205 +// Roll operation is the same as Forth. It steals a value on the stack,
  44.206 +// shifting all stack values down, and then places the stolen value back at
  44.207 +// the top of the stack.
  44.208 +//
  44.209 +//  p = sp[-3]
  44.210 +//  sp[-3] = sp[-2]
  44.211 +//  sp[-2] = sp[-1]
  44.212 +//  sp[-1] = p
  44.213 +OPDEF(OP_ROLL3,         86,         "roll3",        1,      3, 3)
  44.214 +
  44.215 +// Pick operation is the same as Forth. It pushes a copy of a slot at a
  44.216 +// specific depth.
  44.217 +//
  44.218 +// push(sp[-n])
  44.219 +OPDEF(OP_PICK2,         87,         "pick2",        1,      2, 3)
  44.220 +OPDEF(OP_PICK3,         88,         "pick3",        1,      3, 4)
  44.221 +
  44.222 +// Calls a native function. During the course of calling a native, arguments
  44.223 +// on the stack are re-pushed to match the cell-based native calling
  44.224 +// convention expected by ISourcePawnEngine.
  44.225 +//
  44.226 +// Unlike the normal CALL instruction, natives take truly variadic arguments
  44.227 +// and so we must specify the number of arguments. The format is:
  44.228 +//
  44.229 +// [u8 Opcode] [u32 Index] [u32 ArgCount]
  44.230 +//
  44.231 +OPDEF(OP_CALLNATIVE,    89,         "callnative",   9,      -1, 1)
  44.232 +
  44.233 +// Returns from a function that does return a value.
  44.234 +OPDEF(OP_RETURNVOID,    90,         "returnvoid",   1,      0, 0)
  44.235 +
  44.236 +// Loads the module of the running function.
  44.237 +OPDEF(OP_MODULE,        91,         "module",       1,      0, 1)
  44.238 +
  44.239 +// Loads a function from a module object. The operand is the slot number
  44.240 +// in the module.
  44.241 +OPDEF(OP_GETMODULE_FN,  92,         "getmodule.fn", 5,      1, 1)
  44.242 +
  44.243 +// Opcodes for accessing an environment slot in the global scope.
  44.244 +OPDEF(OP_SETGLOBAL_I,   93,         "setglobal.i",  5,      1, 1)
  44.245 +OPDEF(OP_SETGLOBAL_F,   94,         "setglobal.f",  5,      1, 1)
  44.246 +OPDEF(OP_SETGLOBAL_O,   95,         "setglobal.o",  5,      1, 1)
  44.247 +OPDEF(OP_GETGLOBAL_I,   96,         "getglobal.i",  5,      0, 1)
  44.248 +OPDEF(OP_GETGLOBAL_F,   97,         "getglobal.f",  5,      0, 1)
  44.249 +OPDEF(OP_GETGLOBAL_O,   98,         "getglobal.o",  5,      0, 1)
  44.250 \ No newline at end of file
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/src/Parser.cpp	Tue Jul 24 23:53:34 2012 -0700
    45.3 @@ -0,0 +1,1314 @@
    45.4 +/* vim: set ts=4 sw=4 tw=99 et:
    45.5 + *
    45.6 + * Copyright (C) 2012 David Anderson
    45.7 + *
    45.8 + * This file is part of JITCraft.
    45.9 + *
   45.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   45.11 + * the terms of the GNU General Public License as published by the Free
   45.12 + * Software Foundation, either version 3 of the License, or (at your option)
   45.13 + * any later version.
   45.14 + * 
   45.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   45.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   45.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   45.18 + *
   45.19 + * You should have received a copy of the GNU General Public License along with
   45.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   45.21 + */
   45.22 +#include "Zone.h"
   45.23 +#include "Parser.h"
   45.24 +#include "FixedArray.h"
   45.25 +#include "Heap.h"
   45.26 +#include "Strings.h"
   45.27 +#include "Heap-inl.h"
   45.28 +
   45.29 +using namespace ke;
   45.30 +
   45.31 +Parser::Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length)
   45.32 +  : zone_(zone),
   45.33 +    cc_(cc),
   45.34 +    pool_(zone_->pool()),
   45.35 +    scanner_(cc, stream, length),
   45.36 +    scope_(NULL),
   45.37 +    unbound_(NULL)
   45.38 +{
   45.39 +    unbound_ = new (pool_) PoolList<NameProxy *>();
   45.40 +}
   45.41 +
   45.42 +bool
   45.43 +Parser::match(TokenKind kind)
   45.44 +{
   45.45 +    if (scanner_.peek() != kind)
   45.46 +        return false;
   45.47 +    scanner_.scan();
   45.48 +    return true;
   45.49 +}
   45.50 +
   45.51 +bool
   45.52 +Parser::matchSemicolon()
   45.53 +{
   45.54 +    return expect(TOK_SEMICOLON);
   45.55 +}
   45.56 +
   45.57 +bool
   45.58 +Parser::expect(TokenKind kind)
   45.59 +{
   45.60 +    TokenKind got = scanner_.scan();
   45.61 +    if (got == kind)
   45.62 +        return true;
   45.63 +    cc_.reportError(scanner_.begin(), Message_WrongToken, TokenNames[kind], TokenNames[got]);
   45.64 +    return false;
   45.65 +}
   45.66 +
   45.67 +Scope *
   45.68 +Parser::enterScope(Scope::Kind kind)
   45.69 +{
   45.70 +    scope_ = new (pool_) Scope(pool_, kind, scope_);
   45.71 +    if (!scope_->initialize())
   45.72 +        return NULL;
   45.73 +    return scope_;
   45.74 +}
   45.75 +
   45.76 +NameProxy *
   45.77 +Parser::bind(Handle<String> name)
   45.78 +{
   45.79 +    BoundName *bound = scope_->lookup(name);
   45.80 +    NameProxy *proxy = new (pool_) NameProxy(scanner_.begin(), name, bound);
   45.81 +    if (!bound && !unbound_->append(proxy))
   45.82 +        return NULL;
   45.83 +    return proxy;
   45.84 +}
   45.85 +
   45.86 +bool
   45.87 +Parser::matchName(String **name, TokenKind kind)
   45.88 +{
   45.89 +    assert(kind == TOK_NAME || kind == TOK_LABEL);
   45.90 +    *name = NULL;
   45.91 +    if (!match(kind))
   45.92 +        return false;
   45.93 +    *name = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
   45.94 +    return true;
   45.95 +}
   45.96 +
   45.97 +String *
   45.98 +Parser::expectName()
   45.99 +{
  45.100 +    if (!expect(TOK_NAME))
  45.101 +        return NULL;
  45.102 +    return zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
  45.103 +}
  45.104 +
  45.105 +void
  45.106 +Parser::redeclarationError(BoundName *other)
  45.107 +{
  45.108 +    cc_.reportError(scanner_.begin(), Message_RedeclaredName, other->name()->chars(),
  45.109 +                    other->pos().line, other->pos().col);
  45.110 +}
  45.111 +
  45.112 +Expression *
  45.113 +Parser::primitive()
  45.114 +{
  45.115 +    TokenKind kind = scanner_.peek();
  45.116 +    switch (kind) {
  45.117 +      case TOK_NAME:
  45.118 +      {
  45.119 +        Local<String> name(zone_, expectName());
  45.120 +        if (!name)
  45.121 +            return NULL;
  45.122 +        return bind(name);
  45.123 +      }
  45.124 +
  45.125 +      case TOK_FLOAT_LITERAL:
  45.126 +      {
  45.127 +        scanner_.scan();
  45.128 +        double value = Scanner::ParseDouble(scanner_.literal());
  45.129 +        return new (pool_) FloatLiteral(scanner_.begin(), value);
  45.130 +      }
  45.131 +
  45.132 +      case TOK_INTEGER_LITERAL:
  45.133 +      {
  45.134 +        scanner_.scan();
  45.135 +        int value = atoi(scanner_.literal());
  45.136 +        return new (pool_) IntegerLiteral(scanner_.begin(), value);
  45.137 +      }
  45.138 +
  45.139 +      case TOK_STRING_LITERAL:
  45.140 +      {
  45.141 +        scanner_.scan();
  45.142 +        Local<ByteArray> array(zone_, ByteArray::New(zone_, scanner_.literal_length() + 1));
  45.143 +        if (!array)
  45.144 +            return NULL;
  45.145 +        memcpy(array->raw(), scanner_.literal(), scanner_.literal_length() + 1);
  45.146 +        return new (pool_) StringLiteral(scanner_.begin(), array);
  45.147 +      }
  45.148 +
  45.149 +      default:
  45.150 +      {
  45.151 +        if (kind != TOK_ERROR)
  45.152 +            cc_.reportError(scanner_.begin(), Message_ExpectedExpression, TokenNames[kind]);
  45.153 +        return NULL;
  45.154 +      }
  45.155 +    }
  45.156 +}
  45.157 +
  45.158 +Expression *
  45.159 +Parser::prefix()
  45.160 +{
  45.161 +    switch (scanner_.peek()) {
  45.162 +      case TOK_LPAREN:
  45.163 +      {
  45.164 +        scanner_.scan();
  45.165 +        Expression *expr = expression();
  45.166 +        if (!expr)
  45.167 +            return NULL;
  45.168 +        if (!expect(TOK_RPAREN))
  45.169 +            return NULL;
  45.170 +        return expr;
  45.171 +      }
  45.172 +
  45.173 +      default:
  45.174 +        return primitive();
  45.175 +    }
  45.176 +}
  45.177 +
  45.178 +Expression *
  45.179 +Parser::call(Expression *callee)
  45.180 +{
  45.181 +    ExpressionList *arguments = new (pool_) ExpressionList();
  45.182 +
  45.183 +    SourcePosition pos = scanner_.begin();
  45.184 +    expect(TOK_LPAREN);
  45.185 +    
  45.186 +    if (!match(TOK_RPAREN)) {
  45.187 +        while (true) {
  45.188 +            Expression *expr = expression();
  45.189 +            if (!expr)
  45.190 +                return NULL;
  45.191 +
  45.192 +            if (!arguments->append(expr))
  45.193 +                return NULL;
  45.194 +
  45.195 +            if (!match(TOK_COMMA))
  45.196 +                break;
  45.197 +        }
  45.198 +
  45.199 +        if (!expect(TOK_RPAREN))
  45.200 +            return NULL;
  45.201 +    }
  45.202 +
  45.203 +    return new (pool_) CallExpression(pos, callee, arguments);
  45.204 +}
  45.205 +
  45.206 +Expression *
  45.207 +Parser::index(Expression *left)
  45.208 +{
  45.209 +    expect(TOK_LBRACKET);
  45.210 +    
  45.211 +    SourcePosition pos = scanner_.begin();
  45.212 +    Expression *expr = expression();
  45.213 +    if (!expr)
  45.214 +        return NULL;
  45.215 +
  45.216 +    if (!expect(TOK_RBRACKET))
  45.217 +        return NULL;
  45.218 +
  45.219 +    return new (pool_) IndexExpression(pos, left, expr);
  45.220 +}
  45.221 +
  45.222 +Expression *
  45.223 +Parser::primary()
  45.224 +{
  45.225 +    Expression *expr = prefix();
  45.226 +    if (!expr)
  45.227 +        return NULL;
  45.228 +
  45.229 +    for (;;) {
  45.230 +        switch (scanner_.peek()) {
  45.231 +          case TOK_LPAREN:
  45.232 +            expr = call(expr);
  45.233 +            if (!expr)
  45.234 +                return NULL;
  45.235 +            break;
  45.236 +
  45.237 +          case TOK_LBRACKET:
  45.238 +            expr = index(expr);
  45.239 +            if (!expr)
  45.240 +                return NULL;
  45.241 +            break;
  45.242 +
  45.243 +          default:
  45.244 +            return expr;
  45.245 +        }
  45.246 +    }
  45.247 +}
  45.248 +
  45.249 +Expression *
  45.250 +Parser::unary()
  45.251 +{
  45.252 +    TokenKind token = scanner_.peek();
  45.253 +
  45.254 +    SourcePosition pos = scanner_.begin();
  45.255 +    switch (token) {
  45.256 +      case TOK_INCREMENT:
  45.257 +      case TOK_DECREMENT:
  45.258 +      {
  45.259 +        scanner_.scan();
  45.260 +        Expression *expr = expression();
  45.261 +        if (!expr)
  45.262 +            return NULL;
  45.263 +        return new (pool_) IncDecExpression(pos, token, expr, false);
  45.264 +      }
  45.265 +
  45.266 +      case TOK_MINUS:
  45.267 +      case TOK_NOT:
  45.268 +      case TOK_TILDE:
  45.269 +      {
  45.270 +        scanner_.scan();
  45.271 +        Expression *expr = expression();
  45.272 +        if (!expr)
  45.273 +            return NULL;
  45.274 +        return new (pool_) UnaryExpression(pos, token, expr);
  45.275 +      }
  45.276 +
  45.277 +      default:
  45.278 +        break;
  45.279 +    }
  45.280 +
  45.281 +    Expression *expr = primary();
  45.282 +
  45.283 +    token = scanner_.peek();
  45.284 +    if (token == TOK_INCREMENT || token == TOK_DECREMENT) {
  45.285 +        scanner_.scan();
  45.286 +        return new (pool_) IncDecExpression(pos, token, expr, true);
  45.287 +    }
  45.288 +
  45.289 +    return expr;
  45.290 +}
  45.291 +
  45.292 +Expression *
  45.293 +Parser::multiplication()
  45.294 +{
  45.295 +    Expression *left = unary();
  45.296 +    do {
  45.297 +        if (!match(TOK_SLASH) && !match(TOK_STAR) && !match(TOK_PERCENT))
  45.298 +            break;
  45.299 +        SourcePosition pos = scanner_.begin();
  45.300 +        TokenKind kind = scanner_.last();
  45.301 +        Expression *right = unary();
  45.302 +        if (!right)
  45.303 +            return NULL;
  45.304 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
  45.305 +    } while (left);
  45.306 +    return left;
  45.307 +}
  45.308 +
  45.309 +Expression *
  45.310 +Parser::addition()
  45.311 +{
  45.312 +    Expression *left = multiplication();
  45.313 +    while (left) {
  45.314 +        if (!match(TOK_PLUS) && !match(TOK_MINUS))
  45.315 +            break;
  45.316 +        SourcePosition pos = scanner_.begin();
  45.317 +        TokenKind kind = scanner_.last();
  45.318 +        Expression *right = multiplication();
  45.319 +        if (!right)
  45.320 +            return NULL;
  45.321 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
  45.322 +    }
  45.323 +    return left;
  45.324 +}
  45.325 +
  45.326 +Expression *
  45.327 +Parser::shift()
  45.328 +{
  45.329 +    Expression *left = addition();
  45.330 +    while (left) {
  45.331 +        if (!match(TOK_SHL) && !match(TOK_SHR) && !match(TOK_USHR))
  45.332 +            break;
  45.333 +        SourcePosition pos = scanner_.begin();
  45.334 +        TokenKind kind = scanner_.last();
  45.335 +        Expression *right = addition();
  45.336 +        if (!right)
  45.337 +            return NULL;
  45.338 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
  45.339 +    }
  45.340 +    return left;
  45.341 +}
  45.342 +
  45.343 +Expression *
  45.344 +Parser::bitand_()
  45.345 +{
  45.346 +    Expression *left = shift();
  45.347 +    while (left) {
  45.348 +        if (!match(TOK_BITAND))
  45.349 +            break;
  45.350 +        SourcePosition pos = scanner_.begin();
  45.351 +        Expression *right = shift();
  45.352 +        if (!right)
  45.353 +            return NULL;
  45.354 +        left = new (pool_) BinaryExpression(pos, TOK_BITAND, left, right);
  45.355 +    }
  45.356 +    return left;
  45.357 +}
  45.358 +
  45.359 +Expression *
  45.360 +Parser::bitxor()
  45.361 +{
  45.362 +    Expression *left = bitand_();
  45.363 +    while (left) {
  45.364 +        if (!match(TOK_BITXOR))
  45.365 +            break;
  45.366 +        SourcePosition pos = scanner_.begin();
  45.367 +        Expression *right = shift();
  45.368 +        if (!right)
  45.369 +            return NULL;
  45.370 +        left = new (pool_) BinaryExpression(pos, TOK_BITXOR, left, right);
  45.371 +    }
  45.372 +    return left;
  45.373 +}
  45.374 +
  45.375 +Expression *
  45.376 +Parser::bitor_()
  45.377 +{
  45.378 +    Expression *left = bitxor();
  45.379 +    while (left) {
  45.380 +        if (!match(TOK_BITOR))
  45.381 +            break;
  45.382 +        SourcePosition pos = scanner_.begin();
  45.383 +        Expression *right = bitxor();
  45.384 +        if (!right)
  45.385 +            return NULL;
  45.386 +        left = new (pool_) BinaryExpression(pos, TOK_BITOR, left, right);
  45.387 +    }
  45.388 +    return left;
  45.389 +}
  45.390 +
  45.391 +Expression *
  45.392 +Parser::relational()
  45.393 +{
  45.394 +    Expression *left = bitor_();
  45.395 +    while (left) {
  45.396 +        TokenKind kind = scanner_.peek();
  45.397 +        if (kind < TOK_LT || kind > TOK_GE)
  45.398 +            break;
  45.399 +        scanner_.scan();
  45.400 +        SourcePosition pos = scanner_.begin();
  45.401 +        Expression *right = shift();
  45.402 +        if (!right)
  45.403 +            return NULL;
  45.404 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
  45.405 +    }
  45.406 +    return left;
  45.407 +}
  45.408 +
  45.409 +Expression *
  45.410 +Parser::equals()
  45.411 +{
  45.412 +    Expression *left = relational();
  45.413 +    while (left) {
  45.414 +        if (!match(TOK_EQUALS) && !match(TOK_NOTEQUALS))
  45.415 +            break;
  45.416 +        TokenKind kind = scanner_.last();
  45.417 +        SourcePosition pos = scanner_.begin();
  45.418 +        Expression *right = relational();
  45.419 +        if (!right)
  45.420 +            return NULL;
  45.421 +        left = new (pool_) BinaryExpression(pos, kind, left, right);
  45.422 +    }
  45.423 +    return left;
  45.424 +}
  45.425 +
  45.426 +Expression *
  45.427 +Parser::and_()
  45.428 +{
  45.429 +    Expression *left = equals();
  45.430 +    while (left) {
  45.431 +        if (!match(TOK_AND))
  45.432 +            break;
  45.433 +        SourcePosition pos = scanner_.begin();
  45.434 +        Expression *right = equals();
  45.435 +        if (!right)
  45.436 +            return NULL;
  45.437 +        left = new (pool_) BinaryExpression(pos, TOK_AND, left, right);
  45.438 +    }
  45.439 +    return left;
  45.440 +}
  45.441 +
  45.442 +Expression *
  45.443 +Parser::or_()
  45.444 +{
  45.445 +    Expression *left = and_();
  45.446 +    while (left) {
  45.447 +        if (!match(TOK_OR))
  45.448 +            break;
  45.449 +        SourcePosition pos = scanner_.begin();
  45.450 +        Expression *right = and_();
  45.451 +        if (!right)
  45.452 +            return NULL;
  45.453 +        left = new (pool_) BinaryExpression(pos, TOK_OR, left, right);
  45.454 +    }
  45.455 +    return left;
  45.456 +}
  45.457 +
  45.458 +Expression *
  45.459 +Parser::ternary()
  45.460 +{
  45.461 +    Expression *cond = or_();
  45.462 +    if (!cond)
  45.463 +        return NULL;
  45.464 +    
  45.465 +    if (!match(TOK_QMARK))
  45.466 +        return cond;
  45.467 +
  45.468 +    SourcePosition pos = scanner_.begin();
  45.469 +    Expression *left = expression();
  45.470 +    if (!left)
  45.471 +        return NULL;
  45.472 +
  45.473 +    if (!expect(TOK_COLON))
  45.474 +        return NULL;
  45.475 +
  45.476 +    Expression *right = expression();
  45.477 +    if (!right)
  45.478 +        return NULL;
  45.479 +
  45.480 +    return new (pool_) TernaryExpression(pos, cond, left, right);
  45.481 +}
  45.482 +
  45.483 +Expression *
  45.484 +Parser::assignment()
  45.485 +{
  45.486 +    Expression *left = ternary();
  45.487 +    while (left) {
  45.488 +        TokenKind token = scanner_.peek();
  45.489 +        if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL))
  45.490 +            break;
  45.491 +        scanner_.scan();
  45.492 +        SourcePosition pos = scanner_.begin();
  45.493 +        Expression *expr = ternary();
  45.494 +        if (!expr)
  45.495 +            return NULL;
  45.496 +
  45.497 +        left = new (pool_) Assignment(pos, token, left, expr);
  45.498 +    }
  45.499 +    return left;
  45.500 +}
  45.501 +
  45.502 +Expression *
  45.503 +Parser::expression()
  45.504 +{
  45.505 +    return assignment();
  45.506 +}
  45.507 +
  45.508 +Statement *
  45.509 +Parser::while_()
  45.510 +{
  45.511 +    SourcePosition pos = scanner_.begin();
  45.512 +    scanner_.scan();
  45.513 +
  45.514 +    if (!expect(TOK_LPAREN))
  45.515 +        return NULL;
  45.516 +
  45.517 +    Expression *condition = expression();
  45.518 +    if (!condition)
  45.519 +        return NULL;
  45.520 +
  45.521 +    if (!expect(TOK_RPAREN))
  45.522 +        return NULL;
  45.523 +
  45.524 +    // Inside a loop, we force the creation of a scope object. Normally, we
  45.525 +    // will cull scopes if they have no variables. However inside a loop,
  45.526 +    // function calls that take references may compute a LIFO object, and to
  45.527 +    // avoid temporarily leaking many such objects, we ensure that a scope
  45.528 +    // is present so a LIFO slot can be allocated.
  45.529 +    if (!enterScope(Scope::BLOCK))
  45.530 +        return NULL;
  45.531 +
  45.532 +    Statement *body;
  45.533 +    if (scanner_.peek() == TOK_LBRACE)
  45.534 +        body = block(scope_);
  45.535 +    else
  45.536 +        body = localStatement();
  45.537 +    if (!body)
  45.538 +        return NULL;
  45.539 +
  45.540 +    scope_ = scope_->enclosing();
  45.541 +    return new (pool_) WhileStatement(pos, TOK_WHILE, condition, body);
  45.542 +}
  45.543 +
  45.544 +Statement *
  45.545 +Parser::do_()
  45.546 +{
  45.547 +    SourcePosition pos = scanner_.begin();
  45.548 +    scanner_.scan();
  45.549 +
  45.550 +    // See the comment in ::while_() as to why we force a scope.
  45.551 +    if (!enterScope(Scope::BLOCK))
  45.552 +        return NULL;
  45.553 +
  45.554 +    Statement *body;
  45.555 +    if (scanner_.peek() == TOK_LBRACE)
  45.556 +        body = block(scope_);
  45.557 +    else
  45.558 +        body = localStatement();
  45.559 +    if (!body)
  45.560 +        return NULL;
  45.561 +
  45.562 +    scope_ = scope_->enclosing();
  45.563 +
  45.564 +    if (!expect(TOK_WHILE))
  45.565 +        return NULL;
  45.566 +
  45.567 +    if (!expect(TOK_LPAREN))
  45.568 +        return NULL;
  45.569 +    Expression *condition = expression();
  45.570 +    if (!condition)
  45.571 +        return NULL;
  45.572 +    if (!expect(TOK_RPAREN))
  45.573 +        return NULL;
  45.574 +
  45.575 +    return new (pool_) WhileStatement(pos, TOK_DO, condition, body);
  45.576 +}
  45.577 +
  45.578 +Statement *
  45.579 +Parser::forStatement()
  45.580 +{
  45.581 +    SourcePosition pos = scanner_.begin();
  45.582 +    scanner_.scan();
  45.583 +    if (!expect(TOK_LPAREN))
  45.584 +        return NULL;
  45.585 +
  45.586 +    Statement *decl = NULL;
  45.587 +    if (!match(TOK_SEMICOLON)) {
  45.588 +        if (scanner_.peek() == TOK_NEW) {
  45.589 +            if (!enterScope(Scope::BLOCK))
  45.590 +                return NULL;
  45.591 +            if ((decl = variableDeclaration()) == NULL)
  45.592 +                return NULL;
  45.593 +        } else {
  45.594 +            if ((decl = expressionStatement()) == NULL)
  45.595 +                return NULL;
  45.596 +        }
  45.597 +        if (!expect(TOK_SEMICOLON))
  45.598 +            return NULL;
  45.599 +    }
  45.600 +
  45.601 +    Expression *condition = NULL;
  45.602 +    if (!match(TOK_SEMICOLON)) {
  45.603 +        if ((condition = expression()) == NULL)
  45.604 +            return NULL;
  45.605 +        if (!expect(TOK_SEMICOLON))
  45.606 +            return NULL;
  45.607 +    }
  45.608 +
  45.609 +    Statement *update = NULL;
  45.610 +    if (!match(TOK_RPAREN)) {
  45.611 +        if ((update = expressionStatement()) == NULL)
  45.612 +            return NULL;
  45.613 +        if (!expect(TOK_RPAREN))
  45.614 +            return NULL;
  45.615 +    }
  45.616 +
  45.617 +    // See the comment in ::while_() as to why we force a scope.
  45.618 +    if (!enterScope(Scope::BLOCK))
  45.619 +        return NULL;
  45.620 +
  45.621 +    Statement *body;
  45.622 +    if (scanner_.peek() == TOK_LBRACE)
  45.623 +        body = block(scope_);
  45.624 +    else
  45.625 +        body = localStatement();
  45.626 +    if (!body)
  45.627 +        return NULL;
  45.628 +
  45.629 +    scope_ = scope_->enclosing();
  45.630 +
  45.631 +    Scope *declScope = NULL;
  45.632 +    if (decl && decl->isVariableDeclaration()) {
  45.633 +        declScope = scope_->unlinkIfEmpty();
  45.634 +        scope_ = scope_->enclosing();
  45.635 +    }
  45.636 +    return new (pool_) ForStatement(pos, declScope, decl, condition, update, body);
  45.637 +}
  45.638 +
  45.639 +VariableDeclaration *
  45.640 +Parser::variableDeclaration()
  45.641 +{
  45.642 +    if (!expect(TOK_NEW))
  45.643 +        return NULL;
  45.644 +
  45.645 +    Local<String> tag(zone_);
  45.646 +    if (matchName(tag.ref(), TOK_LABEL) && !tag)
  45.647 +        return NULL;
  45.648 +
  45.649 +    Local<String> name(zone_, expectName());
  45.650 +    if (!name)
  45.651 +        return NULL;
  45.652 +
  45.653 +    if (BoundName *other = scope_->localLookup(name)) {
  45.654 +        redeclarationError(other);
  45.655 +        return NULL;
  45.656 +    }
  45.657 +
  45.658 +    Variable *var = scope_->declareVariable(name, scanner_.begin());
  45.659 +    if (!var)
  45.660 +        return NULL;
  45.661 +
  45.662 +    ExpressionList *postDimensions = NULL;
  45.663 +    if (scanner_.peek() == TOK_LBRACKET) {
  45.664 +        postDimensions = new (pool_) ExpressionList();
  45.665 +        while (match(TOK_LBRACKET)) {
  45.666 +            Expression *dim = expression();
  45.667 +            if (!dim)
  45.668 +                return NULL;
  45.669 +
  45.670 +            if (!expect(TOK_RBRACKET))
  45.671 +                return NULL;
  45.672 +
  45.673 +            if (!postDimensions->append(dim))
  45.674 +                return NULL;
  45.675 +        }
  45.676 +    }
  45.677 +    
  45.678 +    Expression *expr = NULL;
  45.679 +    if (match(TOK_ASSIGN)) {
  45.680 +        if ((expr = expression()) == NULL)
  45.681 +            return NULL;
  45.682 +    }
  45.683 +
  45.684 +    return new (pool_) VariableDeclaration(var->pos(), var, tag, postDimensions, expr);
  45.685 +}
  45.686 +
  45.687 +Statement *
  45.688 +Parser::returnStatement()
  45.689 +{
  45.690 +    SourcePosition pos = scanner_.begin();
  45.691 +    if (!expect(TOK_RETURN))
  45.692 +        return NULL;
  45.693 +
  45.694 +    Expression *expr = NULL;
  45.695 +    if (scanner_.peek() != TOK_SEMICOLON) {
  45.696 +        if ((expr = expression()) == NULL)
  45.697 +            return NULL;
  45.698 +
  45.699 +        // We only care about non-void returns when determining whether a
  45.700 +        // tagless function is non-void.
  45.701 +        encounteredReturn_ = true;
  45.702 +    }
  45.703 +
  45.704 +    return new (pool_) ReturnStatement(pos, expr);
  45.705 +}
  45.706 +
  45.707 +Statement *
  45.708 +Parser::expressionStatement()
  45.709 +{
  45.710 +    Expression *left = assignment();
  45.711 +    if (!left)
  45.712 +        return NULL;
  45.713 +
  45.714 +    return new (pool_) ExpressionStatement(left);
  45.715 +}
  45.716 +
  45.717 +Statement *
  45.718 +Parser::block(Scope *scope)
  45.719 +{
  45.720 +    if (!expect(TOK_LBRACE))
  45.721 +        return NULL;
  45.722 +
  45.723 +    SourcePosition pos = scanner_.begin();
  45.724 +    if (!scope && !enterScope(Scope::BLOCK))
  45.725 +        return NULL;
  45.726 +
  45.727 +    StatementList *statements = new (pool_) StatementList();
  45.728 +    while (!match(TOK_RBRACE)) {
  45.729 +        Statement *statement = localStatement();
  45.730 +        if (statement == NULL)
  45.731 +            return NULL;
  45.732 +        if (!statements->append(statement))
  45.733 +            return NULL;
  45.734 +    }
  45.735 +
  45.736 +    if (!scope) {
  45.737 +    	scope = scope_->unlinkIfEmpty();
  45.738 +        scope_ = scope_->enclosing();
  45.739 +    }
  45.740 +    BlockStatement *block = new (pool_) BlockStatement(pos, scope, statements);
  45.741 +    return block;
  45.742 +}
  45.743 +
  45.744 +Statement *
  45.745 +Parser::if_()
  45.746 +{
  45.747 +    expect(TOK_IF);
  45.748 +    
  45.749 +    SourcePosition pos = scanner_.begin();
  45.750 +    if (!expect(TOK_LPAREN))
  45.751 +        return NULL;
  45.752 +
  45.753 +    Expression *cond = expression();
  45.754 +    if (!cond)
  45.755 +        return NULL;
  45.756 +
  45.757 +    if (!expect(TOK_RPAREN))
  45.758 +        return NULL;
  45.759 +
  45.760 +    Statement *ifTrue = localStatement();
  45.761 +    if (!ifTrue)
  45.762 +        return NULL;
  45.763 +
  45.764 +    IfStatement *outer = new (pool_) IfStatement(pos, cond, ifTrue);
  45.765 +
  45.766 +    IfStatement *last = outer;
  45.767 +    while (match(TOK_ELSE)) {
  45.768 +        if (!match(TOK_IF)) {
  45.769 +            Statement *ifFalse = localStatement();
  45.770 +            if (!ifFalse)
  45.771 +                return NULL;
  45.772 +
  45.773 +            last->setIfFalse(ifFalse);
  45.774 +            break;
  45.775 +        }
  45.776 +
  45.777 +        SourcePosition pos = scanner_.begin();
  45.778 +        if (!expect(TOK_LPAREN))
  45.779 +            return NULL;
  45.780 +
  45.781 +        Expression *otherCond = expression();
  45.782 +        if (!otherCond)
  45.783 +            return NULL;
  45.784 +
  45.785 +        if (!expect(TOK_RPAREN))
  45.786 +            return NULL;
  45.787 +
  45.788 +        Statement *otherIfTrue = localStatement();
  45.789 +        if (!otherIfTrue)
  45.790 +            return NULL;
  45.791 +
  45.792 +        IfStatement *inner = new (pool_) IfStatement(pos, otherCond, otherIfTrue);
  45.793 +        last->setIfFalse(inner);
  45.794 +        last = inner;
  45.795 +    }
  45.796 +
  45.797 +    return outer;
  45.798 +}
  45.799 +
  45.800 +Statement *
  45.801 +Parser::localStatement()
  45.802 +{
  45.803 +    Statement *statement = NULL;
  45.804 +
  45.805 +    // Statements which must be followed by a semicolon will break out of the
  45.806 +    // switch. If they may end in BlockStatements, they'll immediately return.
  45.807 +
  45.808 +    switch (scanner_.peek()) {
  45.809 +        case TOK_NEW:
  45.810 +          if ((statement = variableDeclaration()) == NULL)
  45.811 +              return NULL;
  45.812 +          break;
  45.813 +
  45.814 +        case TOK_FOR:
  45.815 +          return forStatement();
  45.816 +
  45.817 +        case TOK_WHILE:
  45.818 +          return while_();
  45.819 +
  45.820 +        case TOK_BREAK:
  45.821 +          scanner_.scan();
  45.822 +          statement = new (pool_) BreakStatement(scanner_.begin());
  45.823 +          break;
  45.824 +
  45.825 +        case TOK_CONTINUE:
  45.826 +          scanner_.scan();
  45.827 +          statement = new (pool_) ContinueStatement(scanner_.begin());
  45.828 +          break;
  45.829 +
  45.830 +        case TOK_DO:
  45.831 +          if ((statement = do_()) == NULL)
  45.832 +              return NULL;
  45.833 +          break;
  45.834 +
  45.835 +        case TOK_RETURN:
  45.836 +          if ((statement = returnStatement()) == NULL)
  45.837 +              return NULL;
  45.838 +          break;
  45.839 +
  45.840 +        case TOK_ENUM:
  45.841 +          if ((statement = enum_()) == NULL)
  45.842 +              return NULL;
  45.843 +          break;
  45.844 +
  45.845 +        case TOK_IF:
  45.846 +          return if_();
  45.847 +
  45.848 +        case TOK_LBRACE:
  45.849 +          return block();
  45.850 +
  45.851 +	default:
  45.852 +	  break;
  45.853 +    }
  45.854 +
  45.855 +    if (!statement) {
  45.856 +        if ((statement = expressionStatement()) == NULL)
  45.857 +            return NULL;
  45.858 +    }
  45.859 +
  45.860 +    if (!expect(TOK_SEMICOLON))
  45.861 +        return NULL;
  45.862 +
  45.863 +    return statement;
  45.864 +}
  45.865 +
  45.866 +Statement *
  45.867 +Parser::enum_()
  45.868 +{
  45.869 +    expect(TOK_ENUM);
  45.870 +
  45.871 +    SourcePosition pos = scanner_.begin();
  45.872 +
  45.873 +    Local<String> name(zone_);
  45.874 +    if (matchName(name.ref())) {
  45.875 +        if (!name)
  45.876 +            return NULL;
  45.877 +
  45.878 +        if (BoundName *other = scope_->localLookup(name)) {
  45.879 +            redeclarationError(other);
  45.880 +            return NULL;
  45.881 +        }
  45.882 +
  45.883 +        if (!scope_->declareEnum(name, scanner_.begin()))
  45.884 +            return NULL;
  45.885 +    }
  45.886 +
  45.887 +    EnumStatement::EntryList *entries = new (pool_) EnumStatement::EntryList();
  45.888 +
  45.889 +    if (!expect(TOK_LBRACE))
  45.890 +        return NULL;
  45.891 +
  45.892 +    do {
  45.893 +        if (scanner_.peek() == TOK_RBRACE)
  45.894 +            break;
  45.895 +
  45.896 +        Local<String> name(zone_, expectName());
  45.897 +        if (!name)
  45.898 +            return NULL;
  45.899 +
  45.900 +        if (BoundName *other = scope_->localLookup(name)) {
  45.901 +            redeclarationError(other);
  45.902 +            return NULL;
  45.903 +        }
  45.904 +
  45.905 +        NamedConstant *constant = scope_->declareConstant(name, scanner_.begin());
  45.906 +        if (!constant)
  45.907 +            return NULL;
  45.908 +
  45.909 +        Expression *expr = NULL;
  45.910 +        if (match(TOK_ASSIGN)) {
  45.911 +            if ((expr = expression()) == NULL)
  45.912 +                return NULL;
  45.913 +        }
  45.914 +
  45.915 +        if (!entries->append(EnumStatement::Entry(constant, expr)))
  45.916 +            return NULL;
  45.917 +    } while (match(TOK_COMMA));
  45.918 +    if (!expect(TOK_RBRACE))
  45.919 +        return NULL;
  45.920 +
  45.921 +    return new (pool_) EnumStatement(pos, name, entries);
  45.922 +}
  45.923 +
  45.924 +Statement *
  45.925 +Parser::function(TokenKind token)
  45.926 +{
  45.927 +    Local<String> name(zone_, expectName());
  45.928 +    if (!name)
  45.929 +        return NULL;
  45.930 +
  45.931 +    SourcePosition pos = scanner_.begin();
  45.932 +
  45.933 +    // The function name goes into the outer (global) scope.
  45.934 +    assert(!scope_->enclosing());
  45.935 +
  45.936 +    NamedFunction *fun;
  45.937 +    if (BoundName *other = scope_->localLookup(name)) {
  45.938 +        // We allow a redeclaration if the new type is a public, and the old
  45.939 +        // type was a forward. However, the forward must come first.
  45.940 +        if (other->kind() != BoundName::FUNCTION) {
  45.941 +            redeclarationError(other);
  45.942 +            return NULL;
  45.943 +        }
  45.944 +
  45.945 +        fun = other->toNamedFunction();
  45.946 +        if (!fun->isForward() || token != TOK_PUBLIC) {
  45.947 +            redeclarationError(other);
  45.948 +            return NULL;
  45.949 +        }
  45.950 +        
  45.951 +        // We've got the same name, but the original is a forward, so let it
  45.952 +        // slide and re-use the original declaration.
  45.953 +        fun->setImplemented(scanner_.begin());
  45.954 +    } else {
  45.955 +        fun = scope_->declareFunction(name, scanner_.begin(), token);
  45.956 +        if (!fun)
  45.957 +            return NULL;
  45.958 +    }
  45.959 +
  45.960 +    Scope *scope = enterScope(Scope::FUNCTION);
  45.961 +    if (!scope)
  45.962 +        return NULL;
  45.963 +
  45.964 +    ParameterList *parameters = new (pool_) ParameterList();
  45.965 +
  45.966 +    if (!expect(TOK_LPAREN))
  45.967 +        return NULL;
  45.968 +    if (!match(TOK_RPAREN)) {
  45.969 +        while (true) {
  45.970 +            bool isConst = match(TOK_CONST);
  45.971 +            bool ref = match(TOK_AMPERSAND);
  45.972 +
  45.973 +            SourcePosition begin = scanner_.begin();
  45.974 +            Local<String> tag(zone_);
  45.975 +            if (matchName(tag.ref(), TOK_LABEL) && !tag)
  45.976 +                return NULL;
  45.977 +
  45.978 +            if (match(TOK_ELLIPSES)) {
  45.979 +                if (isConst || ref) {
  45.980 +                    cc_.reportError(begin, Message_InvalidVarArgs);
  45.981 +                    return NULL;
  45.982 +                }
  45.983 +
  45.984 +                if (token != TOK_NATIVE) {
  45.985 +                    cc_.reportError(begin, Message_VarArgsOutsideNative);
  45.986 +                    return NULL;
  45.987 +                }
  45.988 +
  45.989 +                fun->markNativeVariadic();
  45.990 +                break;
  45.991 +            }
  45.992 +
  45.993 +            Local<String> name(zone_, expectName());
  45.994 +            if (!name)
  45.995 +                return NULL;
  45.996 +
  45.997 +            if (BoundName *other = scope_->localLookup(name)) {
  45.998 +                redeclarationError(other);
  45.999 +                return NULL;
 45.1000 +            }
 45.1001 +            Variable *arg = scope_->declareArgument(name, scanner_.begin());
 45.1002 +            if (!arg)
 45.1003 +                return NULL;
 45.1004 +
 45.1005 +            // Look for dimensions.
 45.1006 +            ExpressionList *postDimensions = NULL;
 45.1007 +            while (match(TOK_LBRACKET)) {
 45.1008 +                if (!postDimensions)
 45.1009 +                    postDimensions = new (pool_) ExpressionList();
 45.1010 +
 45.1011 +                Expression *dim = NULL;
 45.1012 +                if (!match(TOK_RBRACKET)) {
 45.1013 +                    if ((dim = expression()) == NULL)
 45.1014 +                        return NULL;
 45.1015 +                    if (!expect(TOK_RBRACKET))
 45.1016 +                        return NULL;
 45.1017 +                }
 45.1018 +
 45.1019 +                if (!postDimensions->append(dim))
 45.1020 +                    return NULL;
 45.1021 +            }
 45.1022 +
 45.1023 +            Parameter *parameter = new (pool_) Parameter(arg, tag, ref, isConst, postDimensions);
 45.1024 +            if (!parameters->append(parameter))
 45.1025 +                return NULL;
 45.1026 +
 45.1027 +            if (!match(TOK_COMMA))
 45.1028 +                break;
 45.1029 +        }
 45.1030 +        if (!expect(TOK_RPAREN))
 45.1031 +            return NULL;
 45.1032 +    }
 45.1033 +
 45.1034 +    encounteredReturn_ = false;
 45.1035 +
 45.1036 +    Statement *body = NULL;
 45.1037 +    if (token != TOK_FORWARD && token != TOK_NATIVE) {
 45.1038 +        body = block();
 45.1039 +        if (!body)
 45.1040 +            return NULL;
 45.1041 +    }
 45.1042 +
 45.1043 +    scope_ = scope_->enclosing();
 45.1044 +    return new (pool_) FunctionStatement(pos, scope, fun, body, parameters, encounteredReturn_);
 45.1045 +}
 45.1046 +
 45.1047 +ParseTree *
 45.1048 +Parser::parse()
 45.1049 +{
 45.1050 +    StatementList *statements = new (pool_) StatementList();
 45.1051 +
 45.1052 +    if (!enterScope(Scope::GLOBAL))
 45.1053 +        return NULL;
 45.1054 +
 45.1055 +    for (;;) {
 45.1056 +        Statement *statement = NULL;
 45.1057 +
 45.1058 +        switch (scanner_.peek()) {
 45.1059 +          case TOK_ERROR:
 45.1060 +            return NULL;
 45.1061 +
 45.1062 +          case TOK_EOF:
 45.1063 +            break;
 45.1064 +
 45.1065 +          case TOK_NAME:
 45.1066 +            if ((statement = function(TOK_NAME)) == NULL)
 45.1067 +                return NULL;
 45.1068 +            break;
 45.1069 +
 45.1070 +          case TOK_FORWARD:
 45.1071 +          case TOK_PUBLIC:
 45.1072 +          case TOK_NATIVE:
 45.1073 +          {
 45.1074 +            TokenKind kind = scanner_.scan();
 45.1075 +            if ((statement = function(kind)) == NULL)
 45.1076 +                return NULL;
 45.1077 +            if ((kind == TOK_FORWARD || kind == TOK_NATIVE) && !matchSemicolon())
 45.1078 +                return NULL;
 45.1079 +            break;
 45.1080 +          }
 45.1081 +
 45.1082 +          case TOK_NEW:
 45.1083 +          {
 45.1084 +            if ((statement = variableDeclaration()) == NULL)
 45.1085 +               return NULL;
 45.1086 +            if (!matchSemicolon())
 45.1087 +                return NULL;
 45.1088 +            break;
 45.1089 +          }
 45.1090 +
 45.1091 +          case TOK_ENUM:
 45.1092 +            if ((statement = enum_()) == NULL)
 45.1093 +                return NULL;
 45.1094 +            if (!matchSemicolon())
 45.1095 +                return NULL;
 45.1096 +            break;
 45.1097 +
 45.1098 +          default:
 45.1099 +            cc_.reportError(scanner_.begin(), Message_ExpectedGlobal);
 45.1100 +            return NULL;
 45.1101 +        }
 45.1102 +
 45.1103 +        if (!statement)
 45.1104 +            break;
 45.1105 +
 45.1106 +        if (!statements->append(statement))
 45.1107 +            return NULL;
 45.1108 +    }
 45.1109 +
 45.1110 +    return new (pool_) ParseTree(scope_, statements, unbound_);
 45.1111 +}
 45.1112 +
 45.1113 +class AstPrinter : public AstVisitor
 45.1114 +{
 45.1115 +    FILE *fp_;
 45.1116 +    size_t level_;
 45.1117 +
 45.1118 +  private:
 45.1119 +    void prefix() {
 45.1120 +        for (size_t i = 0; i < level_; i++)
 45.1121 +            fprintf(fp_, "  ");
 45.1122 +    }
 45.1123 +    void indent() {
 45.1124 +        level_++;
 45.1125 +    }
 45.1126 +    void unindent() {
 45.1127 +        level_--;
 45.1128 +    }
 45.1129 +
 45.1130 +  public:
 45.1131 +    AstPrinter(FILE *fp)
 45.1132 +      : fp_(fp),
 45.1133 +        level_(0)
 45.1134 +    {
 45.1135 +    }
 45.1136 +
 45.1137 +    void visit(NameProxy *name) {
 45.1138 +        prefix();
 45.1139 +        fprintf(fp_, "[ NameProxy (%s)%s\n", name->name()->chars(),
 45.1140 +                (name->binding() ? "" : " unbound"));
 45.1141 +    }
 45.1142 +    void visit(CallExpression *node) {
 45.1143 +        prefix();
 45.1144 +        fprintf(fp_, "[ CallExpression\n");
 45.1145 +        indent();
 45.1146 +        node->callee()->accept(this);
 45.1147 +        for (size_t i = 0; i < node->arguments()->length(); i++)
 45.1148 +            node->arguments()->at(i)->accept(this);
 45.1149 +        unindent();
 45.1150 +    }
 45.1151 +    void visit(FunctionStatement *node) {
 45.1152 +        prefix();
 45.1153 +        fprintf(fp_, "[ FunctionStatement (%s)\n", node->fun()->name()->chars());
 45.1154 +        indent();
 45.1155 +        if (node->body())
 45.1156 +            node->body()->accept(this);
 45.1157 +        unindent();
 45.1158 +    }
 45.1159 +    void visit(ExpressionStatement *node) {
 45.1160 +        prefix();
 45.1161 +        fprintf(fp_, "[ ExpressionStatement\n");
 45.1162 +        indent();
 45.1163 +        node->expression()->accept(this);
 45.1164 +        unindent();
 45.1165 +    }
 45.1166 +    void visit(Assignment *node) {
 45.1167 +        prefix();
 45.1168 +        fprintf(fp_, "[ Assignment\n");
 45.1169 +        indent();
 45.1170 +        node->lvalue()->accept(this);
 45.1171 +        node->expression()->accept(this);
 45.1172 +        unindent();
 45.1173 +    }
 45.1174 +    void visit(TernaryExpression *node) {
 45.1175 +        prefix();
 45.1176 +        fprintf(fp_, "[ TernaryExpression\n");
 45.1177 +        indent();
 45.1178 +        node->condition()->accept(this);
 45.1179 +        node->left()->accept(this);
 45.1180 +        node->right()->accept(this);
 45.1181 +        unindent();
 45.1182 +    }
 45.1183 +    void visit(BinaryExpression *node) {
 45.1184 +        prefix();
 45.1185 +        fprintf(fp_, "[ BinaryExpression (%s)\n", TokenNames[node->token()]);
 45.1186 +        indent();
 45.1187 +        node->left()->accept(this);
 45.1188 +        node->right()->accept(this);
 45.1189 +        unindent();
 45.1190 +    }
 45.1191 +    void visit(UnaryExpression *node) {
 45.1192 +        prefix();
 45.1193 +        fprintf(fp_, "[ UnaryExpression (%s)\n", TokenNames[node->token()]);
 45.1194 +        indent();
 45.1195 +        node->expression()->accept(this);
 45.1196 +        unindent();
 45.1197 +    }
 45.1198 +    void visit(ReturnStatement *node) {
 45.1199 +        prefix();
 45.1200 +        fprintf(fp_, "[ ReturnStatement\n");
 45.1201 +        indent();
 45.1202 +        if (node->expression())
 45.1203 +            node->expression()->accept(this);
 45.1204 +        unindent();
 45.1205 +    }
 45.1206 +    void visit(ForStatement *node) {
 45.1207 +        prefix();
 45.1208 +        fprintf(fp_, "[ ForStatement\n");
 45.1209 +        indent();
 45.1210 +        if (node->initialization())
 45.1211 +            node->initialization()->accept(this);
 45.1212 +        if (node->condition())
 45.1213 +            node->condition()->accept(this);
 45.1214 +        if (node->update())
 45.1215 +            node->update()->accept(this);
 45.1216 +        node->body()->accept(this);
 45.1217 +        unindent();
 45.1218 +    }
 45.1219 +    void visit(BlockStatement *node) {
 45.1220 +        prefix();
 45.1221 +        fprintf(fp_, "[ BlockStatement\n");
 45.1222 +        indent();
 45.1223 +        for (size_t i = 0; i < node->statements()->length(); i++)
 45.1224 +            node->statements()->at(i)->accept(this);
 45.1225 +        unindent();
 45.1226 +    }
 45.1227 +    void visit(VariableDeclaration *node) {
 45.1228 +        prefix();
 45.1229 +        fprintf(fp_, "[ VariableDeclaration (%s)\n", node->variable()->name()->chars());
 45.1230 +        indent();
 45.1231 +        if (node->initialization())
 45.1232 +            node->initialization()->accept(this);
 45.1233 +        unindent();
 45.1234 +    }
 45.1235 +    void visit(IntegerLiteral *node) {
 45.1236 +        prefix();
 45.1237 +        fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value());
 45.1238 +    }
 45.1239 +    void visit(FloatLiteral *node) {
 45.1240 +        prefix();
 45.1241 +        fprintf(fp_, "[ FloatLiteral (%f)\n", node->value());
 45.1242 +    }
 45.1243 +    void visit(IfStatement *node) {
 45.1244 +        prefix();
 45.1245 +        fprintf(fp_, "[ IfStatement\n");
 45.1246 +        indent();
 45.1247 +        node->ifTrue()->accept(this);
 45.1248 +        if (node->ifFalse())
 45.1249 +            node->ifFalse()->accept(this);
 45.1250 +        unindent();
 45.1251 +    }
 45.1252 +    void visit(IndexExpression *node) {
 45.1253 +        prefix();
 45.1254 +        fprintf(fp_, "[ IndexExpression\n");
 45.1255 +        indent();
 45.1256 +        node->left()->accept(this);
 45.1257 +        node->right()->accept(this);
 45.1258 +        unindent();
 45.1259 +    }
 45.1260 +    void visit(EnumStatement *node) {
 45.1261 +        prefix();
 45.1262 +        fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name()->chars() : "<anonymous>");
 45.1263 +        indent();
 45.1264 +        for (size_t i = 0; i < node->entries()->length(); i++) {
 45.1265 +            prefix();
 45.1266 +            fprintf(fp_, "%s =\n", node->entries()->at(i).name->name()->chars());
 45.1267 +            if (node->entries()->at(i).expr) {
 45.1268 +                indent();
 45.1269 +                node->entries()->at(i).expr->accept(this);
 45.1270 +                unindent();
 45.1271 +            }
 45.1272 +        }
 45.1273 +        unindent();
 45.1274 +    }
 45.1275 +    void visit(WhileStatement *node) {
 45.1276 +        prefix();
 45.1277 +        fprintf(fp_, "[ WhileStatement (%s)\n",
 45.1278 +                (node->token() == TOK_DO) ? "do" : "while");
 45.1279 +        indent();
 45.1280 +        if (node->token() == TOK_DO) {
 45.1281 +            node->condition()->accept(this);
 45.1282 +            node->body()->accept(this);
 45.1283 +        } else {
 45.1284 +            node->condition()->accept(this);
 45.1285 +            node->body()->accept(this);
 45.1286 +        }
 45.1287 +        unindent();
 45.1288 +    }
 45.1289 +    void visit(BreakStatement *node) {
 45.1290 +        prefix();
 45.1291 +        fprintf(fp_, "[ BreakStatement\n");
 45.1292 +    }
 45.1293 +    void visit(ContinueStatement *node) {
 45.1294 +        prefix();
 45.1295 +        fprintf(fp_, "[ ContinueStatement\n");
 45.1296 +    }
 45.1297 +    void visit(StringLiteral *node) {
 45.1298 +        prefix();
 45.1299 +        fprintf(fp_, "[ StringLiteral\n");
 45.1300 +    }
 45.1301 +    void visit(IncDecExpression *node) {
 45.1302 +        prefix();
 45.1303 +        fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix());
 45.1304 +        indent();
 45.1305 +        node->expression()->accept(this);
 45.1306 +        unindent();
 45.1307 +    }
 45.1308 +};
 45.1309 +
 45.1310 +void
 45.1311 +ParseTree::dump(FILE *fp)
 45.1312 +{
 45.1313 +    AstPrinter printer(fp);
 45.1314 +
 45.1315 +    for (size_t i = 0; i < statements_->length(); i++)
 45.1316 +        statements_->at(i)->accept(&printer);
 45.1317 +}
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/src/Parser.h	Tue Jul 24 23:53:34 2012 -0700
    46.3 @@ -0,0 +1,91 @@
    46.4 +/*
    46.5 + * Copyright (C) 2012 David Anderson
    46.6 + *
    46.7 + * This file is part of JITCraft.
    46.8 + *
    46.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   46.10 + * the terms of the GNU General Public License as published by the Free
   46.11 + * Software Foundation, either version 3 of the License, or (at your option)
   46.12 + * any later version.
   46.13 + * 
   46.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   46.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   46.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   46.17 + *
   46.18 + * You should have received a copy of the GNU General Public License along with
   46.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   46.20 + */
   46.21 +#ifndef _include_jitcraft_parser_h_
   46.22 +#define _include_jitcraft_parser_h_
   46.23 +
   46.24 +#include <stdio.h>
   46.25 +#include "AST.h"
   46.26 +#include "Scanner.h"
   46.27 +#include "Scopes.h"
   46.28 +#include "Strings.h"
   46.29 +
   46.30 +namespace ke {
   46.31 +
   46.32 +class Parser
   46.33 +{
   46.34 +    Zone *zone_;
   46.35 +    CompileContext &cc_;
   46.36 +    PoolAllocator &pool_;
   46.37 +    Scanner scanner_;
   46.38 +    Scope *scope_;
   46.39 +    PoolList<NameProxy *> *unbound_;
   46.40 +    bool encounteredReturn_;
   46.41 +
   46.42 +  private:
   46.43 +    void redeclarationError(BoundName *name);
   46.44 +    bool match(TokenKind kind);
   46.45 +    bool expect(TokenKind kind);
   46.46 +    bool matchSemicolon();
   46.47 +
   46.48 +    Scope *enterScope(Scope::Kind kind);
   46.49 +
   46.50 +    VariableDeclaration *variableDeclaration();
   46.51 +    bool matchName(String **name, TokenKind kind = TOK_NAME);
   46.52 +    String *expectName();
   46.53 +    NameProxy *bind(Handle<String> name);
   46.54 +    Expression *primitive();
   46.55 +    Expression *call(Expression *callee);
   46.56 +    Expression *index(Expression *left);
   46.57 +    Expression *prefix();
   46.58 +    Expression *primary();
   46.59 +    Expression *unary();
   46.60 +    Expression *multiplication();
   46.61 +    Expression *addition();
   46.62 +    Expression *shift();
   46.63 +    Expression *bitand_();
   46.64 +    Expression *bitxor();
   46.65 +    Expression *bitor_();
   46.66 +    Expression *relational();
   46.67 +    Expression *equals();
   46.68 +    Expression *and_();
   46.69 +    Expression *or_();
   46.70 +    Expression *ternary();
   46.71 +    Expression *assignment();
   46.72 +    Expression *expression();
   46.73 +
   46.74 +    Statement *enum_();
   46.75 +    Statement *if_();
   46.76 +    Statement *block(Scope *scope = NULL);
   46.77 +    Statement *function(TokenKind tok);
   46.78 +    Statement *expressionStatement();
   46.79 +    Statement *while_();
   46.80 +    Statement *do_();
   46.81 +    Statement *forStatement();
   46.82 +    Statement *localStatement();
   46.83 +    Statement *globalStatement();
   46.84 +    Statement *returnStatement();
   46.85 +
   46.86 +  public:
   46.87 +    Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length);
   46.88 +
   46.89 +    ParseTree *parse();
   46.90 +};
   46.91 +
   46.92 +}
   46.93 +
   46.94 +#endif // _include_jitcraft_parser_h_
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/src/Platform-Posix.cpp	Tue Jul 24 23:53:34 2012 -0700
    47.3 @@ -0,0 +1,101 @@
    47.4 +/* vim: set ts=4 sw=4 tw=99 et:
    47.5 + *
    47.6 + * Copyright (C) 2012 David Anderson
    47.7 + *
    47.8 + * This file is part of JITCraft.
    47.9 + *
   47.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   47.11 + * the terms of the GNU General Public License as published by the Free
   47.12 + * Software Foundation, either version 3 of the License, or (at your option)
   47.13 + * any later version.
   47.14 + * 
   47.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   47.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   47.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   47.18 + *
   47.19 + * You should have received a copy of the GNU General Public License along with
   47.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   47.21 + */
   47.22 +#include <sys/mman.h>
   47.23 +#include "Platform.h"
   47.24 +
   47.25 +using namespace jc;
   47.26 +
   47.27 +static inline int
   47.28 +ToProtBits(OS::Protection prot)
   47.29 +{
   47.30 +    switch (prot) {
   47.31 +      case OS::Prot_ReadWrite:
   47.32 +        return PROT_READ | PROT_WRITE;
   47.33 +      case OS::Prot_ReadWriteExecute:
   47.34 +        return PROT_READ | PROT_WRITE | PROT_EXEC;
   47.35 +      default:
   47.36 +        assert(prot == OS::Prot_ReadExecute);
   47.37 +        return PROT_READ | PROT_EXEC;
   47.38 +    }
   47.39 +}
   47.40 +
   47.41 +Address
   47.42 +OS::MapMemory(size_t amount, MapMode mode, Protection prot_)
   47.43 +{
   47.44 +    int prot = ToProtBits(prot_);
   47.45 +    void *addr = mmap(NULL, amount, prot, MAP_ANON | MAP_PRIVATE, -1, 0);
   47.46 +    if (addr == MAP_FAILED)
   47.47 +        return NULL;
   47.48 +
   47.49 +    return Address(addr);
   47.50 +}
   47.51 +
   47.52 +bool
   47.53 +OS::CommitMemory(Address address, size_t amount, Protection prot_)
   47.54 +{
   47.55 +    return true;
   47.56 +}
   47.57 +
   47.58 +void
   47.59 +OS::UnmapMemory(Address address, size_t size)
   47.60 +{
   47.61 +    munmap(address, size);
   47.62 +}
   47.63 +
   47.64 +OS::AlignableMapping
   47.65 +OS::MapAlignedMemory(size_t amount, size_t alignment, MapMode mode)
   47.66 +{
   47.67 +    assert(amount >= alignment);
   47.68 +    assert(IsPowerOfTwo(alignment));
   47.69 +
   47.70 +    if (alignment == kPageAlignment) {
   47.71 +        Address address = MapMemory(amount, mode, Prot_ReadWrite);
   47.72 +        if (!address)
   47.73 +            return AlignableMapping();
   47.74 +        return AlignableMapping(address, alignment, amount);
   47.75 +    }
   47.76 +
   47.77 +    size_t requested = Min(amount * 2, amount + 2 * alignment);
   47.78 +    Address address = MapMemory(amount, mode, Prot_ReadWrite);
   47.79 +    if (!address)
   47.80 +        return AlignableMapping();
   47.81 +
   47.82 +    size_t begin = 0;
   47.83 +    Address aligned = AlignedBase(address, alignment);
   47.84 +    if (!IsAligned(address, alignment)) {
   47.85 +        // Shave off the first part of the unaligned region.
   47.86 +        aligned += alignment;
   47.87 +        begin = size_t(aligned - address);
   47.88 +        UnmapAlignedMemory(address, begin);
   47.89 +    }
   47.90 +
   47.91 +    if (requested - begin > amount) {
   47.92 +        // Shave off the last part of the unaligned region.
   47.93 +        UnmapAlignedMemory(address + amount, requested - amount - begin);
   47.94 +    }
   47.95 +
   47.96 +    return AlignableMapping(aligned, alignment, amount);
   47.97 +}
   47.98 +
   47.99 +void
  47.100 +OS::UnmapAlignedMemory(Address address, size_t size)
  47.101 +{
  47.102 +    OS::UnmapMemory(address, size);
  47.103 +}
  47.104 +
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/src/Platform-Windows.cpp	Tue Jul 24 23:53:34 2012 -0700
    48.3 @@ -0,0 +1,111 @@
    48.4 +/* vim: set ts=4 sw=4 tw=99 et:
    48.5 + *
    48.6 + * Copyright (C) 2012 David Anderson
    48.7 + *
    48.8 + * This file is part of JITCraft.
    48.9 + *
   48.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   48.11 + * the terms of the GNU General Public License as published by the Free
   48.12 + * Software Foundation, either version 3 of the License, or (at your option)
   48.13 + * any later version.
   48.14 + * 
   48.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   48.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   48.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   48.18 + *
   48.19 + * You should have received a copy of the GNU General Public License along with
   48.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   48.21 + */
   48.22 +
   48.23 +// :TODO: move into utility-style include
   48.24 +#define WIN32_LEAN_AND_MEAN
   48.25 +#include <Windows.h>
   48.26 +#include "Platform.h"
   48.27 +
   48.28 +using namespace ke;
   48.29 +
   48.30 +static inline DWORD
   48.31 +ToProtBits(OS::Protection prot)
   48.32 +{
   48.33 +    switch (prot) {
   48.34 +      case OS::Prot_ReadWrite:
   48.35 +        return PAGE_READWRITE;
   48.36 +      case OS::Prot_ReadWriteExecute:
   48.37 +        return PAGE_EXECUTE_READWRITE;
   48.38 +      default:
   48.39 +        assert(prot == OS::Prot_ReadExecute);
   48.40 +        return PAGE_EXECUTE_READ;
   48.41 +    }
   48.42 +}
   48.43 +
   48.44 +Address
   48.45 +OS::MapMemory(size_t amount, MapMode mode, Protection prot_)
   48.46 +{
   48.47 +    DWORD prot = ToProtBits(prot_);
   48.48 +    DWORD type = MEM_RESERVE;
   48.49 +    if (mode == Map_Commit)
   48.50 +        type |= MEM_COMMIT;
   48.51 +
   48.52 +    return (Address)VirtualAlloc(NULL, amount, type, prot);
   48.53 +}
   48.54 +
   48.55 +bool
   48.56 +OS::CommitMemory(Address address, size_t amount, Protection prot_)
   48.57 +{
   48.58 +    DWORD prot = ToProtBits(prot_);
   48.59 +    return !!VirtualAlloc(address, amount, MEM_COMMIT, prot);
   48.60 +}
   48.61 +
   48.62 +void
   48.63 +OS::UnmapMemory(Address address, size_t size)
   48.64 +{
   48.65 +    VirtualFree(address, 0, MEM_RELEASE);
   48.66 +}
   48.67 +
   48.68 +static Address
   48.69 +MapMemoryAt(Address address, size_t amount, OS::MapMode mode, OS::Protection prot_)
   48.70 +{
   48.71 +    DWORD bits = ToProtBits(prot_);
   48.72 +    DWORD flags = MEM_RESERVE;
   48.73 +    if (mode == OS::Map_Commit)
   48.74 +        flags |= MEM_COMMIT;
   48.75 +
   48.76 +    return (Address)VirtualAlloc((LPVOID)address, amount, flags, bits);
   48.77 +}
   48.78 +
   48.79 +OS::AlignableMapping
   48.80 +OS::MapAlignedMemory(size_t amount, size_t alignment, MapMode mode)
   48.81 +{
   48.82 +    Address addr = MapMemory(amount, mode, OS::Prot_ReadWrite);
   48.83 +    if (!addr)
   48.84 +        return AlignableMapping(NULL, alignment, 0);
   48.85 +
   48.86 +    if (!IsAligned(addr, alignment)) {
   48.87 +        UnmapMemory(addr, amount);
   48.88 +
   48.89 +        // Try to grab the next available aligned address.
   48.90 +        addr = AlignedBase(addr, alignment);
   48.91 +        addr = MapMemoryAt(addr + alignment, amount, mode, OS::Prot_ReadWrite);
   48.92 +        while (!addr) {
   48.93 +            // Try to over-allocate to get the right region. This can race
   48.94 +            // with other threads; we expect this to be rare. If this turns
   48.95 +            // out to be a problem, the API is set up such that we can just
   48.96 +            // return two pointers: the base, and the aligned address into
   48.97 +            // the over-allocated region.
   48.98 +            addr = MapMemory(amount + alignment, mode, OS::Prot_ReadWrite);
   48.99 +            if (!addr)
  48.100 +                return AlignableMapping(NULL, alignment, 0);
  48.101 +            UnmapMemory(addr, amount + alignment);
  48.102 +            addr = AlignedBase(addr, alignment);
  48.103 +            addr = MapMemoryAt(addr + alignment, amount, mode, OS::Prot_ReadWrite);
  48.104 +        }
  48.105 +    }
  48.106 +
  48.107 +    return AlignableMapping(addr, alignment, amount);
  48.108 +}
  48.109 +
  48.110 +void
  48.111 +OS::UnmapAlignedMemory(Address address, size_t size)
  48.112 +{
  48.113 +    OS::UnmapMemory(address, size);
  48.114 +}
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/src/Platform.h	Tue Jul 24 23:53:34 2012 -0700
    49.3 @@ -0,0 +1,91 @@
    49.4 +/* vim: set ts=4 sw=4 tw=99 et:
    49.5 + *
    49.6 + * Copyright (C) 2012 David Anderson
    49.7 + *
    49.8 + * This file is part of JITCraft.
    49.9 + *
   49.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   49.11 + * the terms of the GNU General Public License as published by the Free
   49.12 + * Software Foundation, either version 3 of the License, or (at your option)
   49.13 + * any later version.
   49.14 + * 
   49.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   49.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   49.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   49.18 + *
   49.19 + * You should have received a copy of the GNU General Public License along with
   49.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   49.21 + */
   49.22 +#ifndef _include_jitcraft_platform_h_
   49.23 +#define _include_jitcraft_platform_h_
   49.24 +
   49.25 +#include "Utility.h"
   49.26 +
   49.27 +namespace ke {
   49.28 +
   49.29 +namespace OS {
   49.30 +    enum Protection {
   49.31 +        Prot_ReadWrite,         // rw-, for the heap
   49.32 +        Prot_ReadExecute,       // r-x, for code
   49.33 +        Prot_ReadWriteExecute   // rwx, if disabling r-x for code.
   49.34 +    };
   49.35 +
   49.36 +    enum MapMode {
   49.37 +        Map_Reserve,            // don't ask for actual pages yet
   49.38 +        Map_Commit              // ask for pages right away
   49.39 +    };
   49.40 +
   49.41 +    Address MapMemory(size_t amount, MapMode mode, Protection prot);
   49.42 +    bool CommitMemory(Address address, size_t amount, Protection prot);
   49.43 +    void UnmapMemory(Address address, size_t size);
   49.44 +
   49.45 +    class AlignableMapping {
   49.46 +        Address base_;
   49.47 +        Address aligned_;
   49.48 +        size_t size_;
   49.49 +
   49.50 +      public:
   49.51 +        AlignableMapping(Address ptr, size_t alignment, size_t size)
   49.52 +          : base_(ptr),
   49.53 +            size_(size)
   49.54 +        {
   49.55 +            aligned_ = base_;
   49.56 +            if (!IsAligned(aligned_, alignment))
   49.57 +                aligned_ = AlignedBase(aligned_, alignment) + alignment;
   49.58 +        }
   49.59 +
   49.60 +        AlignableMapping() : base_(NULL), aligned_(NULL), size_(0)
   49.61 +        {
   49.62 +        }
   49.63 +
   49.64 +        Address base() const {
   49.65 +            return base_;
   49.66 +        }
   49.67 +        bool isValid() const {
   49.68 +            return !!base_;
   49.69 +        }
   49.70 +        size_t size() const {
   49.71 +            return size_;
   49.72 +        }
   49.73 +        Address aligned() const {
   49.74 +            return aligned_;
   49.75 +        }
   49.76 +    };
   49.77 +
   49.78 +    // MapAlignedMemory is guaranteed to return zeroed memory.
   49.79 +    AlignableMapping MapAlignedMemory(size_t amount, size_t alignment, MapMode mode);
   49.80 +    void UnmapAlignedMemory(Address address, size_t size);
   49.81 +
   49.82 +    // The default alignment of memory returned via MapMemory().
   49.83 +    // :TODO: better ifdefs
   49.84 +#ifdef _MSC_VER
   49.85 +    static const size_t kPageAlignment = 64 * kKB;
   49.86 +#else
   49.87 +    static const size_t kPageAlignment = 4 * kKB;
   49.88 +#endif
   49.89 +
   49.90 +}
   49.91 +
   49.92 +}
   49.93 +
   49.94 +#endif // _include_jitcraft_platform_h_
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/src/PoolAllocator.cpp	Tue Jul 24 23:53:34 2012 -0700
    50.3 @@ -0,0 +1,129 @@
    50.4 +/*
    50.5 + * Copyright (C) 2012 David Anderson
    50.6 + *
    50.7 + * This file is part of JITCraft.
    50.8 + *
    50.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   50.10 + * the terms of the GNU General Public License as published by the Free
   50.11 + * Software Foundation, either version 3 of the License, or (at your option)
   50.12 + * any later version.
   50.13 + * 
   50.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   50.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   50.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   50.17 + *
   50.18 + * You should have received a copy of the GNU General Public License along with
   50.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   50.20 + */
   50.21 +#include <assert.h>
   50.22 +#include <stdlib.h>
   50.23 +#include <new>
   50.24 +#include "PoolAllocator.h"
   50.25 +#include "Zone.h"
   50.26 +
   50.27 +using namespace ke;
   50.28 +
   50.29 +PoolAllocator::PoolAllocator()
   50.30 +  : reserved_(NULL),
   50.31 +    last_(NULL)
   50.32 +{
   50.33 +}
   50.34 +
   50.35 +PoolAllocator::~PoolAllocator()
   50.36 +{
   50.37 +    unwind(NULL);
   50.38 +    if (reserved_)
   50.39 +        free(reserved_);
   50.40 +}
   50.41 +
   50.42 +char *
   50.43 +PoolAllocator::enter()
   50.44 +{
   50.45 +    if (!last_)
   50.46 +        return NULL;
   50.47 +    return last_->ptr;
   50.48 +}
   50.49 +
   50.50 +void
   50.51 +PoolAllocator::leave(char *pos)
   50.52 +{
   50.53 +    unwind(pos);
   50.54 +}
   50.55 +
   50.56 +void
   50.57 +PoolAllocator::unwind(char *pos)
   50.58 +{
   50.59 +    while (last_) {
   50.60 +        if (pos && pos >= last_->base && pos < last_->end)
   50.61 +            break;
   50.62 +        Pool *prev = last_->prev;
   50.63 +        {
   50.64 +            if (last_->size() <= kMaxReserveSize &&
   50.65 +                (!reserved_ || reserved_->size() < last_->size()))
   50.66 +            {
   50.67 +                if (reserved_)
   50.68 +                    free(reserved_);
   50.69 +                reserved_ = last_;
   50.70 +            } else {
   50.71 +                free(last_);
   50.72 +            }
   50.73 +        }
   50.74 +        last_ = prev;
   50.75 +    }
   50.76 +
   50.77 +    if (!last_) {
   50.78 +        assert(!pos);
   50.79 +        return;
   50.80 +    }
   50.81 +
   50.82 +    last_->ptr = pos;
   50.83 +}
   50.84 +
   50.85 +void *
   50.86 +PoolAllocator::slowAllocate(size_t actualBytes)
   50.87 +{
   50.88 +    size_t bytesNeeded = actualBytes + sizeof(Pool);
   50.89 +    if (bytesNeeded < kDefaultPoolSize)
   50.90 +        bytesNeeded = kDefaultPoolSize;
   50.91 +
   50.92 +    Pool *pool;
   50.93 +    if (reserved_ && reserved_->size() >= bytesNeeded) {
   50.94 +        pool = reserved_;
   50.95 +        reserved_ = NULL;
   50.96 +    } else {
   50.97 +        pool = (Pool *)malloc(bytesNeeded);
   50.98 +        if (!pool) {
   50.99 +            ZONE()->reportOutOfMemory();
  50.100 +            return NULL;
  50.101 +        }
  50.102 +        pool->base = (char *)(pool + 1);
  50.103 +        pool->end = (char *)pool + bytesNeeded;
  50.104 +    }
  50.105 +    pool->ptr = pool->base + actualBytes;
  50.106 +    pool->prev = last_;
  50.107 +    last_ = pool;
  50.108 +    return pool->base;
  50.109 +}
  50.110 +
  50.111 +void
  50.112 +PoolAllocationPolicy::reportOutOfMemory()
  50.113 +{
  50.114 +    ZONE()->reportOutOfMemory();
  50.115 +}
  50.116 +
  50.117 +void
  50.118 +PoolAllocationPolicy::reportAllocationOverflow()
  50.119 +{
  50.120 +    ZONE()->reportError(Message_AllocationOverflow);
  50.121 +}
  50.122 +
  50.123 +void *
  50.124 +PoolAllocationPolicy::malloc(size_t bytes)
  50.125 +{
  50.126 +    return ZONE()->pool().allocate(bytes);
  50.127 +}
  50.128 +
  50.129 +void
  50.130 +PoolAllocationPolicy::free(void *ptr)
  50.131 +{
  50.132 +}
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/src/PoolAllocator.h	Tue Jul 24 23:53:34 2012 -0700
    51.3 @@ -0,0 +1,136 @@
    51.4 +/*
    51.5 + * Copyright (C) 2012 David Anderson
    51.6 + *
    51.7 + * This file is part of JITCraft.
    51.8 + *
    51.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   51.10 + * the terms of the GNU General Public License as published by the Free
   51.11 + * Software Foundation, either version 3 of the License, or (at your option)
   51.12 + * any later version.
   51.13 + * 
   51.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   51.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   51.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   51.17 + *
   51.18 + * You should have received a copy of the GNU General Public License along with
   51.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   51.20 + */
   51.21 +#ifndef _include_jitcraft_pool_allocator_h_
   51.22 +#define _include_jitcraft_pool_allocator_h_
   51.23 +
   51.24 +#include <new>
   51.25 +#include <stddef.h>
   51.26 +#include <limits.h>
   51.27 +#include "Utility.h"
   51.28 +#include "Vector.h"
   51.29 +
   51.30 +namespace ke {
   51.31 +
   51.32 +// Allocates memory in chunks that are not freed until the entire allocator
   51.33 +// is freed. This is intended for use with large, temporary data structures.
   51.34 +class PoolAllocator
   51.35 +{
   51.36 +    friend class PoolAllocationScope;
   51.37 +
   51.38 +    struct Pool {
   51.39 +        char *base;
   51.40 +        char *ptr;
   51.41 +        char *end;
   51.42 +        Pool *prev;
   51.43 +
   51.44 +        size_t size() const {
   51.45 +            return size_t(end - base);
   51.46 +        }
   51.47 +    };
   51.48 +
   51.49 +    static const size_t kDefaultPoolSize = 8 * 1024;
   51.50 +    static const size_t kMaxReserveSize = 64 * 1024;
   51.51 +
   51.52 +  private:
   51.53 +    Pool *reserved_;
   51.54 +    Pool *last_;
   51.55 +
   51.56 +  private:
   51.57 +    void unwind(char *pos);
   51.58 +    void *slowAllocate(size_t actualBytes);
   51.59 +
   51.60 +  public:
   51.61 +    PoolAllocator();
   51.62 +    ~PoolAllocator();
   51.63 +
   51.64 +    void *allocate(size_t bytes) {
   51.65 +        // Guarantee malloc alignment.
   51.66 +        size_t actualBytes = Align(bytes, kMallocAlignment);
   51.67 +        if (!last_ || (size_t(last_->end - last_->ptr) < actualBytes))
   51.68 +            return slowAllocate(actualBytes);
   51.69 +        char *ptr = last_->ptr;
   51.70 +        last_->ptr += actualBytes;
   51.71 +        return ptr;
   51.72 +    }
   51.73 +
   51.74 +    char *enter();
   51.75 +    void leave(char *position);
   51.76 +};
   51.77 +
   51.78 +class PoolScope
   51.79 +{
   51.80 +    PoolAllocator &pool_;
   51.81 +    char *position_;
   51.82 +
   51.83 +  public:
   51.84 +    PoolScope(PoolAllocator &allocator)
   51.85 +      : pool_(allocator),
   51.86 +        position_(allocator.enter())
   51.87 +    {
   51.88 +    }
   51.89 +    ~PoolScope()
   51.90 +    {
   51.91 +        pool_.leave(position_);
   51.92 +    }
   51.93 +};
   51.94 +
   51.95 +class PoolObject
   51.96 +{
   51.97 +  public:
   51.98 +    void *operator new(size_t size, PoolAllocator &pool) {
   51.99 +        return pool.allocate(size);
  51.100 +    }
  51.101 +    void *operator new [](size_t size, PoolAllocator &pool) {
  51.102 +        return pool.allocate(size);
  51.103 +    }
  51.104 +    
  51.105 +    // Using delete on pool-allocated objects is illegal.
  51.106 +    void operator delete(void *ptr, PoolAllocator &pool) {
  51.107 +        assert(false);
  51.108 +    }
  51.109 +    void operator delete [](void *ptr, PoolAllocator &pool) {
  51.110 +        assert(false);
  51.111 +    }
  51.112 +};
  51.113 +
  51.114 +class PoolAllocationPolicy
  51.115 +{
  51.116 +  protected:
  51.117 +    void reportAllocationOverflow();
  51.118 +    void reportOutOfMemory();
  51.119 +
  51.120 +  public:
  51.121 +    void *malloc(size_t bytes);
  51.122 +    void free(void *ptr);
  51.123 +};
  51.124 +
  51.125 +template <typename T>
  51.126 +class PoolList
  51.127 +  : public Vector<T, PoolAllocationPolicy>,
  51.128 +    public PoolObject
  51.129 +{
  51.130 +  public:
  51.131 +    PoolList()
  51.132 +      : Vector(PoolAllocationPolicy())
  51.133 +    {
  51.134 +    }
  51.135 +};
  51.136 +
  51.137 +}
  51.138 +
  51.139 +#endif // _include_jitcraft_pool_allocator_h_
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/src/Reference.cpp	Tue Jul 24 23:53:34 2012 -0700
    52.3 @@ -0,0 +1,58 @@
    52.4 +/*
    52.5 + * Copyright (C) 2012 David Anderson
    52.6 + *
    52.7 + * This file is part of JITCraft.
    52.8 + *
    52.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   52.10 + * the terms of the GNU General Public License as published by the Free
   52.11 + * Software Foundation, either version 3 of the License, or (at your option)
   52.12 + * any later version.
   52.13 + * 
   52.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   52.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   52.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   52.17 + *
   52.18 + * You should have received a copy of the GNU General Public License along with
   52.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   52.20 + */
   52.21 +#include "Reference.h"
   52.22 +#include "Zone.h"
   52.23 +#include "Array.h"
   52.24 +#include "Heap-inl.h"
   52.25 +
   52.26 +using namespace ke;
   52.27 +
   52.28 +Reference *
   52.29 +Reference::NewStack(Zone *zone, void *location, Heap::Tenure tenure)
   52.30 +{
   52.31 +    Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
   52.32 +    if (!ref)
   52.33 +        return NULL;
   52.34 +
   52.35 +    ref->location_ = location;
   52.36 +    return ref;
   52.37 +}
   52.38 +
   52.39 +Reference *
   52.40 +Reference::NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure)
   52.41 +{
   52.42 +    Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
   52.43 +    if (!ref)
   52.44 +        return NULL;
   52.45 +
   52.46 +    ref->location_ = &ref->slot_;
   52.47 +    ref->slot_ = slot;
   52.48 +    return ref;
   52.49 +}
   52.50 +
   52.51 +Reference *
   52.52 +Reference::NewArray(Zone *zone, Handle<Array> base, size_t index, Heap::Tenure tenure)
   52.53 +{
   52.54 +    Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
   52.55 +    if (!ref)
   52.56 +        return NULL;
   52.57 +
   52.58 +    ref->location_ = base->slotPtr(index);
   52.59 +    ref->base_ = base;
   52.60 +    return ref;
   52.61 +}
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/src/Reference.h	Tue Jul 24 23:53:34 2012 -0700
    53.3 @@ -0,0 +1,73 @@
    53.4 +/*
    53.5 + * Copyright (C) 2012 David Anderson
    53.6 + *
    53.7 + * This file is part of JITCraft.
    53.8 + *
    53.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   53.10 + * the terms of the GNU General Public License as published by the Free
   53.11 + * Software Foundation, either version 3 of the License, or (at your option)
   53.12 + * any later version.
   53.13 + * 
   53.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   53.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   53.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   53.17 + *
   53.18 + * You should have received a copy of the GNU General Public License along with
   53.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   53.20 + */
   53.21 +#ifndef _include_jitcraft_reference_h_
   53.22 +#define _include_jitcraft_reference_h_
   53.23 +
   53.24 +#include "Heap.h"
   53.25 +#include "Barriers.h"
   53.26 +#include "Stack.h"
   53.27 +
   53.28 +namespace ke {
   53.29 +
   53.30 +class Array;
   53.31 +
   53.32 +// A Reference is a typed pointer to another location in memory.
   53.33 +class Reference : public Object
   53.34 +{
   53.35 +    void *location_;
   53.36 +    LocalSlot slot_;
   53.37 +    Barriered<Array> base_;
   53.38 +
   53.39 +  public:
   53.40 +    static Reference *NewStack(Zone *zone, void *location, Heap::Tenure tenure = Heap::Tenure_Default);
   53.41 +    static Reference *NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure = Heap::Tenure_Default);
   53.42 +    static Reference *NewArray(Zone *zone, Handle<Array> base, size_t index, Heap::Tenure tenure = Heap::Tenure_Default);
   53.43 +
   53.44 +    int getInt() {
   53.45 +        return *reinterpret_cast<int *>(location_);
   53.46 +    }
   53.47 +    void setInt(int i) {
   53.48 +        *reinterpret_cast<int *>(location_) = i;
   53.49 +    }
   53.50 +    float getFloat() {
   53.51 +        return *reinterpret_cast<float *>(location_);
   53.52 +    }
   53.53 +    void setFloat(float f) {
   53.54 +        *reinterpret_cast<float *>(location_) = f;
   53.55 +    }
   53.56 +
   53.57 +    // WARNING! This should only be for Native calls.
   53.58 +    void *location() {
   53.59 +        return location_;
   53.60 +    }
   53.61 +
   53.62 +    // Begin GC Descriptor.
   53.63 +    static inline size_t offsetOfBase() {
   53.64 +        return offsetof(Reference, base_);
   53.65 +    }
   53.66 +    // End GC Descriptor.
   53.67 +
   53.68 +    static inline Reference *cast(Object *obj) {
   53.69 +        assert(!obj || obj->is(MapKind_Reference));
   53.70 +        return reinterpret_cast<Reference *>(obj);
   53.71 +    }
   53.72 +};
   53.73 +
   53.74 +}
   53.75 +
   53.76 +#endif // _include_jitcraft_reference_h_
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/src/RootScopes.cpp	Tue Jul 24 23:53:34 2012 -0700
    54.3 @@ -0,0 +1,85 @@
    54.4 +/* vim: set ts=4 sw=4 tw=99 et:
    54.5 + *
    54.6 + * Copyright (C) 2012 David Anderson
    54.7 + *
    54.8 + * This file is part of JITCraft.
    54.9 + *
   54.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   54.11 + * the terms of the GNU General Public License as published by the Free
   54.12 + * Software Foundation, either version 3 of the License, or (at your option)
   54.13 + * any later version.
   54.14 + * 
   54.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   54.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   54.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   54.18 + *
   54.19 + * You should have received a copy of the GNU General Public License along with
   54.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   54.21 + */
   54.22 +#include <stdio.h>
   54.23 +#include <stdlib.h>
   54.24 +#include "RootScopes.h"
   54.25 +
   54.26 +using namespace ke;
   54.27 +
   54.28 +RootScopeManager::RootScopeManager()
   54.29 +  : blocks_(&first_),
   54.30 +    first_(NULL),
   54.31 +    scope_(NULL)
   54.32 +{
   54.33 +}
   54.34 +
   54.35 +RootScopeManager::~RootScopeManager()
   54.36 +{
   54.37 +    while (blocks_ != &first_) {
   54.38 +        Block *temp = blocks_;
   54.39 +        delete blocks_;
   54.40 +        blocks_ = temp;
   54.41 +    }
   54.42 +}
   54.43 +
   54.44 +bool
   54.45 +RootScopeManager::grow()
   54.46 +{
   54.47 +    assert(blocks_->cur == blocks_->end);
   54.48 +
   54.49 +    Block *block = new Block(blocks_);
   54.50 +    if (!block) {
   54.51 +        // We are not prepared for this. We'll start dishing out NULL-valued
   54.52 +        // ScopedRoots, and the engine generally assumes infallbility. Rather
   54.53 +        // then NULL check all sorts of nodes on parse trees, or add boolean
   54.54 +        // setters, for now we just abort.
   54.55 +        fprintf(stderr, "Unrecoverable error: could not allocate a local root scope. Aborting!\n");
   54.56 +        abort();
   54.57 +        return false;
   54.58 +    }
   54.59 +
   54.60 +    blocks_ = block;
   54.61 +    return true;
   54.62 +}
   54.63 +
   54.64 +void
   54.65 +RootScopeManager::unwindSlow(Object **pos)
   54.66 +{
   54.67 +    for (;;) {
   54.68 +        if (pos >= blocks_->objects && pos <= blocks_->end)
   54.69 +            break;
   54.70 +        assert(blocks_ != &first_);
   54.71 +        Block *temp = blocks_;
   54.72 +        delete blocks_;
   54.73 +        blocks_ = temp;
   54.74 +    }
   54.75 +
   54.76 +    blocks_->cur = pos;
   54.77 +}
   54.78 +
   54.79 +void
   54.80 +RootScopeManager::accept(VirtualObjectVisitor *visitor)
   54.81 +{
   54.82 +    Block *block = blocks_;
   54.83 +    while (block) {
   54.84 +        for (Object **ptr = block->objects; ptr < block->cur; ptr++)
   54.85 +            visitor->visit(ptr);
   54.86 +        block = block->prev;
   54.87 +    }
   54.88 +}
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/src/RootScopes.h	Tue Jul 24 23:53:34 2012 -0700
    55.3 @@ -0,0 +1,106 @@
    55.4 +/* vim: set ts=4 sw=4 tw=99 et:
    55.5 + *
    55.6 + * Copyright (C) 2012 David Anderson
    55.7 + *
    55.8 + * This file is part of JITCraft.
    55.9 + *
   55.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   55.11 + * the terms of the GNU General Public License as published by the Free
   55.12 + * Software Foundation, either version 3 of the License, or (at your option)
   55.13 + * any later version.
   55.14 + * 
   55.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   55.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   55.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   55.18 + *
   55.19 + * You should have received a copy of the GNU General Public License along with
   55.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   55.21 + */
   55.22 +#ifndef _include_jc_root_scopes_h_
   55.23 +#define _include_jc_root_scopes_h_
   55.24 +
   55.25 +#include "../include/keima.h"
   55.26 +#include "Objects.h"
   55.27 +#include "VirtualObjectVisitor.h"
   55.28 +
   55.29 +namespace ke {
   55.30 +
   55.31 +class RootScope;
   55.32 +
   55.33 +// A RootScopeManager is essentially a specialized PoolAllocator that can
   55.34 +// only allocate Object ** entries. It is used to allow huge, temporary
   55.35 +// heap data structures like ASTs to hold safe references to objects. When
   55.36 +// the data structures is no longer needed, all of the roots are removed
   55.37 +// at once.
   55.38 +class RootScopeManager
   55.39 +{
   55.40 +    static const size_t kObjectsPerBlock = 4096;
   55.41 +
   55.42 +    struct Block {
   55.43 +        Object *objects[kObjectsPerBlock];
   55.44 +        Object **cur;
   55.45 +        Object **end;
   55.46 +        Block *prev;
   55.47 +
   55.48 +        Block(Block *prev)
   55.49 +          : cur(objects),
   55.50 +            end(objects + kObjectsPerBlock),
   55.51 +            prev(prev)
   55.52 +        {
   55.53 +        }
   55.54 +    };
   55.55 +
   55.56 +  private:
   55.57 +    bool grow();
   55.58 +    void unwindSlow(Object **position);
   55.59 +
   55.60 +  public:
   55.61 +    RootScopeManager();
   55.62 +    ~RootScopeManager();
   55.63 +
   55.64 +    Object **position() const {
   55.65 +        return blocks_->cur;
   55.66 +    }
   55.67 +
   55.68 +    void unwind(Object **position) {
   55.69 +        if (position >= blocks_->cur && position <= blocks_->end) {
   55.70 +            blocks_->cur = position;
   55.71 +            return;
   55.72 +        }
   55.73 +        unwindSlow(position);
   55.74 +    }
   55.75 +
   55.76 +    Object **make(Object *obj) {
   55.77 +        assert(scope_);
   55.78 +        if (blocks_->cur + 1 > blocks_->end) {
   55.79 +            if (!grow())
   55.80 +                return NULL;
   55.81 +        }
   55.82 +        Object **ptr = blocks_->cur;
   55.83 +        blocks_->cur++;
   55.84 +        *ptr = obj;
   55.85 +        return ptr;
   55.86 +    }
   55.87 +
   55.88 +    Ke::HandleScope **scope() {
   55.89 +        return &scope_;
   55.90 +    }
   55.91 +
   55.92 +    void accept(VirtualObjectVisitor *visitor);
   55.93 +
   55.94 +  private:
   55.95 +    Block *blocks_;
   55.96 +    Block first_;
   55.97 +    Ke::HandleScope *scope_;
   55.98 +};
   55.99 +
  55.100 +class RootScope : public Ke::HandleScope
  55.101 +{
  55.102 +  public:
  55.103 +    // These are implemented in Zone.h.
  55.104 +    inline RootScope(Zone *zone);
  55.105 +};
  55.106 +
  55.107 +}
  55.108 +
  55.109 +#endif // _include_jc_root_scope_h_
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/src/Scanner.cpp	Tue Jul 24 23:53:34 2012 -0700
    56.3 @@ -0,0 +1,576 @@
    56.4 +/*
    56.5 + * Copyright (C) 2012 David Anderson
    56.6 + *
    56.7 + * This file is part of JITCraft.
    56.8 + *
    56.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   56.10 + * the terms of the GNU General Public License as published by the Free
   56.11 + * Software Foundation, either version 3 of the License, or (at your option)
   56.12 + * any later version.
   56.13 + * 
   56.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   56.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   56.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   56.17 + *
   56.18 + * You should have received a copy of the GNU General Public License along with
   56.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   56.20 + */
   56.21 +#include <assert.h>
   56.22 +#include <ctype.h>
   56.23 +#include <math.h>
   56.24 +#include "Scanner.h"
   56.25 +#include "Utility.h"
   56.26 +
   56.27 +using namespace ke;
   56.28 +
   56.29 +const char *ke::TokenNames[] =
   56.30 +{
   56.31 +#define _(name, str) str,
   56.32 +    TOKENMAP(_)
   56.33 +#undef _
   56.34 +    NULL
   56.35 +};
   56.36 +
   56.37 +Scanner::Scanner(CompileContext &cc, const char *stream, size_t length)
   56.38 +  : cc_(cc),
   56.39 +    stream_(stream),
   56.40 +    length_(length),
   56.41 +    pushed_(false),
   56.42 +    saved_('\0'),
   56.43 +    pos_(stream_)
   56.44 +{
   56.45 +    cur_.line = 1;
   56.46 +    cur_.col = 1;
   56.47 +    last_ = cur_;
   56.48 +}
   56.49 +
   56.50 +char
   56.51 +Scanner::getChar()
   56.52 +{
   56.53 +    if (saved_ != '\0') {
   56.54 +        char temp = saved_;
   56.55 +        saved_ = '\0';
   56.56 +        return temp;
   56.57 +    }
   56.58 +    if (pos_ >= stream_ + length_)
   56.59 +        return '\0';
   56.60 +    last_.col = cur_.col++;
   56.61 +    return *pos_++;
   56.62 +}
   56.63 +
   56.64 +void
   56.65 +Scanner::putChar(char c)
   56.66 +{
   56.67 +    assert(saved_ == '\0');
   56.68 +    saved_ = c;
   56.69 +    cur_.col = last_.col;
   56.70 +}
   56.71 +
   56.72 +void
   56.73 +Scanner::calcNewLine(char c)
   56.74 +{
   56.75 +    cur_.line++;
   56.76 +    cur_.col = 1;
   56.77 +    last_ = cur_;
   56.78 +
   56.79 +    char o;
   56.80 +    if (c == '\r' && ((o = getChar()) != '\n'))
   56.81 +        putChar(o);
   56.82 +}
   56.83 +
   56.84 +void
   56.85 +Scanner::eatSingleLine()
   56.86 +{
   56.87 +    char c;
   56.88 +    while ((c = getChar()) != '\0') {
   56.89 +        if (c == '\n' || c == '\r') {
   56.90 +            calcNewLine(c);
   56.91 +            break;
   56.92 +        }
   56.93 +    }
   56.94 +}
   56.95 +
   56.96 +bool
   56.97 +Scanner::eatComment()
   56.98 +{
   56.99 +    char c;
  56.100 +
  56.101 +    while ((c = getChar()) != '\0') {
  56.102 +        while (c == '*') {
  56.103 +            c = getChar();
  56.104 +            if (c == '\0')
  56.105 +                return false;
  56.106 +            if (c == '/')
  56.107 +                return true;
  56.108 +        }
  56.109 +        if (c == '\r' || c == '\n')
  56.110 +            calcNewLine(c);
  56.111 +    }
  56.112 +
  56.113 +    return false;
  56.114 +}
  56.115 +
  56.116 +static inline bool
  56.117 +IsDigit(char c)
  56.118 +{
  56.119 +    return c >= '0' && c <= '9';
  56.120 +}
  56.121 +
  56.122 +// Based off the logic in sc2.c's ftoi()...
  56.123 +double
  56.124 +Scanner::ParseDouble(const char *string)
  56.125 +{
  56.126 +    const char *ptr = string;
  56.127 +
  56.128 +    double number = 0.0;
  56.129 +    while (IsDigit(*ptr)) {
  56.130 +        number = (number * 10) + (*ptr - '0');
  56.131 +        ptr++;
  56.132 +    }
  56.133 +
  56.134 +    assert(*ptr == '.');
  56.135 +    ptr++;
  56.136 +
  56.137 +    double fraction = 0.0;
  56.138 +    double multiplier = 1.0;
  56.139 +    while (IsDigit(*ptr)) {
  56.140 +        fraction = (fraction * 10) + (*ptr - '0');
  56.141 +        multiplier = multiplier / 10.0;
  56.142 +        ptr++;
  56.143 +    }
  56.144 +
  56.145 +    number += fraction * multiplier;
  56.146 +
  56.147 +    if (*ptr++ == 'e') {
  56.148 +        int sign = 1;
  56.149 +        if (*ptr == '-') {
  56.150 +            sign = -1;
  56.151 +            ptr++;
  56.152 +        }
  56.153 +
  56.154 +        int exponent = 0;
  56.155 +        while (IsDigit(*ptr)) {
  56.156 +            exponent = (exponent * 10) + (*ptr - '0');
  56.157 +            ptr++;
  56.158 +        }
  56.159 +
  56.160 +        multiplier = pow(10.0, exponent * sign);
  56.161 +        number *= multiplier;
  56.162 +    }
  56.163 +
  56.164 +    return number;
  56.165 +}
  56.166 +
  56.167 +static inline bool
  56.168 +IsHexDigit(char c)
  56.169 +{
  56.170 +    return IsDigit(c) ||
  56.171 +           (c >= 'a' && c <= 'f') ||
  56.172 +           (c >= 'A' && c <= 'F');
  56.173 +}
  56.174 +
  56.175 +// Based on the logic for litchar() in sc2.c.
  56.176 +int
  56.177 +Scanner::readEscapeCode()
  56.178 +{
  56.179 +    char c = getChar();
  56.180 +    if (c == '\\')
  56.181 +        return c;
  56.182 +
  56.183 +    switch (c) {
  56.184 +      case 'a':
  56.185 +        return '\a';
  56.186 +      case 'b':
  56.187 +        return '\b';
  56.188 +      case 'e':
  56.189 +        return 27;          // Apparently \e is non-standard.
  56.190 +      case 'f':
  56.191 +        return '\f';
  56.192 +      case 'n':
  56.193 +        return '\n';
  56.194 +      case 'r':
  56.195 +        return '\r';
  56.196 +      case 't':
  56.197 +        return '\t';
  56.198 +      case '\v':
  56.199 +        return '\v';
  56.200 +
  56.201 +      case 'x':
  56.202 +      {
  56.203 +          unsigned digits = 0;
  56.204 +          char r = 0;
  56.205 +  
  56.206 +          c = getChar();
  56.207 +          while (IsHexDigit(c) && digits < 2) {
  56.208 +              if (IsDigit(c))
  56.209 +                  c = (c << 4) + (c - '0');
  56.210 +              else
  56.211 +                  c = (c << 4) + (tolower(c) - 'a' + 10);
  56.212 +              digits++;
  56.213 +              c = getChar();
  56.214 +           }
  56.215 +                
  56.216 +          // Swallow a trailing ';'
  56.217 +          if (c != ';')
  56.218 +              putChar(c);
  56.219 +  
  56.220 +          return r;
  56.221 +      }
  56.222 +
  56.223 +      case '\'':
  56.224 +      case '\"':
  56.225 +      case '%':
  56.226 +        return c;
  56.227 +
  56.228 +      default:
  56.229 +      {
  56.230 +        if (IsDigit(c)) {
  56.231 +            // \ddd
  56.232 +            char r = 0;
  56.233 +            while (IsDigit(c)) {
  56.234 +                r = r * 10 + (c - '0');
  56.235 +                c = getChar();
  56.236 +            }
  56.237 +
  56.238 +            // Swallow a trailing ;
  56.239 +            if (c != ';')
  56.240 +                putChar(c);
  56.241 +
  56.242 +            return r;
  56.243 +        }
  56.244 +        cc_.reportError(begin(), Message_UnknownEscapeCode, c);
  56.245 +        return INT_MAX;
  56.246 +      }
  56.247 +    }
  56.248 +}
  56.249 +
  56.250 +TokenKind
  56.251 +Scanner::stringLiteral()
  56.252 +{
  56.253 +    literal_.clear();
  56.254 +
  56.255 +    for (;;) {
  56.256 +        char c = getChar();
  56.257 +        if (c == '\"')
  56.258 +            break;
  56.259 +        if (c == '\r' || c == '\n' || c == '\0') {
  56.260 +            cc_.reportError(begin(), Message_UnterminatedString);
  56.261 +            return TOK_ERROR;
  56.262 +        }
  56.263 +        if (c == '\\') {
  56.264 +            int code = readEscapeCode();
  56.265 +            if (code == INT_MAX)
  56.266 +                return TOK_ERROR;
  56.267 +            c = char(code);
  56.268 +        }
  56.269 +        literal_ += c;
  56.270 +    }
  56.271 +
  56.272 +    return TOK_STRING_LITERAL;
  56.273 +}
  56.274 +
  56.275 +TokenKind
  56.276 +Scanner::numberLiteral(char first)
  56.277 +{
  56.278 +    literal_ = first;
  56.279 +
  56.280 +    char c;
  56.281 +    for (;;) {
  56.282 +        c = getChar();
  56.283 +        if (!IsDigit(c))
  56.284 +            break;
  56.285 +        literal_ += c;
  56.286 +    }
  56.287 +
  56.288 +    if (c != '.') {
  56.289 +        putChar(c);
  56.290 +        return TOK_INTEGER_LITERAL;
  56.291 +    }
  56.292 +    literal_ += c;
  56.293 +
  56.294 +    c = getChar();
  56.295 +    if (!IsDigit(c)) {
  56.296 +        cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
  56.297 +        return TOK_ERROR;
  56.298 +    }
  56.299 +    literal_ += c;
  56.300 +
  56.301 +    for (;;) {
  56.302 +        c = getChar();
  56.303 +        if (!IsDigit(c))
  56.304 +            break;
  56.305 +        literal_ += c;
  56.306 +    }
  56.307 +
  56.308 +    if (c != 'e') {
  56.309 +        putChar(c);
  56.310 +    } else {
  56.311 +        literal_ += c;
  56.312 +        c = getChar();
  56.313 +        if (c == '-') {
  56.314 +            literal_ += c;
  56.315 +            c = getChar();
  56.316 +        }
  56.317 +        if (!IsDigit(c)) {
  56.318 +            cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
  56.319 +            return TOK_ERROR;
  56.320 +        }
  56.321 +        literal_ += c;
  56.322 +        for (;;) {
  56.323 +            c = getChar();
  56.324 +            if (!IsDigit(c)) {
  56.325 +                putChar(c);
  56.326 +                break;
  56.327 +            }
  56.328 +            literal_ += c;
  56.329 +        }
  56.330 +    }
  56.331 +
  56.332 +    return TOK_FLOAT_LITERAL;
  56.333 +}
  56.334 +
  56.335 +TokenKind
  56.336 +Scanner::identifier(char first)
  56.337 +{
  56.338 +    literal_ = first;
  56.339 +
  56.340 +    char c;
  56.341 +    for (;;) {
  56.342 +        c = getChar();
  56.343 +        if (!isascii(c) || (!isalnum(c) && c != '_')) {
  56.344 +            if (c != ':')
  56.345 +                putChar(c);
  56.346 +            break;
  56.347 +        }
  56.348 +        literal_ += c;
  56.349 +    }
  56.350 +
  56.351 +    if (literal_ == "new")
  56.352 +        return TOK_NEW;
  56.353 +    if (literal_ == "for")
  56.354 +        return TOK_FOR;
  56.355 +    if (literal_ == "return")
  56.356 +        return TOK_RETURN;
  56.357 +    if (literal_ == "if")
  56.358 +        return TOK_IF;
  56.359 +    if (literal_ == "else")
  56.360 +        return TOK_ELSE;
  56.361 +    if (literal_ == "enum")
  56.362 +        return TOK_ENUM;
  56.363 +    if (literal_ == "while")
  56.364 +        return TOK_WHILE;
  56.365 +    if (literal_ == "do")
  56.366 +        return TOK_DO;
  56.367 +    if (literal_ == "break")
  56.368 +        return TOK_BREAK;
  56.369 +    if (literal_ == "continue")
  56.370 +        return TOK_CONTINUE;
  56.371 +    if (literal_ == "forward")
  56.372 +        return TOK_FORWARD;
  56.373 +    if (literal_ == "public")
  56.374 +        return TOK_PUBLIC;
  56.375 +    if (literal_ == "const")
  56.376 +        return TOK_CONST;
  56.377 +    if (literal_ == "native")
  56.378 +        return TOK_NATIVE;
  56.379 +    return (c == ':') ? TOK_LABEL : TOK_NAME;
  56.380 +}
  56.381 +
  56.382 +TokenKind
  56.383 +Scanner::next()
  56.384 +{
  56.385 +    assert(!pushed_);
  56.386 +
  56.387 +    for (;;) {
  56.388 +        begin_ = cur_;
  56.389 +
  56.390 +        char c = getChar();
  56.391 +        switch (c) {
  56.392 +          case '/':
  56.393 +          {
  56.394 +            c = getChar();
  56.395 +            if (c == '/') {
  56.396 +                eatSingleLine();
  56.397 +                break;
  56.398 +            }
  56.399 +            if (c == '*') {
  56.400 +                if (!eatComment()) {
  56.401 +                    cc_.reportError(begin(), Message_UnterminatedComment);
  56.402 +                    return TOK_ERROR;
  56.403 +                }
  56.404 +                break;
  56.405 +            }
  56.406 +            putChar(c);
  56.407 +            return TOK_SLASH;
  56.408 +          }
  56.409 +
  56.410 +          case '\n':
  56.411 +          case '\r':
  56.412 +            calcNewLine(c);
  56.413 +            break;
  56.414 +
  56.415 +          case ';': return TOK_SEMICOLON;
  56.416 +          case '{': return TOK_LBRACE;
  56.417 +          case '}': return TOK_RBRACE;
  56.418 +          case '(': return TOK_LPAREN;
  56.419 +          case ')': return TOK_RPAREN;
  56.420 +          case '[': return TOK_LBRACKET;
  56.421 +          case ']': return TOK_RBRACKET;
  56.422 +          case '~': return TOK_TILDE;
  56.423 +          case '?': return TOK_QMARK;
  56.424 +          case ':': return TOK_COLON;
  56.425 +
  56.426 +          case '.':
  56.427 +            c = getChar();
  56.428 +            if (c == '.') {
  56.429 +                c = getChar();
  56.430 +                if (c == '.')
  56.431 +                    return TOK_ELLIPSES;
  56.432 +            }
  56.433 +            cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
  56.434 +            return TOK_ERROR;
  56.435 +
  56.436 +          case '*':
  56.437 +            c = getChar();
  56.438 +            if (c == '=')
  56.439 +                return TOK_ASSIGN_MUL;
  56.440 +            putChar(c);
  56.441 +            return TOK_STAR;
  56.442 +
  56.443 +          case '+':
  56.444 +            c = getChar();
  56.445 +            if (c == '=')
  56.446 +                return TOK_ASSIGN_ADD;
  56.447 +            if (c == '+')
  56.448 +                return TOK_INCREMENT;
  56.449 +            putChar(c);
  56.450 +            return TOK_PLUS;
  56.451 +
  56.452 +          case '&':
  56.453 +            c = getChar();
  56.454 +            if (c == '=')
  56.455 +                return TOK_ASSIGN_BITAND;
  56.456 +            if (c == '&')
  56.457 +                return TOK_AND;
  56.458 +            putChar(c);
  56.459 +            return TOK_BITAND;
  56.460 +
  56.461 +          case '|':
  56.462 +            c = getChar();
  56.463 +            if (c == '=')
  56.464 +                return TOK_ASSIGN_BITOR;
  56.465 +            if (c == '|')
  56.466 +                return TOK_OR;
  56.467 +            putChar(c);
  56.468 +            return TOK_BITOR;
  56.469 +
  56.470 +          case '^':
  56.471 +            c = getChar();
  56.472 +            if (c == '=')
  56.473 +                return TOK_ASSIGN_BITXOR;
  56.474 +            putChar(c);
  56.475 +            return TOK_BITXOR;
  56.476 +
  56.477 +          case '%':
  56.478 +            c = getChar();
  56.479 +            if (c == '=')
  56.480 +                return TOK_ASSIGN_MOD;
  56.481 +            putChar(c);
  56.482 +            return TOK_PERCENT;
  56.483 +
  56.484 +          case '-':
  56.485 +            c = getChar();
  56.486 +            if (c == '=')
  56.487 +                return TOK_ASSIGN_SUB;
  56.488 +            if (c == '-')
  56.489 +                return TOK_DECREMENT;
  56.490 +            putChar(c);
  56.491 +            return TOK_MINUS;
  56.492 +
  56.493 +          case ',': return TOK_COMMA;
  56.494 +          case '\0': return TOK_EOF;
  56.495 +
  56.496 +          case '!':
  56.497 +            c = getChar();
  56.498 +            if (c == '=')
  56.499 +                return TOK_NOTEQUALS;
  56.500 +            putChar(c);
  56.501 +            return TOK_NOT;
  56.502 +
  56.503 +          case '=':
  56.504 +            c = getChar();
  56.505 +            if (c == '=')
  56.506 +                return TOK_EQUALS;
  56.507 +            putChar(c);
  56.508 +            return TOK_ASSIGN;
  56.509 +
  56.510 +          case '<':
  56.511 +            c = getChar();
  56.512 +            if (c == '=')
  56.513 +                return TOK_LE;
  56.514 +            if (c == '<') {
  56.515 +                c = getChar();
  56.516 +                if (c == '=')
  56.517 +                    return TOK_ASSIGN_SHL;
  56.518 +                return TOK_SHL;
  56.519 +            }
  56.520 +            putChar(c);
  56.521 +            return TOK_LT;
  56.522 +
  56.523 +          case '>':
  56.524 +            c = getChar();
  56.525 +            if (c == '=')
  56.526 +                return TOK_GE;
  56.527 +            if (c == '>') {
  56.528 +                c = getChar();
  56.529 +                if (c == '>') {
  56.530 +                    c = getChar();
  56.531 +                    if (c == '=')
  56.532 +                        return TOK_ASSIGN_USHR;
  56.533 +                    putChar(c);
  56.534 +                    return TOK_USHR;
  56.535 +                }
  56.536 +                return TOK_SHR;
  56.537 +            }
  56.538 +            putChar(c);
  56.539 +            return TOK_GT;
  56.540 +
  56.541 +          case ' ':
  56.542 +          case '\t':
  56.543 +          case '\f':
  56.544 +            break;
  56.545 +
  56.546 +          case '"':
  56.547 +            return stringLiteral();
  56.548 +
  56.549 +          default:
  56.550 +            if (c >= '0' && c <= '9')
  56.551 +                return numberLiteral(c);
  56.552 +            if (c == '_' || (isascii(c) && isalpha(c)))
  56.553 +                return identifier(c);
  56.554 +            cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
  56.555 +            return TOK_ERROR;
  56.556 +        }
  56.557 +    }
  56.558 +}
  56.559 +
  56.560 +TokenKind
  56.561 +Scanner::scan()
  56.562 +{
  56.563 +    if (pushed_) {
  56.564 +        pushed_ = false;
  56.565 +        return lastToken_;
  56.566 +    }
  56.567 +    lastToken_ = next();
  56.568 +    return lastToken_;
  56.569 +}
  56.570 +
  56.571 +TokenKind
  56.572 +Scanner::peek()
  56.573 +{
  56.574 +    if (pushed_)
  56.575 +        return lastToken_;
  56.576 +    scan();
  56.577 +    pushed_ = true;
  56.578 +    return lastToken_;
  56.579 +}
    57.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.2 +++ b/src/Scanner.h	Tue Jul 24 23:53:34 2012 -0700
    57.3 @@ -0,0 +1,81 @@
    57.4 +/*
    57.5 + * Copyright (C) 2012 David Anderson
    57.6 + *
    57.7 + * This file is part of JITCraft.
    57.8 + *
    57.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   57.10 + * the terms of the GNU General Public License as published by the Free
   57.11 + * Software Foundation, either version 3 of the License, or (at your option)
   57.12 + * any later version.
   57.13 + * 
   57.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   57.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   57.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   57.17 + *
   57.18 + * You should have received a copy of the GNU General Public License along with
   57.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   57.20 + */
   57.21 +#ifndef _include_jitcraft_scanner_h_
   57.22 +#define _include_jitcraft_scanner_h_
   57.23 +
   57.24 +#include <string>
   57.25 +#include "Token.h"
   57.26 +#include "CompileContext.h"
   57.27 +
   57.28 +namespace ke {
   57.29 +
   57.30 +class Scanner
   57.31 +{
   57.32 +    CompileContext &cc_;
   57.33 +    const char *stream_;
   57.34 +    size_t length_;
   57.35 +    bool pushed_;
   57.36 +    char saved_;
   57.37 +    const char *pos_;
   57.38 +    std::string literal_;
   57.39 +    TokenKind lastToken_;
   57.40 +    SourcePosition last_;
   57.41 +    SourcePosition cur_;
   57.42 +    SourcePosition begin_;
   57.43 +
   57.44 +  private:
   57.45 +    char getChar();
   57.46 +    void putChar(char c);
   57.47 +    void eatSingleLine();
   57.48 +    bool eatComment();
   57.49 +    void calcNewLine(char c);
   57.50 +    int readEscapeCode();
   57.51 +    TokenKind stringLiteral();
   57.52 +    TokenKind numberLiteral(char first);
   57.53 +    TokenKind identifier(char first);
   57.54 +
   57.55 +    TokenKind next();
   57.56 +
   57.57 +  public:
   57.58 +    Scanner(CompileContext &cc, const char *stream, size_t length);
   57.59 +
   57.60 +    static double ParseDouble(const char *string);
   57.61 +
   57.62 +    TokenKind scan();
   57.63 +    TokenKind peek();
   57.64 +    TokenKind last() const {
   57.65 +        return lastToken_;
   57.66 +    }
   57.67 +
   57.68 +    // Beginning source position of the last instruction.
   57.69 +    SourcePosition begin() const {
   57.70 +        return begin_;
   57.71 +    }
   57.72 +
   57.73 +    // Note: the literal may have embedded NUL characters.
   57.74 +    const char *literal() const {
   57.75 +        return literal_.c_str();
   57.76 +    }
   57.77 +    size_t literal_length() const {
   57.78 +        return literal_.size();
   57.79 +    }
   57.80 +};
   57.81 +
   57.82 +} // namespace ke
   57.83 +
   57.84 +#endif // _include_jitcraft_scanner_h_
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/src/Scopes.cpp	Tue Jul 24 23:53:34 2012 -0700
    58.3 @@ -0,0 +1,273 @@
    58.4 +/* vim: set ts=4 sw=4 tw=99 et:
    58.5 + *
    58.6 + * Copyright (C) 2012 David Anderson
    58.7 + *
    58.8 + * This file is part of JITCraft.
    58.9 + *
   58.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   58.11 + * the terms of the GNU General Public License as published by the Free
   58.12 + * Software Foundation, either version 3 of the License, or (at your option)
   58.13 + * any later version.
   58.14 + * 
   58.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   58.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   58.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   58.18 + *
   58.19 + * You should have received a copy of the GNU General Public License along with
   58.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   58.21 + */
   58.22 +#include "Scopes.h"
   58.23 +#include "Zone.h"
   58.24 +#include "Types.h"
   58.25 +#include "TypeManager.h"
   58.26 +#include "Strings.h"
   58.27 +#include "CompileContext.h"
   58.28 +#include "Environments.h"
   58.29 +
   58.30 +using namespace ke;
   58.31 +
   58.32 +Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
   58.33 +  : pool_(pool),
   58.34 +    locals_(0),
   58.35 +    maxContainedLocals_(0),
   58.36 +    numFunctions_(0),
   58.37 +    numNatives_(0),
   58.38 +    lifoSlot_(NULL),
   58.39 +    kind_(kind),
   58.40 +    enclosing_(enclosing)
   58.41 +{
   58.42 +}
   58.43 +
   58.44 +bool
   58.45 +Scope::initialize()
   58.46 +{
   58.47 +    if (enclosing_ && !enclosing_->children_.append(this))
   58.48 +        return false;
   58.49 +    return true;
   58.50 +}
   58.51 +
   58.52 +void
   58.53 +Scope::unlink()
   58.54 +{
   58.55 +    assert(empty());
   58.56 +
   58.57 +    assert(enclosing_->children_[enclosing_->children_.length() - 1] == this);
   58.58 +    enclosing_->children_.pop();
   58.59 +
   58.60 +    // OOM here is swallowed and checked after compilation.
   58.61 +    // :TODO: make the above true.
   58.62 +    for (size_t i = 0; i < children_.length(); i++)
   58.63 +        enclosing_->children_.append(children_[i]);
   58.64 +}
   58.65 +
   58.66 +Scope *
   58.67 +Scope::unlinkIfEmpty()
   58.68 +{
   58.69 +    if (empty()) {
   58.70 +        unlink();
   58.71 +        return NULL;
   58.72 +    }
   58.73 +    return this;
   58.74 +}
   58.75 +
   58.76 +BoundName *
   58.77 +Scope::localLookup(Handle<String> name)
   58.78 +{
   58.79 +    for (size_t i = 0; i < names_.length(); i++) {
   58.80 +        if (names_[i]->name() == name)
   58.81 +            return names_[i];
   58.82 +    }
   58.83 +    return NULL;
   58.84 +}
   58.85 +
   58.86 +BoundName *
   58.87 +Scope::lookup(Handle<String> name)
   58.88 +{
   58.89 +    for (Scope *scope = this; scope; scope = scope->enclosing()) {
   58.90 +        if (BoundName *bound = scope->localLookup(name))
   58.91 +            return bound;
   58.92 +    }
   58.93 +    return NULL;
   58.94 +}
   58.95 +
   58.96 +Variable *
   58.97 +Scope::declareVariable(Handle<String> name, const SourcePosition &pos)
   58.98 +{
   58.99 +    assert(!localLookup(name));
  58.100 +    
  58.101 +    Variable *var = new (pool_) Variable(this, name, pos);
  58.102 +    if (!names_.append(var))
  58.103 +        return NULL;
  58.104 +    return var;
  58.105 +}
  58.106 +
  58.107 +Variable *
  58.108 +Scope::declareArgument(Handle<String> name, const SourcePosition &pos)
  58.109 +{
  58.110 +    assert(kind() == FUNCTION);
  58.111 +    Variable *var = declareVariable(name, pos);
  58.112 +    if (!names_.append(var))
  58.113 +        return NULL;
  58.114 +    if (!parameters_.append(var))
  58.115 +        return NULL;
  58.116 +    return var;
  58.117 +}
  58.118 +
  58.119 +NamedFunction *
  58.120 +Scope::declareFunction(Handle<String> name, const SourcePosition &pos, TokenKind token)
  58.121 +{
  58.122 +    assert(!localLookup(name));
  58.123 +    assert(kind() == GLOBAL);
  58.124 +
  58.125 +    NamedFunction *fun = new (pool_) NamedFunction(this, name, pos, token);
  58.126 +    if (!names_.append(fun))
  58.127 +        return NULL;
  58.128 +    return fun;
  58.129 +}
  58.130 +
  58.131 +NamedEnum *
  58.132 +Scope::declareEnum(Handle<String> name, const SourcePosition &pos)
  58.133 +{
  58.134 +    NamedEnum *e = new (pool_) NamedEnum(this, name, pos);
  58.135 +    if (!names_.append(e))
  58.136 +        return NULL;
  58.137 +    return e;
  58.138 +}
  58.139 +
  58.140 +NamedConstant *
  58.141 +Scope::declareConstant(Handle<String> name, const SourcePosition &pos)
  58.142 +{
  58.143 +    NamedConstant *constant = new (pool_) NamedConstant(this, name, pos);
  58.144 +    if (!names_.append(constant))
  58.145 +        return NULL;
  58.146 +    return constant;
  58.147 +}
  58.148 +
  58.149 +void
  58.150 +Scope::allocateGlobals()
  58.151 +{
  58.152 +    assert(kind() == GLOBAL);
  58.153 +
  58.154 +    for (size_t i = 0; i < children_.length(); i++) {
  58.155 +        assert(children_[i]->kind() == FUNCTION);
  58.156 +        children_[i]->allocate();
  58.157 +    }
  58.158 +
  58.159 +    Local<Type> type(ZONE());
  58.160 +    for (size_t i = 0; i < names_.length(); i++) {
  58.161 +        BoundName *name = names_[i];
  58.162 +        
  58.163 +        if (name->kind() == BoundName::FUNCTION) {
  58.164 +            NamedFunction *fun = name->toNamedFunction();
  58.165 +            if (fun->isNative())
  58.166 +                fun->allocate(numNatives_++);
  58.167 +            else
  58.168 +                fun->allocate(numFunctions_++);
  58.169 +        } else if (name->kind() == BoundName::VARIABLE) {
  58.170 +            allocate(name->toVariable());
  58.171 +        }
  58.172 +    }
  58.173 +}
  58.174 +
  58.175 +void
  58.176 +Scope::allocate(Variable *var)
  58.177 +{
  58.178 +    if (!var->unallocated())
  58.179 +        return;
  58.180 +
  58.181 +    if (kind() == GLOBAL) {
  58.182 +        var->allocate(Variable::ENVIRONMENT, envVars_.length());
  58.183 +        envVars_.append(var);
  58.184 +    } else {
  58.185 +        var->allocate(Variable::STACK, maxContainedLocals_ + locals_);
  58.186 +        locals_++;
  58.187 +    }
  58.188 +}
  58.189 +
  58.190 +void
  58.191 +Scope::allocate()
  58.192 +{
  58.193 +    maxContainedLocals_ = 0;
  58.194 +    for (size_t i = 0; i < children_.length(); i++) {
  58.195 +        Scope *scope = children_[i];
  58.196 +        scope->allocate();
  58.197 +        if (scope->maxContainedLocals() > maxContainedLocals_)
  58.198 +            maxContainedLocals_ = scope->maxContainedLocals();
  58.199 +    }
  58.200 +
  58.201 +    for (size_t i = 0; i < parameters_.length(); i++)
  58.202 +        parameters_[i]->allocate(Variable::PARAMETER, i);
  58.203 +
  58.204 +    if (lifoSlot_)
  58.205 +        allocate(lifoSlot_);
  58.206 +    for (size_t i = 0; i < names_.length(); i++) {
  58.207 +        if (names_[i]->kind() != BoundName::VARIABLE)
  58.208 +            continue;
  58.209 +
  58.210 +        allocate(names_[i]->toVariable());
  58.211 +    }
  58.212 +
  58.213 +    maxContainedLocals_ += locals_;
  58.214 +}
  58.215 +
  58.216 +bool
  58.217 +Scope::Bind(CompileContext &cc, ParseTree *tree)
  58.218 +{
  58.219 +    Local<String> name(ZONE());
  58.220 +    for (size_t i = 0; i < tree->unbound()->length(); i++) {
  58.221 +        NameProxy *proxy = tree->unbound()->at(i);
  58.222 +        name = proxy->name();
  58.223 +        BoundName *binding = tree->scope()->lookup(name);
  58.224 +
  58.225 +        if (!binding) {
  58.226 +            cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars());
  58.227 +            return false;
  58.228 +        }
  58.229 +
  58.230 +        // We only allow global functions to be late-bound.
  58.231 +        if (binding->kind() != BoundName::FUNCTION ||
  58.232 +            binding->scope()->kind() != Scope::GLOBAL)
  58.233 +        {
  58.234 +            cc.reportError(proxy->pos(), Message_IdentifierNotFound, name->chars());
  58.235 +            return false;
  58.236 +        }
  58.237 +
  58.238 +        proxy->bind(binding);
  58.239 +    }
  58.240 +    return true;
  58.241 +}
  58.242 +
  58.243 +void
  58.244 +Scope::Allocate(ParseTree *tree)
  58.245 +{
  58.246 +    tree->scope()->allocateGlobals();
  58.247 +}
  58.248 +
  58.249 +void
  58.250 +Scope::setUsesLifoHeap()
  58.251 +{
  58.252 +    // Only one lifo slot is needed per scope.
  58.253 +    if (lifoSlot_)
  58.254 +        return;
  58.255 +
  58.256 +    // If the parent of this scope is the function scope, then this is the
  58.257 +    // function's block scope, and the lifo slot is part of the Frame instead.
  58.258 +    // Note we can get a function scope here if we're making a temporary in a
  58.259 +    // function with no local variables.
  58.260 +    if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
  58.261 +        return;
  58.262 +
  58.263 +    Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
  58.264 +    if (!type)
  58.265 +        return;
  58.266 +
  58.267 +    Local<String> name(ZONE());
  58.268 +    lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
  58.269 +    lifoSlot_->setType(type);
  58.270 +}
  58.271 +
  58.272 +EnvironmentMap *
  58.273 +Scope::createEnvironmentMap(Zone *zone)
  58.274 +{
  58.275 +    return EnvironmentMap::New(zone, envVars_.length(), envVars_.buffer());
  58.276 +}
    59.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.2 +++ b/src/Scopes.h	Tue Jul 24 23:53:34 2012 -0700
    59.3 @@ -0,0 +1,119 @@
    59.4 +/*
    59.5 + * Copyright (C) 2012 David Anderson
    59.6 + *
    59.7 + * This file is part of JITCraft.
    59.8 + *
    59.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   59.10 + * the terms of the GNU General Public License as published by the Free
   59.11 + * Software Foundation, either version 3 of the License, or (at your option)
   59.12 + * any later version.
   59.13 + * 
   59.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   59.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   59.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   59.17 + *
   59.18 + * You should have received a copy of the GNU General Public License along with
   59.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   59.20 + */
   59.21 +#ifndef _include_jitcraft_scopes_h_
   59.22 +#define _include_jitcraft_scopes_h_
   59.23 +
   59.24 +#include "PoolAllocator.h"
   59.25 +#include "AST.h"
   59.26 +#include "NameBinding.h"
   59.27 +#include "Structures.h"
   59.28 +
   59.29 +namespace ke {
   59.30 +
   59.31 +class CompileContext;
   59.32 +class EnvironmentMap;
   59.33 +
   59.34 +class Scope : public PoolObject
   59.35 +{
   59.36 +    PoolAllocator &pool_;
   59.37 +    PoolList<BoundName *> names_;
   59.38 +    PoolList<Scope *> children_;
   59.39 +    PoolList<Variable *> parameters_;
   59.40 +    unsigned locals_;
   59.41 +    unsigned maxContainedLocals_;
   59.42 +    unsigned numFunctions_;
   59.43 +    unsigned numNatives_;
   59.44 +    PoolList<Variable *> envVars_;
   59.45 +    Variable *lifoSlot_;
   59.46 +    
   59.47 +    bool empty() const {
   59.48 +        return names_.length() == 0;
   59.49 +    }
   59.50 +    void unlink();
   59.51 +
   59.52 +  public:
   59.53 +    enum Kind {
   59.54 +        GLOBAL,
   59.55 +        FUNCTION,
   59.56 +        BLOCK
   59.57 +    };
   59.58 +
   59.59 +  public:
   59.60 +    Scope(PoolAllocator &pool, Kind kind, Scope *enclosing);
   59.61 +    bool initialize();
   59.62 +
   59.63 +    Kind kind() const {
   59.64 +        return kind_;
   59.65 +    }
   59.66 +    Scope *enclosing() const {
   59.67 +        return enclosing_;
   59.68 +    }
   59.69 +    unsigned locals() const {
   59.70 +        return locals_;
   59.71 +    }
   59.72 +    unsigned maxContainedLocals() const {
   59.73 +        return maxContainedLocals_;
   59.74 +    }
   59.75 +    unsigned numFunctions() const {
   59.76 +        return numFunctions_;
   59.77 +    }
   59.78 +    unsigned numNatives() const {
   59.79 +        return numNatives_;
   59.80 +    }
   59.81 +    unsigned numArguments() const {
   59.82 +        return parameters_.length();
   59.83 +    }
   59.84 +    unsigned numEnvironmentVars() const {
   59.85 +        return envVars_.length();
   59.86 +    }
   59.87 +    Variable *getArgument(size_t index) {
   59.88 +        return parameters_[index];
   59.89 +    }
   59.90 +    Variable *lifoSlot() {
   59.91 +        return lifoSlot_;
   59.92 +    }
   59.93 +    void setUsesLifoHeap();
   59.94 +
   59.95 +    Scope *unlinkIfEmpty();
   59.96 +    BoundName *localLookup(Handle<String> name);
   59.97 +    BoundName *lookup(Handle<String> name);
   59.98 +
   59.99 +    NamedFunction *declareFunction(Handle<String> name, const SourcePosition &pos, TokenKind token);
  59.100 +    Variable *declareVariable(Handle<String> name, const SourcePosition &pos);
  59.101 +    Variable *declareArgument(Handle<String> name, const SourcePosition &pos);
  59.102 +    NamedEnum *declareEnum(Handle<String> name, const SourcePosition &pos);
  59.103 +    NamedConstant *declareConstant(Handle<String> name, const SourcePosition &pos);
  59.104 +
  59.105 +    EnvironmentMap *createEnvironmentMap(Zone *zone);
  59.106 +
  59.107 +    void allocate(Variable *var);
  59.108 +    void allocate();
  59.109 +    void allocateGlobals();
  59.110 +
  59.111 +  public:
  59.112 +    static bool Bind(CompileContext &cc, ParseTree *tree);
  59.113 +    static void Allocate(ParseTree *tree);
  59.114 +
  59.115 +  private:
  59.116 +    Kind kind_;
  59.117 +    Scope *enclosing_;
  59.118 +};
  59.119 +
  59.120 +}
  59.121 +
  59.122 +#endif // _include_jitcraft_scopes_h_
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/src/SemanticAnalysis.cpp	Tue Jul 24 23:53:34 2012 -0700
    60.3 @@ -0,0 +1,1092 @@
    60.4 +/* vim: set ts=4 sw=4 tw=99 et:
    60.5 + *
    60.6 + * Copyright (C) 2012 David Anderson
    60.7 + *
    60.8 + * This file is part of JITCraft.
    60.9 + *
   60.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   60.11 + * the terms of the GNU General Public License as published by the Free
   60.12 + * Software Foundation, either version 3 of the License, or (at your option)
   60.13 + * any later version.
   60.14 + * 
   60.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   60.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   60.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   60.18 + *
   60.19 + * You should have received a copy of the GNU General Public License along with
   60.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   60.21 + */
   60.22 +#include "SemanticAnalysis.h"
   60.23 +#include "Types.h"
   60.24 +#include "Zone.h"
   60.25 +#include "TypeManager.h"
   60.26 +#include "Scopes.h"
   60.27 +#include "NameBinding.h"
   60.28 +#include "Heap-inl.h"
   60.29 +#include "Strings.h"
   60.30 +
   60.31 +using namespace ke;
   60.32 +
   60.33 +static inline bool
   60.34 +IsPrimitiveType(Type *type, PrimitiveType primitive)
   60.35 +{
   60.36 +    if (!type)
   60.37 +        return false;
   60.38 +
   60.39 +    if (!type->isPrimitive())
   60.40 +        return false;
   60.41 +
   60.42 +    return primitive == type->primitive();
   60.43 +}
   60.44 +
   60.45 +static inline bool
   60.46 +EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
   60.47 +                        BoxedPrimitive *out)
   60.48 +{
   60.49 +    switch (kind) {
   60.50 +      case TOK_PLUS:
   60.51 +        *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
   60.52 +        return true;
   60.53 +
   60.54 +      case TOK_SHL:
   60.55 +        *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
   60.56 +        return true;
   60.57 +
   60.58 +      default:
   60.59 +        return false;
   60.60 +    }
   60.61 +}
   60.62 +
   60.63 +static bool
   60.64 +EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
   60.65 +{
   60.66 +    switch (expression->kind()) {
   60.67 +      case AstNode::kBinaryExpression:
   60.68 +      {
   60.69 +        BoxedPrimitive left;
   60.70 +        BoxedPrimitive right;
   60.71 +        BinaryExpression *b = expression->toBinaryExpression();
   60.72 +        if (!EvaluateForConstant(b->left(), &left) ||
   60.73 +            !EvaluateForConstant(b->right(), &right))
   60.74 +        {
   60.75 +            return false;
   60.76 +        }
   60.77 +        return EvaluateBinaryOperation(b->token(), left, right, out);
   60.78 +      }
   60.79 +
   60.80 +      case AstNode::kNameProxy:
   60.81 +      {
   60.82 +        NameProxy *proxy = expression->toNameProxy();
   60.83 +        if (proxy->binding()->kind() != BoundName::CONSTANT)
   60.84 +            return false;
   60.85 +
   60.86 +        NamedConstant *c = proxy->binding()->toNamedConstant();
   60.87 +        if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
   60.88 +            return false;
   60.89 +
   60.90 +        *out = c->value();
   60.91 +        return true;
   60.92 +      }
   60.93 +
   60.94 +      case AstNode::kIntegerLiteral:
   60.95 +        *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
   60.96 +        return true;
   60.97 +
   60.98 +      default:
   60.99 +        return false;
  60.100 +    }
  60.101 +}
  60.102 +
  60.103 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
  60.104 +  : zone_(zone),
  60.105 +    cc_(cc),
  60.106 +    tree_(tree),
  60.107 +    scope_(NULL),
  60.108 +    loop_(NULL)
  60.109 +{
  60.110 +}
  60.111 +
  60.112 +bool
  60.113 +SemanticAnalysis::analyze()
  60.114 +{
  60.115 +    if (cc_.failures())
  60.116 +        return false;
  60.117 +
  60.118 +    scope_ = tree_->scope();
  60.119 +
  60.120 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  60.121 +        Statement *statement = tree_->statements()->at(i);
  60.122 +        if (statement->isFunctionStatement()) {
  60.123 +            FunctionStatement *funstmt = statement->toFunctionStatement();
  60.124 +            if (!preanalyze(funstmt))
  60.125 +                return false;
  60.126 +        }
  60.127 +    }
  60.128 +
  60.129 +    for (size_t i = 0; i < tree_->statements()->length(); i++) {
  60.130 +        Statement *statement = tree_->statements()->at(i);
  60.131 +        statement->accept(this);
  60.132 +    }
  60.133 +
  60.134 +    return !cc_.failures();
  60.135 +}
  60.136 +
  60.137 +Type *
  60.138 +SemanticAnalysis::visitAndApplyType(Expression *expression)
  60.139 +{
  60.140 +    expression->accept(this);
  60.141 +    return expression->type();
  60.142 +}
  60.143 +
  60.144 +Type *
  60.145 +SemanticAnalysis::visitForLoad(Expression *expression)
  60.146 +{
  60.147 +    Local<Type> type(zone_, visitAndApplyType(expression));
  60.148 +    if (!type)
  60.149 +        return NULL;
  60.150 +
  60.151 +    if (type->isReference()) {
  60.152 +        expression->setType(type->contained());
  60.153 +    } else if (expression->isIndexExpression()) {
  60.154 +        if (type->isArray())
  60.155 +            expression->setType(type->contained());
  60.156 +    } else if (expression->isCallExpression()) {
  60.157 +        if (type->isVoid()) {
  60.158 +            CallExpression *call = expression->toCallExpression();
  60.159 +            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
  60.160 +            return NULL;
  60.161 +        }
  60.162 +    }
  60.163 +
  60.164 +    return expression->type();
  60.165 +}
  60.166 +
  60.167 +// :TODO: this leaks an interior pointer.
  60.168 +static inline const char *
  60.169 +GetTypeName(Type *type)
  60.170 +{
  60.171 +    if (type->isArray())
  60.172 +        return "array";
  60.173 +    if (type->isFunction())
  60.174 +        return "function";
  60.175 +    if (type->isReference())
  60.176 +        type = type->contained();
  60.177 +    if (type->tag())
  60.178 +        return type->tag()->chars();
  60.179 +    return "int";
  60.180 +}
  60.181 +
  60.182 +void
  60.183 +SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type)
  60.184 +{
  60.185 +    const char *op = TokenNames[token];
  60.186 +    const char *name = GetTypeName(type);
  60.187 +
  60.188 +    cc_.reportError(node->pos(), Message_UnaryTypeError, op, name);
  60.189 +}
  60.190 +
  60.191 +void
  60.192 +SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
  60.193 +{
  60.194 +    const char *op = TokenNames[token];
  60.195 +    const char *leftName = GetTypeName(left);
  60.196 +    const char *rightName = GetTypeName(right);
  60.197 +
  60.198 +    cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName);
  60.199 +}
  60.200 +
  60.201 +Type *
  60.202 +SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
  60.203 +{
  60.204 +    if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
  60.205 +        (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
  60.206 +    {
  60.207 +        // If either side is a float, the other side must be a float or int.
  60.208 +        if (left->isFloat() || right->isFloat()) {
  60.209 +            Type *floatType = left->isFloat() ? left : right;
  60.210 +            Type *other = left->isFloat() ? right : left;
  60.211 +            if (other->isFloat() || (other->isInt32() && !other->tag()))
  60.212 +                return floatType;
  60.213 +        }
  60.214 +    }
  60.215 +
  60.216 +    if (token == TOK_OR || token == TOK_AND) {
  60.217 +        if (!canTest(node, left) || !canTest(node, right))
  60.218 +            return NULL;
  60.219 +        return zone_->types()->getPrimitive(PrimitiveType_Int32);
  60.220 +    }
  60.221 +
  60.222 +    if (token >= TOK_EQUALS && token <= TOK_GE) {
  60.223 +        if ((left->isFloat() || (left->isInt32() && !left->tag())) &&
  60.224 +            (right->isFloat() || (right->isInt32() && !right->tag())))
  60.225 +        {
  60.226 +            return zone_->types()->getPrimitive(PrimitiveType_Int32);
  60.227 +        }
  60.228 +        binaryTypeError(node, token, left, right);
  60.229 +        return NULL;
  60.230 +    }
  60.231 +
  60.232 +    if ((!left->isInt32() || left->tag()) ||
  60.233 +        (!right->isInt32() || right->tag()))
  60.234 +    {
  60.235 +        binaryTypeError(node, token, left, right);
  60.236 +        return NULL;
  60.237 +    }
  60.238 +
  60.239 +    return left;
  60.240 +}
  60.241 +
  60.242 +bool
  60.243 +SemanticAnalysis::canTest(AstNode *node, Handle<Type> type)
  60.244 +{
  60.245 +    if (type->isArray() || (type->isInt32() && type->tag())) {
  60.246 +        cc_.reportError(node->pos(), Message_ArrayIsNotBoolean);
  60.247 +        return false;
  60.248 +    }
  60.249 +    return true;
  60.250 +}
  60.251 +
  60.252 +Type *
  60.253 +SemanticAnalysis::visitForLValue(Expression *expression)
  60.254 +{
  60.255 +    if (expression->isIndexExpression()) {
  60.256 +        Type *type = visitAndApplyType(expression);
  60.257 +        if (!type)
  60.258 +            return NULL;
  60.259 +
  60.260 +        if (type->isConst()) {
  60.261 +            cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  60.262 +            return NULL;
  60.263 +        }
  60.264 +
  60.265 +        return type->contained();
  60.266 +    }
  60.267 +
  60.268 +    if (!expression->isNameProxy()) {
  60.269 +        cc_.reportError(expression->pos(), Message_ExpectedLValue);
  60.270 +        return NULL;
  60.271 +    }
  60.272 +
  60.273 +    NameProxy *proxy = expression->toNameProxy();
  60.274 +    if (!proxy->binding()->kind() == BoundName::VARIABLE) {
  60.275 +        cc_.reportError(expression->pos(), Message_ExpectedLValue);
  60.276 +        return NULL;
  60.277 +    }
  60.278 +
  60.279 +    Variable *var = proxy->binding()->toVariable();
  60.280 +    if (!var->type())
  60.281 +        return NULL;
  60.282 +
  60.283 +    if  (var->type()->isReference()) {
  60.284 +        if (var->type()->isConst()) {
  60.285 +            cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
  60.286 +            return NULL;
  60.287 +        }
  60.288 +        return var->type()->contained();
  60.289 +    }
  60.290 +    return var->type();
  60.291 +}
  60.292 +
  60.293 +SemanticAnalysis::ControlStatus
  60.294 +SemanticAnalysis::visitForControl(Statement *statement)
  60.295 +{
  60.296 +    ControlScope scope(&control_);
  60.297 +    statement->accept(this);
  60.298 +    return scope.status();
  60.299 +}
  60.300 +
  60.301 +void
  60.302 +SemanticAnalysis::visit(NameProxy *name)
  60.303 +{
  60.304 +    name->setType(name->binding()->type());
  60.305 +}
  60.306 +
  60.307 +void
  60.308 +SemanticAnalysis::visit(Assignment *node)
  60.309 +{
  60.310 +    Local<Type> exprType(zone_, visitForLoad(node->expression()));
  60.311 +    if (!exprType)
  60.312 +        return ;
  60.313 +
  60.314 +    Local<Type> type(zone_, visitForLValue(node->lvalue()));
  60.315 +    if (!type)
  60.316 +        return;
  60.317 +
  60.318 +    if (node->token() != TOK_ASSIGN) {
  60.319 +        if (!typeCheckBinary(node, node->token(), type, exprType))
  60.320 +            return;
  60.321 +    }
  60.322 +
  60.323 +    if (!typeCheckAssignment(node, exprType, type, true))
  60.324 +        return;
  60.325 +
  60.326 +    node->setType(type);
  60.327 +}
  60.328 +
  60.329 +void
  60.330 +SemanticAnalysis::visit(IncDecExpression *node)
  60.331 +{
  60.332 +    Local<Type> type(zone_, visitForLValue(node->expression()));
  60.333 +    if (!type)
  60.334 +        return;
  60.335 +
  60.336 +    assert(!type->isReference());
  60.337 +
  60.338 +    if ((!type->isInt32() || (type->isInt32() && type->tag())) && !type->isFloat()) {
  60.339 +        unaryTypeError(node, node->token(), type);
  60.340 +        return;
  60.341 +    }
  60.342 +
  60.343 +    node->setType(type);
  60.344 +}
  60.345 +
  60.346 +void
  60.347 +SemanticAnalysis::visit(UnaryExpression *node)
  60.348 +{
  60.349 +    Local<Type> type(zone_, visitForLoad(node->expression()));
  60.350 +    if (!type)
  60.351 +        return;
  60.352 +
  60.353 +    switch (node->token())
  60.354 +    {
  60.355 +      case TOK_NOT:
  60.356 +        if (!canTest(node->expression(), type))
  60.357 +            return;
  60.358 +        type = zone_->types()->getPrimitive(PrimitiveType_Int32);
  60.359 +        if (!type)
  60.360 +            return;
  60.361 +        node->setType(type);
  60.362 +        break;
  60.363 +
  60.364 +      case TOK_MINUS:
  60.365 +        if (!type->isFloat() && (!type->isInt32() || type->tag())) {
  60.366 +            unaryTypeError(node, node->token(), type);
  60.367 +            return;
  60.368 +        }
  60.369 +        node->setType(type);
  60.370 +        break;
  60.371 +
  60.372 +      default:
  60.373 +        assert(node->token() == TOK_TILDE);
  60.374 +        if (!type->isInt32() || type->tag()) {
  60.375 +            unaryTypeError(node, node->token(), type);
  60.376 +            return;
  60.377 +        }
  60.378 +        node->setType(type);
  60.379 +        break;
  60.380 +    }
  60.381 +}
  60.382 +
  60.383 +void
  60.384 +SemanticAnalysis::visit(TernaryExpression *node)
  60.385 +{
  60.386 +    Local<Type> type(zone_, visitForLoad(node->condition()));
  60.387 +    if (!type)
  60.388 +        return;
  60.389 +
  60.390 +    if (!canTest(node->condition(), type))
  60.391 +        return;
  60.392 +
  60.393 +    Local<Type> left(zone_, visitForLoad(node->left()));
  60.394 +    Local<Type> right(zone_, visitForLoad(node->right()));
  60.395 +    if (!left || !right)
  60.396 +        return;
  60.397 +
  60.398 +    if (left != right) {
  60.399 +        binaryTypeError(node, TOK_QMARK, left, right);
  60.400 +        return;
  60.401 +    }
  60.402 +}
  60.403 +
  60.404 +void
  60.405 +SemanticAnalysis::visit(BinaryExpression *node)
  60.406 +{
  60.407 +    Local<Type> left(zone_, visitForLoad(node->left()));
  60.408 +    Local<Type> right(zone_, visitForLoad(node->right()));
  60.409 +    if (!left || !right)
  60.410 +        return;
  60.411 +
  60.412 +    Local<Type> result(zone_, typeCheckBinary(node, node->token(), left, right));
  60.413 +    if (!result)
  60.414 +        return;
  60.415 +
  60.416 +    node->setType(result);
  60.417 +}
  60.418 +
  60.419 +void
  60.420 +SemanticAnalysis::visit(ReturnStatement *node)
  60.421 +{
  60.422 +    // Set this early, so if we error we don't get more errors.
  60.423 +    control_->returns(Returns_Always);
  60.424 +
  60.425 +    if (!node->expression()) {
  60.426 +        if (!function_->returnType()->isVoid())
  60.427 +            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
  60.428 +        return;
  60.429 +    }
  60.430 +
  60.431 +    Local<Type> type(zone_, visitForLoad(node->expression()));
  60.432 +    if (!type)
  60.433 +        return;
  60.434 +
  60.435 +    Local<Type> returnType(zone_, function_->returnType());
  60.436 +    if (!typeCheckAssignment(node, type, returnType, true))
  60.437 +        return;
  60.438 +}
  60.439 +
  60.440 +void
  60.441 +SemanticAnalysis::visit(ForStatement *node)
  60.442 +{
  60.443 +    LoopScope loop(&loop_);
  60.444 +
  60.445 +    if (node->scope())
  60.446 +        scope_ = node->scope();
  60.447 +
  60.448 +    if (node->initialization())
  60.449 +        node->initialization()->accept(this);
  60.450 +
  60.451 +    if (node->condition()) {
  60.452 +        Local<Type> type(zone_, visitForLoad(node->condition()));
  60.453 +        if (!type || !canTest(node->condition(), type)) {
  60.454 +            return;
  60.455 +        }
  60.456 +    }
  60.457 +
  60.458 +    if (node->update())
  60.459 +        node->update()->accept(this);
  60.460 +
  60.461 +    ControlStatus status = visitForControl(node->body());
  60.462 +
  60.463 +    // If there is a condition, we treat this like a while loop. Otherwise,
  60.464 +    // join point is only reachable if the loop contains a break. The
  60.465 +    // termination status doesn't tell us anything yet.
  60.466 +    if (node->condition() || loop.breaks())
  60.467 +        control_->merge(status, ControlStatus(false, Returns_Never));
  60.468 +    else
  60.469 +        control_->terminate(status.returns());
  60.470 +
  60.471 +    if (node->scope())
  60.472 +        scope_ = scope_->enclosing();
  60.473 +}
  60.474 +
  60.475 +void 
  60.476 +SemanticAnalysis::visit(WhileStatement *node)
  60.477 +{
  60.478 +    LoopScope loop(&loop_);
  60.479 +
  60.480 +    Local<Type> type(zone_, visitForLoad(node->condition()));
  60.481 +    if (!type || !canTest(node->condition(), type)) {
  60.482 +        return;
  60.483 +    }
  60.484 +
  60.485 +    ControlStatus status = visitForControl(node->body());
  60.486 +
  60.487 +    // Detect loops that will always have a fork in the control-flow graph.
  60.488 +    // This will be a |while| loop, or a |do-while| loop whose body does
  60.489 +    // not terminate.
  60.490 +    //
  60.491 +    // For now, we treat these as an |if| regardless of the direction the
  60.492 +    // branch can take. That means the control-flow is always conditional.
  60.493 +    if (node->token() == TOK_WHILE ||
  60.494 +        !status.terminates() ||
  60.495 +        loop.breaks())
  60.496 +    {
  60.497 +        control_->merge(status, ControlStatus(false, Returns_Never));
  60.498 +    } else {
  60.499 +        // At this point, we've got a do-while loop with a |return| or
  60.500 +        // |continue|, meaning that the rest of the block is unreachable.
  60.501 +        control_->terminate(status.returns());
  60.502 +    }
  60.503 +}
  60.504 +
  60.505 +void
  60.506 +SemanticAnalysis::visit(BlockStatement *node)
  60.507 +{
  60.508 +    if (node->scope())
  60.509 +        scope_ = node->scope();
  60.510 +    for (size_t i = 0; i < node->statements()->length(); i++) {
  60.511 +        Statement *statement = node->statements()->at(i);
  60.512 +        statement->accept(this);
  60.513 +    }
  60.514 +    if (node->scope())
  60.515 +        scope_ = scope_->enclosing();
  60.516 +}
  60.517 +
  60.518 +void
  60.519 +SemanticAnalysis::visit(VariableDeclaration *node)
  60.520 +{
  60.521 +    Local<String> tag(zone_, node->tag());
  60.522 +    Local<Type> type(zone_, zone_->types()->getPrimitiveForTag(tag));
  60.523 +    if (!type)
  60.524 +        return;
  60.525 +
  60.526 +    if (node->postDimensions()) {
  60.527 +        Local<Type> init(zone_);
  60.528 +        if (node->initialization()) {
  60.529 +            if ((init = visitForLoad(node->initialization())) == NULL)
  60.530 +                return;
  60.531 +        }
  60.532 +
  60.533 +        if (node->postDimensions()->length() > Type::MAX_UNSAFE_ARRAY_DEPTH) {
  60.534 +            cc_.reportError(node->pos(), Message_MaximumArrayDepth);
  60.535 +            return;
  60.536 +        }
  60.537 +
  60.538 +        // If we have an initializer, make sure it's the same type.
  60.539 +        if (init && node->postDimensions()->length() != init->levels()) {
  60.540 +            cc_.reportError(node->pos(), Message_ArrayInitializerDepth);
  60.541 +            return;
  60.542 +        }
  60.543 +
  60.544 +        Local<Type> check(zone_, init);
  60.545 +        for (size_t i = node->postDimensions()->length() - 1; i < node->postDimensions()->length(); i--) {
  60.546 +            Expression *expr = node->postDimensions()->at(i);
  60.547 +            int size = -1;
  60.548 +
  60.549 +            if (expr) {
  60.550 +                Local<Type> exprType(zone_, visitForLoad(expr));
  60.551 +                if (!exprType)
  60.552 +                    return;
  60.553 +
  60.554 +                if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) {
  60.555 +                    cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
  60.556 +                    return;
  60.557 +                }
  60.558 +
  60.559 +                BoxedPrimitive box;
  60.560 +                if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
  60.561 +                    size = box.toInt();
  60.562 +                    if (size <= 0) {
  60.563 +                        cc_.reportError(expr->pos(), Message_BadArraySize);
  60.564 +                        return;
  60.565 +                    }
  60.566 +                    if (size >= INT_MAX / sizeof(int)) {
  60.567 +                        cc_.reportError(expr->pos(), Message_ArraySizeTooBig);
  60.568 +                        return;
  60.569 +                    }
  60.570 +
  60.571 +                    if (check) {
  60.572 +                        if (check->elements() == -1) {
  60.573 +                            cc_.reportError(expr->pos(), Message_ArraySizeCannotBeDetermined);
  60.574 +                            return;
  60.575 +                        }
  60.576 +
  60.577 +                        if (check->isCharArray()) {
  60.578 +                            if (check->elements() > size) {
  60.579 +                                cc_.reportError(node->pos(), Message_ArrayAssignmentTooBig);
  60.580 +                                return;
  60.581 +                            }
  60.582 +                        } else if (check->elements() != size) {
  60.583 +                            cc_.reportError(node->pos(), Message_ArrayDimensionSizeMismatch, unsigned(i));
  60.584 +                            return;
  60.585 +                        }
  60.586 +                    }
  60.587 +                } else {
  60.588 +                    if (init) {
  60.589 +                        cc_.reportError(node->pos(), Message_DynamicArrayHasInitializer);
  60.590 +                        return;
  60.591 +                    }
  60.592 +
  60.593 +                    // here until we get dynamic array support.
  60.594 +                    cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
  60.595 +                    return;
  60.596 +                }
  60.597 +            } else {
  60.598 +                // Infer the size from the initializer.
  60.599 +                if (!init) {
  60.600 +                    cc_.reportError(node->pos(), Message_ArraySizeNotSpecified);
  60.601 +                    return;
  60.602 +                }
  60.603 +                if (init->elements() == -1) {
  60.604 +                    cc_.reportError(node->pos(), Message_ArraySizeCannotBeDetermined);
  60.605 +                    return;
  60.606 +                }
  60.607 +                size = init->elements();
  60.608 +            }
  60.609 +
  60.610 +            type = zone_->types()->unsafeArray(type, size, false);
  60.611 +            if (!type)
  60.612 +                return;
  60.613 +
  60.614 +            if (check)
  60.615 +                check = check->contained();
  60.616 +        }
  60.617 +
  60.618 +        // If this variable is stack allocated, we could use the LIFO heap
  60.619 +        // to allocate it. If that's the case, make sure to reserve a slot
  60.620 +        // so we can unwind the LIFO heap at the end of this scope.
  60.621 +        if (!node->variable()->needsHeapAllocation())
  60.622 +            scope_->setUsesLifoHeap();
  60.623 +    } else {
  60.624 +        if (node->initialization()) {
  60.625 +            Local<Type> right(zone_, visitForLoad(node->initialization()));
  60.626 +            if (!right)
  60.627 +                return;
  60.628 +            if (!typeCheckAssignment(node, type, right, true))
  60.629 +                return;
  60.630 +        }
  60.631 +        if (type->primitive() == PrimitiveType_Char) {
  60.632 +            cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
  60.633 +            return;
  60.634 +        }
  60.635 +    }
  60.636 +
  60.637 +    node->variable()->setType(type);
  60.638 +}
  60.639 +
  60.640 +void
  60.641 +SemanticAnalysis::visit(IntegerLiteral *node)
  60.642 +{
  60.643 +    node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
  60.644 +}
  60.645 +
  60.646 +void
  60.647 +SemanticAnalysis::visit(ExpressionStatement *node)
  60.648 +{
  60.649 +    visitAndApplyType(node->expression());
  60.650 +}
  60.651 +
  60.652 +bool
  60.653 +SemanticAnalysis::preanalyze(FunctionStatement *node)
  60.654 +{
  60.655 +    Local<FixedArray> args(zone_, FixedArray::New(zone_, node->parameters()->length(), Heap::Tenure_Old));
  60.656 +    if (!args)
  60.657 +        return false;
  60.658 +
  60.659 +    // Apply types to arguments.
  60.660 +    for (size_t i = 0; i < node->parameters()->length(); i++) {
  60.661 +        Parameter *parameter = node->parameters()->at(i);
  60.662 +        
  60.663 +        Local<String> tag(zone_, parameter->tag());
  60.664 +        Local<Type> type(zone_, zone_->types()->getPrimitiveForTag(tag));
  60.665 +        if (!type)
  60.666 +            return false;
  60.667 +
  60.668 +        if (parameter->reference()) {
  60.669 +            if (parameter->dimensions()) {
  60.670 +                cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference);
  60.671 +                return NULL;
  60.672 +            }
  60.673 +
  60.674 +            type = zone_->types()->getReference(type, parameter->isConst());
  60.675 +            if (!type)
  60.676 +                return false;
  60.677 +        } else if (parameter->dimensions()) {
  60.678 +            if (parameter->dimensions()->length() > Type::MAX_UNSAFE_ARRAY_DEPTH) {
  60.679 +                cc_.reportError(parameter->variable()->pos(), Message_MaximumArrayDepth);
  60.680 +                return false;
  60.681 +            }
  60.682 +
  60.683 +            if (node->fun()->isNative() && parameter->dimensions()->length() > 1) {
  60.684 +                cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative);
  60.685 +                return false;
  60.686 +            }
  60.687 +
  60.688 +            for (size_t i = parameter->dimensions()->length() - 1;
  60.689 +                 i < parameter->dimensions()->length();
  60.690 +                 i++)
  60.691 +            {
  60.692 +                int size = Type::UNKNOWN_SIZE;
  60.693 +                if (Expression *expr = parameter->dimensions()->at(i)) {
  60.694 +                    BoxedPrimitive box;
  60.695 +                    if (!EvaluateForConstant(expr, &box)) {
  60.696 +                        cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant);
  60.697 +                        return false;
  60.698 +                    }
  60.699 +                    size = box.toInt();
  60.700 +                }
  60.701 +
  60.702 +                type = zone_->types()->unsafeArray(type, size, parameter->isConst());
  60.703 +                if (!type)
  60.704 +                    return false;
  60.705 +            }
  60.706 +        }
  60.707 +
  60.708 +        if ((type->isPrimitive() && type->primitive() == PrimitiveType_Char) ||
  60.709 +            (type->isReference() && type->contained()->primitive() == PrimitiveType_Char))
  60.710 +        {
  60.711 +            cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
  60.712 +            return false;
  60.713 +        }
  60.714 +
  60.715 +        args->set(zone_, i, type);
  60.716 +        parameter->variable()->setType(type);
  60.717 +    }
  60.718 +
  60.719 +    Local<Type> returnType(zone_);
  60.720 +    if (node->hasExplicitReturn() || node->fun()->isNative())
  60.721 +        returnType = zone_->types()->getPrimitive(PrimitiveType_Int32);
  60.722 +    else
  60.723 +        returnType = zone_->types()->getVoid();
  60.724 +    if (!returnType)
  60.725 +        return false;
  60.726 +
  60.727 +    Local<Type> funtype(zone_);
  60.728 +    if (node->fun()->isNative())
  60.729 +        funtype = zone_->types()->newNative(returnType, args, node->fun()->isNativeVariadic());
  60.730 +    else
  60.731 +        funtype = zone_->types()->newFunction(returnType, args);
  60.732 +    if (!funtype)
  60.733 +        return false;
  60.734 +    
  60.735 +    // If the function already has a type, it was forward declared before, and
  60.736 +    // now this is our chance to type check the second declaration.
  60.737 +    if (node->fun()->type()) {
  60.738 +        Local<Type> forward(zone_, node->fun()->type());
  60.739 +        if (!Type::Compare(funtype, forward)) {
  60.740 +            cc_.reportError(node->pos(), Message_ForwardDeclareMismatches);
  60.741 +            return false;
  60.742 +        }
  60.743 +        node->fun()->setForwardType(forward);
  60.744 +    }
  60.745 +
  60.746 +    node->fun()->setType(funtype);
  60.747 +
  60.748 +    return true;
  60.749 +}
  60.750 +
  60.751 +void
  60.752 +SemanticAnalysis::visit(FunctionStatement *node)
  60.753 +{
  60.754 +    function_ = node->fun()->type();
  60.755 +    scope_ = node->scope();
  60.756 +
  60.757 +    ControlScope control(&control_);
  60.758 +    if (node->body()) {
  60.759 +        node->body()->accept(this);
  60.760 +
  60.761 +        ControlStatus status = control.status();
  60.762 +        if (status.returns() == Returns_Sometimes) {
  60.763 +            cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
  60.764 +        } else if (status.returns() == Returns_Never) {
  60.765 +            if (!function_->returnType()->isVoid())
  60.766 +                cc_.reportError(node->pos(), Message_MissingReturnValue);
  60.767 +        }
  60.768 +    }
  60.769 +
  60.770 +    scope_ = NULL;
  60.771 +    function_ = NULL;
  60.772 +}
  60.773 +
  60.774 +bool
  60.775 +SemanticAnalysis::typeCheckArrayAssignment(AstNode *node, Handle<Type> argGiven, Handle<Type> argActual, bool forAssign)
  60.776 +{
  60.777 +    Local<Type> actual(zone_, argActual);
  60.778 +    Local<Type> given(zone_, argGiven);
  60.779 +
  60.780 +    if (!given->isArray()) {
  60.781 +        cc_.reportError(node->pos(), Message_ExpectedArray);
  60.782 +        return false;
  60.783 +    }
  60.784 +    if (given->levels() != actual->levels()) {
  60.785 +        cc_.reportError(node->pos(), Message_ArrayDimensionsMismatch);
  60.786 +        return false;
  60.787 +    }
  60.788 +
  60.789 +    unsigned level = 0;
  60.790 +    while (given->isArray()) {
  60.791 +        if (actual->elements() != -1) {
  60.792 +            if (forAssign) {
  60.793 +                if (given->elements() == -1 || actual->elements() == -1) {
  60.794 +                    cc_.reportError(node->pos(), Message_ArraySizeNotKnown);
  60.795 +                    return false;
  60.796 +                }
  60.797 +
  60.798 +                if (actual->isCharArray()) {
  60.799 +                    // String assignment can have a truncated |given|.
  60.800 +                    if (given->elements() > actual->elements()) {
  60.801 +                        cc_.reportError(node->pos(), Message_ArrayAssignmentTooBig);
  60.802 +                        return false;
  60.803 +                    }
  60.804 +                } else {
  60.805 +                    if (given->elements() != actual->elements()) {
  60.806 +                        cc_.reportError(node->pos(), Message_ArrayDimensionSizeMismatch, level);
  60.807 +                        return false;
  60.808 +                    }
  60.809 +                }
  60.810 +            } else {
  60.811 +                if (actual->elements() != -1 && given->elements() != actual->elements()) {
  60.812 +                    cc_.reportError(node->pos(), Message_ArrayDimensionSizeMismatch, level);
  60.813 +                    return false;
  60.814 +                }
  60.815 +            }
  60.816 +        }
  60.817 +        given = given->contained();
  60.818 +        actual = actual->contained();
  60.819 +    }
  60.820 +
  60.821 +    if (given->primitive() != actual->primitive()) {
  60.822 +        // :TODO: leaks an interior pointer.
  60.823 +        const char *givenTag = given->tag() ? given->tag()->chars() : "_";
  60.824 +        const char *actualTag = given->tag() ? given->tag()->chars() : "_";
  60.825 +        cc_.reportError(node->pos(), Message_TagMismatch, actualTag, givenTag);
  60.826 +        return false;
  60.827 +    }
  60.828 +
  60.829 +    return true;
  60.830 +}
  60.831 +
  60.832 +bool
  60.833 +SemanticAnalysis::typeCheckAssignment(AstNode *node, Handle<Type> argGiven, Handle<Type> argActual, bool forAssign)
  60.834 +{
  60.835 +    Local<Type> actual(zone_, argActual);
  60.836 +    Local<Type> given(zone_, argGiven);
  60.837 +
  60.838 +    if (actual->isArray())
  60.839 +        return typeCheckArrayAssignment(node, given, actual, forAssign);
  60.840 +
  60.841 +    if (given->isArray()) {
  60.842 +        cc_.reportError(node->pos(), Message_CannotAssignArrayToScalar);
  60.843 +        return false;
  60.844 +    }
  60.845 +
  60.846 +    // The given type may not have been dereferenced.
  60.847 +    if (given->isReference())
  60.848 +        given = given->contained();
  60.849 +    if (actual->isReference())
  60.850 +        actual = actual->contained();
  60.851 +
  60.852 +    if (!given->isPrimitive() || !actual->isPrimitive()) {
  60.853 +        cc_.reportError(node->pos(), Message_UnsupportedType);
  60.854 +        return false;
  60.855 +    }
  60.856 +    
  60.857 +    if (given->primitive() != actual->primitive()) {
  60.858 +        // :TODO: leaks an interior pointer
  60.859 +        const char *givenTag = given->tag() ? given->tag()->chars() : "_";
  60.860 +        const char *actualTag = actual->tag() ? actual->tag()->chars() : "_";
  60.861 +        cc_.reportError(node->pos(), Message_TagMismatch, actualTag, givenTag);
  60.862 +        return false;
  60.863 +    }
  60.864 +
  60.865 +    return true;
  60.866 +}
  60.867 +
  60.868 +bool
  60.869 +SemanticAnalysis::typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual)
  60.870 +{
  60.871 +    return typeCheckAssignment(node, given, actual, false);
  60.872 +}
  60.873 +
  60.874 +void
  60.875 +SemanticAnalysis::visit(CallExpression *node)
  60.876 +{
  60.877 +    Local<Type> type(zone_, visitForLoad(node->callee()));
  60.878 +    if (!type)
  60.879 +        return;
  60.880 +
  60.881 +    if (!type->isFunction()) {
  60.882 +        cc_.reportError(node->pos(), Message_CalleeNotFunction);
  60.883 +        return;
  60.884 +    }
  60.885 +    if (node->arguments()->length() != type->parameters()->length()) {
  60.886 +        if (!type->isNative() ||
  60.887 +            !type->isNativeVariadic() ||
  60.888 +            node->arguments()->length() < type->parameters()->length())
  60.889 +        {
  60.890 +            cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
  60.891 +            return;
  60.892 +        }
  60.893 +    }
  60.894 +
  60.895 +    // Currently, only calls from a NameProxy are possible.
  60.896 +    NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
  60.897 +    if (fun->isForward()) {
  60.898 +        cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
  60.899 +        return;
  60.900 +    }
  60.901 +
  60.902 +    for (unsigned i = 0; i < node->arguments()->length(); i++) {
  60.903 +        // Note: we don't compute references unless the callee needs a
  60.904 +        // reference type.
  60.905 +        Expression *expression = node->arguments()->at(i);
  60.906 +        Local<Type> given(zone_, visitAndApplyType(expression));
  60.907 +        if (!given)
  60.908 +            return;
  60.909 +
  60.910 +        // Since we skip a load, check for a call expression that returns void.
  60.911 +        if (given->isVoid()) {
  60.912 +            assert(expression->isCallExpression());
  60.913 +            CallExpression *call = expression->toCallExpression();
  60.914 +            cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
  60.915 +            return;
  60.916 +        }
  60.917 +        
  60.918 +        // If it's an IndexExpression, we special case the ability to compute
  60.919 +        // a reference.
  60.920 +        if (expression->isIndexExpression())
  60.921 +            given = given->contained();
  60.922 +
  60.923 +        bool mustComputeReference;
  60.924 +        if (i >= type->parameters()->length()) {
  60.925 +            // Special handling for natives. Arguments past the formal must
  60.926 +            // always have references computed. However, arrays are already
  60.927 +            // references for natives.  
  60.928 +            assert(type->isNative() && type->isNativeVariadic());
  60.929 +            mustComputeReference = !given->isReference() && !given->isArray();
  60.930 +        } else {
  60.931 +            Local<Type> actual(zone_, type->parameterAt(i));
  60.932 +            if (!typeCheckParameter(expression, given, actual))
  60.933 +                return;
  60.934 +            mustComputeReference = actual->isReference() && !given->isReference();
  60.935 +        }
  60.936 +
  60.937 +        // If the actual is a reference, and the given is not, we'll need to
  60.938 +        // compute a reference, which may be allocated on the stack.
  60.939 +        if (mustComputeReference)
  60.940 +            scope_->setUsesLifoHeap();
  60.941 +    }
  60.942 +
  60.943 +    node->setType(fun->type()->returnType());
  60.944 +}
  60.945 +
  60.946 +void
  60.947 +SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
  60.948 +{
  60.949 +    // If both sides terminate in a return, we consider this a return as well.
  60.950 +    if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
  60.951 +        terminate(Returns_Always);
  60.952 +        return;
  60.953 +    }
  60.954 +
  60.955 +    ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
  60.956 +                          ? Returns_Never
  60.957 +                          : Returns_Sometimes;
  60.958 +
  60.959 +    if (left.terminates() && right.terminates())
  60.960 +        terminate(status);
  60.961 +    else
  60.962 +        returns(status);
  60.963 +}
  60.964 +
  60.965 +void
  60.966 +SemanticAnalysis::visit(IfStatement *node)
  60.967 +{
  60.968 +    Local<Type> type(zone_, visitForLoad(node->condition()));
  60.969 +    if (!type)
  60.970 +        return;
  60.971 +
  60.972 +    if (!canTest(node, type))
  60.973 +        return;
  60.974 +
  60.975 +    ControlStatus trueBranch = visitForControl(node->ifTrue());
  60.976 +    ControlStatus falseBranch = ControlStatus(false, Returns_Never);
  60.977 +
  60.978 +    if (node->ifFalse())
  60.979 +        falseBranch = visitForControl(node->ifFalse());
  60.980 +
  60.981 +    control_->merge(trueBranch, falseBranch);
  60.982 +}
  60.983 +
  60.984 +void
  60.985 +SemanticAnalysis::visit(IndexExpression *node)
  60.986 +{
  60.987 +    Local<Type> left(zone_, visitForLoad(node->left()));
  60.988 +    Local<Type> right(zone_, visitForLoad(node->right()));
  60.989 +
  60.990 +    if (!left || !right)
  60.991 +        return;
  60.992 +
  60.993 +    if (!right->isInt32()) {
  60.994 +        cc_.reportError(node->right()->pos(), Message_IndexMustBeInteger);
  60.995 +        return;
  60.996 +    }
  60.997 +    if (!left->isArray()) {
  60.998 +        cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
  60.999 +        return;
 60.1000 +    }
 60.1001 +    node->setType(left);
 60.1002 +}
 60.1003 +
 60.1004 +void
 60.1005 +SemanticAnalysis::visit(EnumStatement *node)
 60.1006 +{
 60.1007 +    // Forbid the blessed types.
 60.1008 +    Local<String> tag(zone_, node->name());
 60.1009 +    if (!strcmp(tag->chars(), "Float") ||
 60.1010 +        !strcmp(tag->chars(), "String") ||
 60.1011 +        !strcmp(tag->chars(), "any") ||
 60.1012 +        !strcmp(tag->chars(), "bool"))
 60.1013 +    {
 60.1014 +        cc_.reportError(node->pos(), Message_InvalidEnumName);
 60.1015 +        return;
 60.1016 +    }
 60.1017 +
 60.1018 +    Local<Type> type(zone_, zone_->types()->getPrimitiveForTag(tag));
 60.1019 +    if (!type)
 60.1020 +        return;
 60.1021 +
 60.1022 +    int value = 0;
 60.1023 +    for (size_t i = 0; i < node->entries()->length(); i++) {
 60.1024 +        EnumStatement::Entry &entry = node->entries()->at(i);
 60.1025 +
 60.1026 +        BoxedPrimitive box = BoxedPrimitive::Int(value);
 60.1027 +        if (entry.expr) {
 60.1028 +            entry.expr->accept(this);
 60.1029 +            if (!EvaluateForConstant(entry.expr, &box)) {
 60.1030 +                cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
 60.1031 +                return;
 60.1032 +            }
 60.1033 +
 60.1034 +            assert(box.type() == PrimitiveType_Int32);
 60.1035 +            value = box.toInt();
 60.1036 +        }
 60.1037 +
 60.1038 +        entry.name->set(type, box);
 60.1039 +        value++;
 60.1040 +    }
 60.1041 +}
 60.1042 +
 60.1043 +void
 60.1044 +SemanticAnalysis::visit(StringLiteral *node)
 60.1045 +{
 60.1046 +    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Char));
 60.1047 +    if (!type)
 60.1048 +        return;
 60.1049 +
 60.1050 +    type = Type::NewArray(zone_, type, node->string()->length() + 1, true);
 60.1051 +    if (!type)
 60.1052 +        return;
 60.1053 +
 60.1054 +    node->setType(type);
 60.1055 +}
 60.1056 +
 60.1057 +void
 60.1058 +SemanticAnalysis::visit(FloatLiteral *node)
 60.1059 +{
 60.1060 +    Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
 60.1061 +    if (!type)
 60.1062 +        return;
 60.1063 +
 60.1064 +    node->setType(type);
 60.1065 +}
 60.1066 +
 60.1067 +void
 60.1068 +SemanticAnalysis::visit(BreakStatement *node)
 60.1069 +{
 60.1070 +    if (!loop_) {
 60.1071 +        cc_.reportError(node->pos(), Message_BreakOutsideLoop);
 60.1072 +        return;
 60.1073 +    }
 60.1074 +
 60.1075 +    // Note: ignore breaks that occur in unreachable control-flow.
 60.1076 +    if (!control_->status().terminates())
 60.1077 +        loop_->addBreak();
 60.1078 +
 60.1079 +    control_->terminate(Returns_Never);
 60.1080 +}
 60.1081 +
 60.1082 +void
 60.1083 +SemanticAnalysis::visit(ContinueStatement *node)
 60.1084 +{
 60.1085 +    if (!loop_) {
 60.1086 +        cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
 60.1087 +        return;
 60.1088 +    }
 60.1089 +
 60.1090 +    // Note: ignore continues that occur in unreachable control-flow.
 60.1091 +    if (!control_->status().terminates())
 60.1092 +        loop_->addContinue();
 60.1093 +
 60.1094 +    control_->terminate(Returns_Never);
 60.1095 +}
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/src/SemanticAnalysis.h	Tue Jul 24 23:53:34 2012 -0700
    61.3 @@ -0,0 +1,204 @@
    61.4 +/* vim: set ts=4 sw=4 tw=99 et:
    61.5 + *
    61.6 + * Copyright (C) 2012 David Anderson
    61.7 + *
    61.8 + * This file is part of JITCraft.
    61.9 + *
   61.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   61.11 + * the terms of the GNU General Public License as published by the Free
   61.12 + * Software Foundation, either version 3 of the License, or (at your option)
   61.13 + * any later version.
   61.14 + * 
   61.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   61.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   61.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   61.18 + *
   61.19 + * You should have received a copy of the GNU General Public License along with
   61.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   61.21 + */
   61.22 +#ifndef _include_semantic_analysis_h_
   61.23 +#define _include_semantic_analysis_h_
   61.24 +
   61.25 +#include <assert.h>
   61.26 +#include "AST.h"
   61.27 +
   61.28 +namespace ke {
   61.29 +
   61.30 +class SemanticAnalysis : public AstVisitor
   61.31 +{
   61.32 +    Zone *zone_;
   61.33 +    CompileContext &cc_;
   61.34 +    ParseTree *tree_;
   61.35 +    Scope *scope_;
   61.36 +    ScopedRoot<Type> function_;
   61.37 +
   61.38 +    enum ReturnStatus
   61.39 +    {
   61.40 +        Returns_Never,
   61.41 +        Returns_Sometimes,
   61.42 +        Returns_Always
   61.43 +    };
   61.44 +
   61.45 +    // Tuple that describes whether a path terminates control flow, and
   61.46 +    // if it is guaranteed to end in a return.
   61.47 +    class ControlStatus
   61.48 +    {
   61.49 +        bool terminates_;
   61.50 +        ReturnStatus returns_;
   61.51 +
   61.52 +      public:
   61.53 +        ControlStatus(bool terminates, ReturnStatus returns)
   61.54 +          : terminates_(terminates),
   61.55 +            returns_(returns)
   61.56 +        {
   61.57 +        }
   61.58 +
   61.59 +        bool terminates() const {
   61.60 +            return terminates_;
   61.61 +        }
   61.62 +        ReturnStatus returns() const {
   61.63 +            return returns_;
   61.64 +        }
   61.65 +    };
   61.66 +
   61.67 +    // Used to keep track of terminating control flow and return statements
   61.68 +    // inside control structures.
   61.69 +    class ControlScope
   61.70 +    {
   61.71 +        ReturnStatus returns_;
   61.72 +        ControlScope **prevp_;
   61.73 +        ControlScope *prev_;
   61.74 +        bool terminates_;
   61.75 +
   61.76 +      public:
   61.77 +        ControlScope(ControlScope **prev)
   61.78 +          : returns_(Returns_Never),
   61.79 +            prevp_(prev),
   61.80 +            prev_(*prev),
   61.81 +            terminates_(false)
   61.82 +        {
   61.83 +            *prevp_ = this;
   61.84 +        }
   61.85 +
   61.86 +        ControlStatus status() const {
   61.87 +            return ControlStatus(terminates_, returns_);
   61.88 +        }
   61.89 +
   61.90 +        // We allow multiple terminators, but only the first one takes effect.
   61.91 +        // For example, |break; continue;| is legal but the continue is
   61.92 +        // unreachable.
   61.93 +        void returns(ReturnStatus status) {
   61.94 +            if (terminates_)
   61.95 +                return;
   61.96 +            if (status > returns_)
   61.97 +                returns_ = status;
   61.98 +        }
   61.99 +        void terminate(ReturnStatus status) {
  61.100 +            if (terminates_)
  61.101 +                return;
  61.102 +            terminates_ = true;
  61.103 +            returns_ = status;
  61.104 +        }
  61.105 +        void merge(const ControlStatus &left, const ControlStatus &right);
  61.106 +
  61.107 +        ~ControlScope()
  61.108 +        {
  61.109 +            *prevp_ = prev_;
  61.110 +        }
  61.111 +    };
  61.112 +
  61.113 +    class LoopScope
  61.114 +    {
  61.115 +        LoopScope **prevp_;
  61.116 +        LoopScope *prev_;
  61.117 +        unsigned breaks_;
  61.118 +        unsigned continues_;
  61.119 +
  61.120 +      public:
  61.121 +        LoopScope(LoopScope **prev)
  61.122 +          : prevp_(prev),
  61.123 +            prev_(*prev),
  61.124 +            breaks_(0),
  61.125 +            continues_(0)
  61.126 +        {
  61.127 +            *prevp_ = this;
  61.128 +        }
  61.129 +
  61.130 +        ~LoopScope()
  61.131 +        {
  61.132 +            *prevp_ = prev_;
  61.133 +        }
  61.134 +
  61.135 +        void addBreak() {
  61.136 +            breaks_++;
  61.137 +        }
  61.138 +        void addContinue() {
  61.139 +            continues_++;
  61.140 +        }
  61.141 +        unsigned breaks() const {
  61.142 +            return breaks_;
  61.143 +        }
  61.144 +        unsigned continues() const {
  61.145 +            return continues_;
  61.146 +        }
  61.147 +    };
  61.148 +
  61.149 +    ControlScope *control_;
  61.150 +    LoopScope *loop_;
  61.151 +
  61.152 +  private:
  61.153 +    bool canTest(AstNode *node, Handle<Type> type);
  61.154 +    void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
  61.155 +    void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
  61.156 +    Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
  61.157 +
  61.158 +    // These check if one type is compatible with another type, for various
  61.159 +    // purposes, like:
  61.160 +    //      return (expr) matches function return type
  61.161 +    //      call(a, b)    matches expected arg type
  61.162 +    //      a = b         matches declared type
  61.163 +    //
  61.164 +    bool typeCheckArrayAssignment(AstNode *node, Handle<Type> given, Handle<Type> actual, bool forAssign);
  61.165 +    bool typeCheckAssignment(AstNode *node, Handle<Type> given, Handle<Type> actual, bool forAssign);
  61.166 +    bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
  61.167 +
  61.168 +    Type *visitForLoad(Expression *expression);
  61.169 +    bool preanalyze(FunctionStatement *node);
  61.170 +    Type *visitForLValue(Expression *expression);
  61.171 +    Type *visitAndApplyType(Expression *expression);
  61.172 +    ControlStatus visitForControl(Statement *statement);
  61.173 +
  61.174 +    void markCallResultUsed(CallExpression *call);
  61.175 +
  61.176 +  public:
  61.177 +    SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
  61.178 +    bool analyze();
  61.179 +
  61.180 +  public:
  61.181 +    void visit(NameProxy *name);
  61.182 +    void visit(Assignment *node);
  61.183 +    void visit(BinaryExpression *node);
  61.184 +    void visit(ReturnStatement *node);
  61.185 +    void visit(ForStatement *node);
  61.186 +    void visit(BlockStatement *node);
  61.187 +    void visit(VariableDeclaration *node);
  61.188 +    void visit(IntegerLiteral *node);
  61.189 +    void visit(ExpressionStatement *node);
  61.190 +    void visit(FunctionStatement *node);
  61.191 +    void visit(CallExpression *node);
  61.192 +    void visit(IfStatement *node);
  61.193 +    void visit(IndexExpression *node);
  61.194 +    void visit(EnumStatement *node);
  61.195 +    void visit(FloatLiteral *node);
  61.196 +    void visit(WhileStatement *node);
  61.197 +    void visit(BreakStatement *node);
  61.198 +    void visit(ContinueStatement *node);
  61.199 +    void visit(StringLiteral *node);
  61.200 +    void visit(IncDecExpression *node);
  61.201 +    void visit(UnaryExpression *node);
  61.202 +    void visit(TernaryExpression *node);
  61.203 +};
  61.204 +
  61.205 +} // namespace ke
  61.206 +
  61.207 +#endif // _include_semantic_analysis_h_
    62.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    62.2 +++ b/src/Spaces-inl.h	Tue Jul 24 23:53:34 2012 -0700
    62.3 @@ -0,0 +1,59 @@
    62.4 +/* vim: set ts=4 sw=4 tw=99 et:
    62.5 + *
    62.6 + * Copyright (C) 2012 David Anderson
    62.7 + *
    62.8 + * This file is part of JITCraft.
    62.9 + *
   62.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   62.11 + * the terms of the GNU General Public License as published by the Free
   62.12 + * Software Foundation, either version 3 of the License, or (at your option)
   62.13 + * any later version.
   62.14 + * 
   62.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   62.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   62.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   62.18 + *
   62.19 + * You should have received a copy of the GNU General Public License along with
   62.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   62.21 + */
   62.22 +#ifndef _include_jitcraft_spaces_inl_h_
   62.23 +#define _include_jitcraft_spaces_inl_h_
   62.24 +
   62.25 +namespace ke {
   62.26 +
   62.27 +inline Address
   62.28 +HeapStack::allocate(size_t nbytes)
   62.29 +{
   62.30 +    nbytes = Align(nbytes, kObjectAlignment);
   62.31 +
   62.32 +    if (cursor_ + nbytes > chunk_->end())
   62.33 +        return NULL;
   62.34 +
   62.35 +    Address ptr = cursor_;
   62.36 +    cursor_ += nbytes;
   62.37 +    return ptr;
   62.38 +}
   62.39 +
   62.40 +inline void
   62.41 +HeapStack::unwind(Address to)
   62.42 +{
   62.43 +    assert(to <= cursor_ && to >= chunk_->first());
   62.44 +    cursor_ = to;
   62.45 +}
   62.46 +
   62.47 +inline Address
   62.48 +OldSpace::allocate(size_t nbytes)
   62.49 +{
   62.50 +    assert(IsAligned(nbytes, kObjectAlignment));
   62.51 +
   62.52 +    if (cursor_ + nbytes > last_->end())
   62.53 +        return allocateSlow(nbytes);
   62.54 +
   62.55 +    Address addr = cursor_;
   62.56 +    cursor_ += nbytes;
   62.57 +    return addr;
   62.58 +}
   62.59 +
   62.60 +}
   62.61 +
   62.62 +#endif // _include_jitcraft_spaces_inl_h_
    63.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.2 +++ b/src/Spaces.cpp	Tue Jul 24 23:53:34 2012 -0700
    63.3 @@ -0,0 +1,307 @@
    63.4 +/* vim: set ts=4 sw=4 tw=99 et:
    63.5 + *
    63.6 + * Copyright (C) 2012 David Anderson
    63.7 + *
    63.8 + * This file is part of JITCraft.
    63.9 + *
   63.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   63.11 + * the terms of the GNU General Public License as published by the Free
   63.12 + * Software Foundation, either version 3 of the License, or (at your option)
   63.13 + * any later version.
   63.14 + * 
   63.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   63.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   63.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   63.18 + *
   63.19 + * You should have received a copy of the GNU General Public License along with
   63.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   63.21 + */
   63.22 +#include "Zone.h"
   63.23 +#include "Spaces.h"
   63.24 +#include "Platform.h"
   63.25 +#include "Spaces-inl.h"
   63.26 +
   63.27 +using namespace ke;
   63.28 +
   63.29 +HeapStack::HeapStack()
   63.30 +  : chunk_(NULL),
   63.31 +    cursor_(NULL)
   63.32 +{
   63.33 +}
   63.34 +
   63.35 +HeapStack::~HeapStack()
   63.36 +{
   63.37 +    if (chunk_)
   63.38 +        HeapChunk::Destroy(chunk_);
   63.39 +}
   63.40 +
   63.41 +bool
   63.42 +HeapStack::initialize()
   63.43 +{
   63.44 +    chunk_ = HeapChunk::New(NULL, kStackSize);
   63.45 +    cursor_ = chunk_->first();
   63.46 +    return true;
   63.47 +}
   63.48 +
   63.49 +HeapChunk *
   63.50 +HeapChunk::New(HeapChunk *prev, size_t size)
   63.51 +{
   63.52 +    OS::AlignableMapping map = 
   63.53 +        OS::MapAlignedMemory(size, HeapChunk::kAlignment, OS::Map_Commit);
   63.54 +
   63.55 +    if (!map.base())
   63.56 +        return NULL;
   63.57 +
   63.58 +    HeapChunk *chunk = reinterpret_cast<HeapChunk *>(map.aligned());
   63.59 +    chunk->base_ = map.base();
   63.60 +    chunk->end_ = map.base() + map.size();
   63.61 +    if (prev)
   63.62 +        prev->next_ = chunk;
   63.63 +
   63.64 +    return chunk;
   63.65 +}
   63.66 +
   63.67 +void
   63.68 +HeapChunk::Destroy(HeapChunk *chunk)
   63.69 +{
   63.70 +    OS::UnmapAlignedMemory(chunk->base(), chunk->size());
   63.71 +}
   63.72 +
   63.73 +void
   63.74 +HeapChunk::resetMarkBits()
   63.75 +{
   63.76 +    memset(markBits(), 0, kMarkBytes);
   63.77 +}
   63.78 +
   63.79 +FreeList::FreeList()
   63.80 +  : small_objects_(NULL),
   63.81 +    medium_objects_(NULL),
   63.82 +    large_objects_(NULL),
   63.83 +    huge_objects_(NULL)
   63.84 +{
   63.85 +}
   63.86 +
   63.87 +void
   63.88 +FreeList::add(FreedObject *obj)
   63.89 +{
   63.90 +    if (obj->size() < kMinObjectSize) 
   63.91 +        return;
   63.92 +
   63.93 +    FreedObject **list;
   63.94 +    if (obj->size() < kMaxSmallObject)
   63.95 +        list = &small_objects_;
   63.96 +    else if (obj->size() < kMaxMediumObject)
   63.97 +        list = &medium_objects_;
   63.98 +    else if (obj->size() < kMaxLargeObject)
   63.99 +        list = &large_objects_;
  63.100 +    else
  63.101 +        list = &huge_objects_;
  63.102 +
  63.103 +    if (*list)
  63.104 +        (*list)->setNext(obj);
  63.105 +    *list = obj;
  63.106 +}
  63.107 +
  63.108 +FreedObject *
  63.109 +FreeList::pick(size_t size)
  63.110 +{
  63.111 +    if (size < kMinObjectSize && small_objects_) {
  63.112 +        FreedObject *obj = small_objects_;
  63.113 +        small_objects_ = small_objects_->next();
  63.114 +        return obj;
  63.115 +    }
  63.116 +    if (size < kMaxSmallObject && medium_objects_) {
  63.117 +        FreedObject *obj = medium_objects_;
  63.118 +        medium_objects_ = medium_objects_->next();
  63.119 +        return obj;
  63.120 +    }
  63.121 +    if (size < kMaxMediumObject && large_objects_) {
  63.122 +        FreedObject *obj = large_objects_;
  63.123 +        large_objects_ = large_objects_->next();
  63.124 +        return obj;
  63.125 +    }
  63.126 +    if (huge_objects_) {
  63.127 +        FreedObject *obj = huge_objects_;
  63.128 +        huge_objects_ = huge_objects_->next();
  63.129 +        return obj;
  63.130 +    }
  63.131 +    return NULL;
  63.132 +}
  63.133 +
  63.134 +void
  63.135 +FreeList::reset()
  63.136 +{
  63.137 +    small_objects_ = NULL;
  63.138 +    medium_objects_ = NULL;
  63.139 +    large_objects_ = NULL;
  63.140 +    huge_objects_ = NULL;
  63.141 +}
  63.142 +
  63.143 +OldSpace::OldSpace(Zone *zone)
  63.144 +  : zone_(zone),
  63.145 +    first_(NULL),
  63.146 +    last_(NULL)
  63.147 +{
  63.148 +}
  63.149 +
  63.150 +bool
  63.151 +OldSpace::initialize()
  63.152 +{
  63.153 +    first_ = HeapChunk::New(first_, HeapChunk::kDefaultSize);
  63.154 +    last_ = first_;
  63.155 +    cursor_ = first_->first();
  63.156 +
  63.157 +    return !!first_;
  63.158 +}
  63.159 +
  63.160 +OldSpace::~OldSpace()
  63.161 +{
  63.162 +    while (first_) {
  63.163 +        HeapChunk *temp = first_->next();
  63.164 +        HeapChunk::Destroy(first_);
  63.165 +        first_ = temp;
  63.166 +    }
  63.167 +}
  63.168 +
  63.169 +Address
  63.170 +OldSpace::allocateSlow(size_t nbytes)
  63.171 +{
  63.172 +    if (FreedObject *obj = freelist_.pick(nbytes)) {
  63.173 +        Address address = reinterpret_cast<Address>(obj);
  63.174 +        size_t actual = obj->size();
  63.175 +        assert(actual >= nbytes);
  63.176 +        if (actual != nbytes)
  63.177 +            markRegionFree(address + nbytes, actual - nbytes);
  63.178 +
  63.179 +        return address;
  63.180 +    }
  63.181 +
  63.182 +    // Free unused stuff at the end of the current chunk.
  63.183 +    if (cursor_ != last_->end())
  63.184 +        markRegionFree(cursor_, last_->end() - cursor_);
  63.185 +
  63.186 +    HeapChunk *chunk;
  63.187 +    if (last_->next()) {
  63.188 +        // The next chunk is guaranteed to be empty.
  63.189 +        chunk = last_->next();
  63.190 +    } else {
  63.191 +        chunk = HeapChunk::New(last_, HeapChunk::kDefaultSize);
  63.192 +        if (!chunk)
  63.193 +            return NULL;
  63.194 +    }
  63.195 +
  63.196 +    last_ = chunk;
  63.197 +    cursor_ = chunk->first();
  63.198 +
  63.199 +    assert(cursor_ + nbytes <= chunk->end());
  63.200 +
  63.201 +    Address address = cursor_;
  63.202 +    cursor_ += nbytes;
  63.203 +    return address;
  63.204 +}
  63.205 +
  63.206 +void
  63.207 +OldSpace::markRegionFree(Address start, size_t length)
  63.208 +{
  63.209 +    FreedObject *obj = reinterpret_cast<FreedObject *>(start);
  63.210 +    new (obj) FreedObject(zone_->getMap(MapKind_FreeRegion), length);
  63.211 +
  63.212 +    if (length < sizeof(FreedObject)) {
  63.213 +        // Can't encode a list in this object, but it's marked free, so we're done.
  63.214 +        return;
  63.215 +    }
  63.216 +
  63.217 +    freelist_.add(obj);
  63.218 +}
  63.219 +
  63.220 +void
  63.221 +OldSpace::freeUnusedPages()
  63.222 +{
  63.223 +    HeapChunk **prev = &first_;
  63.224 +    HeapChunk *empty = NULL;
  63.225 +    while (*prev) {
  63.226 +        HeapChunk *chunk = *prev;
  63.227 +        if (chunk->isEmpty()) {
  63.228 +            *prev = chunk->next();
  63.229 +            if (empty) {
  63.230 +                // Remove this chunk.
  63.231 +                HeapChunk::Destroy(chunk);
  63.232 +                continue;
  63.233 +            }
  63.234 +            empty = chunk;                
  63.235 +        }
  63.236 +        prev = chunk->nextp();
  63.237 +    }
  63.238 +
  63.239 +    if (empty) {
  63.240 +        *empty->nextp() = NULL;
  63.241 +        *last_->nextp() = empty;
  63.242 +    }
  63.243 +}
  63.244 +
  63.245 +void
  63.246 +OldSpace::resetFreeList()
  63.247 +{
  63.248 +    freelist_.reset();
  63.249 +}
  63.250 +
  63.251 +LargeObjectSpace::LargeObjectSpace()
  63.252 +  : first_(NULL),
  63.253 +    last_(NULL)
  63.254 +{
  63.255 +}
  63.256 +
  63.257 +LargeObjectSpace::~LargeObjectSpace()
  63.258 +{
  63.259 +    while (first_) {
  63.260 +        HeapChunk *temp = first_->next();
  63.261 +        HeapChunk::Destroy(first_);
  63.262 +        first_ = temp;
  63.263 +    }
  63.264 +}
  63.265 +
  63.266 +bool
  63.267 +LargeObjectSpace::initialize()
  63.268 +{
  63.269 +    return true;
  63.270 +}
  63.271 +
  63.272 +Address
  63.273 +LargeObjectSpace::allocate(size_t nbytes)
  63.274 +{
  63.275 +    assert(IsAligned(nbytes, kObjectAlignment));
  63.276 +
  63.277 +    // Always allocate a new chunk for large objects.
  63.278 +    HeapChunk *chunk = HeapChunk::New(last_, nbytes);
  63.279 +    if (!chunk)
  63.280 +        return NULL;
  63.281 +
  63.282 +    if (!first_)
  63.283 +        first_ = chunk;
  63.284 +    last_ = chunk;
  63.285 +
  63.286 +    return chunk->first();
  63.287 +}
  63.288 +
  63.289 +void
  63.290 +LargeObjectSpace::sweep()
  63.291 +{
  63.292 +    if (!first_)
  63.293 +        return;
  63.294 +
  63.295 +    HeapChunk **pprev = &first_;
  63.296 +    do {
  63.297 +        HeapChunk *chunk = *pprev;
  63.298 +        Object *obj = reinterpret_cast<Object *>(chunk->first());
  63.299 +        MarkBit bit = HeapChunk::GetMarkBit(obj);
  63.300 +        if (HeapChunk::IsWhite(bit)) {
  63.301 +            *pprev = chunk->next();
  63.302 +            HeapChunk::Destroy(chunk);
  63.303 +        } else {
  63.304 +            assert(HeapChunk::IsBlack(bit));
  63.305 +            HeapChunk::Clear(bit);
  63.306 +            pprev = chunk->nextp();
  63.307 +            last_ = chunk;
  63.308 +        }
  63.309 +    } while (*pprev);
  63.310 +}
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/src/Spaces.h	Tue Jul 24 23:53:34 2012 -0700
    64.3 @@ -0,0 +1,434 @@
    64.4 +/* vim: set ts=4 sw=4 tw=99 et:
    64.5 + *
    64.6 + * Copyright (C) 2012 David Anderson
    64.7 + *
    64.8 + * This file is part of JITCraft.
    64.9 + *
   64.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   64.11 + * the terms of the GNU General Public License as published by the Free
   64.12 + * Software Foundation, either version 3 of the License, or (at your option)
   64.13 + * any later version.
   64.14 + * 
   64.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   64.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   64.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   64.18 + *
   64.19 + * You should have received a copy of the GNU General Public License along with
   64.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   64.21 + */
   64.22 +#ifndef _include_jitcraft_spaces_h_
   64.23 +#define _include_jitcraft_spaces_h_
   64.24 +
   64.25 +#include <limits.h>
   64.26 +#include "Utility.h"
   64.27 +#include "Platform.h"
   64.28 +
   64.29 +namespace ke {
   64.30 +
   64.31 +class Zone;
   64.32 +class Object;
   64.33 +class Map;
   64.34 +
   64.35 +static const size_t kObjectAlignment = sizeof(Object *);
   64.36 +
   64.37 +// Every object gets two successive mark bits. These bits represent various
   64.38 +// states during garbage collection:
   64.39 +//
   64.40 +//  WHITE (00): The object is dead or unmarked.
   64.41 +//  GREY  (11): The object is live but its children have not been marked.
   64.42 +//  BLACK (10): The object and all its children have been marked.
   64.43 +//
   64.44 +// These colors assist in maintaining the "tri-color invariant", explained
   64.45 +// in Heap.h. The bits are organized such that transitioning an object from
   64.46 +// White to Black requires one bit change, and Black to Grey requires another.
   64.47 +class MarkBit
   64.48 +{
   64.49 +    uint32 *word_;
   64.50 +    uint32 bit_;
   64.51 +
   64.52 +  public:
   64.53 +    MarkBit(uint32 *word, uint32 bit)
   64.54 +      : word_(word),
   64.55 +        bit_(bit)
   64.56 +    {
   64.57 +        assert(bit_ < sizeof(*word_) * 8);
   64.58 +    }
   64.59 +
   64.60 +    bool isSet() const {
   64.61 +        return !!(*word_ & (1 << bit_));
   64.62 +    }
   64.63 +    void set() {
   64.64 +        *word_ |= (1 << bit_);
   64.65 +    }
   64.66 +    void unset() {
   64.67 +        *word_ &= ~(1 << bit_);
   64.68 +    }
   64.69 +    uint32 *word() {
   64.70 +        return word_;
   64.71 +    }
   64.72 +    MarkBit next() const {
   64.73 +        if (bit_ == (sizeof(*word_) * 8) - 1)
   64.74 +            return MarkBit(word_ + 1, 0);
   64.75 +        return MarkBit(word_, bit_ + 1);
   64.76 +    }
   64.77 +};
   64.78 +
   64.79 +class HeapChunk
   64.80 +{
   64.81 +    HeapChunk *next_;
   64.82 +
   64.83 +    // Base address, from OS::AlignableMapping.
   64.84 +    Address base_;
   64.85 +
   64.86 +    // End of the allocated region.
   64.87 +    Address end_;
   64.88 +
   64.89 +    uintptr_t flags_;
   64.90 +
   64.91 +  public:
   64.92 +    enum Flag {
   64.93 +        HAS_OVERFLOWED_OBJECT = (1 << 0),
   64.94 +        EMPTY = (1 << 1)
   64.95 +    };
   64.96 +
   64.97 +  public:
   64.98 +    static const size_t kDefaultSize = 1 * kMB;
   64.99 +    static const size_t kAlignment = 1 * kMB;
  64.100 +
  64.101 +    // Maximum size of an object that will fit in a page. We limit this
  64.102 +    // specifically to help JITs: the computation of a[i] has a special
  64.103 +    // instruction form on most CPUs, but the index might not be sign-
  64.104 +    // extended on 64-bit architectures. We limit the size such that:
  64.105 +    //
  64.106 +    //    index * sizeof(Object *)
  64.107 +    //
  64.108 +    // Is guaranteed to not overflow a signed 32-bit integer.
  64.109 +    static const size_t kMaxObjectSize = INT_MAX / sizeof(Object *);
  64.110 +
  64.111 +    // Size of a HeapChunk header.
  64.112 +    static const size_t kHeaderSize =
  64.113 +        sizeof(HeapChunk *) +
  64.114 +        sizeof(Address) +
  64.115 +        sizeof(Address) +
  64.116 +        sizeof(Address);
  64.117 +
  64.118 +    // All objects must be allocated in the first kAlignment bytes of the
  64.119 +    // chunk. We need two mark bits for every allocatable object, since there
  64.120 +    // are three possible states: White (00), Black (11), and Grey (10). These
  64.121 +    // bits are stored immediately after the HeapChunk header, and before the
  64.122 +    // first allocatable object.
  64.123 +    //
  64.124 +    // Although object alignment is only at word boundaries, we guarantee that
  64.125 +    // every object is at least two words. This means we don't need to reserve
  64.126 +    // two mark bits for every object, just one mark bit for every allocatable
  64.127 +    // address. That also means a pair of mark bits can cross a byte boundary.
  64.128 +    //
  64.129 +    // --- Math ---
  64.130 +    //
  64.131 +    // The number of mark bits needed is:
  64.132 +    //
  64.133 +    // MaxObjectsPerChunk = (kAlignment / kObjectAlignment)
  64.134 +    //                    -> 256KB (128KB on 64-bit)
  64.135 +    //
  64.136 +    // The number of bytes needed for these mark bits is:
  64.137 +    //
  64.138 +    // NumMarkBytes       = MaxObjectsPerChunk / 8
  64.139 +    //                    = 32KB (16KB on 64-bit)
  64.140 +    //
  64.141 +    // The number of uint32s needed to store these bytes is:
  64.142 +    //
  64.143 +    // NumMarkWords       = NumMarkBytes / sizeof(uint32)
  64.144 +    //                    = 8KB (4KB on 64-bit)
  64.145 +    //
  64.146 +    static const size_t kMaxObjectsPerChunk = kAlignment / kObjectAlignment;
  64.147 +    static const size_t kMarkBits = kMaxObjectsPerChunk;
  64.148 +    static const size_t kMarkBytes = kMarkBits / 8;
  64.149 +    static const size_t kMarkWords = kMarkBytes / sizeof(uint32);
  64.150 +    static const size_t kMarkBitsPerWord = sizeof(uint32) * 8;
  64.151 +
  64.152 +    static const size_t kMarkBitsOffset = kHeaderSize;
  64.153 +    static const size_t kFirstObject = kMarkBitsOffset + kMarkBytes;
  64.154 +
  64.155 +    // Threshold for allocating an object in the large object space.
  64.156 +    static const size_t kLargeObjectThreshold = kAlignment - kFirstObject;
  64.157 +
  64.158 +    static inline void StaticAsserts() {
  64.159 +        STATIC_ASSERT(kHeaderSize == sizeof(HeapChunk));
  64.160 +        STATIC_ASSERT(IS_ALIGNED(kHeaderSize, kObjectAlignment));
  64.161 +        STATIC_ASSERT(IS_ALIGNED(kFirstObject, kObjectAlignment));
  64.162 +    }
  64.163 +
  64.164 +  public:
  64.165 +    static HeapChunk *New(HeapChunk *prev, size_t size);
  64.166 +    static void Destroy(HeapChunk *chunk);
  64.167 +
  64.168 +  public:
  64.169 +    HeapChunk *next() {
  64.170 +        return next_;
  64.171 +    }
  64.172 +    Address base() {
  64.173 +        return base_;
  64.174 +    }
  64.175 +    Address address() {
  64.176 +        return reinterpret_cast<Address>(this);
  64.177 +    }
  64.178 +    Address end() {
  64.179 +        return end_;
  64.180 +    }
  64.181 +    size_t size() {
  64.182 +        return end() - base();
  64.183 +    }
  64.184 +    Address first() {
  64.185 +        return reinterpret_cast<Address>(this) + kFirstObject;
  64.186 +    }
  64.187 +    HeapChunk **nextp() {
  64.188 +        return &next_;
  64.189 +    }
  64.190 +    uint32 *markBits() {
  64.191 +        return reinterpret_cast<uint32 *>(reinterpret_cast<Address>(this) + kMarkBitsOffset);
  64.192 +    }
  64.193 +    void resetMarkBits();
  64.194 +
  64.195 +    // Marking functions.
  64.196 +    static inline MarkBit GetMarkBit(Object *obj) {
  64.197 +        uintptr_t address = reinterpret_cast<uintptr_t>(obj);
  64.198 +
  64.199 +        HeapChunk *chunk = reinterpret_cast<HeapChunk *>(address & ~(kAlignment - 1));
  64.200 +        assert(Address(obj) >= chunk->first() && Address(obj) < chunk->end());
  64.201 +
  64.202 +        size_t index = (address & (kAlignment - 1)) / kObjectAlignment;
  64.203 +        assert(index < kMaxObjectsPerChunk);
  64.204 +
  64.205 +        uint32 *word = chunk->markBits() + (index / kMarkBitsPerWord);
  64.206 +        uint32 bit = index & (kMarkBitsPerWord - 1);
  64.207 +        return MarkBit(word, bit);
  64.208 +    }
  64.209 +    static inline Address FromMarkBit(HeapChunk *chunk, uint32 *word, uint32 bit) {
  64.210 +        // word = bits + (index / kMarkBitsPerWord)
  64.211 +        // word - bits = index / kMarkBitsPerWord
  64.212 +        // (word - bits) * kMarkBitsPerWord = index
  64.213 +        assert(word >= chunk->markBits() && word < chunk->markBits() + kMarkWords);
  64.214 +        size_t index = ((word - chunk->markBits()) * kMarkBitsPerWord) + bit;
  64.215 +        return chunk->address() + (index * kObjectAlignment);
  64.216 +    }
  64.217 +    static inline bool IsWhite(const MarkBit &bit) {
  64.218 +        assert(bit.isSet() || !bit.next().isSet());
  64.219 +        return !bit.isSet();
  64.220 +    }
  64.221 +    static inline bool IsBlack(const MarkBit &bit) {
  64.222 +        return bit.isSet() && !bit.next().isSet();
  64.223 +    }
  64.224 +    static inline bool IsGrey(const MarkBit &bit) {
  64.225 +        return bit.isSet() && bit.next().isSet();
  64.226 +    }
  64.227 +    static inline bool IsBlackOrGrey(const MarkBit &bit) {
  64.228 +        return bit.isSet();
  64.229 +    }
  64.230 +    static inline void WhiteToBlack(MarkBit &bit) {
  64.231 +        assert(IsWhite(bit));
  64.232 +        bit.set();
  64.233 +    }
  64.234 +    static inline void BlackToGrey(MarkBit &bit) {
  64.235 +        assert(IsBlack(bit));
  64.236 +        bit.next().set();
  64.237 +    }
  64.238 +    static inline void GreyToBlack(MarkBit &bit) {
  64.239 +        assert(IsGrey(bit));
  64.240 +        bit.next().unset();
  64.241 +    }
  64.242 +    static inline void Clear(MarkBit &bit) {
  64.243 +        bit.unset();
  64.244 +        bit.next().unset();
  64.245 +    }
  64.246 +
  64.247 +    bool hasOverflowedObject() {
  64.248 +        return !!(flags_ & HAS_OVERFLOWED_OBJECT);
  64.249 +    }
  64.250 +    void setHasOverflowedObject() {
  64.251 +        flags_ |= HAS_OVERFLOWED_OBJECT;
  64.252 +    }
  64.253 +    bool isEmpty() {
  64.254 +        return !!(flags_ & EMPTY);
  64.255 +    }
  64.256 +    void setEmpty() {
  64.257 +        flags_ |= EMPTY;
  64.258 +    }
  64.259 +};
  64.260 +
  64.261 +template <typename SizeEvaluator>
  64.262 +class ChunkObjectIteratorBase
  64.263 +{
  64.264 +    HeapChunk *chunk_;
  64.265 +    Address top_;
  64.266 +    SizeEvaluator evaluator_;
  64.267 +    Address current_;
  64.268 +
  64.269 +  public:
  64.270 +    ChunkObjectIteratorBase(HeapChunk *start, Address top, const SizeEvaluator &evaluator)
  64.271 +      : chunk_(start),
  64.272 +        top_(top),
  64.273 +        evaluator_(evaluator),
  64.274 +        current_(start ? start->first() : NULL)
  64.275 +    {
  64.276 +    }
  64.277 +
  64.278 +    Object *next() {
  64.279 +        while (current_ && current_ != top_) {
  64.280 +            Object *obj = reinterpret_cast<Object *>(current_);
  64.281 +            size_t size = evaluator_(obj, obj->map());
  64.282 +            current_ += size;
  64.283 +            if (current_ == chunk_->end()) {
  64.284 +                chunk_ = chunk_->next();
  64.285 +                current_ = chunk_ ? chunk_->first() : NULL;
  64.286 +            }
  64.287 +            if (obj->is(MapKind_FreeRegion))
  64.288 +                continue;
  64.289 +        }
  64.290 +        return NULL;
  64.291 +    }
  64.292 +};
  64.293 +
  64.294 +class FreedObject
  64.295 +{
  64.296 +    Map *map_;
  64.297 +    size_t bytes_;
  64.298 +    FreedObject *next_;
  64.299 +
  64.300 +  public:
  64.301 +    FreedObject(Map *map, size_t bytes)
  64.302 +      : map_(map),
  64.303 +        bytes_(bytes)
  64.304 +    {
  64.305 +        assert(bytes_ >= sizeof(Map *) + sizeof(size_t));
  64.306 +        if (bytes_ >= sizeof(FreedObject))
  64.307 +            next_ = NULL;
  64.308 +    }
  64.309 +
  64.310 +    void setNext(FreedObject *obj) {
  64.311 +        assert(bytes_ >= sizeof(FreedObject));
  64.312 +        next_ = obj;
  64.313 +    }
  64.314 +    FreedObject *next() {
  64.315 +        assert(bytes_ >= sizeof(FreedObject));
  64.316 +        return next_;
  64.317 +    }
  64.318 +    size_t size() {
  64.319 +        return bytes_;
  64.320 +    }
  64.321 +};
  64.322 +
  64.323 +// Free-region list used in old spaces. Based on V8's. Each object pool
  64.324 +// is used to allocate objects of the previous pool's size. For example,
  64.325 +// the medium object pool is used to allocate small objects.
  64.326 +class FreeList
  64.327 +{
  64.328 +  private:
  64.329 +    static const size_t kMinObjectSize = 32;
  64.330 +    static const size_t kMaxSmallObject = 255;
  64.331 +    static const size_t kMaxMediumObject = (2 * kKB) - 1;
  64.332 +    static const size_t kMaxLargeObject = (16 * kKB) - 1;
  64.333 +
  64.334 +  public:
  64.335 +    FreeList();
  64.336 +
  64.337 +  public:
  64.338 +    void add(FreedObject *obj);
  64.339 +    FreedObject *pick(size_t size);
  64.340 +    void reset();
  64.341 +
  64.342 +  private:
  64.343 +    FreedObject *small_objects_;
  64.344 +    FreedObject *medium_objects_;
  64.345 +    FreedObject *large_objects_;
  64.346 +    FreedObject *huge_objects_;
  64.347 +};
  64.348 +
  64.349 +// The heap stack is designed for structures which are known to not escape the
  64.350 +// program stack, and can thus be quickly allocated in a LIFO manner.
  64.351 +// 
  64.352 +class HeapStack
  64.353 +{
  64.354 +    OS::AlignableMapping map_;
  64.355 +    HeapChunk *chunk_;
  64.356 +    Address cursor_;
  64.357 +    uintptr_t mask_;
  64.358 +
  64.359 +  private:
  64.360 +    static const size_t kStackSize = 1024 * 1024;
  64.361 +
  64.362 +  public:
  64.363 +    HeapStack();
  64.364 +    ~HeapStack();
  64.365 +    bool initialize();
  64.366 +
  64.367 +  public:
  64.368 +    Address position() const {
  64.369 +        return cursor_;
  64.370 +    }
  64.371 +    inline Address allocate(size_t nbytes);
  64.372 +    inline void unwind(Address to);
  64.373 +
  64.374 +    inline bool contains(Object *obj) {
  64.375 +        return (reinterpret_cast<uintptr_t>(obj) & mask_) == reinterpret_cast<uintptr_t>(chunk_);
  64.376 +    }
  64.377 +
  64.378 +    template <typename Evaluator>
  64.379 +    ChunkObjectIteratorBase<Evaluator> begin(const Evaluator &evaluator) {
  64.380 +        return ChunkObjectIteratorBase<Evaluator>(chunk_, cursor_, evaluator);
  64.381 +    }
  64.382 +};
  64.383 +
  64.384 +class OldSpace
  64.385 +{
  64.386 +    Zone *zone_;
  64.387 +    HeapChunk *first_;
  64.388 +    HeapChunk *last_;
  64.389 +    Address cursor_;
  64.390 +    FreeList freelist_;
  64.391 +
  64.392 +  public:
  64.393 +    OldSpace(Zone *zone);
  64.394 +    ~OldSpace();
  64.395 +
  64.396 +    bool initialize();
  64.397 +
  64.398 +  public:
  64.399 +    inline Address allocate(size_t nbytes);
  64.400 +    Address allocateSlow(size_t nbytes);
  64.401 +    void markRegionFree(Address start, size_t size);
  64.402 +    void freeUnusedPages();
  64.403 +
  64.404 +    template <typename Evaluator>
  64.405 +    ChunkObjectIteratorBase<Evaluator> begin(const Evaluator &evaluator) {
  64.406 +        return ChunkObjectIteratorBase<Evaluator>(first_, cursor_, evaluator);
  64.407 +    }
  64.408 +
  64.409 +    HeapChunk *first() {
  64.410 +        return first_;
  64.411 +    }
  64.412 +    void resetFreeList();
  64.413 +};
  64.414 +
  64.415 +class LargeObjectSpace
  64.416 +{
  64.417 +    HeapChunk *first_;
  64.418 +    HeapChunk *last_;
  64.419 +
  64.420 +  public:
  64.421 +    LargeObjectSpace();
  64.422 +    ~LargeObjectSpace();
  64.423 +
  64.424 +    bool initialize();
  64.425 +
  64.426 +  public:
  64.427 +    Address allocate(size_t nbytes);
  64.428 +
  64.429 +    HeapChunk *first() {
  64.430 +        return first_;
  64.431 +    }
  64.432 +    void sweep();
  64.433 +};
  64.434 +
  64.435 +}
  64.436 +
  64.437 +#endif // _include_jitcraft_spaces_h_
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/src/Stack.cpp	Tue Jul 24 23:53:34 2012 -0700
    65.3 @@ -0,0 +1,321 @@
    65.4 +/* vim: set ts=4 sw=4 tw=99 et:
    65.5 + *
    65.6 + * Copyright (C) 2012 David Anderson
    65.7 + *
    65.8 + * This file is part of JITCraft.
    65.9 + *
   65.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   65.11 + * the terms of the GNU General Public License as published by the Free
   65.12 + * Software Foundation, either version 3 of the License, or (at your option)
   65.13 + * any later version.
   65.14 + * 
   65.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   65.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   65.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   65.18 + *
   65.19 + * You should have received a copy of the GNU General Public License along with
   65.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   65.21 + */
   65.22 +#include <new>
   65.23 +#include <stdlib.h>
   65.24 +#include "Stack.h"
   65.25 +#include "Zone.h"
   65.26 +#include "Strings.h"
   65.27 +#include "Modules.h"
   65.28 +#include "Heap-inl.h"
   65.29 +
   65.30 +using namespace ke;
   65.31 +
   65.32 +Stack::Stack(Zone *zone)
   65.33 +  : zone_(zone),
   65.34 +    buffer_(NULL),
   65.35 +    end_(NULL)
   65.36 +{
   65.37 +}
   65.38 +
   65.39 +Stack::~Stack()
   65.40 +{
   65.41 +    free(buffer_);
   65.42 +}
   65.43 +
   65.44 +bool
   65.45 +Stack::initialize()
   65.46 +{
   65.47 +    buffer_ = (char *)malloc(STACK_SIZE);
   65.48 +    if (!buffer_)
   65.49 +        return false;
   65.50 +
   65.51 +    top_.sp = reinterpret_cast<LocalSlot *>(buffer_);
   65.52 +    top_.pc = NULL;
   65.53 +    top_.fp = NULL;
   65.54 +    end_ = buffer_ + STACK_SIZE;
   65.55 +    return true;
   65.56 +}
   65.57 +
   65.58 +InvokeArgs::~InvokeArgs()
   65.59 +{
   65.60 +    stack_->popInvokeFrame(*this);
   65.61 +}
   65.62 +
   65.63 +NativeArgs::~NativeArgs()
   65.64 +{
   65.65 +    stack_->popNativeFrame(*this);
   65.66 +}
   65.67 +
   65.68 +static inline size_t
   65.69 +SizeForCodeFrame(Code *code)
   65.70 +{
   65.71 +    return sizeof(Frame) + sizeof(LocalSlot) * (code->nlocals() + code->maxStackDepth());
   65.72 +}
   65.73 +
   65.74 +bool
   65.75 +Stack::pushInvokeFrame(Handle<Function> fun, InvokeArgs &args)
   65.76 +{
   65.77 +    size_t nbytes = SizeForCodeFrame(fun->code()) +
   65.78 +                    sizeof(LocalSlot) * fun->nargs();
   65.79 +    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
   65.80 +        assert(false);
   65.81 +        return false;
   65.82 +    }
   65.83 +
   65.84 +    memset(top_.sp, 0, sizeof(LocalSlot) * fun->nargs());
   65.85 +    args.args_ = top_.sp;
   65.86 +    args.nargs_ = fun->nargs();
   65.87 +    args.stack_ = this;
   65.88 +    top_.sp += fun->nargs();
   65.89 +    
   65.90 +    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
   65.91 +    new (frame) Frame(top_.fp, top_.pc, fun, fun->code(), zone_->heap().lifoPosition());
   65.92 +    
   65.93 +    top_.pc = frame->code()->start();
   65.94 +    top_.sp = frame->stackBase();
   65.95 +    top_.fp = frame;
   65.96 +
   65.97 +    return true;
   65.98 +}
   65.99 +
  65.100 +bool
  65.101 +Stack::pushModuleFrame(Handle<Module> module, InvokeArgs &args)
  65.102 +{
  65.103 +    size_t nbytes = SizeForCodeFrame(module->code());
  65.104 +    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
  65.105 +        assert(false);
  65.106 +        return false;
  65.107 +    }
  65.108 +
  65.109 +    args.args_ = top_.sp;
  65.110 +    args.nargs_ = 0;
  65.111 +    args.stack_ = this;
  65.112 +    
  65.113 +    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
  65.114 +    new (frame) Frame(top_.fp, top_.pc, NULL, module->code(), zone_->heap().lifoPosition());
  65.115 +    
  65.116 +    top_.pc = frame->code()->start();
  65.117 +    top_.sp = frame->stackBase();
  65.118 +    top_.fp = frame;
  65.119 +
  65.120 +    return true;
  65.121 +}
  65.122 +
  65.123 +bool
  65.124 +Stack::pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc)
  65.125 +{
  65.126 +    size_t nbytes = sizeof(intptr_t) * argc + sizeof(Frame);
  65.127 +    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
  65.128 +        assert(false);
  65.129 +        return false;
  65.130 +    }
  65.131 +
  65.132 +    memset(top_.sp, 0, sizeof(intptr_t) * argc);
  65.133 +    args.argsBase_ = top_.sp;
  65.134 +    args.stack_ = this;
  65.135 +    top_.sp = reinterpret_cast<LocalSlot *>(reinterpret_cast<intptr_t *>(top_.sp) + argc);
  65.136 +
  65.137 +    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
  65.138 +    new (frame) Frame(top_.fp, top_.pc, native, zone_->heap().lifoPosition());
  65.139 +
  65.140 +    top_.pc = NULL;
  65.141 +    top_.sp = reinterpret_cast<LocalSlot *>(frame + 1);
  65.142 +    top_.fp = frame;
  65.143 +
  65.144 +    return true;
  65.145 +}
  65.146 +
  65.147 +Frame *
  65.148 +Stack::pushInlineFrame(Handle<Function> fun)
  65.149 +{
  65.150 +    Code *code = fun->code();
  65.151 +    size_t nbytes = SizeForCodeFrame(code);
  65.152 +    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
  65.153 +        zone_->reportError(Message_TooMuchRecursion);
  65.154 +        return NULL;
  65.155 +    }
  65.156 +
  65.157 +    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
  65.158 +    new (frame) Frame(top_.fp, top_.pc, fun, code, zone_->heap().lifoPosition());
  65.159 +    memset(frame->locals(), 0, sizeof(LocalSlot) * code->nlocals());
  65.160 +
  65.161 +    top_.pc = frame->code()->start();
  65.162 +    top_.sp = frame->stackBase();
  65.163 +    top_.fp = frame;
  65.164 +
  65.165 +    return frame;
  65.166 +}
  65.167 +
  65.168 +
  65.169 +Frame *
  65.170 +Stack::popInlineFrame()
  65.171 +{
  65.172 +    zone_->heap().unwindLifo(top_.fp->lifoPosition());
  65.173 +
  65.174 +    Frame *prev = top_.fp->prev();
  65.175 +    Function *fun = top_.fp->fun();
  65.176 +
  65.177 +    top_.pc = top_.fp->prevpc();
  65.178 +    top_.sp = reinterpret_cast<LocalSlot *>(top_.fp) - fun->nargs();
  65.179 +    top_.fp = prev;
  65.180 +    return prev;
  65.181 +}
  65.182 +
  65.183 +void
  65.184 +Stack::popInvokeFrame(InvokeArgs &args)
  65.185 +{
  65.186 +    zone_->heap().unwindLifo(top_.fp->lifoPosition());
  65.187 +
  65.188 +    top_.pc = top_.fp->prevpc();
  65.189 +    top_.sp = args.args_;
  65.190 +    top_.fp = top_.fp->prev();
  65.191 +}
  65.192 +
  65.193 +void
  65.194 +Stack::popNativeFrame(NativeArgs &args)
  65.195 +{
  65.196 +    zone_->heap().unwindLifo(top_.fp->lifoPosition());
  65.197 +
  65.198 +    top_.pc = top_.fp->prevpc();
  65.199 +    top_.sp = args.argsBase_;
  65.200 +    top_.fp = top_.fp->prev();
  65.201 +}
  65.202 +
  65.203 +void
  65.204 +Frame::accept(VirtualObjectVisitor *visitor)
  65.205 +{
  65.206 +    visitor->visit(reinterpret_cast<Object **>(&callee_));
  65.207 +    visitor->visit(reinterpret_cast<Object **>(&code_));
  65.208 +}
  65.209 +
  65.210 +static void
  65.211 +TraceFunctionFrame(VirtualObjectVisitor *visitor, Frame *fp, LocalSlot *sp, bytecode *pc)
  65.212 +{
  65.213 +    Code *code = fp->code();
  65.214 +    LocalSlot *slots = fp->locals();
  65.215 +
  65.216 +    // Trace local variables.
  65.217 +    for (unsigned i = 0; i < code->nlocals(); i++) {
  65.218 +        Type *type = code->localType(i);
  65.219 +        if (type->isTraceable())
  65.220 +            visitor->visit(&slots[i].obj);
  65.221 +    }
  65.222 +
  65.223 +    // Trace arguments, if a function call. Note that this means we usually
  65.224 +    // mark arguments twice, once on the caller side and once on the callee.
  65.225 +    // This makes it easier to deal with invoke frames which have no caller.
  65.226 +    if (Function *fun = fp->maybeFun()) {
  65.227 +        for (unsigned i = 0; i < fun->nargs(); i++) {
  65.228 +            Type *type = fun->argType(i);
  65.229 +            if (type->isTraceable())
  65.230 +                visitor->visit(&fp->arg(i).obj);
  65.231 +        }
  65.232 +    }
  65.233 +
  65.234 +    // Finally, trace stack slots. Not every gc-point in the bytecode will
  65.235 +    // have a safepoint; since they are actually uncommon, we don't emit
  65.236 +    // them unless at least one stack slot would be marked.
  65.237 +    if (uint8 *safepoint = code->safepointAt(code->pcToOffset(pc))) {
  65.238 +        LocalSlot *base = fp->stackBase();
  65.239 +        unsigned stackDepth = unsigned(sp - fp->stackBase());
  65.240 +        assert(stackDepth <= code->maxStackDepth());
  65.241 +
  65.242 +        for (unsigned i = 0; i < stackDepth; i++) {
  65.243 +            if (safepoint[i / 8] & (1 << (i % 8)))
  65.244 +                visitor->visit(&base[i].obj);
  65.245 +        }
  65.246 +    }
  65.247 +}
  65.248 +
  65.249 +void
  65.250 +Stack::accept(VirtualObjectVisitor *visitor)
  65.251 +{
  65.252 +    LocalSlot *sp = top_.sp;
  65.253 +    bytecode *pc = top_.pc;
  65.254 +
  65.255 +    for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
  65.256 +        if (!frame->isNative())
  65.257 +            TraceFunctionFrame(visitor, frame, sp, pc);
  65.258 +        frame->accept(visitor);
  65.259 +
  65.260 +        sp = reinterpret_cast<LocalSlot *>(frame);
  65.261 +        pc = frame->prevpc();
  65.262 +    }
  65.263 +}
  65.264 +
  65.265 +bool
  65.266 +Stack::isInCallStack(Handle<Module> module)
  65.267 +{
  65.268 +    for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
  65.269 +        if (frame->code()->module() == module)
  65.270 +            return true;
  65.271 +    }
  65.272 +    return false;
  65.273 +}
  65.274 +
  65.275 +StackIter::StackIter(Zone *zone)
  65.276 +  : pc_(zone->stack().top()->pc),
  65.277 +    fp_(zone->stack().top()->fp)
  65.278 +{
  65.279 +}
  65.280 +
  65.281 +bool
  65.282 +StackIter::done() const
  65.283 +{
  65.284 +    return !fp_;
  65.285 +}
  65.286 +
  65.287 +const char *
  65.288 +StackIter::function() const
  65.289 +{
  65.290 +    if (fp_->isNative())
  65.291 +        return fp_->native()->name()->chars();
  65.292 +    if (Function *fun = fp_->maybeFun())
  65.293 +        return fun->name()->chars();
  65.294 +    return "<toplevel>";
  65.295 +}
  65.296 +
  65.297 +unsigned
  65.298 +StackIter::lineNumber() const
  65.299 +{
  65.300 +    if (fp_->isNative())
  65.301 +        return 0;
  65.302 +    if (fp_->maybeFun()) {
  65.303 +        unsigned offs = fp_->code()->pcToOffset(pc_);
  65.304 +        return fp_->code()->pcToSource(offs).line;
  65.305 +    }
  65.306 +    return fp_->code()->lineNumber();
  65.307 +}
  65.308 +
  65.309 +const char *
  65.310 +StackIter::source() const
  65.311 +{
  65.312 +    if (fp_->isNative())
  65.313 +        return "<native>";
  65.314 +    return fp_->code()->module()->file()
  65.315 +           ? fp_->code()->module()->file()->chars()
  65.316 +           : "(anonymous)";
  65.317 +}
  65.318 +
  65.319 +void
  65.320 +StackIter::prev()
  65.321 +{
  65.322 +    pc_ = fp_->prevpc();
  65.323 +    fp_ = fp_->prev();
  65.324 +}
    66.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    66.2 +++ b/src/Stack.h	Tue Jul 24 23:53:34 2012 -0700
    66.3 @@ -0,0 +1,233 @@
    66.4 +/* vim: set ts=4 sw=4 tw=99 et:
    66.5 + *
    66.6 + * Copyright (C) 2012 David Anderson
    66.7 + *
    66.8 + * This file is part of JITCraft.
    66.9 + *
   66.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   66.11 + * the terms of the GNU General Public License as published by the Free
   66.12 + * Software Foundation, either version 3 of the License, or (at your option)
   66.13 + * any later version.
   66.14 + * 
   66.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   66.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   66.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   66.18 + *
   66.19 + * You should have received a copy of the GNU General Public License along with
   66.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   66.21 + */
   66.22 +#ifndef _include_jc_stack_h_
   66.23 +#define _include_jc_stack_h_
   66.24 +
   66.25 +#include <stddef.h>
   66.26 +#include "Utility.h"
   66.27 +#include "Code.h"
   66.28 +#include "Functions.h"
   66.29 +#include "VirtualObjectVisitor.h"
   66.30 +
   66.31 +namespace ke {
   66.32 +
   66.33 +class Object;
   66.34 +class Array;
   66.35 +class Reference;
   66.36 +class Frame;
   66.37 +class Stack;
   66.38 +class Zone;
   66.39 +class Module;
   66.40 +    
   66.41 +union LocalSlot
   66.42 +{
   66.43 +    int i32;
   66.44 +    float f;
   66.45 +    Address address;
   66.46 +    Object *obj;
   66.47 +    Array *array;
   66.48 +    Reference *ref;
   66.49 +    Function *fun;
   66.50 +    Module *module;
   66.51 +};
   66.52 +
   66.53 +struct Top
   66.54 +{
   66.55 +    LocalSlot *sp;
   66.56 +    bytecode *pc;
   66.57 +    Frame *fp;
   66.58 +};
   66.59 +
   66.60 +class Frame
   66.61 +{
   66.62 +    friend class Stack;
   66.63 +
   66.64 +    Frame *prev_;
   66.65 +    bytecode *prevpc_;
   66.66 +    union {
   66.67 +        Function *fun_;
   66.68 +        Native *native_;
   66.69 +        Object *callee_;
   66.70 +    };
   66.71 +    Code *code_;
   66.72 +    Address lifoPosition_;
   66.73 +
   66.74 +  public:
   66.75 +    Frame(Frame *prev, bytecode *prevpc, Function *fun, Code *code, Address lifoPosition)
   66.76 +      : prev_(prev),
   66.77 +        prevpc_(prevpc),
   66.78 +        fun_(fun),
   66.79 +        code_(code),
   66.80 +        lifoPosition_(lifoPosition)
   66.81 +    {
   66.82 +    }
   66.83 +
   66.84 +    Frame(Frame *prev, bytecode *prevpc, Native *native, Address lifoPosition)
   66.85 +      : prev_(prev),
   66.86 +        prevpc_(prevpc),
   66.87 +        native_(native),
   66.88 +        code_(NULL),
   66.89 +        lifoPosition_(lifoPosition)
   66.90 +    {
   66.91 +    }
   66.92 +
   66.93 +    LocalSlot *locals() {
   66.94 +        return reinterpret_cast<LocalSlot *>(this + 1);
   66.95 +    }
   66.96 +    LocalSlot *stackBase() {
   66.97 +        return locals() + code_->nlocals();
   66.98 +    }
   66.99 +    Function *fun() const {
  66.100 +        assert(fun_ && callee_->is(MapKind_Function));
  66.101 +        return fun_;
  66.102 +    }
  66.103 +    Function *maybeFun() const {
  66.104 +        return (fun_ && callee_->is(MapKind_Function)) ? fun_ : NULL;
  66.105 +    }
  66.106 +    bool isNative() const {
  66.107 +        return callee_ && callee_->is(MapKind_Native);
  66.108 +    }
  66.109 +    Native *native() const {
  66.110 +        assert(isNative());
  66.111 +        return native_;
  66.112 +    }
  66.113 +    Code *code() const {
  66.114 +        assert(code_);
  66.115 +        return code_;
  66.116 +    }
  66.117 +    Frame *prev() const {
  66.118 +        return prev_;
  66.119 +    }
  66.120 +    bytecode *prevpc() const {
  66.121 +        return prevpc_;
  66.122 +    }
  66.123 +    Address lifoPosition() const {
  66.124 +        return lifoPosition_;
  66.125 +    }
  66.126 +    LocalSlot &arg(unsigned slot) {
  66.127 +        assert(slot < fun()->nargs());
  66.128 +        return *(reinterpret_cast<LocalSlot *>(this) - slot - 1);
  66.129 +    }
  66.130 +    void accept(VirtualObjectVisitor *visitor);
  66.131 +};
  66.132 +
  66.133 +// RAII object for calling a function from C++.
  66.134 +class InvokeArgs
  66.135 +{
  66.136 +    friend class Stack;
  66.137 +
  66.138 +    Stack *stack_;
  66.139 +    LocalSlot *args_;
  66.140 +    unsigned nargs_;
  66.141 +
  66.142 +  public:
  66.143 +    InvokeArgs()
  66.144 +      : stack_(NULL),
  66.145 +        args_(NULL),
  66.146 +        nargs_(0)
  66.147 +    {
  66.148 +    }
  66.149 +
  66.150 +    ~InvokeArgs();
  66.151 +
  66.152 +    LocalSlot &arg(unsigned index) {
  66.153 +        assert(index < nargs_);
  66.154 +        return args_[nargs_ - index - 1];
  66.155 +    }
  66.156 +};
  66.157 +
  66.158 +// RAII object for calling a native from C++.
  66.159 +class NativeArgs
  66.160 +{
  66.161 +    friend class Stack;
  66.162 +
  66.163 +    Stack *stack_;
  66.164 +    LocalSlot *argsBase_;
  66.165 +
  66.166 +  public:
  66.167 +    NativeArgs()
  66.168 +      : stack_(NULL),
  66.169 +        argsBase_(NULL)
  66.170 +    {
  66.171 +    }
  66.172 +
  66.173 +    ~NativeArgs();
  66.174 +
  66.175 +    intptr_t *args() {
  66.176 +        return reinterpret_cast<intptr_t *>(argsBase_);
  66.177 +    }
  66.178 +};
  66.179 +
  66.180 +class Stack
  66.181 +{
  66.182 +    friend class InvokeArgs;
  66.183 +    friend class NativeArgs;
  66.184 +
  66.185 +  private:
  66.186 +    static const size_t STACK_SIZE = 1024 * 1024;
  66.187 +
  66.188 +  public:
  66.189 +    Stack(Zone *zone);
  66.190 +    ~Stack();
  66.191 +
  66.192 +    bool initialize();
  66.193 +
  66.194 +  public:
  66.195 +    Frame *pushInlineFrame(Handle<Function> fun);
  66.196 +    Frame *popInlineFrame();
  66.197 +
  66.198 +    bool pushInvokeFrame(Handle<Function> fun, InvokeArgs &args);
  66.199 +    bool pushModuleFrame(Handle<Module> module, InvokeArgs &args);
  66.200 +    bool pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc);
  66.201 +
  66.202 +    Top *top() {
  66.203 +        return &top_;
  66.204 +    }
  66.205 +    bool isInCallStack(Handle<Module> module);
  66.206 +    void accept(VirtualObjectVisitor *visitor);
  66.207 +
  66.208 +  private:
  66.209 +    void popInvokeFrame(InvokeArgs &args);
  66.210 +    void popNativeFrame(NativeArgs &args);
  66.211 +
  66.212 +  private:
  66.213 +    Zone *zone_;
  66.214 +    char *buffer_;
  66.215 +    char *end_;
  66.216 +    Top top_;
  66.217 +};
  66.218 +
  66.219 +class StackIter
  66.220 +{
  66.221 +    bytecode *pc_;
  66.222 +    Frame *fp_;
  66.223 +
  66.224 +  public:
  66.225 +    StackIter(Zone *zone);
  66.226 +
  66.227 +    bool done() const;
  66.228 +    const char *function() const;
  66.229 +    unsigned lineNumber() const;
  66.230 +    const char *source() const;
  66.231 +    void prev();
  66.232 +};
  66.233 +
  66.234 +}
  66.235 +
  66.236 +#endif // _include_jc_stack_h_
    67.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    67.2 +++ b/src/StringPool.cpp	Tue Jul 24 23:53:34 2012 -0700
    67.3 @@ -0,0 +1,69 @@
    67.4 +/*
    67.5 + * Copyright (C) 2012 David Anderson
    67.6 + *
    67.7 + * This file is part of JITCraft.
    67.8 + *
    67.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   67.10 + * the terms of the GNU General Public License as published by the Free
   67.11 + * Software Foundation, either version 3 of the License, or (at your option)
   67.12 + * any later version.
   67.13 + * 
   67.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   67.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   67.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   67.17 + *
   67.18 + * You should have received a copy of the GNU General Public License along with
   67.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   67.20 + */
   67.21 +#include "StringPool.h"
   67.22 +#include "Strings.h"
   67.23 +#include "Spaces.h"
   67.24 +
   67.25 +using namespace ke;
   67.26 +
   67.27 +StringPool::StringPool(Zone *zone)
   67.28 +  : zone_(zone),
   67.29 +    set_(ZoneAllocatorPolicy())
   67.30 +{
   67.31 +}
   67.32 +
   67.33 +StringPool::~StringPool()
   67.34 +{
   67.35 +}
   67.36 +
   67.37 +bool
   67.38 +StringPool::initialize()
   67.39 +{
   67.40 +    if (!set_.init(32))
   67.41 +        return false;
   67.42 +    return true;
   67.43 +}
   67.44 +
   67.45 +String *
   67.46 +StringPool::add(const char *str, size_t length)
   67.47 +{
   67.48 +    StringSet::Insert i = set_.findForAdd(CharsAndLength(str, length));
   67.49 +    if (i.found())
   67.50 +        return *i;
   67.51 +
   67.52 +    Local<String> obj(zone_, String::New(zone_, str, length, Heap::Tenure_Old));
   67.53 +    if (!obj)
   67.54 +        return NULL;
   67.55 +
   67.56 +    set_.add(i, obj);
   67.57 +    return obj;
   67.58 +}
   67.59 +
   67.60 +void
   67.61 +StringPool::sweep()
   67.62 +{
   67.63 +    for (StringSet::iterator i(&set_); !i.empty(); i.next()) {
   67.64 +        String *obj = *i;
   67.65 +        MarkBit bits = HeapChunk::GetMarkBit(obj);
   67.66 +        if (HeapChunk::IsWhite(bits))
   67.67 +            i.erase();
   67.68 +        else
   67.69 +            assert(HeapChunk::IsBlack(bits));
   67.70 +    }
   67.71 +    set_.checkDensity();
   67.72 +}
    68.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    68.2 +++ b/src/StringPool.h	Tue Jul 24 23:53:34 2012 -0700
    68.3 @@ -0,0 +1,85 @@
    68.4 +/*
    68.5 + * Copyright (C) 2012 David Anderson
    68.6 + *
    68.7 + * This file is part of JITCraft.
    68.8 + *
    68.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   68.10 + * the terms of the GNU General Public License as published by the Free
   68.11 + * Software Foundation, either version 3 of the License, or (at your option)
   68.12 + * any later version.
   68.13 + * 
   68.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   68.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   68.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   68.17 + *
   68.18 + * You should have received a copy of the GNU General Public License along with
   68.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   68.20 + */
   68.21 +#ifndef _include_jitcraft_string_pool_h_
   68.22 +#define _include_jitcraft_string_pool_h_
   68.23 +
   68.24 +#include "AllocatorPolicies.h"
   68.25 +#include "HashTable.h"
   68.26 +#include "Strings.h"
   68.27 +
   68.28 +namespace ke {
   68.29 +
   68.30 +class Zone;
   68.31 +class String;
   68.32 +
   68.33 +// Guarantee that strings with the same contents will map to one pointer. 
   68.34 +class StringPool
   68.35 +{
   68.36 +    class CharsAndLength {
   68.37 +        const char *str_;
   68.38 +        size_t length_;
   68.39 +
   68.40 +      public:
   68.41 +        CharsAndLength(const char *str, size_t length)
   68.42 +          : str_(str),
   68.43 +            length_(length)
   68.44 +        {
   68.45 +        }
   68.46 +
   68.47 +        const char *str() const {
   68.48 +            return str_;
   68.49 +        }
   68.50 +        size_t length() const {
   68.51 +            return length_;
   68.52 +        }
   68.53 +    };
   68.54 +
   68.55 +    struct Policy
   68.56 +    {
   68.57 +        typedef String * Payload;
   68.58 +
   68.59 +        static uint32 hash(const CharsAndLength &key) {
   68.60 +            return HashCharSequence(key.str(), key.length());
   68.61 +        }
   68.62 +        
   68.63 +        static bool matches(const CharsAndLength &key, String *string) {
   68.64 +            if (string->length() != key.length())
   68.65 +                return false;
   68.66 +            return memcmp(string->chars(), key.str(), key.length() * sizeof(char)) == 0;
   68.67 +        }
   68.68 +    };
   68.69 +
   68.70 +    typedef HashTable<Policy, ZoneAllocatorPolicy> StringSet;
   68.71 +
   68.72 +  public:
   68.73 +    StringPool(Zone *zone);
   68.74 +    ~StringPool();
   68.75 +    bool initialize();
   68.76 +
   68.77 +  public:
   68.78 +    String *add(const char *str, size_t len);
   68.79 +    void sweep();
   68.80 +
   68.81 +  private:
   68.82 +    Zone *zone_;
   68.83 +    StringSet set_;
   68.84 +};
   68.85 +
   68.86 +}
   68.87 +
   68.88 +#endif // _include_jitcraft_string_pool_h_
    69.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    69.2 +++ b/src/Strings.cpp	Tue Jul 24 23:53:34 2012 -0700
    69.3 @@ -0,0 +1,43 @@
    69.4 +/* vim: set ts=4 sw=4 tw=99 et:
    69.5 + *
    69.6 + * Copyright (C) 2012 David Anderson
    69.7 + *
    69.8 + * This file is part of JITCraft.
    69.9 + *
   69.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   69.11 + * the terms of the GNU General Public License as published by the Free
   69.12 + * Software Foundation, either version 3 of the License, or (at your option)
   69.13 + * any later version.
   69.14 + * 
   69.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   69.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   69.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   69.18 + *
   69.19 + * You should have received a copy of the GNU General Public License along with
   69.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   69.21 + */
   69.22 +#include "Strings.h"
   69.23 +#include "Zone.h"
   69.24 +#include "Heap-inl.h"
   69.25 +
   69.26 +using namespace ke;
   69.27 +
   69.28 +String *
   69.29 +String::New(Zone *zone, const char *from, Heap::Tenure tenure)
   69.30 +{
   69.31 +    return New(zone, from, strlen(from), tenure);
   69.32 +}
   69.33 +
   69.34 +String *
   69.35 +String::New(Zone *zone, const char *from, size_t length, Heap::Tenure tenure)
   69.36 +{
   69.37 +    size_t bytes = SizeFor(length);
   69.38 +    Local<String> string(zone, String::cast(zone->allocate(MapKind_String, bytes, tenure)));
   69.39 +    if (!string)
   69.40 +        return NULL;
   69.41 +
   69.42 +    string->length_ = length;
   69.43 +    memcpy(string->chars(), from, length + 1);
   69.44 +
   69.45 +    return string;
   69.46 +}
    70.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    70.2 +++ b/src/Strings.h	Tue Jul 24 23:53:34 2012 -0700
    70.3 @@ -0,0 +1,54 @@
    70.4 +/* vim: set ts=4 sw=4 tw=99 et:
    70.5 + *
    70.6 + * Copyright (C) 2012 David Anderson
    70.7 + *
    70.8 + * This file is part of JITCraft.
    70.9 + *
   70.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   70.11 + * the terms of the GNU General Public License as published by the Free
   70.12 + * Software Foundation, either version 3 of the License, or (at your option)
   70.13 + * any later version.
   70.14 + * 
   70.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   70.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   70.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   70.18 + *
   70.19 + * You should have received a copy of the GNU General Public License along with
   70.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   70.21 + */
   70.22 +#ifndef _include_jitcraft_string_h_
   70.23 +#define _include_jitcraft_string_h_
   70.24 +
   70.25 +#include "Heap.h"
   70.26 +
   70.27 +namespace ke {
   70.28 +
   70.29 +// A fixed-length string containing UTF-8 characters.
   70.30 +class String : public Object
   70.31 +{
   70.32 +    uint32 length_;
   70.33 +    
   70.34 +  public:
   70.35 +    static String *New(Zone *zone, const char *from, Heap::Tenure tenure = Heap::Tenure_Default);
   70.36 +    static String *New(Zone *zone, const char *from, size_t length, Heap::Tenure tenure = Heap::Tenure_Default);
   70.37 +
   70.38 +    unsigned length() {
   70.39 +        return length_;
   70.40 +    }
   70.41 +    char *chars() {
   70.42 +        return reinterpret_cast<char *>(this + 1);
   70.43 +    }
   70.44 +
   70.45 +    static size_t SizeFor(unsigned length) {
   70.46 +        return Align(sizeof(String) + sizeof(char) * (length + 1), kObjectAlignment);
   70.47 +    }
   70.48 +
   70.49 +    static inline String *cast(Object *obj) {
   70.50 +        assert(!obj || obj->is(MapKind_String));
   70.51 +        return reinterpret_cast<String *>(obj);
   70.52 +    }
   70.53 +};
   70.54 +
   70.55 +}
   70.56 +
   70.57 +#endif // _include_jitcraft_string_h_
    71.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    71.2 +++ b/src/Structures.cpp	Tue Jul 24 23:53:34 2012 -0700
    71.3 @@ -0,0 +1,46 @@
    71.4 +/* vim: set ts=4 sw=4 tw=99 et
    71.5 + *
    71.6 + * Copyright (C) 2012 David Anderson
    71.7 + *
    71.8 + * This file is part of JITCraft.
    71.9 + *
   71.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   71.11 + * the terms of the GNU General Public License as published by the Free
   71.12 + * Software Foundation, either version 3 of the License, or (at your option)
   71.13 + * any later version.
   71.14 + * 
   71.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   71.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   71.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   71.18 + *
   71.19 + * You should have received a copy of the GNU General Public License along with
   71.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   71.21 + */
   71.22 +#include "Structures.h"
   71.23 +#include "Types.h"
   71.24 +
   71.25 +using namespace ke;
   71.26 +
   71.27 +StructureBufferBuilder::StructureBufferBuilder()
   71.28 +  : size_(0)
   71.29 +{
   71.30 +}
   71.31 +
   71.32 +bool
   71.33 +StructureBufferBuilder::add(Handle<Type> type, unsigned *offset)
   71.34 +{
   71.35 +    *offset = size_;
   71.36 +
   71.37 +    if (!type->isTraceable()) {
   71.38 +        // For now, assume the size of primitives is 4-byte.
   71.39 +        assert(type->isInt32() || type->isFloat());
   71.40 +        size_ += 4;
   71.41 +        return true;
   71.42 +    }
   71.43 +
   71.44 +    if (!offsets_.append(size_))
   71.45 +        return false;
   71.46 +
   71.47 +    size_ += sizeof(Object *);
   71.48 +    return true;
   71.49 +}
    72.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    72.2 +++ b/src/Structures.h	Tue Jul 24 23:53:34 2012 -0700
    72.3 @@ -0,0 +1,60 @@
    72.4 +/* vim: set ts=4 sw=4 tw=99 et
    72.5 + *
    72.6 + * Copyright (C) 2012 David Anderson
    72.7 + *
    72.8 + * This file is part of JITCraft.
    72.9 + *
   72.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   72.11 + * the terms of the GNU General Public License as published by the Free
   72.12 + * Software Foundation, either version 3 of the License, or (at your option)
   72.13 + * any later version.
   72.14 + * 
   72.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   72.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   72.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   72.18 + *
   72.19 + * You should have received a copy of the GNU General Public License along with
   72.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   72.21 + */
   72.22 +#ifndef _include_jc_structure_h_
   72.23 +#define _include_jc_structure_h_
   72.24 +
   72.25 +#include "Objects.h"
   72.26 +#include "Handles.h"
   72.27 +#include "Vector.h"
   72.28 +
   72.29 +namespace ke {
   72.30 +
   72.31 +class Type;
   72.32 +class String;
   72.33 +class FixedArray;
   72.34 +
   72.35 +// When describing composite structures, the GC must be able to trace interior
   72.36 +// references to Objects. To make this possible, maps that describe composite
   72.37 +// structures must provide a list of offsets into their objects that are
   72.38 +// traceable. StructureBufferBuilder assists with this.
   72.39 +class StructureBufferBuilder
   72.40 +{
   72.41 +  public:
   72.42 +    StructureBufferBuilder();
   72.43 +
   72.44 +    bool add(Handle<Type> type, unsigned *offset);
   72.45 +
   72.46 +    unsigned structureSize() const {
   72.47 +        return size_;
   72.48 +    }
   72.49 +    unsigned traceableOffsetCount() const {
   72.50 +        return offsets_.length();
   72.51 +    }
   72.52 +    const unsigned *offsets() {
   72.53 +        return offsets_.buffer();
   72.54 +    }
   72.55 +
   72.56 +  private:
   72.57 +    Vector<unsigned> offsets_;
   72.58 +    unsigned size_;
   72.59 +};
   72.60 +
   72.61 +}
   72.62 +
   72.63 +#endif // _include_jc_structure_h_
    73.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    73.2 +++ b/src/Token.h	Tue Jul 24 23:53:34 2012 -0700
    73.3 @@ -0,0 +1,128 @@
    73.4 +/*
    73.5 + * Copyright (C) 2012 David Anderson
    73.6 + *
    73.7 + * This file is part of JITCraft.
    73.8 + *
    73.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   73.10 + * the terms of the GNU General Public License as published by the Free
   73.11 + * Software Foundation, either version 3 of the License, or (at your option)
   73.12 + * any later version.
   73.13 + * 
   73.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   73.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   73.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   73.17 + *
   73.18 + * You should have received a copy of the GNU General Public License along with
   73.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   73.20 + */
   73.21 +#ifndef _include_jitcraft_token_h_
   73.22 +#define _include_jitcraft_token_h_
   73.23 +
   73.24 +namespace ke {
   73.25 +
   73.26 +struct SourcePosition
   73.27 +{
   73.28 +    int line;
   73.29 +    int col;
   73.30 +
   73.31 +    SourcePosition()
   73.32 +      : line(-1),
   73.33 +        col(-1)
   73.34 +    {
   73.35 +    }
   73.36 +
   73.37 +    SourcePosition(unsigned line, unsigned col)
   73.38 +      : line(line),
   73.39 +        col(col)
   73.40 +    {
   73.41 +    }
   73.42 +};
   73.43 +
   73.44 +// List of tokens the scanner can recognize.
   73.45 +//
   73.46 +// Some restrictions:
   73.47 +//   * (ASSIGN_ADD - TOK_PLUS) must be the delta between an operator and its
   73.48 +//     op-and-assign equivalent.
   73.49 +#define TOKENMAP(_)                                     \
   73.50 +    _(ERROR,              "<error>")                    \
   73.51 +    _(NEW,                "'new'")                      \
   73.52 +    _(FOR,                "'for'")                      \
   73.53 +    _(RETURN,             "'return'")                   \
   73.54 +    _(NAME,               "<name>")                     \
   73.55 +    _(INTEGER_LITERAL,    "<integer>")                  \
   73.56 +    _(FLOAT_LITERAL,      "<float>")                    \
   73.57 +    _(STRING_LITERAL,     "<string>")                   \
   73.58 +    _(IF,                 "<if>")                       \
   73.59 +    _(ELSE,               "<else>")                     \
   73.60 +    _(ENUM,               "<enum>")                     \
   73.61 +    _(LABEL,              "<label>")                    \
   73.62 +    _(WHILE,              "<while>")                    \
   73.63 +    _(DO,                 "<do>")                       \
   73.64 +    _(BREAK,              "<break>")                    \
   73.65 +    _(CONTINUE,           "<continue>")                 \
   73.66 +    _(FORWARD,            "<forward>")                  \
   73.67 +    _(PUBLIC,             "<public>")                   \
   73.68 +    _(CONST,              "<const>")                    \
   73.69 +    _(NATIVE,             "<native>")                   \
   73.70 +    _(ELLIPSES,           "...")                        \
   73.71 +    _(PLUS,               "+")                          \
   73.72 +    _(MINUS,              "-")                          \
   73.73 +    _(STAR,               "*")                          \
   73.74 +    _(SLASH,              "/")                          \
   73.75 +    _(PERCENT,            "%")                          \
   73.76 +    _(AMPERSAND,          "&")                          \
   73.77 +    _(BITOR,              "|")                          \
   73.78 +    _(BITXOR,             "^")                          \
   73.79 +    _(SHR,                ">>")                         \
   73.80 +    _(USHR,               ">>>")                        \
   73.81 +    _(SHL,                "<<")                         \
   73.82 +    _(ASSIGN,             "=")                          \
   73.83 +    _(SEMICOLON,          ";")                          \
   73.84 +    _(LBRACE,             "{")                          \
   73.85 +    _(RBRACE,             "}")                          \
   73.86 +    _(LPAREN,             "(")                          \
   73.87 +    _(RPAREN,             ")")                          \
   73.88 +    _(LBRACKET,           "[")                          \
   73.89 +    _(RBRACKET,           "]")                          \
   73.90 +    _(ASSIGN_ADD,         "+=")                         \
   73.91 +    _(ASSIGN_SUB,         "-=")                         \
   73.92 +    _(ASSIGN_MUL,         "*=")                         \
   73.93 +    _(ASSIGN_DIV,         "/=")                         \
   73.94 +    _(ASSIGN_MOD,         "%=")                         \
   73.95 +    _(ASSIGN_BITAND,      "&=")                         \
   73.96 +    _(ASSIGN_BITOR,       "|=")                         \
   73.97 +    _(ASSIGN_BITXOR,      "^=")                         \
   73.98 +    _(ASSIGN_SHR,         ">>=")                        \
   73.99 +    _(ASSIGN_USHR,        ">>>=")                       \
  73.100 +    _(ASSIGN_SHL,         "<<=")                        \
  73.101 +    _(INCREMENT,          "++")                         \
  73.102 +    _(DECREMENT,          "--")                         \
  73.103 +    _(EQUALS,             "==")                         \
  73.104 +    _(NOTEQUALS,          "!=")                         \
  73.105 +    _(LT,                 "<")                          \
  73.106 +    _(LE,                 "<=")                         \
  73.107 +    _(GT,                 ">")                          \
  73.108 +    _(GE,                 ">=")                         \
  73.109 +    _(AND,                "&&")                         \
  73.110 +    _(OR,                 "||")                         \
  73.111 +    _(COMMA,              ",")                          \
  73.112 +    _(NOT,                "!")                          \
  73.113 +    _(TILDE,              "~")                          \
  73.114 +    _(QMARK,              "?")                          \
  73.115 +    _(COLON,              ":")                          \
  73.116 +    _(EOF,                "<end-of-file>")
  73.117 +
  73.118 +enum TokenKind
  73.119 +{
  73.120 +#   define _(name, str) TOK_##name,
  73.121 +    TOKENMAP(_)
  73.122 +#   undef _
  73.123 +    TOK_BITAND = TOK_AMPERSAND,
  73.124 +    TOKENS_TOTAL
  73.125 +};
  73.126 +
  73.127 +extern const char *TokenNames[];
  73.128 +
  73.129 +} // namespace ke
  73.130 +
  73.131 +#endif //_include_jitcraft_token_h_
    74.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    74.2 +++ b/src/TypeManager.cpp	Tue Jul 24 23:53:34 2012 -0700
    74.3 @@ -0,0 +1,119 @@
    74.4 +/* vim: set ts=4 sw=4 tw=99 et:
    74.5 + *
    74.6 + * Copyright (C) 2012 David Anderson
    74.7 + *
    74.8 + * This file is part of JITCraft.
    74.9 + *
   74.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   74.11 + * the terms of the GNU General Public License as published by the Free
   74.12 + * Software Foundation, either version 3 of the License, or (at your option)
   74.13 + * any later version.
   74.14 + * 
   74.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   74.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   74.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   74.18 + *
   74.19 + * You should have received a copy of the GNU General Public License along with
   74.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   74.21 + */
   74.22 +#include "Types.h"
   74.23 +#include "TypeManager.h"
   74.24 +#include "Zone.h"
   74.25 +#include "Strings.h"
   74.26 +
   74.27 +using namespace ke;
   74.28 +
   74.29 +
   74.30 +TypeManager::TypeManager(Zone *zone)
   74.31 +  : zone_(zone)
   74.32 +{
   74.33 +}
   74.34 +
   74.35 +bool
   74.36 +TypeManager::initialize()
   74.37 +{
   74.38 +    voidType_ = Type::NewVoid(zone_);
   74.39 +    if (!voidType_)
   74.40 +        return false;
   74.41 +
   74.42 +    Local<String> floatTag(zone_, zone_->makeSymbol("Float"));
   74.43 +    if (!floatTag)
   74.44 +        return false;
   74.45 +
   74.46 +    Local<String> stringTag(zone_, zone_->makeSymbol("String"));
   74.47 +    if (!stringTag)
   74.48 +        return false;
   74.49 +
   74.50 +    Local<String> nullTag(zone_);
   74.51 +
   74.52 +    if ((primitiveTypes_[PrimitiveType_Int32] = Type::NewPrimitive(zone_, nullTag)) == NULL)
   74.53 +        return false;
   74.54 +    if ((primitiveTypes_[PrimitiveType_Float] = Type::NewPrimitive(zone_, floatTag)) == NULL)
   74.55 +        return false;
   74.56 +    if ((primitiveTypes_[PrimitiveType_Native] = Type::NewPrimitive(zone_, PrimitiveType_Native)) == NULL)
   74.57 +        return false;
   74.58 +    if ((primitiveTypes_[PrimitiveType_Char] = Type::NewPrimitive(zone_, stringTag)) == NULL)
   74.59 +        return false;
   74.60 +
   74.61 +    Local<Type> type(zone_);
   74.62 +    for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
   74.63 +        type = primitiveTypes_[i];
   74.64 +        if ((referenceTypes_[i] = Type::NewReference(zone_, type, false)) == NULL)
   74.65 +            return false;
   74.66 +    }
   74.67 +
   74.68 +    return true;
   74.69 +}
   74.70 +
   74.71 +Type *
   74.72 +TypeManager::getPrimitiveForTag(Handle<String> tag)
   74.73 +{
   74.74 +    if (!tag)
   74.75 +        return getPrimitive(PrimitiveType_Int32);
   74.76 +    if (strcmp(tag->chars(), "Float") == 0)
   74.77 +        return getPrimitive(PrimitiveType_Float);
   74.78 +    if (strcmp(tag->chars(), "String") == 0)
   74.79 +        return getPrimitive(PrimitiveType_Char);
   74.80 +    return NULL;
   74.81 +}
   74.82 +
   74.83 +Type *
   74.84 +TypeManager::unsafeArray(Handle<Type> contained, int elements, bool isConst)
   74.85 +{
   74.86 +    // :TODO: cache this.
   74.87 +    return Type::NewArray(zone_, contained, elements, isConst);
   74.88 +}
   74.89 +
   74.90 +Type *
   74.91 +TypeManager::getReference(Handle<Type> type, bool isConst)
   74.92 +{
   74.93 +    if (!isConst && (type->isFloat() || (type->isInt32() && !type->tag())))
   74.94 +        return referenceTypes_[type->primitive()];
   74.95 +
   74.96 +    // :TODO: cache this.
   74.97 +    return Type::NewReference(zone_, type, isConst);
   74.98 +}
   74.99 +
  74.100 +Type *
  74.101 +TypeManager::newFunction(Handle<Type> returnType, Handle<FixedArray> args)
  74.102 +{
  74.103 +    // :TODO: cache this.
  74.104 +    return Type::NewFunction(zone_, returnType, args);
  74.105 +}
  74.106 +
  74.107 +Type *
  74.108 +TypeManager::newNative(Handle<Type> returnType, Handle<FixedArray> args, bool variadic)
  74.109 +{
  74.110 +    // :TODO: cache this.
  74.111 +    return Type::NewNative(zone_, returnType, args, variadic);
  74.112 +}
  74.113 +
  74.114 +void
  74.115 +TypeManager::accept(VirtualObjectVisitor *visitor)
  74.116 +{
  74.117 +    visitor->visit(voidType_.address());
  74.118 +    for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
  74.119 +        visitor->visit(primitiveTypes_[i].address());
  74.120 +        visitor->visit(referenceTypes_[i].address());
  74.121 +    }
  74.122 +}
    75.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    75.2 +++ b/src/TypeManager.h	Tue Jul 24 23:53:34 2012 -0700
    75.3 @@ -0,0 +1,61 @@
    75.4 +/*
    75.5 + * Copyright (C) 2012 David Anderson
    75.6 + *
    75.7 + * This file is part of JITCraft.
    75.8 + *
    75.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   75.10 + * the terms of the GNU General Public License as published by the Free
   75.11 + * Software Foundation, either version 3 of the License, or (at your option)
   75.12 + * any later version.
   75.13 + * 
   75.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   75.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   75.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   75.17 + *
   75.18 + * You should have received a copy of the GNU General Public License along with
   75.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   75.20 + */
   75.21 +#ifndef _include_jitcraft_type_manager_h_
   75.22 +#define _include_jitcraft_type_manager_h_
   75.23 +
   75.24 +#include "Barriers.h"
   75.25 +#include "Types.h"
   75.26 +#include "VirtualObjectVisitor.h"
   75.27 +
   75.28 +namespace ke {
   75.29 +
   75.30 +class String;
   75.31 +
   75.32 +class TypeManager
   75.33 +{
   75.34 +    Zone *zone_;
   75.35 +
   75.36 +    // Primitive type cache.
   75.37 +    Unbarriered<Type> voidType_;
   75.38 +    Unbarriered<Type> primitiveTypes_[PrimitiveTypes_Total];
   75.39 +    Unbarriered<Type> referenceTypes_[PrimitiveTypes_Total];
   75.40 +
   75.41 +  public:
   75.42 +    TypeManager(Zone *zone);
   75.43 +
   75.44 +    bool initialize();
   75.45 +
   75.46 +    Type *getPrimitiveForTag(Handle<String>);
   75.47 +    Type *getPrimitive(PrimitiveType type) {
   75.48 +        return primitiveTypes_[type];
   75.49 +    }
   75.50 +
   75.51 +    Type *getVoid() {
   75.52 +        return voidType_;
   75.53 +    }
   75.54 +    Type *getReference(Handle<Type> type, bool isConst);
   75.55 +    Type *unsafeArray(Handle<Type> contained, int elements, bool isConst);
   75.56 +    Type *newFunction(Handle<Type> returnType, Handle<FixedArray> args);
   75.57 +    Type *newNative(Handle<Type> returnType, Handle<FixedArray> args, bool variadic);
   75.58 +    
   75.59 +    void accept(VirtualObjectVisitor *visitor);
   75.60 +};
   75.61 +
   75.62 +}
   75.63 +
   75.64 +#endif // _include_jitcraft_type_manager_h_
    76.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    76.2 +++ b/src/Types.cpp	Tue Jul 24 23:53:34 2012 -0700
    76.3 @@ -0,0 +1,187 @@
    76.4 +/*
    76.5 + * Copyright (C) 2012 David Anderson
    76.6 + *
    76.7 + * This file is part of JITCraft.
    76.8 + *
    76.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   76.10 + * the terms of the GNU General Public License as published by the Free
   76.11 + * Software Foundation, either version 3 of the License, or (at your option)
   76.12 + * any later version.
   76.13 + * 
   76.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   76.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   76.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   76.17 + *
   76.18 + * You should have received a copy of the GNU General Public License along with
   76.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   76.20 + */
   76.21 +#include "Types.h"
   76.22 +#include "Zone.h"
   76.23 +#include "Strings.h"
   76.24 +#include "Heap-inl.h"
   76.25 +
   76.26 +using namespace ke;
   76.27 +
   76.28 +Type *
   76.29 +Type::NewVoid(Zone *zone)
   76.30 +{
   76.31 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   76.32 +    if (!type)
   76.33 +        return NULL;
   76.34 +
   76.35 +    type->kind_ = VOID;
   76.36 +    type->tag_ = NULL;
   76.37 +    type->contained_ = NULL;
   76.38 +    type->returnType_ = NULL;
   76.39 +    type->parameters_ = NULL;
   76.40 +    return type;
   76.41 +}
   76.42 +
   76.43 +Type *
   76.44 +Type::NewPrimitive(Zone *zone, Handle<String> tag)
   76.45 +{
   76.46 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   76.47 +    if (!type)
   76.48 +        return NULL;
   76.49 +
   76.50 +    type->kind_ = PRIMITIVE;
   76.51 +    type->tag_ = tag;
   76.52 +    type->contained_ = NULL;
   76.53 +    type->returnType_ = NULL;
   76.54 +    type->parameters_ = NULL;
   76.55 +
   76.56 +    if (tag && strcmp(tag->chars(), "Float") == 0)
   76.57 +        type->primitive_ = PrimitiveType_Float;
   76.58 +    else if (tag && strcmp(tag->chars(), "String") == 0)
   76.59 +        type->primitive_ = PrimitiveType_Char;
   76.60 +    else
   76.61 +        type->primitive_ = PrimitiveType_Int32;
   76.62 +    return type;
   76.63 +}
   76.64 +
   76.65 +Type *
   76.66 +Type::NewPrimitive(Zone *zone, PrimitiveType prim)
   76.67 +{
   76.68 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   76.69 +    if (!type)
   76.70 +        return NULL;
   76.71 +
   76.72 +    type->kind_ = PRIMITIVE;
   76.73 +    type->tag_ = NULL;
   76.74 +    type->contained_ = NULL;
   76.75 +    type->returnType_ = NULL;
   76.76 +    type->parameters_ = NULL;
   76.77 +    type->primitive_ = prim;
   76.78 +    return type;
   76.79 +}
   76.80 +
   76.81 +Type *
   76.82 +Type::NewArray(Zone *zone, Handle<Type> contained, int elements, bool isConst)
   76.83 +{
   76.84 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   76.85 +    if (!type)
   76.86 +        return NULL;
   76.87 +
   76.88 +    type->kind_ = ARRAY;
   76.89 +    type->tag_ = NULL;
   76.90 +    type->contained_ = contained;
   76.91 +    type->returnType_ = NULL;
   76.92 +    type->parameters_ = NULL;
   76.93 +    type->elements_ = elements;
   76.94 +    if (contained->isPrimitive())
   76.95 +        type->levels_ = 1;
   76.96 +    else
   76.97 +        type->levels_ = contained->levels() + 1;
   76.98 +    type->const_ = isConst;
   76.99 +    return type;
  76.100 +}
  76.101 +
  76.102 +Type *
  76.103 +Type::NewReference(Zone *zone, Handle<Type> contained, bool isConst)
  76.104 +{
  76.105 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  76.106 +    if (!type)
  76.107 +        return NULL;
  76.108 +
  76.109 +    type->kind_ = REFERENCE;
  76.110 +    type->tag_ = NULL;
  76.111 +    type->contained_ = contained;
  76.112 +    type->returnType_ = NULL;
  76.113 +    type->parameters_ = NULL;
  76.114 +    type->const_ = isConst;
  76.115 +    return type;
  76.116 +}
  76.117 +
  76.118 +Type *
  76.119 +Type::NewFunction(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters)
  76.120 +{
  76.121 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  76.122 +    if (!type)
  76.123 +        return NULL;
  76.124 +
  76.125 +    type->kind_ = FUNCTION;
  76.126 +    type->contained_ = NULL;
  76.127 +    type->returnType_ = returnType;
  76.128 +    type->parameters_ = parameters;
  76.129 +    return type;
  76.130 +}
  76.131 +
  76.132 +Type *
  76.133 +Type::NewNative(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters, bool variadic)
  76.134 +{
  76.135 +    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
  76.136 +    if (!type)
  76.137 +        return NULL;
  76.138 +
  76.139 +    type->kind_ = NATIVE;
  76.140 +    type->contained_ = NULL;
  76.141 +    type->returnType_ = returnType;
  76.142 +    type->parameters_ = parameters;
  76.143 +    type->variadicNative_ = variadic;
  76.144 +    return type;
  76.145 +}
  76.146 +
  76.147 +bool
  76.148 +Type::Compare(Type *left, Type *right)
  76.149 +{
  76.150 +    if (left->kind() != right->kind())
  76.151 +        return false;
  76.152 +
  76.153 +    switch (left->kind()) {
  76.154 +      case Type::PRIMITIVE:
  76.155 +        return (left->primitive() == right->primitive() &&
  76.156 +                left->tag() == right->tag());
  76.157 +
  76.158 +      case Type::ARRAY:
  76.159 +      {
  76.160 +        if (left->levels() != right->levels())
  76.161 +          return false;
  76.162 +        if (left->elements() != right->elements())
  76.163 +          return false;
  76.164 +        return Compare(left->contained(), right->contained());
  76.165 +      }
  76.166 +
  76.167 +      case Type::FUNCTION:
  76.168 +      {
  76.169 +        if (!Compare(left->returnType(), right->returnType()))
  76.170 +            return false;
  76.171 +        if (left->parameters()->length() != right->parameters()->length())
  76.172 +            return false;
  76.173 +        if (left->isNative() != right->isNative())
  76.174 +            return false;
  76.175 +        if (left->isNative() && (left->isNativeVariadic() != right->isNativeVariadic()))
  76.176 +            return false;
  76.177 +        for (unsigned i = 0; i < left->parameters()->length(); i++) {
  76.178 +            Type *leftparam = left->parameterAt(i);
  76.179 +            Type *rightparam = right->parameterAt(i);
  76.180 +            if (!Compare(leftparam, rightparam))
  76.181 +                return false;
  76.182 +        }
  76.183 +        return true;
  76.184 +      }
  76.185 +
  76.186 +      default:
  76.187 +        assert(left->kind() == Type::REFERENCE);
  76.188 +        return Compare(left->contained(), right->contained());
  76.189 +    }
  76.190 +}
    77.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    77.2 +++ b/src/Types.h	Tue Jul 24 23:53:34 2012 -0700
    77.3 @@ -0,0 +1,215 @@
    77.4 +/* vim: set ts=4 sw=4 tw=99 et:
    77.5 + *
    77.6 + * Copyright (C) 2012 David Anderson
    77.7 + *
    77.8 + * This file is part of JITCraft.
    77.9 + *
   77.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   77.11 + * the terms of the GNU General Public License as published by the Free
   77.12 + * Software Foundation, either version 3 of the License, or (at your option)
   77.13 + * any later version.
   77.14 + * 
   77.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   77.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   77.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   77.18 + *
   77.19 + * You should have received a copy of the GNU General Public License along with
   77.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   77.21 + */
   77.22 +#ifndef _include_jc_types_h_
   77.23 +#define _include_jc_types_h_
   77.24 +
   77.25 +#include "Heap.h"
   77.26 +#include "Barriers.h"
   77.27 +#include "FixedArray.h"
   77.28 +
   77.29 +namespace ke {
   77.30 +
   77.31 +class String;
   77.32 +
   77.33 +enum PrimitiveType
   77.34 +{
   77.35 +    PrimitiveType_Char,         // signed, 8-bit character
   77.36 +    PrimitiveType_Int32,        // signed, 32-bit integer
   77.37 +    PrimitiveType_Float,        // 32-bit IEEE-754 float
   77.38 +    PrimitiveType_Native,       // native-sized word
   77.39 +    PrimitiveTypes_Total
   77.40 +};
   77.41 +
   77.42 +class Type : public Object
   77.43 +{
   77.44 +    enum Kind {
   77.45 +        PRIMITIVE,
   77.46 +        ARRAY,
   77.47 +        REFERENCE,
   77.48 +        FUNCTION,
   77.49 +        NATIVE,
   77.50 +        VOID
   77.51 +    };
   77.52 +
   77.53 +  private:
   77.54 +    Kind kind() {
   77.55 +        return kind_;
   77.56 +    }
   77.57 +
   77.58 +  public:
   77.59 +    static const int UNKNOWN_SIZE = -1;
   77.60 +    static const size_t MAX_UNSAFE_ARRAY_DEPTH = 5;
   77.61 +    
   77.62 +    static Type *NewVoid(Zone *zone);
   77.63 +    static Type *NewPrimitive(Zone *zone, Handle<String> tag);
   77.64 +    static Type *NewPrimitive(Zone *zone, PrimitiveType type);
   77.65 +    static Type *NewArray(Zone *zone, Handle<Type> contained, int elements, bool isConst);
   77.66 +    static Type *NewReference(Zone *zone, Handle<Type> contained, bool isConst);
   77.67 +    static Type *NewFunction(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters);
   77.68 +    static Type *NewNative(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters, bool isVariadic);
   77.69 +
   77.70 +    static bool Compare(Type *left, Type *right);
   77.71 +
   77.72 +    static Type *cast(Object *obj) {
   77.73 +        assert(!obj || obj->is(MapKind_Type));
   77.74 +        return (Type *)obj;
   77.75 +    }
   77.76 +
   77.77 +    bool isPrimitive() {
   77.78 +        return kind() == PRIMITIVE;
   77.79 +    }
   77.80 +    bool isArray() {
   77.81 +        return kind() == ARRAY;
   77.82 +    }
   77.83 +    bool isReference() {
   77.84 +        return kind() == REFERENCE;
   77.85 +    }
   77.86 +    bool isFunction() {
   77.87 +        return kind() == FUNCTION || kind() == NATIVE;
   77.88 +    }
   77.89 +    bool isNative() {
   77.90 +        return kind() == NATIVE;
   77.91 +    }
   77.92 +    bool isVoid() {
   77.93 +        return kind() == VOID;
   77.94 +    }
   77.95 +    bool isNativeVariadic() {
   77.96 +        assert(isNative());
   77.97 +        return variadicNative_;
   77.98 +    }
   77.99 +    PrimitiveType primitive() {
  77.100 +        assert(isPrimitive());
  77.101 +        return primitive_;
  77.102 +    }
  77.103 +    Type *contained() {
  77.104 +        assert(isArray() || isReference());
  77.105 +        return Type::cast(contained_);
  77.106 +    }
  77.107 +    int elements() {
  77.108 +        assert(isArray());
  77.109 +        return elements_;
  77.110 +    }
  77.111 +    unsigned levels() {
  77.112 +        assert(isArray());
  77.113 +        return levels_;
  77.114 +    }
  77.115 +    String *tag() {
  77.116 +        assert(isPrimitive());
  77.117 +        return tag_;
  77.118 +    }
  77.119 +    Type *innermost() {
  77.120 +        assert(isArray());
  77.121 +        Type *temp = contained();
  77.122 +        while (temp->isArray())
  77.123 +            temp = temp->contained();
  77.124 +        return temp;
  77.125 +    }
  77.126 +    bool isFloat() {
  77.127 +        return isPrimitive() && primitive() == PrimitiveType_Float;
  77.128 +    }
  77.129 +    bool isInt32() {
  77.130 +        return isPrimitive() && primitive() == PrimitiveType_Int32;
  77.131 +    }
  77.132 +    bool isCharArray() {
  77.133 +        return isArray() &&
  77.134 +               contained()->isPrimitive() &&
  77.135 +               contained()->primitive() == PrimitiveType_Char;
  77.136 +    }
  77.137 +    Type *returnType() {
  77.138 +        assert(isFunction());
  77.139 +        return returnType_;
  77.140 +    }
  77.141 +    FixedArray *parameters() {
  77.142 +        assert(isFunction());
  77.143 +        return parameters_;
  77.144 +    }
  77.145 +    Type *parameterAt(size_t i) {
  77.146 +        return Type::cast(parameters()->at(i));
  77.147 +    }
  77.148 +    bool isTraceable() {
  77.149 +        return !isPrimitive();
  77.150 +    }
  77.151 +    bool isConst() {
  77.152 +        assert(kind() == PRIMITIVE || kind() == ARRAY || kind() == REFERENCE);
  77.153 +        return const_;
  77.154 +    }
  77.155 +
  77.156 +    // GC Descriptor.
  77.157 +    static inline size_t offsetOfContained() {
  77.158 +        return offsetof(Type, contained_);
  77.159 +    }
  77.160 +    static inline size_t offsetOfReturnType() {
  77.161 +        return offsetof(Type, returnType_);
  77.162 +    }
  77.163 +    static inline size_t offsetOfParameters() {
  77.164 +        return offsetof(Type, parameters_);
  77.165 +    }
  77.166 +    static inline size_t offsetOfTag() {
  77.167 +        return offsetof(Type, tag_);
  77.168 +    }
  77.169 +    // End GC Descriptor.
  77.170 +
  77.171 +  private:
  77.172 +    Kind kind_;
  77.173 +    PrimitiveType primitive_;
  77.174 +    Barriered<String> tag_;
  77.175 +
  77.176 +    // Primitives, arrays, and references.
  77.177 +    bool const_;
  77.178 +
  77.179 +    // Arrays only.
  77.180 +    int32 elements_;
  77.181 +    unsigned levels_;
  77.182 +
  77.183 +    // Arrays and references only.
  77.184 +    Barriered<Type> contained_;
  77.185 +
  77.186 +    // Functions only.
  77.187 +    Barriered<Type> returnType_;
  77.188 +    Barriered<FixedArray> parameters_;
  77.189 +    bool variadicNative_;
  77.190 +};
  77.191 +
  77.192 +class BoxedPrimitive
  77.193 +{
  77.194 +    PrimitiveType type_;
  77.195 +    union {
  77.196 +        int i_;
  77.197 +    };
  77.198 +
  77.199 +  public:
  77.200 +    static BoxedPrimitive Int(int i) {
  77.201 +        BoxedPrimitive b;
  77.202 +        b.type_ = PrimitiveType_Int32;
  77.203 +        b.i_ = i;
  77.204 +        return b;
  77.205 +    }
  77.206 +
  77.207 +    PrimitiveType type() const {
  77.208 +        return type_;
  77.209 +    }
  77.210 +    int toInt() const {
  77.211 +        assert(type() == PrimitiveType_Int32);
  77.212 +        return i_;
  77.213 +    }
  77.214 +};
  77.215 +
  77.216 +}
  77.217 +
  77.218 +#endif // _include_jc_types_h_
    78.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    78.2 +++ b/src/Utility.h	Tue Jul 24 23:53:34 2012 -0700
    78.3 @@ -0,0 +1,243 @@
    78.4 +/* vim: set ts=4 sw=4 tw=99 et:
    78.5 + *
    78.6 + * Copyright (C) 2012 David Anderson
    78.7 + *
    78.8 + * This file is part of JITCraft.
    78.9 + *
   78.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   78.11 + * the terms of the GNU General Public License as published by the Free
   78.12 + * Software Foundation, either version 3 of the License, or (at your option)
   78.13 + * any later version.
   78.14 + * 
   78.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   78.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   78.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   78.18 + *
   78.19 + * You should have received a copy of the GNU General Public License along with
   78.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   78.21 + */
   78.22 +#ifndef _include_jitcraft_utility_h_
   78.23 +#define _include_jitcraft_utility_h_
   78.24 +
   78.25 +#include <assert.h>
   78.26 +#include <stdint.h>
   78.27 +#ifdef _MSC_VER
   78.28 +# include <intrin.h>
   78.29 +#endif
   78.30 +
   78.31 +#ifdef _MSC_VER
   78.32 +# pragma warning(disable:4355)
   78.33 +#endif
   78.34 +
   78.35 +namespace ke {
   78.36 +
   78.37 +static const size_t kMallocAlignment = sizeof(void *) * 2;
   78.38 +
   78.39 +typedef uint8_t uint8;
   78.40 +typedef int32_t int32;
   78.41 +typedef uint32_t uint32;
   78.42 +
   78.43 +typedef uint8 * Address;
   78.44 +
   78.45 +static const size_t kKB = 1024;
   78.46 +static const size_t kMB = 1024 * kKB;
   78.47 +static const size_t kGB = 1024 * kMB;
   78.48 +
   78.49 +template <typename T>
   78.50 +class AutoVec
   78.51 +{
   78.52 +    T *t_;
   78.53 +
   78.54 +  public:
   78.55 +    AutoVec()
   78.56 +      : t_(NULL)
   78.57 +    {
   78.58 +    }
   78.59 +    AutoVec(T *t)
   78.60 +      : t_(t)
   78.61 +    {
   78.62 +    }
   78.63 +    ~AutoVec() {
   78.64 +        delete [] t_;
   78.65 +    }
   78.66 +    operator T *() {
   78.67 +        return t_;
   78.68 +    }
   78.69 +    void operator =(T *t) {
   78.70 +        if (t_)
   78.71 +            delete [] t_;
   78.72 +        t_ = t;
   78.73 +    }
   78.74 +};
   78.75 +
   78.76 +// Bob Jenkin's one-at-a-time hash function[1].
   78.77 +//
   78.78 +// [1] http://burtleburtle.net/bob/hash/doobs.html
   78.79 +class CharacterStreamHasher
   78.80 +{
   78.81 +    uint32 hash;
   78.82 +
   78.83 +  public:
   78.84 +    CharacterStreamHasher()
   78.85 +      : hash(0)
   78.86 +    { }
   78.87 +
   78.88 +    void add(char c) {
   78.89 +        hash += c;
   78.90 +        hash += (hash << 10);
   78.91 +        hash ^= (hash >> 6);
   78.92 +    }
   78.93 +
   78.94 +    void add(const char *s, size_t length) {
   78.95 +        for (size_t i = 0; i < length; i++)
   78.96 +            add(s[i]);
   78.97 +    }
   78.98 +
   78.99 +    uint32 result() {
  78.100 +        hash += (hash << 3);
  78.101 +        hash ^= (hash >> 11);
  78.102 +        hash += (hash << 15);
  78.103 +        return hash;
  78.104 +    }
  78.105 +};
  78.106 +
  78.107 +static inline uint32
  78.108 +HashCharSequence(const char *s, size_t length)
  78.109 +{
  78.110 +    CharacterStreamHasher hasher;
  78.111 +    hasher.add(s, length);
  78.112 +    return hasher.result();
  78.113 +}
  78.114 +
  78.115 +static inline size_t
  78.116 +Log2(size_t number)
  78.117 +{
  78.118 +    assert(number != 0);
  78.119 +
  78.120 +#ifdef _MSC_VER
  78.121 +    unsigned long rval;
  78.122 +# ifdef _M_IX86
  78.123 +    _BitScanReverse(&rval, number);
  78.124 +# elif _M_X64
  78.125 +    _BitScanReverse64(&rval, number);
  78.126 +# endif
  78.127 +    return rval;
  78.128 +#else
  78.129 +	size_t bit;
  78.130 +	asm("bsr %1, %0\n"
  78.131 +		: "=r" (bit)
  78.132 +		: "rm" (number));
  78.133 +	return bit;
  78.134 +#endif
  78.135 +}
  78.136 +
  78.137 +static inline size_t
  78.138 +FindRightmostBit(size_t number)
  78.139 +{
  78.140 +    assert(number != 0);
  78.141 +
  78.142 +#ifdef _MSC_VER
  78.143 +    unsigned long rval;
  78.144 +# ifdef _M_IX86
  78.145 +    _BitScanForward(&rval, number);
  78.146 +# elif _M_X64
  78.147 +    _BitScanForward64(&rval, number);
  78.148 +# endif
  78.149 +    return rval;
  78.150 +#else
  78.151 +	size_t bit;
  78.152 +	asm("bsf %1, %0\n"
  78.153 +		: "=r" (bit)
  78.154 +		: "rm" (number));
  78.155 +	return bit;
  78.156 +#endif
  78.157 +}
  78.158 +
  78.159 +static inline bool
  78.160 +IsPowerOfTwo(size_t value)
  78.161 +{
  78.162 +    if (value == 0)
  78.163 +        return false;
  78.164 +    return !(value & (value - 1));
  78.165 +}
  78.166 +
  78.167 +static inline size_t
  78.168 +Align(size_t count, size_t alignment)
  78.169 +{
  78.170 +    assert(IsPowerOfTwo(alignment));
  78.171 +    return count + (alignment - (count % alignment)) % alignment;
  78.172 +}
  78.173 +
  78.174 +static inline bool
  78.175 +IsUint32AddSafe(unsigned a, unsigned b)
  78.176 +{
  78.177 +    if (!a || !b)
  78.178 +        return true;
  78.179 +    size_t log2_a = Log2(a);
  78.180 +    size_t log2_b = Log2(b);
  78.181 +    return (log2_a < sizeof(unsigned) * 8) &&
  78.182 +           (log2_b < sizeof(unsigned) * 8);
  78.183 +}
  78.184 +
  78.185 +static inline bool
  78.186 +IsUintPtrAddSafe(size_t a, size_t b)
  78.187 +{
  78.188 +    if (!a || !b)
  78.189 +        return true;
  78.190 +    size_t log2_a = Log2(a);
  78.191 +    size_t log2_b = Log2(b);
  78.192 +    return (log2_a < sizeof(size_t) * 8) &&
  78.193 +           (log2_b < sizeof(size_t) * 8);
  78.194 +}
  78.195 +
  78.196 +static inline bool
  78.197 +IsUint32MultiplySafe(unsigned a, unsigned b)
  78.198 +{
  78.199 +    if (a <= 1 || b <= 1)
  78.200 +        return true;
  78.201 +
  78.202 +    size_t log2_a = Log2(a);
  78.203 +    size_t log2_b = Log2(b);
  78.204 +    return log2_a + log2_b <= sizeof(unsigned) * 8;
  78.205 +}
  78.206 +
  78.207 +static inline bool
  78.208 +IsUintPtrMultiplySafe(size_t a, size_t b)
  78.209 +{
  78.210 +    if (a <= 1 || b <= 1)
  78.211 +        return true;
  78.212 +
  78.213 +    size_t log2_a = Log2(a);
  78.214 +    size_t log2_b = Log2(b);
  78.215 +    return log2_a + log2_b <= sizeof(size_t) * 8;
  78.216 +}
  78.217 +
  78.218 +#define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
  78.219 +#define STATIC_ASSERT(cond) extern int static_assert_f(int a[(cond) ? 1 : -1])
  78.220 +
  78.221 +#define IS_ALIGNED(addr, alignment)	(!(uintptr_t(addr) & ((alignment) - 1)))
  78.222 +
  78.223 +template <typename T>
  78.224 +static inline bool
  78.225 +IsAligned(T addr, size_t alignment)
  78.226 +{
  78.227 +    assert(IsPowerOfTwo(alignment));
  78.228 +    return !(uintptr_t(addr) & (alignment - 1));
  78.229 +}
  78.230 +
  78.231 +static inline Address
  78.232 +AlignedBase(Address addr, size_t alignment)
  78.233 +{
  78.234 +    assert(IsPowerOfTwo(alignment));
  78.235 +    return Address(uintptr_t(addr) & ~(alignment - 1));
  78.236 +}
  78.237 +
  78.238 +template <typename T> static inline T
  78.239 +Min(const T &t1, const T &t2)
  78.240 +{
  78.241 +    return t1 < t2 ? t1 : t2;
  78.242 +}
  78.243 +
  78.244 +}
  78.245 +
  78.246 +#endif // _include_jitcraft_utility_h_
    79.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    79.2 +++ b/src/Vector.h	Tue Jul 24 23:53:34 2012 -0700
    79.3 @@ -0,0 +1,119 @@
    79.4 +/* vim: set ts=4 sw=4 tw=99 et:
    79.5 + *
    79.6 + * Copyright (C) 2012 David Anderson
    79.7 + *
    79.8 + * This file is part of JITCraft.
    79.9 + *
   79.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   79.11 + * the terms of the GNU General Public License as published by the Free
   79.12 + * Software Foundation, either version 3 of the License, or (at your option)
   79.13 + * any later version.
   79.14 + * 
   79.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   79.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   79.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   79.18 + *
   79.19 + * You should have received a copy of the GNU General Public License along with
   79.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   79.21 + */
   79.22 +#ifndef _INCLUDE_KEIMA_TPL_CPP_VECTOR_H_
   79.23 +#define _INCLUDE_KEIMA_TPL_CPP_VECTOR_H_
   79.24 +
   79.25 +#include <new>
   79.26 +#include <stdlib.h>
   79.27 +#include "AllocatorPolicies.h"
   79.28 +#include "Utility.h"
   79.29 +
   79.30 +namespace ke {
   79.31 +
   79.32 +template <typename T, typename AllocPolicy = ZoneAllocatorPolicy>
   79.33 +class Vector : public AllocPolicy
   79.34 +{
   79.35 +  public:
   79.36 +    Vector(AllocPolicy = AllocPolicy())
   79.37 +      : data(NULL),
   79.38 +        nitems(0),
   79.39 +        maxsize(0)
   79.40 +    { }
   79.41 +    ~Vector() {
   79.42 +        for (size_t i = 0; i < nitems; i++)
   79.43 +            data[i].~T();
   79.44 +        this->free(data);
   79.45 +    }
   79.46 +    bool append(const T& item) {
   79.47 +        if (!GrowIfNeeded(1))
   79.48 +            return false;
   79.49 +        new (&data[nitems]) T(item);
   79.50 +        nitems++;
   79.51 +        return true;
   79.52 +    }
   79.53 +    void pop() {
   79.54 +        assert(nitems);
   79.55 +        data[nitems - 1].~T();
   79.56 +        nitems--;
   79.57 +    }
   79.58 +    size_t length() const {
   79.59 +        return nitems;
   79.60 +    }
   79.61 +    T& at(size_t i) {
   79.62 +        assert(i < length());
   79.63 +        return data[i];
   79.64 +    }
   79.65 +    const T& at(size_t i) const {
   79.66 +        assert(i < length());
   79.67 +        return data[i];
   79.68 +    }
   79.69 +    T& operator [](size_t i) {
   79.70 +        return at(i);
   79.71 +    }
   79.72 +    const T& operator [](size_t i) const {
   79.73 +        return at(i);
   79.74 +    }
   79.75 +    void clear() {
   79.76 +        nitems = 0;
   79.77 +    }
   79.78 +
   79.79 +    T *buffer() const {
   79.80 +        return data;
   79.81 +    }
   79.82 +
   79.83 +  private:
   79.84 +    bool GrowIfNeeded(size_t needed)
   79.85 +    {
   79.86 +        if (!IsUintPtrAddSafe(nitems, needed)) {
   79.87 +            this->reportAllocationOverflow();
   79.88 +            return false;
   79.89 +        }
   79.90 +        if (maxsize == 0)
   79.91 +            maxsize = 8;
   79.92 +        while (nitems + needed > maxsize)
   79.93 +        {
   79.94 +            if (!IsUintPtrMultiplySafe(maxsize, 2)) {
   79.95 +                this->reportAllocationOverflow();
   79.96 +                return false;
   79.97 +            }
   79.98 +            maxsize *= 2;
   79.99 +        }
  79.100 +        T* newdata = (T*)this->malloc(sizeof(T) * maxsize);
  79.101 +        if (newdata == NULL)
  79.102 +            return false;
  79.103 +        for (size_t i = 0; i < nitems; i++)
  79.104 +        {
  79.105 +            new (&newdata[i]) T(data[i]);
  79.106 +            data[i].~T();
  79.107 +        }
  79.108 +        this->free(data);
  79.109 +        data = newdata;
  79.110 +        return true;
  79.111 +    }
  79.112 +
  79.113 +  private:
  79.114 +    T* data;
  79.115 +    size_t nitems;
  79.116 +    size_t maxsize;
  79.117 +};
  79.118 +
  79.119 +}
  79.120 +
  79.121 +#endif /* _INCLUDE_KEIMA_TPL_CPP_VECTOR_H_ */
  79.122 +
    80.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    80.2 +++ b/src/VirtualObjectVisitor.h	Tue Jul 24 23:53:34 2012 -0700
    80.3 @@ -0,0 +1,34 @@
    80.4 +/* vim: set ts=4 sw=4 tw=99 et:
    80.5 + *
    80.6 + * Copyright (C) 2012 David Anderson
    80.7 + *
    80.8 + * This file is part of JITCraft.
    80.9 + *
   80.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   80.11 + * the terms of the GNU General Public License as published by the Free
   80.12 + * Software Foundation, either version 3 of the License, or (at your option)
   80.13 + * any later version.
   80.14 + * 
   80.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   80.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   80.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   80.18 + *
   80.19 + * You should have received a copy of the GNU General Public License along with
   80.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   80.21 + */
   80.22 +#ifndef _include_jc_virtual_object_visitor_h_
   80.23 +#define _include_jc_virtual_object_visitor_h_
   80.24 +
   80.25 +namespace ke {
   80.26 +
   80.27 +class Object;
   80.28 +
   80.29 +class VirtualObjectVisitor
   80.30 +{
   80.31 +  public:
   80.32 +    virtual void visit(Object **ptr) = 0;
   80.33 +};
   80.34 +
   80.35 +}
   80.36 +
   80.37 +#endif // _include_jc_virtual_object_visitor_h_
    81.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    81.2 +++ b/src/Zone.cpp	Tue Jul 24 23:53:34 2012 -0700
    81.3 @@ -0,0 +1,312 @@
    81.4 +/* vim: set ts=4 sw=4 tw=99 et:
    81.5 + *
    81.6 + * Copyright (C) 2012 David Anderson
    81.7 + *
    81.8 + * This file is part of JITCraft.
    81.9 + *
   81.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   81.11 + * the terms of the GNU General Public License as published by the Free
   81.12 + * Software Foundation, either version 3 of the License, or (at your option)
   81.13 + * any later version.
   81.14 + * 
   81.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   81.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   81.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   81.18 + *
   81.19 + * You should have received a copy of the GNU General Public License along with
   81.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   81.21 + */
   81.22 +#include <stdlib.h>
   81.23 +#include "Zone.h"
   81.24 +#include "StringPool.h"
   81.25 +#include "TypeManager.h"
   81.26 +#include "GlobalRoots.h"
   81.27 +#include "AllocatorPolicies.h"
   81.28 +#include "Array.h"
   81.29 +
   81.30 +using namespace ke;
   81.31 +
   81.32 +Zone *ke::SingleThreadedZone;
   81.33 +
   81.34 +Zone::Zone()
   81.35 +  : stack_(thisFromCtor()),
   81.36 +    heap_(thisFromCtor()),
   81.37 +    types_(NULL),
   81.38 +    symbols_(NULL),
   81.39 +    globalRoots_(NULL),
   81.40 +    lastLocalRoot_(NULL),
   81.41 +    hasPendingException_(false),
   81.42 +    reporter_(NULL)
   81.43 +{
   81.44 +}
   81.45 +
   81.46 +Zone::~Zone()
   81.47 +{
   81.48 +    delete types_;
   81.49 +    delete symbols_;
   81.50 +    delete globalRoots_;
   81.51 +}
   81.52 +
   81.53 +bool
   81.54 +Zone::initialize()
   81.55 +{
   81.56 +    if (!stack_.initialize())
   81.57 +        return false;
   81.58 +    if (!heap_.initialize())
   81.59 +        return false;
   81.60 +
   81.61 +    symbols_ = new StringPool(this);
   81.62 +    if (!symbols_ || !symbols_->initialize())
   81.63 +        return false;
   81.64 +
   81.65 +    globalRoots_ = new GlobalRoots(this);
   81.66 +    if (!globalRoots_ || !globalRoots_->initialize())
   81.67 +        return false;
   81.68 +
   81.69 +    maps_[MapKind_Meta] = heap_.metaMap();
   81.70 +    if ((maps_[MapKind_Type] = allocateMap(MapKind_Type, sizeof(Map))) == NULL)
   81.71 +        return false;
   81.72 +    if ((maps_[MapKind_FixedArray] = allocateMap(MapKind_FixedArray, sizeof(Map))) == NULL)
   81.73 +        return false;
   81.74 +    if ((maps_[MapKind_ByteArray] = allocateMap(MapKind_ByteArray, sizeof(Map))) == NULL)
   81.75 +        return false;
   81.76 +    if ((maps_[MapKind_Code] = allocateMap(MapKind_Code, sizeof(Map))) == NULL)
   81.77 +        return false;
   81.78 +    if ((maps_[MapKind_Reference] = allocateMap(MapKind_Reference, sizeof(Map))) == NULL)
   81.79 +        return false;
   81.80 +    if ((maps_[MapKind_MetaArray] = allocateMap(MapKind_MetaArray, sizeof(Map))) == NULL)
   81.81 +        return false;
   81.82 +    if ((maps_[MapKind_MetaEnvironment] = allocateMap(MapKind_MetaEnvironment, sizeof(Map))) == NULL)
   81.83 +        return false;
   81.84 +    if ((maps_[MapKind_Module] = allocateMap(MapKind_Module, sizeof(Map))) == NULL)
   81.85 +        return false;
   81.86 +    if ((maps_[MapKind_Function] = allocateMap(MapKind_Function, sizeof(Map))) == NULL)
   81.87 +        return false;
   81.88 +    if ((maps_[MapKind_String] = allocateMap(MapKind_String, sizeof(Map))) == NULL)
   81.89 +        return false;
   81.90 +    if ((maps_[MapKind_Native] = allocateMap(MapKind_Native, sizeof(Map))) == NULL)
   81.91 +        return false;
   81.92 +    if ((maps_[MapKind_FreeRegion] = allocateMap(MapKind_FreeRegion, sizeof(Map))) == NULL)
   81.93 +        return false;
   81.94 +    if ((maps_[MapKind_EnvironmentSlotDescriptorArray] =
   81.95 +         allocateMap(MapKind_EnvironmentSlotDescriptorArray, sizeof(Map))) == NULL)
   81.96 +    {
   81.97 +        return false;
   81.98 +    }
   81.99 +
  81.100 +    types_ = new TypeManager(this);
  81.101 +    if (!types_ || !types_->initialize())
  81.102 +        return false;
  81.103 +
  81.104 +    // Create the cached array maps for generic arrays. This is for the API
  81.105 +    // version of Invoke(), which needs to make arrays very quickly from C++.
  81.106 +    {
  81.107 +        // Generic "cell" array (contents do not matter, just non-gc things).
  81.108 +        Local<Type> type(this, types_->getPrimitive(PrimitiveType_Int32));
  81.109 +        if (!type)
  81.110 +            return false;
  81.111 +
  81.112 +        type = types_->unsafeArray(type, Type::UNKNOWN_SIZE, false);
  81.113 +        if (!type)
  81.114 +            return false;
  81.115 +
  81.116 +        Local<ArrayMap> contained(this);
  81.117 +        genericArrayMap_ = ArrayMap::New(this, type, contained);
  81.118 +        if (!genericArrayMap_)
  81.119 +            return false;
  81.120 +
  81.121 +        type = types_->getPrimitive(PrimitiveType_Char);
  81.122 +        if (!type)
  81.123 +            return false;
  81.124 +
  81.125 +        type = types_->unsafeArray(type, Type::UNKNOWN_SIZE, false);
  81.126 +        if (!type)
  81.127 +            return false;
  81.128 +
  81.129 +        charArrayMap_ = ArrayMap::New(this, type, contained);
  81.130 +        if (!charArrayMap_)
  81.131 +            return false;
  81.132 +    }
  81.133 +
  81.134 +    return true;
  81.135 +}
  81.136 +
  81.137 +Map *
  81.138 +Zone::allocateMap(MapKind kind, size_t bytes, MapKind parent)
  81.139 +{
  81.140 +    assert(maps_[parent]);
  81.141 +    Map *map = heap_.allocateMap(kind, bytes);
  81.142 +    if (!map)
  81.143 +        return NULL;
  81.144 +    map->init(maps_[parent]);
  81.145 +    return map;
  81.146 +}
  81.147 +
  81.148 +void
  81.149 +Zone::accept(VirtualObjectVisitor *visitor)
  81.150 +{
  81.151 +    for (unsigned i = 0; i < MapKinds_Total; i++)
  81.152 +        visitor->visit(maps_[i].address());
  81.153 +    visitor->visit(charArrayMap_.address());
  81.154 +    visitor->visit(genericArrayMap_.address());
  81.155 +    types()->accept(visitor);
  81.156 +
  81.157 +    Local<Object> *local = lastLocalRoot_;
  81.158 +    while (local) {
  81.159 +        visitor->visit(local->address());
  81.160 +        local = local->prev();
  81.161 +    }
  81.162 +
  81.163 +    globalRoots_->accept(visitor);
  81.164 +    rootScopes_.accept(visitor);
  81.165 +
  81.166 +    stack_.accept(visitor);
  81.167 +}
  81.168 +
  81.169 +String *
  81.170 +Zone::makeSymbol(const char *str, size_t length)
  81.171 +{
  81.172 +    return symbols_->add(str, length);
  81.173 +}
  81.174 +
  81.175 +String *
  81.176 +Zone::makeSymbol(const char *str)
  81.177 +{
  81.178 +    return makeSymbol(str, strlen(str));
  81.179 +}
  81.180 +
  81.181 +bool
  81.182 +Zone::hasPendingException()
  81.183 +{
  81.184 +    return hasPendingException_;
  81.185 +}
  81.186 +
  81.187 +void
  81.188 +Zone::reportOutOfMemory()
  81.189 +{
  81.190 +    
  81.191 +}
  81.192 +
  81.193 +void
  81.194 +Zone::reportError(Message message, ...)
  81.195 +{
  81.196 +    va_list ap;
  81.197 +    va_start(ap, message);
  81.198 +    reportErrorVA(message, ap);
  81.199 +    va_end(ap);
  81.200 +}
  81.201 +
  81.202 +#if defined(_MSC_VER)
  81.203 +# define VA_COPY(to, from)  to = from
  81.204 +#else
  81.205 +# define VA_COPY(to, from)  va_copy(to, from)
  81.206 +#endif
  81.207 +
  81.208 +static char *
  81.209 +BuildErrorMessage(const char *format, va_list ap)
  81.210 +{
  81.211 +    va_list use;
  81.212 +    VA_COPY(use, ap);
  81.213 +
  81.214 +    // We over-allocate and zero terminate ahead of time, since LIBCRT's
  81.215 +    // version of vsnprintf is screwy.
  81.216 +    size_t size = 255;
  81.217 +    char *buffer = (char *)calloc(size + 1, 1);
  81.218 +    if (!buffer)
  81.219 +        return NULL;
  81.220 +
  81.221 +    for (;;) {
  81.222 +        int r = vsnprintf(buffer, size, format, use);
  81.223 +
  81.224 +        if (r > -1 && size_t(r) < size)
  81.225 +            return buffer;
  81.226 +       
  81.227 +#if defined(_MSC_VER)
  81.228 +        if (r < 0)
  81.229 +            size *= 2;
  81.230 +#else
  81.231 +        if (r > -1)
  81.232 +            size = size_t(r) + 1;
  81.233 +        else
  81.234 +            size *= 2;
  81.235 +#endif
  81.236 +
  81.237 +        free(buffer);
  81.238 +        if ((buffer = (char *)calloc(size + 1, 1)) == NULL)
  81.239 +            return NULL;
  81.240 +
  81.241 +        VA_COPY(use, ap);
  81.242 +    }
  81.243 +}
  81.244 +
  81.245 +void
  81.246 +Zone::reportErrorVA(Message message, va_list ap)
  81.247 +{
  81.248 +    char *report = BuildErrorMessage(Messages[message].format, ap);
  81.249 +    if (!report) {
  81.250 +        reportOutOfMemory();
  81.251 +        return;
  81.252 +    }
  81.253 +
  81.254 +    if (reporter_) {
  81.255 +        // Reporters can re-enter. When we start having actual exception
  81.256 +        // objects that can be caught and inspected, this code will have to
  81.257 +        // save and restore the exception state.
  81.258 +        reporter_->onUncaughtException(report);
  81.259 +    }
  81.260 +
  81.261 +    hasPendingException_ = true;
  81.262 +
  81.263 +    free(report);
  81.264 +}
  81.265 +
  81.266 +void
  81.267 +Zone::beginCompilationErrors(const char *file)
  81.268 +{
  81.269 +    if (reporter_)
  81.270 +        reporter_->beginCompilationErrors(file);
  81.271 +}
  81.272 +
  81.273 +void
  81.274 +Zone::reportCompilationError(Message message, unsigned line, unsigned col, va_list ap)
  81.275 +{
  81.276 +    char *report = BuildErrorMessage(Messages[message].format, ap);
  81.277 +    if (!report) {
  81.278 +        reportOutOfMemory();
  81.279 +        return;
  81.280 +    }
  81.281 +
  81.282 +    if (reporter_) {
  81.283 +        // Reporters can re-enter. When we start having actual exception
  81.284 +        // objects that can be caught and inspected, this code will have to
  81.285 +        // save and restore the exception state.
  81.286 +        reporter_->reportCompilationError(report, line, col);
  81.287 +    }
  81.288 +
  81.289 +    free(report);
  81.290 +}
  81.291 +
  81.292 +void
  81.293 +Zone::endCompilationErrors()
  81.294 +{
  81.295 +    if (reporter_)
  81.296 +        reporter_->endCompilationErrors();
  81.297 +}
  81.298 +
  81.299 +void
  81.300 +Zone::installErrorReporter(Ke::IMessageReporter *reporter)
  81.301 +{
  81.302 +    reporter_ = reporter;
  81.303 +}
  81.304 +
  81.305 +void
  81.306 +ZoneAllocatorPolicy::reportOutOfMemory()
  81.307 +{
  81.308 +    ZONE()->reportOutOfMemory();
  81.309 +}
  81.310 +
  81.311 +void
  81.312 +ZoneAllocatorPolicy::reportAllocationOverflow()
  81.313 +{
  81.314 +    ZONE()->reportError(Message_AllocationOverflow);
  81.315 +}
    82.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    82.2 +++ b/src/Zone.h	Tue Jul 24 23:53:34 2012 -0700
    82.3 @@ -0,0 +1,189 @@
    82.4 +/* vim: set ts=4 sw=4 tw=99 et:
    82.5 + *
    82.6 + * Copyright (C) 2012 David Anderson
    82.7 + *
    82.8 + * This file is part of JITCraft.
    82.9 + *
   82.10 + * JITCraft is free software: you can redistribute it and/or modify it under
   82.11 + * the terms of the GNU General Public License as published by the Free
   82.12 + * Software Foundation, either version 3 of the License, or (at your option)
   82.13 + * any later version.
   82.14 + * 
   82.15 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   82.16 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   82.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   82.18 + *
   82.19 + * You should have received a copy of the GNU General Public License along with
   82.20 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   82.21 + */
   82.22 +#ifndef _include_jitcraft_thread_h_
   82.23 +#define _include_jitcraft_thread_h_
   82.24 +
   82.25 +#include <stdarg.h>
   82.26 +#include "PoolAllocator.h"
   82.27 +#include "Stack.h"
   82.28 +#include "Heap.h"
   82.29 +#include "Barriers.h"
   82.30 +#include "Handles.h"
   82.31 +#include "Messages.h"
   82.32 +#include "RootScopes.h"
   82.33 +#include "VirtualObjectVisitor.h"
   82.34 +
   82.35 +namespace ke {
   82.36 +
   82.37 +class TypeManager;
   82.38 +class String;
   82.39 +class StringPool;
   82.40 +class GlobalRoots;
   82.41 +class ArrayMap;
   82.42 +class Exception;
   82.43 +
   82.44 +class Zone
   82.45 +{
   82.46 +    PoolAllocator pool_;
   82.47 +    Stack stack_;
   82.48 +    Heap heap_;
   82.49 +
   82.50 +    // Map cache.
   82.51 +    Unbarriered<Map> maps_[MapKinds_Total];
   82.52 +    Unbarriered<ArrayMap> genericArrayMap_;
   82.53 +    Unbarriered<ArrayMap> charArrayMap_;
   82.54 +
   82.55 +    TypeManager *types_;
   82.56 +    StringPool *symbols_;
   82.57 +    GlobalRoots *globalRoots_;
   82.58 +
   82.59 +    // Root list.
   82.60 +    Local<Object> *lastLocalRoot_;
   82.61 +    RootScopeManager rootScopes_;
   82.62 +
   82.63 +    // Exception stuff.
   82.64 +    bool hasPendingException_;
   82.65 +    Ke::IMessageReporter *reporter_;
   82.66 +
   82.67 +  private:
   82.68 +    Zone *thisFromCtor() {
   82.69 +        return this;
   82.70 +    }
   82.71 +
   82.72 +  public:
   82.73 +    Zone();
   82.74 +    ~Zone();
   82.75 +    bool initialize();
   82.76 +
   82.77 +    PoolAllocator &pool() {
   82.78 +        return pool_;
   82.79 +    }
   82.80 +    Stack &stack() {
   82.81 +        return stack_;
   82.82 +    }
   82.83 +    Heap &heap() {
   82.84 +        return heap_;
   82.85 +    }
   82.86 +    Object *allocate(MapKind kind, size_t bytes, Heap::Tenure tenure = Heap::Tenure_Default) {
   82.87 +        assert(maps_[kind]);
   82.88 +        Local<Map> map(this, maps_[kind]);
   82.89 +        return allocate(map, bytes, tenure);
   82.90 +    }
   82.91 +    Object *allocate(Handle<Map> map, size_t bytes, Heap::Tenure tenure = Heap::Tenure_Default) {
   82.92 +        return heap_.allocate(map, bytes, tenure);
   82.93 +    }
   82.94 +    Map *getMap(MapKind kind) {
   82.95 +        return maps_[kind];
   82.96 +    }
   82.97 +    Map *allocateMap(MapKind kind, size_t bytes, MapKind parent = MapKind_Meta);
   82.98 +
   82.99 +    ArrayMap *genericArrayMap() {
  82.100 +        return genericArrayMap_;
  82.101 +    }
  82.102 +    ArrayMap *charArrayMap() {
  82.103 +        return charArrayMap_;
  82.104 +    }
  82.105 +
  82.106 +    TypeManager *types() const {
  82.107 +        return types_;
  82.108 +    }
  82.109 +    Local<Object> **lastLocalRoot() {
  82.110 +        return &lastLocalRoot_;
  82.111 +    }
  82.112 +    Object **makeScopedRoot(Object *ptr) {
  82.113 +        return rootScopes_.make(ptr);
  82.114 +    }
  82.115 +    RootScopeManager &rootScopes() {
  82.116 +        return rootScopes_;
  82.117 +    }
  82.118 +    StringPool *symbols() {
  82.119 +        return symbols_;
  82.120 +    }
  82.121 +    GlobalRoots *globalRoots() {
  82.122 +        return globalRoots_;
  82.123 +    }
  82.124 +
  82.125 +    String *makeSymbol(const char *string, size_t length);
  82.126 +    String *makeSymbol(const char *string);
  82.127 +
  82.128 +    void reportOutOfMemory();
  82.129 +    void reportError(Message message, ...);
  82.130 +    void reportErrorVA(Message message, va_list ap);
  82.131 +    bool hasPendingException();
  82.132 +    void installErrorReporter(Ke::IMessageReporter *reporter);
  82.133 +    void beginCompilationErrors(const char *file);
  82.134 +    void reportCompilationError(Message message, unsigned line, unsigned col, va_list ap);
  82.135 +    void endCompilationErrors();
  82.136 +
  82.137 +    void accept(VirtualObjectVisitor *visitor);
  82.138 +};
  82.139 +
  82.140 +// In a multi-threaded system, this would be a TLS variable.
  82.141 +// In the interest of simplicity, we are single-threaded for now.
  82.142 +extern Zone *SingleThreadedZone;
  82.143 +
  82.144 +static inline Zone *ZONE()
  82.145 +{
  82.146 +    return SingleThreadedZone;
  82.147 +}
  82.148 +
  82.149 +template <typename T>
  82.150 +Local<T>::Local(Zone *zone, T *thing)
  82.151 +  : zone_(zone),
  82.152 +    thing_(thing),
  82.153 +    prev_(*zone->lastLocalRoot())
  82.154 +{
  82.155 +    *zone->lastLocalRoot() = toRaw();
  82.156 +}
  82.157 +
  82.158 +template <typename T>
  82.159 +Local<T>::~Local()
  82.160 +{
  82.161 +    assert(*zone_->lastLocalRoot() == toRaw());
  82.162 +    *zone_->lastLocalRoot() = prev_;
  82.163 +}
  82.164 +
  82.165 +template <typename T>
  82.166 +ScopedRoot<T>::ScopedRoot()
  82.167 +  : thingp_(make(NULL))
  82.168 +{
  82.169 +}
  82.170 +
  82.171 +template <typename T>
  82.172 +ScopedRoot<T>::ScopedRoot(T *thing)
  82.173 +  : thingp_(make(thing))
  82.174 +{
  82.175 +    // Type check that T is an Object.
  82.176 +    (void)static_cast<Object *>(thing);
  82.177 +}
  82.178 +
  82.179 +template <typename T> T **
  82.180 +ScopedRoot<T>::make(T *other)
  82.181 +{
  82.182 +    return reinterpret_cast<T **>(ZONE()->makeScopedRoot(other));
  82.183 +}
  82.184 +
  82.185 +RootScope::RootScope(Zone *zone)
  82.186 +  : Ke::HandleScope(zone, zone->rootScopes().position(), *zone->rootScopes().scope())
  82.187 +{
  82.188 +}
  82.189 +
  82.190 +}
  82.191 +
  82.192 +#endif // _include_jitcraft_thread_h_
    83.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    83.2 +++ b/src/configure.in	Tue Jul 24 23:53:34 2012 -0700
    83.3 @@ -0,0 +1,47 @@
    83.4 +#                                               -*- Autoconf -*-
    83.5 +# Process this file with autoconf to produce a configure script.
    83.6 +
    83.7 +AC_PREREQ([2.61])
    83.8 +AC_INIT(foobar, 0.1, https://bugs.alliedmods.net/)
    83.9 +AC_CONFIG_AUX_DIR(${srcdir}/build/autoconf)
   83.10 +AC_CONFIG_SRCDIR([Heap.cpp])
   83.11 +AC_LANG(C++)
   83.12 +AC_CANONICAL_HOST
   83.13 +
   83.14 +# Checks for programs.
   83.15 +AC_PROG_CXX
   83.16 +
   83.17 +# Checks for libraries.
   83.18 +
   83.19 +# Checks for header files.
   83.20 +AC_CHECK_HEADERS([limits.h stddef.h stdint.h stdlib.h string.h sys/time.h unistd.h])
   83.21 +
   83.22 +# Checks for typedefs, structures, and compiler characteristics.
   83.23 +AC_C_INLINE
   83.24 +
   83.25 +# Checks for library functions.
   83.26 +AC_FUNC_MALLOC
   83.27 +AC_FUNC_REALLOC
   83.28 +AC_CHECK_FUNCS([gettimeofday memset strchr])
   83.29 +
   83.30 +mkdir -p .deps
   83.31 +touch .deps/
   83.32 +
   83.33 +#AX_COMPILER_VENDOR
   83.34 +
   83.35 +CXXVENDOR=$ax_cv_cxx_compiler_vendor
   83.36 +AC_SUBST(CXXVENDOR)
   83.37 +
   83.38 +case "$host" in
   83.39 +    *-linux*)
   83.40 +        PLATFORM="linux"
   83.41 +        ;;
   83.42 +    *-darwin*)
   83.43 +        PLATFORM="darwin"
   83.44 +        ;;
   83.45 +esac
   83.46 +
   83.47 +AC_SUBST(PLATFORM)
   83.48 +
   83.49 +AC_OUTPUT(Makefile)
   83.50 +
    84.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    84.2 +++ b/src/jitcraft.vcxproj	Tue Jul 24 23:53:34 2012 -0700
    84.3 @@ -0,0 +1,188 @@
    84.4 +<?xml version="1.0" encoding="utf-8"?>
    84.5 +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    84.6 +  <ItemGroup Label="ProjectConfigurations">
    84.7 +    <ProjectConfiguration Include="Debug - Library|Win32">
    84.8 +      <Configuration>Debug - Library</Configuration>
    84.9 +      <Platform>Win32</Platform>
   84.10 +    </ProjectConfiguration>
   84.11 +    <ProjectConfiguration Include="Debug|Win32">
   84.12 +      <Configuration>Debug</Configuration>
   84.13 +      <Platform>Win32</Platform>
   84.14 +    </ProjectConfiguration>
   84.15 +    <ProjectConfiguration Include="Release|Win32">
   84.16 +      <Configuration>Release</Configuration>
   84.17 +      <Platform>Win32</Platform>
   84.18 +    </ProjectConfiguration>
   84.19 +  </ItemGroup>
   84.20 +  <PropertyGroup Label="Globals">
   84.21 +    <ProjectGuid>{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}</ProjectGuid>
   84.22 +    <Keyword>Win32Proj</Keyword>
   84.23 +    <RootNamespace>jitcraft</RootNamespace>
   84.24 +  </PropertyGroup>
   84.25 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   84.26 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   84.27 +    <ConfigurationType>Application</ConfigurationType>
   84.28 +    <UseDebugLibraries>true</UseDebugLibraries>
   84.29 +    <CharacterSet>Unicode</CharacterSet>
   84.30 +  </PropertyGroup>
   84.31 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   84.32 +    <ConfigurationType>Application</ConfigurationType>
   84.33 +    <UseDebugLibraries>false</UseDebugLibraries>
   84.34 +    <WholeProgramOptimization>true</WholeProgramOptimization>
   84.35 +    <CharacterSet>Unicode</CharacterSet>
   84.36 +  </PropertyGroup>
   84.37 +  <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug - Library|Win32'">
   84.38 +    <ConfigurationType>StaticLibrary</ConfigurationType>
   84.39 +  </PropertyGroup>
   84.40 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   84.41 +  <ImportGroup Label="ExtensionSettings">
   84.42 +  </ImportGroup>
   84.43 +  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   84.44 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   84.45 +  </ImportGroup>
   84.46 +  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
   84.47 +    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   84.48 +  </ImportGroup>
   84.49 +  <PropertyGroup Label="UserMacros" />
   84.50 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   84.51 +    <LinkIncremental>true</LinkIncremental>
   84.52 +  </PropertyGroup>
   84.53 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
   84.54 +    <LinkIncremental>false</LinkIncremental>
   84.55 +  </PropertyGroup>
   84.56 +  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - Library|Win32'">
   84.57 +    <TargetExt>.lib</TargetExt>
   84.58 +    <TargetName>keima</TargetName>
   84.59 +  </PropertyGroup>
   84.60 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   84.61 +    <ClCompile>
   84.62 +      <PrecompiledHeader>
   84.63 +      </PrecompiledHeader>
   84.64 +      <WarningLevel>Level3</WarningLevel>
   84.65 +      <Optimization>Disabled</Optimization>
   84.66 +      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions); _CRT_SECURE_NO_WARNINGS;KE_EXPORTING</PreprocessorDefinitions>
   84.67 +    </ClCompile>
   84.68 +    <Link>
   84.69 +      <SubSystem>Console</SubSystem>
   84.70 +      <GenerateDebugInformation>true</GenerateDebugInformation>
   84.71 +      <RandomizedBaseAddress>false</RandomizedBaseAddress>
   84.72 +    </Link>
   84.73 +  </ItemDefinitionGroup>
   84.74 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
   84.75 +    <ClCompile>
   84.76 +      <WarningLevel>Level3</WarningLevel>
   84.77 +      <PrecompiledHeader>
   84.78 +      </PrecompiledHeader>
   84.79 +      <Optimization>MaxSpeed</Optimization>
   84.80 +      <FunctionLevelLinking>true</FunctionLevelLinking>
   84.81 +      <IntrinsicFunctions>true</IntrinsicFunctions>
   84.82 +      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
   84.83 +    </ClCompile>
   84.84 +    <Link>
   84.85 +      <SubSystem>Console</SubSystem>
   84.86 +      <GenerateDebugInformation>true</GenerateDebugInformation>
   84.87 +      <EnableCOMDATFolding>true</EnableCOMDATFolding>
   84.88 +      <OptimizeReferences>true</OptimizeReferences>
   84.89 +    </Link>
   84.90 +  </ItemDefinitionGroup>
   84.91 +  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug - Library|Win32'">
   84.92 +    <ClCompile>
   84.93 +      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
   84.94 +      <ExceptionHandling>false</ExceptionHandling>
   84.95 +      <RuntimeTypeInfo>false</RuntimeTypeInfo>
   84.96 +      <Optimization>Disabled</Optimization>
   84.97 +    </ClCompile>
   84.98 +  </ItemDefinitionGroup>
   84.99 +  <ItemGroup>
  84.100 +    <ClCompile Include="API.cpp" />
  84.101 +    <ClCompile Include="Array.cpp" />
  84.102 +    <ClCompile Include="BytecodeCompiler.cpp" />
  84.103 +    <ClCompile Include="BytecodeEmitter.cpp" />
  84.104 +    <ClCompile Include="CompileContext.cpp" />
  84.105 +    <ClCompile Include="Environments.cpp" />
  84.106 +    <ClCompile Include="Exception.cpp" />
  84.107 +    <ClCompile Include="FixedArray.cpp" />
  84.108 +    <ClCompile Include="Functions.cpp" />
  84.109 +    <ClCompile Include="GlobalRoots.cpp" />
  84.110 +    <ClCompile Include="Heap.cpp" />
  84.111 +    <ClCompile Include="Interpreter.cpp" />
  84.112 +    <ClCompile Include="main.cpp" />
  84.113 +    <ClCompile Include="Modules.cpp" />
  84.114 +    <ClCompile Include="NameBinding.cpp" />
  84.115 +    <ClCompile Include="Opcodes.cpp" />
  84.116 +    <ClCompile Include="Parser.cpp" />
  84.117 +    <ClCompile Include="Platform-Windows.cpp" />
  84.118 +    <ClCompile Include="PoolAllocator.cpp" />
  84.119 +    <ClCompile Include="Reference.cpp" />
  84.120 +    <ClCompile Include="RootScopes.cpp" />
  84.121 +    <ClCompile Include="Scanner.cpp" />
  84.122 +    <ClCompile Include="Scopes.cpp" />
  84.123 +    <ClCompile Include="SemanticAnalysis.cpp" />
  84.124 +    <ClCompile Include="Spaces.cpp" />
  84.125 +    <ClCompile Include="Stack.cpp" />
  84.126 +    <ClCompile Include="StringPool.cpp" />
  84.127 +    <ClCompile Include="Strings.cpp" />
  84.128 +    <ClCompile Include="Structures.cpp" />
  84.129 +    <ClCompile Include="TypeManager.cpp" />
  84.130 +    <ClCompile Include="Types.cpp" />
  84.131 +    <ClCompile Include="Zone.cpp" />
  84.132 +  </ItemGroup>
  84.133 +  <ItemGroup>
  84.134 +    <ClInclude Include="..\include\keima.h" />
  84.135 +    <ClInclude Include="..\include\keima_util.h" />
  84.136 +    <ClInclude Include="AllocatorPolicies.h" />
  84.137 +    <ClInclude Include="Array.h" />
  84.138 +    <ClInclude Include="AST.h" />
  84.139 +    <ClInclude Include="Barriers.h" />
  84.140 +    <ClInclude Include="BytecodeEmitter.h" />
  84.141 +    <ClInclude Include="BytecodeCompiler.h" />
  84.142 +    <ClInclude Include="CompactBuffer.h" />
  84.143 +    <ClInclude Include="CompileContext.h" />
  84.144 +    <ClInclude Include="Environments.h" />
  84.145 +    <ClInclude Include="FixedArray.h" />
  84.146 +    <ClInclude Include="Functions.h" />
  84.147 +    <ClInclude Include="GlobalRoots.h" />
  84.148 +    <ClInclude Include="Handles-inl.h" />
  84.149 +    <ClInclude Include="HashTable.h" />
  84.150 +    <ClInclude Include="Heap-inl.h" />
  84.151 +    <ClInclude Include="InlineList.h" />
  84.152 +    <ClInclude Include="Interpreter.h" />
  84.153 +    <ClInclude Include="Messages.h" />
  84.154 +    <ClInclude Include="Modules.h" />
  84.155 +    <ClInclude Include="NameBinding.h" />
  84.156 +    <ClInclude Include="Heap.h" />
  84.157 +    <ClInclude Include="Objects.h" />
  84.158 +    <ClInclude Include="ObjectVisitor.h" />
  84.159 +    <ClInclude Include="Opcodes.h" />
  84.160 +    <ClInclude Include="Parser.h" />
  84.161 +    <ClInclude Include="Platform.h" />
  84.162 +    <ClInclude Include="PoolAllocator.h" />
  84.163 +    <ClInclude Include="Handles.h" />
  84.164 +    <ClInclude Include="Reference.h" />
  84.165 +    <ClInclude Include="RootScopes.h" />
  84.166 +    <ClInclude Include="Scanner.h" />
  84.167 +    <ClInclude Include="Scopes.h" />
  84.168 +    <ClInclude Include="Code.h" />
  84.169 +    <ClInclude Include="SemanticAnalysis.h" />
  84.170 +    <ClInclude Include="Spaces-inl.h" />
  84.171 +    <ClInclude Include="Spaces.h" />
  84.172 +    <ClInclude Include="Stack.h" />
  84.173 +    <ClInclude Include="Strings.h" />
  84.174 +    <ClInclude Include="StringPool.h" />
  84.175 +    <ClInclude Include="Structures.h" />
  84.176 +    <ClInclude Include="TypeManager.h" />
  84.177 +    <ClInclude Include="Types.h" />
  84.178 +    <ClInclude Include="Vector.h" />
  84.179 +    <ClInclude Include="VirtualObjectVisitor.h" />
  84.180 +    <ClInclude Include="Zone.h" />
  84.181 +    <ClInclude Include="Token.h" />
  84.182 +    <ClInclude Include="Utility.h" />
  84.183 +  </ItemGroup>
  84.184 +  <ItemGroup>
  84.185 +    <None Include="Messages.tbl" />
  84.186 +    <None Include="Opcodes.tbl" />
  84.187 +  </ItemGroup>
  84.188 +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  84.189 +  <ImportGroup Label="ExtensionTargets">
  84.190 +  </ImportGroup>
  84.191 +</Project>
  84.192 \ No newline at end of file
    85.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    85.2 +++ b/src/main.cpp	Tue Jul 24 23:53:34 2012 -0700
    85.3 @@ -0,0 +1,132 @@
    85.4 +/*
    85.5 + * Copyright (C) 2012 David Anderson
    85.6 + *
    85.7 + * This file is part of JITCraft.
    85.8 + *
    85.9 + * JITCraft is free software: you can redistribute it and/or modify it under
   85.10 + * the terms of the GNU General Public License as published by the Free
   85.11 + * Software Foundation, either version 3 of the License, or (at your option)
   85.12 + * any later version.
   85.13 + * 
   85.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
   85.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   85.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   85.17 + *
   85.18 + * You should have received a copy of the GNU General Public License along with
   85.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
   85.20 + */
   85.21 +#include <stdio.h>
   85.22 +#include "Utility.h"
   85.23 +#include "Scanner.h"
   85.24 +#include "Parser.h"
   85.25 +#include "SemanticAnalysis.h"
   85.26 +#include "Zone.h"
   85.27 +#include "BytecodeCompiler.h"
   85.28 +#include "Code.h"
   85.29 +#include "Interpreter.h"
   85.30 +#include "Modules.h"
   85.31 +#include "RootScopes.h"
   85.32 +#include "../include/keima.h"
   85.33 +
   85.34 +using namespace ke;
   85.35 +
   85.36 +class MessageReporter : public Ke::IMessageReporter
   85.37 +{
   85.38 +  public:
   85.39 +    void onOutOfMemory() {
   85.40 +        fprintf(stderr, "Out of memory!\n");
   85.41 +    }
   85.42 +    void onUncaughtException(const char *message) {
   85.43 +        fprintf(stderr, "Uncaught exception: %s\n", message);
   85.44 +
   85.45 +        Ke::IStackFrameIterator *iter = Ke::Keima::NewStackFrameIterator();
   85.46 +        unsigned index = 0;
   85.47 +        while (!iter->done()) {
   85.48 +            fprintf(stderr, "[%d] %s (%s line %d)\n",
   85.49 +                    index,
   85.50 +                    iter->function(),
   85.51 +                    iter->source(),
   85.52 +                    iter->lineNumber());
   85.53 +            iter->prev();
   85.54 +            index++;
   85.55 +        }
   85.56 +    }
   85.57 +    virtual void beginCompilationErrors(const char *file) {
   85.58 +        fprintf(stderr, "\nDisplaying compilation errors for \"%s\"\n", file);
   85.59 +    }
   85.60 +    virtual void reportCompilationError(const char *message, unsigned line, unsigned col) {
   85.61 +        fprintf(stderr, "  line %d, col %d: %s\n", line, col, message);
   85.62 +    }
   85.63 +    virtual void endCompilationErrors() {
   85.64 +    }
   85.65 +} s_Reporter;
   85.66 +
   85.67 +#if 0
   85.68 +static bool
   85.69 +Compile(const char *stream, size_t length)
   85.70 +{
   85.71 +
   85.72 +    printf("\n ------------ \n\n");
   85.73 +
   85.74 +    Disassemble(module->getFunction(1)->code(), stdout);
   85.75 +    //Disassemble(module->getFunction(1), stdout);
   85.76 +
   85.77 +    printf("\n ------------ \n\n");
   85.78 +
   85.79 +    Function *main = module->getFunction(1);
   85.80 +
   85.81 +    Top top = ZONE()->stack().begin();
   85.82 +    LocalTop localTop(top);
   85.83 +
   85.84 +    Frame *frame = ZONE()->stack().pushFrame(main);
   85.85 +    if (!frame)
   85.86 +        return false;
   85.87 +
   85.88 +    LocalSlot result;
   85.89 +    if (!Interpret(ZONE(), frame, &result))
   85.90 +        return false;
   85.91 +
   85.92 +    printf("Result: %d\n", result.i32);
   85.93 +
   85.94 +    return true;
   85.95 +}
   85.96 +#endif
   85.97 +
   85.98 +intptr_t PrintToServer(void *blah, intptr_t *params)
   85.99 +{
  85.100 +    assert(params[0] == 3);
  85.101 +    const char *fmt = reinterpret_cast<const char *>(params[1]);
  85.102 +    const char *str = reinterpret_cast<const char *>(params[2]);
  85.103 +    int *d = reinterpret_cast<int *>(params[3]);
  85.104 +    printf(fmt, str, *d);
  85.105 +    return 16;
  85.106 +}
  85.107 +
  85.108 +int main(int argc, char **argv)
  85.109 +{
  85.110 +    if (argc < 2) {
  85.111 +        fprintf(stderr, "Usage: <file>\n");
  85.112 +        return 1;
  85.113 +    }
  85.114 +
  85.115 +    if (!Ke::Keima::Initialize())
  85.116 +        return 1;
  85.117 +    Ke::Keima::InstallMessageReporter(&s_Reporter);
  85.118 +    {
  85.119 +        Ke::HandleScope scope;
  85.120 +        Ke::Local<Ke::Module> module = Ke::Compile(argv[1]);
  85.121 +        if (!module)
  85.122 +            return 1;
  85.123 +
  85.124 +        //Ke::Local<Ke::Native> native = module->getNative(0);
  85.125 +        //native->bind(reinterpret_cast<void *>(PrintToServer));
  85.126 +        //module->setNativeIdentity(reinterpret_cast<void *>(5));
  85.127 +
  85.128 +        int result;
  85.129 +        Ke::Local<Ke::Function> fun = module->getPublic(0);
  85.130 +        if (Ke::Keima::Invoke(fun, NULL, 0, &result))
  85.131 +            printf("%d\n", result);
  85.132 +    }
  85.133 +
  85.134 +    Ke::Keima::Shutdown();
  85.135 +}