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