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