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