src/API.cpp
author Michael Busby <prodigysim@gmail.com>
Mon Jun 10 01:50:18 2013 +0100 (2013-06-10)
changeset 264 70b8f318c379
parent 262 c4b1341297e5
permissions -rw-r--r--
Parse assignment RTL instead of LTR, fixes multiple assignment (bug 5420).
     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 "compiler/CompileContext.h"
    24 #include "Modules.h"
    25 #include "GlobalRoots.h"
    26 #include "Reference.h"
    27 #include "Array.h"
    28 #include "Interpreter.h"
    29 #include "Stack.h"
    30 #include "Strings.h"
    31 #include "Packages.h"
    32 #include "NativeTable.h"
    33 #include "Spaces-inl.h"
    34 #include "Heap-inl.h"
    35 
    36 using namespace ke;
    37 
    38 bool
    39 Ke::Keima::Initialize()
    40 {
    41     SingleThreadedZone = new Zone();
    42     if (!SingleThreadedZone || !SingleThreadedZone->initialize())
    43         return false;
    44     return true;
    45 }
    46 
    47 void
    48 Ke::Keima::Shutdown()
    49 {
    50     delete SingleThreadedZone;
    51     SingleThreadedZone = NULL;
    52 }
    53 
    54 Ke::HandleScope::HandleScope()
    55   : zone_(ke::ZONE()),
    56     position_(zone_->rootScopes().position()),
    57     prev_(*zone_->rootScopes().scope())
    58 {
    59     *zone_->rootScopes().scope() = this;
    60 }
    61 
    62 Ke::HandleScope::~HandleScope()
    63 {
    64     zone_->rootScopes().unwind(position_);
    65     *zone_->rootScopes().scope() = prev_;
    66 }
    67 
    68 ke::Object **
    69 Ke::HandleScope::CreateHandle(ke::Object *obj)
    70 {
    71     if (!obj)
    72         return NULL;
    73 
    74     return ZONE()->rootScopes().make(obj);
    75 }
    76 
    77 template <typename From, typename To> static inline To *
    78 Open(Ke::Handle<From> from)
    79 {
    80     if (!from)
    81         return NULL;
    82     return *reinterpret_cast<To **>(*from);
    83 }
    84 
    85 template <typename From, typename To> static inline To *
    86 Open(From *from)
    87 {
    88     if (!from)
    89         return NULL;
    90     return *reinterpret_cast<To **>(from);
    91 }
    92 
    93 template <typename From, typename To> static inline Ke::Local<To>
    94 ToLocal(From *from)
    95 {
    96     if (!from)
    97         return Ke::Local<To>();
    98     return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
    99 }
   100 
   101 bool
   102 InternalCompile(ke::Handle<ke::Package> package, const char *name)
   103 {
   104     PoolScope poolScope(ZONE()->pool());
   105     RootScope roots(ZONE());
   106     CompileContext cc(ZONE());
   107 
   108     if (!cc.initialize(package, name))
   109         return false;
   110 
   111     if (!cc.compile())
   112         return false;
   113 
   114     return true;
   115 }
   116 
   117 // This is split out from InternalCompile so the RootScope doesn't conflict
   118 // with making a return handle.
   119 bool
   120 Ke::Keima::Compile(Handle<Package> argPackage, const char *name)
   121 {
   122     ke::Local<ke::Package> package(ke::ZONE(), Open<Ke::Package, ke::Package>(argPackage));
   123     return InternalCompile(package, name);
   124 }
   125 
   126 void
   127 Ke::Keima::InstallMessageReporter(Ke::IMessageReporter *reporter)
   128 {
   129     ZONE()->installErrorReporter(reporter);
   130 }
   131 
   132 class StackFrameIterator : public Ke::IStackFrameIterator
   133 {
   134     StackIter iter_;
   135 
   136   public:
   137     StackFrameIterator()
   138       : iter_(ZONE())
   139     {
   140     }
   141 
   142     virtual bool done() {
   143         return iter_.done();
   144     }
   145 
   146     const char *function() {
   147         return iter_.function();
   148     }
   149 
   150     const char *source() {
   151         return iter_.source();
   152     }
   153 
   154     unsigned lineNumber() {
   155         return iter_.lineNumber();
   156     }
   157 
   158     void prev() {
   159         iter_.prev();
   160     }
   161 };
   162 
   163 Ke::IStackFrameIterator *
   164 Ke::Keima::NewStackFrameIterator()
   165 {
   166     return new StackFrameIterator();
   167 }
   168 
   169 static inline ke::HeapRoot *
   170 FromAPI(ke::HeapRoot *from)
   171 {
   172     ke::Address address = reinterpret_cast<ke::Address>(from);
   173     address -= offsetof(ke::HeapRoot, obj);
   174     return reinterpret_cast<ke::HeapRoot *>(address);
   175 }
   176 
   177 ke::HeapRoot *
   178 Ke::Internals::NewHeapRoot()
   179 {
   180     ke::HeapRoot *root = ke::ZONE()->globalRoots()->create();
   181     if (!root)
   182         return NULL;
   183 
   184     // Compute an interior pointer, so it looks like a Handle to an object.
   185     return reinterpret_cast<ke::HeapRoot *>(&root->obj);
   186 }
   187 
   188 void
   189 Ke::Internals::Destroy(ke::HeapRoot *root)
   190 {
   191     ZONE()->globalRoots()->destroy(FromAPI(root));
   192 }
   193 
   194 #if 0
   195 bool
   196 Ke::Keima::IsInCallStack(Handle<Package> package)
   197 {
   198     ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(argModule));
   199     return ZONE()->stack().isInCallStack(module);
   200 }
   201 #endif
   202 
   203 void
   204 Ke::Keima::CollectGarbage()
   205 {
   206     ke::ZONE()->heap().reclaim();
   207 }
   208 
   209 void
   210 Ke::Keima::ClearPendingException()
   211 {
   212     ke::ZONE()->clearPendingException();
   213 }
   214 
   215 void
   216 Ke::Package::setNativeIdentity(void *identity)
   217 {
   218     ke::Local<ke::Package> package(ke::ZONE(), Open<Ke::Package, ke::Package>(this));
   219     package->setNativeIdentity(identity);
   220 }
   221 
   222 unsigned
   223 Ke::String::length()
   224 {
   225     ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
   226     return obj->length();
   227 }
   228 
   229 const char *
   230 Ke::String::chars()
   231 {
   232     ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
   233     return obj->chars();
   234 }
   235 
   236 Ke::Local<Ke::String>
   237 Ke::Function::name()
   238 {
   239     ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(this));
   240     return ToLocal<ke::String, Ke::String>(fun->name());
   241 }
   242 
   243 Ke::Local<Ke::Package>
   244 Ke::Package::New(Handle<Package> argParent,
   245                  Handle<String> argName,
   246                  const char *path,
   247                  unsigned flags)
   248 {
   249     ke::Local<ke::Package> parent(ke::ZONE(), Open<Ke::Package, ke::Package>(argParent));
   250     ke::Local<ke::String> name(ke::ZONE(), Open<Ke::String, ke::String>(argName));
   251     ke::Local<ke::Package> package(ke::ZONE(), ke::Package::New(ke::ZONE(), parent, path, name, flags));
   252     return ToLocal<ke::Package, Ke::Package>(package);
   253 }
   254 
   255 static inline const char *
   256 GetInvokeTypeName(Ke::Parameter::Type type)
   257 {
   258     switch (type) {
   259       case Ke::Parameter::Array:
   260         return "array";
   261       case Ke::Parameter::CharArray:
   262         return "String";
   263       case Ke::Parameter::Float:
   264         return "Float";
   265       case Ke::Parameter::FloatRef:
   266         return "&Float";
   267       case Ke::Parameter::Int:
   268         return "int";
   269       case Ke::Parameter::IntRef:
   270         return "&int";
   271       default:
   272         return "<unknown>";
   273     }
   274 }
   275 
   276 static inline bool
   277 CheckInvokeType(const Ke::Parameter &param, Type *type)
   278 {
   279     switch (param.type()) {
   280       case Ke::Parameter::Array:
   281       {
   282         if (!type->isArray())
   283             return false;
   284 
   285         ArrayType *atype = ArrayType::cast(type);
   286         return atype->levels() == 1 &&
   287                (atype->contained()->isPrimitive() || atype->contained()->isEnum()) &&
   288                (atype->contained()->primitive() != PrimitiveType_Char);
   289       }
   290       case Ke::Parameter::CharArray:
   291         return type->isArray() && ArrayType::cast(type)->isCharArray();
   292       case Ke::Parameter::Float:
   293         return type->isFloat();
   294       case Ke::Parameter::FloatRef:
   295         return type->isReference() && ReferenceType::cast(type)->contained()->isFloat();
   296       case Ke::Parameter::Int:
   297         return type->isInt32() || type->isEnum();
   298       case Ke::Parameter::IntRef:
   299        return type->isReference() &&
   300               (ReferenceType::cast(type)->contained()->isInt32() ||
   301                ReferenceType::cast(type)->contained()->isEnum());
   302       default:
   303         return false;
   304     }
   305 }
   306 
   307 static bool
   308 CheckInvokeTypes(Ke::Handle<Ke::Function> argFun, const Ke::Parameter *params, unsigned nparams)
   309 {
   310     ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
   311 
   312     if (fun->nargs() != nparams)
   313         return false;
   314 
   315     for (unsigned i = 0; i < nparams; i++) {
   316         if (!CheckInvokeType(params[i], fun->argType(i))) {
   317             char name[255];
   318             ke::ZONE()->reportError(Message_TypeMismatchDuringInvoke,
   319                                     GetInvokeTypeName(params[i].type()),
   320                                     GetTypeName(fun->argType(i), name, sizeof(name)));
   321             return false;
   322         }
   323     }
   324 
   325     // Functions can only return tagged cells, for ISPE1-compatible Invoke().
   326     ke::Local<ke::Type> returnType(ke::ZONE(), fun->type()->returnType());
   327     if (!returnType->isPrimitive() &&
   328         !returnType->isEnum() &&
   329         !returnType->isVoid())
   330     {
   331         char name[255];
   332         ke::ZONE()->reportError(Message_CannotInvokeReturnType,
   333                                 GetTypeName(returnType, name, sizeof(name)));
   334         return false;
   335     }
   336 
   337     return true;
   338 }
   339 
   340 bool
   341 Ke::Keima::Invoke(Handle<Function> argFun, const Parameter *params, unsigned nparams,
   342                   bool checkTypes, int *retval)
   343 {
   344     assert(CheckInvokeTypes(argFun, params, nparams));
   345 
   346     ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
   347 
   348     if (fun->nargs() != nparams) {
   349         // :TODO: report error
   350         assert(false);
   351         return false;
   352     }
   353 
   354     ke::InvokeArgs args;
   355     if (!ke::ZONE()->stack().pushInvokeFrame(fun, args))
   356         return false;
   357 
   358     if (checkTypes && !CheckInvokeTypes(argFun, params, nparams))
   359         return false;
   360 
   361     for (unsigned i = 0; i < nparams; i++) {
   362         ke::LocalSlot &slot = args.arg(i);
   363         switch (params[i].type()) {
   364           case Ke::Parameter::Int:
   365             slot.i32 = params[i].i32();
   366             break;
   367 
   368           case Ke::Parameter::Float:
   369             slot.f = params[i].f();
   370             break;
   371 
   372           case Ke::Parameter::IntRef:
   373             if (params[i].writeback()) {
   374                 slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack);
   375             } else {
   376                 LocalSlot other;
   377                 other.i32 = *params[i].i32p();
   378                 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
   379             }
   380             if (!slot.ref)
   381                 return false;
   382             break;
   383 
   384           case Ke::Parameter::FloatRef:
   385             if (params[i].writeback()) {
   386                 slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack);
   387             } else {
   388                 LocalSlot other;
   389                 other.f = *params[i].fp();
   390                 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
   391             }
   392             if (!slot.ref)
   393                 return false;
   394             break;
   395 
   396           case Ke::Parameter::Array:
   397           {
   398             ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->externalGenericArrayMap());
   399             if (params[i].writeback()) {
   400                 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].buffer(),
   401                                               params[i].length(), Heap::Tenure_Stack);
   402                 if (!slot.obj)
   403                     return false;
   404             } else {
   405                 Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
   406                 if (!slot.obj)
   407                     return false;
   408                 if (params[i].length())
   409                     memcpy(array->bytes(), params[i].buffer(), params[i].length() * sizeof(int));
   410             }
   411             break;
   412           }
   413 
   414           case Ke::Parameter::CharArray:
   415           {
   416             ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->externalCharArrayMap());
   417             if (params[i].writeback()) {
   418                 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].buffer(),
   419                                               params[i].length(), Heap::Tenure_Stack);
   420                 if (!slot.obj)
   421                     return false;
   422             } else {
   423                 Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
   424                 if (!slot.obj)
   425                     return false;
   426                 if (params[i].length())
   427                     memcpy(array->bytes(), params[i].buffer(), params[i].length() * sizeof(char));
   428             }
   429             break;
   430           }
   431         }
   432     }
   433 
   434     LocalSlot result;
   435     if (!Interpret(ke::ZONE(), NULL, &result))
   436         return false;
   437 
   438     if (fun->type()->returnType()->isVoid())
   439         result.i32 = 0;
   440 
   441     *retval = result.i32;
   442     return true;
   443 }
   444 
   445 bool
   446 Ke::Keima::BindNative(const char *name, void *address)
   447 {
   448     return ke::ZONE()->nativeTable()->bind(name, address);
   449 }
   450 
   451 void
   452 Ke::Keima::SetPublicFunctionListener(IPublicFunctionListener *listener)
   453 {
   454     ke::ZONE()->setPublicFunctionListener(listener);
   455 }
   456 
   457 void
   458 Zone::registerPublic(ke::Handle<Function> fun)
   459 {
   460     if (!publicFunctionListener_)
   461         return;
   462 
   463     Ke::Local<Ke::Function> local = ToLocal<ke::Function, Ke::Function>(fun);
   464     publicFunctionListener_->registerPublic(local);
   465 }