jitcraft/API.cpp
author David Anderson <dvander@alliedmods.net>
Mon Jul 09 01:22:03 2012 -0700 (2012-07-09)
changeset 65 7c942b5adebc
parent 64 11c81eb30246
child 68 b40b0e18a918
permissions -rw-r--r--
Added ISPE-oriented API for invoking functions.
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@61
    32
dvander@61
    33
using namespace ke;
dvander@61
    34
dvander@61
    35
bool
dvander@62
    36
Ke::Keima::Initialize()
dvander@61
    37
{
dvander@61
    38
    SingleThreadedZone = new Zone();
dvander@61
    39
    if (!SingleThreadedZone || !SingleThreadedZone->initialize())
dvander@61
    40
        return false;
dvander@61
    41
    return true;
dvander@61
    42
}
dvander@61
    43
dvander@61
    44
void
dvander@62
    45
Ke::Keima::Shutdown()
dvander@61
    46
{
dvander@61
    47
    delete SingleThreadedZone;
dvander@61
    48
    SingleThreadedZone = NULL;
dvander@61
    49
}
dvander@61
    50
dvander@60
    51
Ke::HandleScope::HandleScope()
dvander@60
    52
  : zone_(ke::ZONE()),
dvander@60
    53
    position_(zone_->rootScopes().position()),
dvander@60
    54
    prev_(*zone_->rootScopes().scope())
dvander@60
    55
{
dvander@60
    56
    *zone_->rootScopes().scope() = this;
dvander@60
    57
}
dvander@60
    58
dvander@61
    59
Ke::HandleScope::~HandleScope()
dvander@61
    60
{
dvander@61
    61
    zone_->rootScopes().unwind(position_);
dvander@61
    62
    *zone_->rootScopes().scope() = prev_;
dvander@61
    63
}
dvander@61
    64
dvander@61
    65
ke::Object **
dvander@61
    66
Ke::HandleScope::CreateHandle(ke::Object *obj)
dvander@61
    67
{
dvander@61
    68
    if (!obj)
dvander@61
    69
        return NULL;
dvander@61
    70
dvander@61
    71
    return ZONE()->rootScopes().make(obj);
dvander@61
    72
}
dvander@61
    73
dvander@62
    74
template <typename From, typename To> static inline To *
dvander@62
    75
Open(Ke::Handle<From> from)
dvander@62
    76
{
dvander@62
    77
    return *reinterpret_cast<To **>(*from);
dvander@62
    78
}
dvander@62
    79
dvander@64
    80
template <typename From, typename To> static inline To *
dvander@64
    81
Open(From *from)
dvander@64
    82
{
dvander@64
    83
    return *reinterpret_cast<To **>(from);
dvander@64
    84
}
dvander@64
    85
dvander@61
    86
template <typename From, typename To> static inline Ke::Local<To>
dvander@64
    87
ToLocal(From *from)
dvander@61
    88
{
dvander@61
    89
    return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
dvander@61
    90
}
dvander@61
    91
dvander@61
    92
static ke::Module *
dvander@61
    93
CompileFromSource(CompileContext &cc, const char *path, const char *stream, size_t length)
dvander@61
    94
{
dvander@61
    95
    Parser parser(ZONE(), cc, stream, length);
dvander@61
    96
    ParseTree *tree = parser.parse();
dvander@61
    97
    if (!tree)
dvander@61
    98
        return NULL;
dvander@61
    99
    tree->dump(stdout);
dvander@61
   100
dvander@61
   101
    if (!Scope::Bind(tree))
dvander@61
   102
        return NULL;
dvander@61
   103
dvander@61
   104
    SemanticAnalysis semantics(ZONE(), cc, tree);
dvander@61
   105
    if (!semantics.analyze())
dvander@61
   106
        return NULL;
dvander@61
   107
dvander@61
   108
    Scope::Allocate(tree);
dvander@61
   109
dvander@61
   110
    BytecodeCompiler compiler(ZONE(), tree, NULL);
dvander@61
   111
    return compiler.compile();
dvander@61
   112
}
dvander@61
   113
dvander@61
   114
Ke::Local<Ke::Module>
dvander@61
   115
Ke::Compile(const char *path)
dvander@61
   116
{
dvander@61
   117
    RootScope roots(ZONE());
dvander@61
   118
    CompileContext cc(ZONE());
dvander@61
   119
dvander@61
   120
    char *bytes = NULL;
dvander@61
   121
    size_t length;
dvander@61
   122
    {
dvander@61
   123
        FILE *fp = fopen(path, "rb");
dvander@61
   124
        if (!fp) {
dvander@61
   125
            cc.reportError(SourcePosition(), Message_CantOpenFile);
dvander@61
   126
            return Ke::Local<Ke::Module>();
dvander@61
   127
        }
dvander@61
   128
dvander@61
   129
        if (fseek(fp, 0, SEEK_END)) {
dvander@61
   130
            cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
dvander@61
   131
            fclose(fp);
dvander@61
   132
            return Ke::Local<Ke::Module>();;
dvander@61
   133
        }
dvander@61
   134
        long size = ftell(fp);
dvander@61
   135
        if (size < 0) {
dvander@61
   136
            cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
dvander@61
   137
            fclose(fp);
dvander@61
   138
            return Ke::Local<Ke::Module>();;
dvander@61
   139
        }
dvander@61
   140
        rewind(fp);
dvander@61
   141
        length = size_t(size);
dvander@61
   142
        bytes = new char[length + 1];
dvander@61
   143
        if (fread(bytes, 1, length, fp) != length) {
dvander@61
   144
            cc.reportError(SourcePosition(), Message_ErrorReadingFile);
dvander@61
   145
            fclose(fp);
dvander@61
   146
            delete [] bytes;
dvander@61
   147
            return Ke::Local<Ke::Module>();;
dvander@61
   148
        }
dvander@61
   149
        fclose(fp);
dvander@61
   150
    }
dvander@61
   151
dvander@61
   152
    ke::Local<ke::Module> module(ZONE(),  CompileFromSource(cc, path, bytes, length));
dvander@61
   153
    delete [] bytes;
dvander@61
   154
    if (!module)
dvander@61
   155
        return Ke::Local<Ke::Module>();
dvander@61
   156
dvander@61
   157
    return ToLocal<ke::Module, Ke::Module>(module);
dvander@61
   158
}
dvander@61
   159
dvander@61
   160
static inline ke::HeapRoot *
dvander@61
   161
FromAPI(ke::HeapRoot *from)
dvander@61
   162
{
dvander@61
   163
    ke::Address address = reinterpret_cast<ke::Address>(from);
dvander@61
   164
    address -= offsetof(ke::HeapRoot, obj);
dvander@61
   165
    return reinterpret_cast<ke::HeapRoot *>(address);
dvander@61
   166
}
dvander@61
   167
dvander@61
   168
ke::HeapRoot *
dvander@61
   169
Ke::Internals::NewHeapRoot(ke::Object **ptr)
dvander@61
   170
{
dvander@61
   171
    ke::Local<ke::Object> obj(ZONE(), *ptr);
dvander@61
   172
    ke::HeapRoot *root = ke::ZONE()->globalRoots()->create(obj);
dvander@61
   173
    if (!root)
dvander@61
   174
        return NULL;
dvander@61
   175
dvander@61
   176
    // Compute an interior pointer, so it looks like a Handle to an object.
dvander@61
   177
    return reinterpret_cast<ke::HeapRoot *>(&root->obj);
dvander@61
   178
}
dvander@61
   179
dvander@61
   180
void
dvander@61
   181
Ke::Internals::IncRef(ke::HeapRoot *root)
dvander@61
   182
{
dvander@61
   183
    ZONE()->globalRoots()->incref(FromAPI(root));
dvander@61
   184
}
dvander@61
   185
dvander@61
   186
void
dvander@61
   187
Ke::Internals::DecRef(ke::HeapRoot *root)
dvander@61
   188
{
dvander@61
   189
    ZONE()->globalRoots()->decref(FromAPI(root));
dvander@61
   190
}
dvander@62
   191
dvander@62
   192
bool
dvander@62
   193
Ke::Keima::IsInCallStack(Handle<Module> argModule)
dvander@62
   194
{
dvander@62
   195
    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(argModule));
dvander@62
   196
    return ZONE()->stack().isInCallStack(module);
dvander@62
   197
}
dvander@62
   198
dvander@62
   199
void
dvander@62
   200
Ke::Keima::CollectGarbage()
dvander@62
   201
{
dvander@62
   202
    ke::ZONE()->heap().reclaim();
dvander@62
   203
}
dvander@64
   204
dvander@64
   205
unsigned
dvander@64
   206
Ke::Module::numPublics()
dvander@64
   207
{
dvander@64
   208
    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
dvander@65
   209
    if (!module->publics())
dvander@65
   210
        return 0;
dvander@64
   211
    return module->publics()->length();
dvander@64
   212
}
dvander@64
   213
dvander@64
   214
Ke::Local<Ke::Function>
dvander@64
   215
Ke::Module::getPublic(unsigned index)
dvander@64
   216
{
dvander@64
   217
    ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
dvander@64
   218
    ke::Local<ke::Function> fun(ke::ZONE(), ke::Function::cast(module->publics()->at(index)));
dvander@64
   219
    return ToLocal<ke::Function, Ke::Function>(fun);
dvander@64
   220
}
dvander@64
   221
dvander@64
   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@65
   243
static inline bool
dvander@65
   244
CheckInvokeType(const Ke::Parameter &param, Type *type)
dvander@65
   245
{
dvander@65
   246
    switch (param.type()) {
dvander@65
   247
      case Ke::Parameter::Array:
dvander@65
   248
        return type->isArray() &&
dvander@65
   249
               type->levels() == 1 &&
dvander@65
   250
               type->contained()->isPrimitive() &&
dvander@65
   251
               (type->contained()->primitive() != PrimitiveType_Char);
dvander@65
   252
      case Ke::Parameter::CharArray:
dvander@65
   253
        return type->isCharArray();
dvander@65
   254
      case Ke::Parameter::Float:
dvander@65
   255
        return type->isFloat();
dvander@65
   256
      case Ke::Parameter::FloatRef:
dvander@65
   257
        return type->isReference() && type->contained()->isFloat();
dvander@65
   258
      case Ke::Parameter::Int:
dvander@65
   259
        return type->isInt32();
dvander@65
   260
      case Ke::Parameter::IntRef:
dvander@65
   261
       return type->isReference() && type->contained()->isInt32();
dvander@65
   262
      default:
dvander@65
   263
        return false;
dvander@65
   264
    }
dvander@65
   265
}
dvander@65
   266
dvander@65
   267
bool
dvander@65
   268
Ke::Keima::CheckInvokeTypes(Ke::Handle<Ke::Function> argFun, const Ke::Parameter *params, unsigned nparams)
dvander@65
   269
{
dvander@65
   270
    ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
dvander@65
   271
dvander@65
   272
    if (fun->nargs() != nparams)
dvander@65
   273
        return false;
dvander@65
   274
dvander@65
   275
    for (unsigned i = 0; i < nparams; i++) {
dvander@65
   276
        if (!CheckInvokeType(params[i], fun->argType(i)))
dvander@65
   277
            return false;
dvander@65
   278
    }
dvander@65
   279
dvander@65
   280
    // Functions can only return tagged cells, for ISPE1-compatible Invoke().
dvander@65
   281
    if (!fun->type()->returnType()->isPrimitive() || fun->type()->returnType()->isTraceable())
dvander@65
   282
        return false;
dvander@65
   283
dvander@65
   284
    return true;
dvander@65
   285
}
dvander@65
   286
dvander@65
   287
bool
dvander@65
   288
Ke::Keima::Invoke(Handle<Function> argFun, const Parameter *params, unsigned nparams, int *retval)
dvander@65
   289
{
dvander@65
   290
    assert(CheckInvokeTypes(argFun, params, nparams));
dvander@65
   291
dvander@65
   292
    ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
dvander@65
   293
dvander@65
   294
    if (fun->nargs() != nparams) {
dvander@65
   295
        // :TODO: report error
dvander@65
   296
        assert(false);
dvander@65
   297
        return false;
dvander@65
   298
    }
dvander@65
   299
dvander@65
   300
    ke::InvokeArgs args;
dvander@65
   301
    if (!ke::ZONE()->stack().pushInvokeFrame(fun, args))
dvander@65
   302
        return false;
dvander@65
   303
dvander@65
   304
    for (unsigned i = 0; i < nparams; i++) {
dvander@65
   305
        ke::LocalSlot &slot = args.arg(i);
dvander@65
   306
        switch (params[i].type()) {
dvander@65
   307
          case Ke::Parameter::Int:
dvander@65
   308
            slot.i32 = params[i].i32();
dvander@65
   309
            break;
dvander@65
   310
dvander@65
   311
          case Ke::Parameter::Float:
dvander@65
   312
            slot.f = params[i].f();
dvander@65
   313
            break;
dvander@65
   314
dvander@65
   315
          case Ke::Parameter::IntRef:
dvander@65
   316
            if (params[i].writeback()) {
dvander@65
   317
                slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack);
dvander@65
   318
            } else {
dvander@65
   319
                LocalSlot other;
dvander@65
   320
                other.i32 = *params[i].i32p();
dvander@65
   321
                slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
dvander@65
   322
            }
dvander@65
   323
            if (!slot.ref)
dvander@65
   324
                return false;
dvander@65
   325
            break;
dvander@65
   326
dvander@65
   327
          case Ke::Parameter::FloatRef:
dvander@65
   328
            if (params[i].writeback()) {
dvander@65
   329
                slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack);
dvander@65
   330
            } else {
dvander@65
   331
                LocalSlot other;
dvander@65
   332
                other.f = *params[i].fp();
dvander@65
   333
                slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
dvander@65
   334
            }
dvander@65
   335
            if (!slot.ref)
dvander@65
   336
                return false;
dvander@65
   337
            break;
dvander@65
   338
dvander@65
   339
          case Ke::Parameter::Array:
dvander@65
   340
          {
dvander@65
   341
            ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->genericArrayMap());
dvander@65
   342
            if (params[i].writeback()) {
dvander@65
   343
                slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
dvander@65
   344
                                              params[i].buffer(), Heap::Tenure_Stack);
dvander@65
   345
                if (!slot.obj)
dvander@65
   346
                    return false;
dvander@65
   347
            } else {
dvander@65
   348
                Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
dvander@65
   349
                if (!slot.obj)
dvander@65
   350
                    return false;
dvander@65
   351
                memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(int));
dvander@65
   352
            }
dvander@65
   353
            break;
dvander@65
   354
          }
dvander@65
   355
dvander@65
   356
          case Ke::Parameter::CharArray:
dvander@65
   357
          {
dvander@65
   358
            ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->charArrayMap());
dvander@65
   359
            if (params[i].writeback()) {
dvander@65
   360
                slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
dvander@65
   361
                                              params[i].buffer(), Heap::Tenure_Stack);
dvander@65
   362
                if (!slot.obj)
dvander@65
   363
                    return false;
dvander@65
   364
            } else {
dvander@65
   365
                Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
dvander@65
   366
                if (!slot.obj)
dvander@65
   367
                    return false;
dvander@65
   368
                memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(char));
dvander@65
   369
            }
dvander@65
   370
            break;
dvander@65
   371
          }
dvander@65
   372
        }
dvander@65
   373
    }
dvander@65
   374
dvander@65
   375
    LocalSlot result;
dvander@65
   376
    if (!Interpret(ke::ZONE(), NULL, &result))
dvander@65
   377
        return false;
dvander@65
   378
dvander@65
   379
    *retval = result.i32;
dvander@65
   380
    return true;
dvander@65
   381
}