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