Renamed jitcraft/ to src/, fixed some /Wp64 warnings.
Renamed jitcraft/ to src/, fixed some /Wp64 warnings.
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 ¶m, 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 +}