src/API.cpp
author David Anderson <dvander@alliedmods.net>
Sat Jul 28 17:12:42 2012 -0700 (2012-07-28)
changeset 111 0a0c37ddad13
parent 92 e3974e7360e9
child 129 86b368a4d80d
permissions -rw-r--r--
Trigger build.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     7  * JITCraft is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * JITCraft. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #include <string.h>
    20 #include "../include/keima.h"
    21 #include "Zone.h"
    22 #include "RootScopes.h"
    23 #include "CompileContext.h"
    24 #include "Parser.h"
    25 #include "Scopes.h"
    26 #include "SemanticAnalysis.h"
    27 #include "BytecodeCompiler.h"
    28 #include "Modules.h"
    29 #include "GlobalRoots.h"
    30 #include "Reference.h"
    31 #include "Array.h"
    32 #include "Interpreter.h"
    33 #include "Stack.h"
    34 #include "Strings.h"
    35 #include "Spaces-inl.h"
    36 #include "Heap-inl.h"
    37 
    38 using namespace ke;
    39 
    40 bool
    41 Ke::Keima::Initialize()
    42 {
    43     SingleThreadedZone = new Zone();
    44     if (!SingleThreadedZone || !SingleThreadedZone->initialize())
    45         return false;
    46     return true;
    47 }
    48 
    49 void
    50 Ke::Keima::Shutdown()
    51 {
    52     delete SingleThreadedZone;
    53     SingleThreadedZone = NULL;
    54 }
    55 
    56 Ke::HandleScope::HandleScope()
    57   : zone_(ke::ZONE()),
    58     position_(zone_->rootScopes().position()),
    59     prev_(*zone_->rootScopes().scope())
    60 {
    61     *zone_->rootScopes().scope() = this;
    62 }
    63 
    64 Ke::HandleScope::~HandleScope()
    65 {
    66     zone_->rootScopes().unwind(position_);
    67     *zone_->rootScopes().scope() = prev_;
    68 }
    69 
    70 ke::Object **
    71 Ke::HandleScope::CreateHandle(ke::Object *obj)
    72 {
    73     if (!obj)
    74         return NULL;
    75 
    76     return ZONE()->rootScopes().make(obj);
    77 }
    78 
    79 template <typename From, typename To> static inline To *
    80 Open(Ke::Handle<From> from)
    81 {
    82     return *reinterpret_cast<To **>(*from);
    83 }
    84 
    85 template <typename From, typename To> static inline To *
    86 Open(From *from)
    87 {
    88     return *reinterpret_cast<To **>(from);
    89 }
    90 
    91 template <typename From, typename To> static inline Ke::Local<To>
    92 ToLocal(From *from)
    93 {
    94     return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
    95 }
    96 
    97 static ke::Module *
    98 CompileFromSource(CompileContext &cc, const char *path, const char *stream, size_t length)
    99 {
   100     Parser parser(ZONE(), cc, stream, length);
   101     ParseTree *tree = parser.parse();
   102     if (!tree)
   103         return NULL;
   104     tree->dump(stdout);
   105 
   106     if (!Scope::Bind(cc, tree))
   107         return NULL;
   108 
   109     SemanticAnalysis semantics(ZONE(), cc, tree);
   110     if (!semantics.analyze())
   111         return NULL;
   112 
   113     Scope::Allocate(tree);
   114 
   115     BytecodeCompiler compiler(ZONE(), tree, NULL);
   116     ke::Local<Module> module(ke::ZONE(), compiler.compile());
   117     if (!module)
   118         return NULL;
   119 
   120     ke::InvokeArgs args;
   121     if (!ke::ZONE()->stack().pushModuleFrame(module, args))
   122         return NULL;
   123     if (!ke::Interpret(ke::ZONE(), NULL, NULL))
   124         return NULL;
   125 
   126     return module;
   127 }
   128 
   129 Ke::Local<Ke::Module>
   130 Ke::Compile(const char *path)
   131 {
   132     RootScope roots(ZONE());
   133     CompileContext cc(ZONE(), path);
   134 
   135     char *bytes = NULL;
   136     size_t length;
   137     {
   138         FILE *fp = fopen(path, "rb");
   139         if (!fp) {
   140             cc.reportError(SourcePosition(), Message_CantOpenFile);
   141             return Ke::Local<Ke::Module>();
   142         }
   143 
   144         if (fseek(fp, 0, SEEK_END)) {
   145             cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
   146             fclose(fp);
   147             return Ke::Local<Ke::Module>();;
   148         }
   149         long size = ftell(fp);
   150         if (size < 0) {
   151             cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
   152             fclose(fp);
   153             return Ke::Local<Ke::Module>();;
   154         }
   155         rewind(fp);
   156         length = size_t(size);
   157         bytes = new char[length + 1];
   158         if (fread(bytes, 1, length, fp) != length) {
   159             cc.reportError(SourcePosition(), Message_ErrorReadingFile);
   160             fclose(fp);
   161             delete [] bytes;
   162             return Ke::Local<Ke::Module>();;
   163         }
   164         fclose(fp);
   165     }
   166 
   167     ke::Local<ke::Module> module(ZONE(),  CompileFromSource(cc, path, bytes, length));
   168     delete [] bytes;
   169     if (!module)
   170         return Ke::Local<Ke::Module>();
   171 
   172     ke::Local<ke::String> pathstr(ZONE(), ke::String::New(ZONE(), path, Heap::Tenure_Old));
   173     if (!pathstr)
   174         return Ke::Local<Ke::Module>();
   175 
   176     module->setPath(pathstr);
   177     return ToLocal<ke::Module, Ke::Module>(module);
   178 }
   179 
   180 void
   181 Ke::Keima::InstallMessageReporter(Ke::IMessageReporter *reporter)
   182 {
   183     ZONE()->installErrorReporter(reporter);
   184 }
   185 
   186 class StackFrameIterator : public Ke::IStackFrameIterator
   187 {
   188     StackIter iter_;
   189 
   190   public:
   191     StackFrameIterator()
   192       : iter_(ZONE())
   193     {
   194     }
   195 
   196     virtual bool done() {
   197         return iter_.done();
   198     }
   199 
   200     const char *function() {
   201         return iter_.function();
   202     }
   203 
   204     const char *source() {
   205         return iter_.source();
   206     }
   207 
   208     unsigned lineNumber() {
   209         return iter_.lineNumber();
   210     }
   211 
   212     void prev() {
   213         iter_.prev();
   214     }
   215 };
   216 
   217 Ke::IStackFrameIterator *
   218 Ke::Keima::NewStackFrameIterator()
   219 {
   220     return new StackFrameIterator();
   221 }
   222 
   223 static inline ke::HeapRoot *
   224 FromAPI(ke::HeapRoot *from)
   225 {
   226     ke::Address address = reinterpret_cast<ke::Address>(from);
   227     address -= offsetof(ke::HeapRoot, obj);
   228     return reinterpret_cast<ke::HeapRoot *>(address);
   229 }
   230 
   231 ke::HeapRoot *
   232 Ke::Internals::NewHeapRoot(ke::Object **ptr)
   233 {
   234     ke::Local<ke::Object> obj(ZONE(), *ptr);
   235     ke::HeapRoot *root = ke::ZONE()->globalRoots()->create(obj);
   236     if (!root)
   237         return NULL;
   238 
   239     // Compute an interior pointer, so it looks like a Handle to an object.
   240     return reinterpret_cast<ke::HeapRoot *>(&root->obj);
   241 }
   242 
   243 void
   244 Ke::Internals::IncRef(ke::HeapRoot *root)
   245 {
   246     ZONE()->globalRoots()->incref(FromAPI(root));
   247 }
   248 
   249 void
   250 Ke::Internals::DecRef(ke::HeapRoot *root)
   251 {
   252     ZONE()->globalRoots()->decref(FromAPI(root));
   253 }
   254 
   255 bool
   256 Ke::Keima::IsInCallStack(Handle<Module> argModule)
   257 {
   258     ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(argModule));
   259     return ZONE()->stack().isInCallStack(module);
   260 }
   261 
   262 void
   263 Ke::Keima::CollectGarbage()
   264 {
   265     ke::ZONE()->heap().reclaim();
   266 }
   267 
   268 unsigned
   269 Ke::Module::numPublics()
   270 {
   271     ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   272     if (!module->publics())
   273         return 0;
   274     return module->publics()->length();
   275 }
   276 
   277 Ke::Local<Ke::Function>
   278 Ke::Module::getPublic(unsigned index)
   279 {
   280     ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   281     ke::Local<ke::Function> fun(ke::ZONE(), ke::Function::cast(module->publics()->at(index)));
   282     return ToLocal<ke::Function, Ke::Function>(fun);
   283 }
   284 
   285 unsigned
   286 Ke::Module::numNatives()
   287 {
   288     ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   289     if (!module->natives())
   290         return 0;
   291     return module->natives()->length();
   292 }
   293 
   294 Ke::Local<Ke::Native>
   295 Ke::Module::getNative(unsigned index)
   296 {
   297     ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   298     ke::Local<ke::Native> fun(ke::ZONE(), ke::Native::cast(module->natives()->at(index)));
   299     return ToLocal<ke::Native, Ke::Native>(fun);
   300 }
   301 
   302 void
   303 Ke::Module::setNativeIdentity(void *identity)
   304 {
   305     ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
   306     module->setNativeIdentity(identity);
   307 }
   308 
   309 unsigned
   310 Ke::String::length()
   311 {
   312     ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
   313     return obj->length();
   314 }
   315 
   316 const char *
   317 Ke::String::chars()
   318 {
   319     ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
   320     return obj->chars();
   321 }
   322 
   323 Ke::Local<Ke::String>
   324 Ke::Function::name()
   325 {
   326     ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(this));
   327     return ToLocal<ke::String, Ke::String>(fun->name());
   328 }
   329 
   330 Ke::Local<Ke::String>
   331 Ke::Native::name()
   332 {
   333     ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
   334     return ToLocal<ke::String, Ke::String>(native->name());
   335 }
   336 
   337 void
   338 Ke::Native::bind(void *function)
   339 {
   340     ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
   341     native->bind(function);
   342 }
   343 
   344 static inline bool
   345 CheckInvokeType(const Ke::Parameter &param, Type *type)
   346 {
   347     switch (param.type()) {
   348       case Ke::Parameter::Array:
   349         return type->isArray() &&
   350                type->levels() == 1 &&
   351                type->contained()->isPrimitive() &&
   352                (type->contained()->primitive() != PrimitiveType_Char);
   353       case Ke::Parameter::CharArray:
   354         return type->isCharArray();
   355       case Ke::Parameter::Float:
   356         return type->isFloat();
   357       case Ke::Parameter::FloatRef:
   358         return type->isReference() && type->contained()->isFloat();
   359       case Ke::Parameter::Int:
   360         return type->isInt32();
   361       case Ke::Parameter::IntRef:
   362        return type->isReference() && type->contained()->isInt32();
   363       default:
   364         return false;
   365     }
   366 }
   367 
   368 bool
   369 Ke::Keima::CheckInvokeTypes(Ke::Handle<Ke::Function> argFun, const Ke::Parameter *params, unsigned nparams)
   370 {
   371     ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
   372 
   373     if (fun->nargs() != nparams)
   374         return false;
   375 
   376     for (unsigned i = 0; i < nparams; i++) {
   377         if (!CheckInvokeType(params[i], fun->argType(i)))
   378             return false;
   379     }
   380 
   381     // Functions can only return tagged cells, for ISPE1-compatible Invoke().
   382     ke::Local<ke::Type> returnType(ke::ZONE(), fun->type()->returnType());
   383     if ((!returnType->isPrimitive() && !returnType->isVoid()) || returnType->isTraceable())
   384         return false;
   385 
   386     return true;
   387 }
   388 
   389 bool
   390 Ke::Keima::Invoke(Handle<Function> argFun, const Parameter *params, unsigned nparams, int *retval)
   391 {
   392     assert(CheckInvokeTypes(argFun, params, nparams));
   393 
   394     ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
   395 
   396     if (fun->nargs() != nparams) {
   397         // :TODO: report error
   398         assert(false);
   399         return false;
   400     }
   401 
   402     ke::InvokeArgs args;
   403     if (!ke::ZONE()->stack().pushInvokeFrame(fun, args))
   404         return false;
   405 
   406     for (unsigned i = 0; i < nparams; i++) {
   407         ke::LocalSlot &slot = args.arg(i);
   408         switch (params[i].type()) {
   409           case Ke::Parameter::Int:
   410             slot.i32 = params[i].i32();
   411             break;
   412 
   413           case Ke::Parameter::Float:
   414             slot.f = params[i].f();
   415             break;
   416 
   417           case Ke::Parameter::IntRef:
   418             if (params[i].writeback()) {
   419                 slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack);
   420             } else {
   421                 LocalSlot other;
   422                 other.i32 = *params[i].i32p();
   423                 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
   424             }
   425             if (!slot.ref)
   426                 return false;
   427             break;
   428 
   429           case Ke::Parameter::FloatRef:
   430             if (params[i].writeback()) {
   431                 slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack);
   432             } else {
   433                 LocalSlot other;
   434                 other.f = *params[i].fp();
   435                 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
   436             }
   437             if (!slot.ref)
   438                 return false;
   439             break;
   440 
   441           case Ke::Parameter::Array:
   442           {
   443             ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->genericArrayMap());
   444             if (params[i].writeback()) {
   445                 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
   446                                               params[i].buffer(), Heap::Tenure_Stack);
   447                 if (!slot.obj)
   448                     return false;
   449             } else {
   450                 Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
   451                 if (!slot.obj)
   452                     return false;
   453                 memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(int));
   454             }
   455             break;
   456           }
   457 
   458           case Ke::Parameter::CharArray:
   459           {
   460             ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->charArrayMap());
   461             if (params[i].writeback()) {
   462                 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
   463                                               params[i].buffer(), Heap::Tenure_Stack);
   464                 if (!slot.obj)
   465                     return false;
   466             } else {
   467                 Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
   468                 if (!slot.obj)
   469                     return false;
   470                 memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(char));
   471             }
   472             break;
   473           }
   474         }
   475     }
   476 
   477     LocalSlot result;
   478     if (!Interpret(ke::ZONE(), NULL, &result))
   479         return false;
   480 
   481     if (fun->type()->returnType()->isVoid())
   482         result.i32 = 0;
   483 
   484     *retval = result.i32;
   485     return true;
   486 }