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