sourcepawn/jit/x86/jit_x86.cpp
author David Anderson <dvander@alliedmods.net>
Wed Aug 14 23:54:25 2013 -0700 (2013-08-14)
changeset 4013 6201c1180e0e
parent 3993 d06d6dacfa18
child 4022 9c0a32892063
permissions -rw-r--r--
Implement a watchdog timer for scripts that take too long to execute (bug 5837, r=fyren).
dvander@367
     1
/**
danderson@3977
     2
 * vim: set ts=2 sw=2 tw=99 et:
ds@1330
     3
 * =============================================================================
dvander@2114
     4
 * SourceMod
dvander@2114
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@367
     7
 *
dvander@2114
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@2114
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2114
    10
 * Free Software Foundation.
dvander@2114
    11
 * 
dvander@2114
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2114
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2114
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2114
    15
 * details.
dvander@2114
    16
 *
dvander@2114
    17
 * You should have received a copy of the GNU General Public License along with
dvander@2114
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2114
    19
 *
dvander@2114
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2114
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2114
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2114
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2114
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2114
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2114
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2114
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@367
    28
 *
dvander@367
    29
 * Version: $Id$
dvander@367
    30
 */
dvander@367
    31
dvander@157
    32
#include <string.h>
dvander@157
    33
#include <stdlib.h>
dvander@157
    34
#include <assert.h>
dvander@157
    35
#include "jit_x86.h"
dvander@2193
    36
#include "../sp_vm_engine.h"
dvander@2193
    37
#include "../engine2.h"
dvander@2193
    38
#include "../BaseRuntime.h"
dvander@2193
    39
#include "../sp_vm_basecontext.h"
dvander@4013
    40
#include "watchdog_timer.h"
ds@1952
    41
dvander@2226
    42
using namespace Knight;
dvander@157
    43
dvander@157
    44
#if defined USE_UNGEN_OPCODES
dvander@157
    45
#include "ungen_opcodes.h"
dvander@157
    46
#endif
dvander@157
    47
danderson@3977
    48
#define __ masm.
danderson@3977
    49
dvander@2226
    50
JITX86 g_Jit;
dvander@2226
    51
KeCodeCache *g_pCodeCache = NULL;
dvander@2193
    52
ISourcePawnEngine *engine = &g_engine1;
dvander@2193
    53
dvander@4013
    54
static inline uint8_t *
danderson@3977
    55
LinkCode(AssemblerX86 &masm)
dvander@157
    56
{
danderson@3977
    57
  if (masm.outOfMemory())
danderson@3977
    58
    return NULL;
dvander@157
    59
danderson@3977
    60
  void *code = Knight::KE_AllocCode(g_pCodeCache, masm.length());
danderson@3977
    61
  if (!code)
danderson@3977
    62
    return NULL;
dvander@157
    63
danderson@3977
    64
  masm.emitToExecutableMemory(code);
dvander@4013
    65
  return reinterpret_cast<uint8_t *>(code);
dvander@157
    66
}
dvander@157
    67
danderson@3977
    68
static inline ConditionCode
danderson@3977
    69
OpToCondition(OPCODE op)
dvander@157
    70
{
danderson@3977
    71
  switch (op) {
danderson@3977
    72
   case OP_EQ:
danderson@3977
    73
   case OP_JEQ:
danderson@3977
    74
    return equal;
danderson@3977
    75
   case OP_NEQ:
danderson@3977
    76
   case OP_JNEQ:
danderson@3977
    77
    return not_equal;
danderson@3977
    78
   case OP_SLESS:
danderson@3977
    79
   case OP_JSLESS:
danderson@3977
    80
    return less;
danderson@3977
    81
   case OP_SLEQ:
danderson@3977
    82
   case OP_JSLEQ:
danderson@3977
    83
    return less_equal;
danderson@3977
    84
   case OP_SGRTR:
danderson@3977
    85
   case OP_JSGRTR:
danderson@3977
    86
    return greater;
danderson@3977
    87
   case OP_SGEQ:
danderson@3977
    88
   case OP_JSGEQ:
danderson@3977
    89
    return greater_equal;
danderson@3977
    90
   default:
danderson@3977
    91
    assert(false);
danderson@3977
    92
    return negative;
danderson@3977
    93
  }
dvander@157
    94
}
dvander@157
    95
danderson@3977
    96
struct array_creation_t
dvander@157
    97
{
danderson@3977
    98
  const cell_t *dim_list;     /* Dimension sizes */
danderson@3977
    99
  cell_t dim_count;           /* Number of dimensions */
danderson@3977
   100
  cell_t *data_offs;          /* Current offset AFTER the indirection vectors (data) */
danderson@3977
   101
  cell_t *base;               /* array base */
danderson@3977
   102
};
dvander@157
   103
danderson@3977
   104
static cell_t
danderson@3977
   105
GenerateInnerArrayIndirectionVectors(array_creation_t *ar, int dim, cell_t cur_offs)
dvander@157
   106
{
danderson@3977
   107
  cell_t write_offs = cur_offs;
danderson@3977
   108
  cell_t *data_offs = ar->data_offs;
dvander@157
   109
danderson@3977
   110
  cur_offs += ar->dim_list[dim];
dvander@157
   111
danderson@3977
   112
  // Dimension n-x where x > 2 will have sub-vectors.  
danderson@3977
   113
  // Otherwise, we just need to reference the data section.
danderson@3977
   114
  if (ar->dim_count > 2 && dim < ar->dim_count - 2) {
danderson@3977
   115
    // For each index at this dimension, write offstes to our sub-vectors.
danderson@3977
   116
    // After we write one sub-vector, we generate its sub-vectors recursively.
danderson@3977
   117
    // At the end, we're given the next offset we can use.
danderson@3977
   118
    for (int i = 0; i < ar->dim_list[dim]; i++) {
danderson@3977
   119
      ar->base[write_offs] = (cur_offs - write_offs) * sizeof(cell_t);
danderson@3977
   120
      write_offs++;
danderson@3977
   121
      cur_offs = GenerateInnerArrayIndirectionVectors(ar, dim + 1, cur_offs);
danderson@3977
   122
    }
danderson@3977
   123
  } else {
danderson@3977
   124
    // In this section, there are no sub-vectors, we need to write offsets 
danderson@3977
   125
    // to the data.  This is separate so the data stays in one big chunk.
danderson@3977
   126
    // The data offset will increment by the size of the last dimension, 
danderson@3977
   127
    // because that is where the data is finally computed as. 
danderson@3977
   128
    for (int i = 0; i < ar->dim_list[dim]; i++) {
danderson@3977
   129
      ar->base[write_offs] = (*data_offs - write_offs) * sizeof(cell_t);
danderson@3977
   130
      write_offs++;
danderson@3977
   131
      *data_offs = *data_offs + ar->dim_list[dim + 1];
danderson@3977
   132
    }
danderson@3977
   133
  }
dvander@157
   134
danderson@3977
   135
  return cur_offs;
dvander@157
   136
}
dvander@157
   137
danderson@3977
   138
static cell_t
danderson@3977
   139
calc_indirection(const array_creation_t *ar, cell_t dim)
dvander@157
   140
{
danderson@3977
   141
  cell_t size = ar->dim_list[dim];
danderson@3977
   142
  if (dim < ar->dim_count - 2)
danderson@3977
   143
    size += ar->dim_list[dim] * calc_indirection(ar, dim + 1);
danderson@3977
   144
  return size;
dvander@157
   145
}
dvander@157
   146
dvander@3982
   147
static cell_t
danderson@3977
   148
GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], cell_t _dimcount, bool autozero)
dvander@157
   149
{
danderson@3977
   150
  array_creation_t ar;
danderson@3977
   151
  cell_t data_offs;
dvander@157
   152
danderson@3977
   153
  /* Reverse the dimensions */
danderson@3977
   154
  cell_t dim_list[sDIMEN_MAX];
danderson@3977
   155
  int cur_dim = 0;
danderson@3977
   156
  for (int i = _dimcount - 1; i >= 0; i--)
danderson@3977
   157
    dim_list[cur_dim++] = dims[i];
danderson@3977
   158
  
danderson@3977
   159
  ar.base = arraybase;
danderson@3977
   160
  ar.dim_list = dim_list;
danderson@3977
   161
  ar.dim_count = _dimcount;
danderson@3977
   162
  ar.data_offs = &data_offs;
dvander@157
   163
danderson@3977
   164
  data_offs = calc_indirection(&ar, 0);
danderson@3977
   165
  GenerateInnerArrayIndirectionVectors(&ar, 0, 0);
dvander@3982
   166
  return data_offs;
dvander@157
   167
}
dvander@157
   168
danderson@3977
   169
static int
dvander@3991
   170
PopTrackerAndSetHeap(BaseRuntime *rt)
dvander@157
   171
{
dvander@3991
   172
  sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
dvander@3991
   173
  tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
dvander@3982
   174
  assert(trk->pCur > trk->pBase);
dvander@3982
   175
dvander@3982
   176
  trk->pCur--;
dvander@3982
   177
  if (trk->pCur < trk->pBase)
dvander@3982
   178
    return SP_ERROR_TRACKER_BOUNDS;
dvander@3982
   179
dvander@3982
   180
  ucell_t amt = *trk->pCur;
dvander@3991
   181
  if (amt > (ctx->hp - rt->plugin()->data_size))
dvander@3982
   182
    return SP_ERROR_HEAPMIN;
dvander@3982
   183
dvander@3991
   184
  ctx->hp -= amt;
dvander@3982
   185
  return SP_ERROR_NONE;
dvander@157
   186
}
dvander@157
   187
danderson@3977
   188
static int
dvander@3982
   189
PushTracker(sp_context_t *ctx, size_t amount)
dvander@157
   190
{
danderson@3977
   191
  tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
dvander@157
   192
danderson@3977
   193
  if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
danderson@3977
   194
    return SP_ERROR_TRACKER_BOUNDS;
dvander@157
   195
dvander@3982
   196
  if (trk->pCur + 1 - (trk->pBase + trk->size) == 0) {
danderson@3977
   197
    size_t disp = trk->size - 1;
danderson@3977
   198
    trk->size *= 2;
danderson@3977
   199
    trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
dvander@157
   200
danderson@3977
   201
    if (!trk->pBase)
danderson@3977
   202
      return SP_ERROR_TRACKER_BOUNDS;
danderson@3977
   203
danderson@3977
   204
    trk->pCur = trk->pBase + disp;
danderson@3977
   205
  }
danderson@3977
   206
dvander@3982
   207
  *trk->pCur++ = amount;
dvander@3982
   208
  return SP_ERROR_NONE;
dvander@3982
   209
}
dvander@3982
   210
dvander@3982
   211
static int
dvander@3993
   212
GenerateArray(BaseRuntime *rt, uint32_t argc, cell_t *argv, int autozero)
dvander@3982
   213
{
dvander@3991
   214
  sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
dvander@3991
   215
dvander@3982
   216
  // Calculate how many cells are needed.
dvander@3982
   217
  if (argv[0] <= 0)
dvander@3982
   218
    return SP_ERROR_ARRAY_TOO_BIG;
dvander@3982
   219
dvander@3982
   220
  uint32_t dim = 1;         // second to last dimension
dvander@3982
   221
  uint32_t cells = argv[0];
dvander@3982
   222
dvander@3982
   223
  for (uint32_t dim = 1; dim < argc; dim++) {
dvander@3982
   224
    cell_t dimsize = argv[dim];
dvander@3982
   225
    if (dimsize <= 0)
dvander@3982
   226
      return SP_ERROR_ARRAY_TOO_BIG;
dvander@3982
   227
    if (!ke::IsUint32MultiplySafe(cells, dimsize))
dvander@3982
   228
      return SP_ERROR_ARRAY_TOO_BIG;
dvander@3982
   229
    cells *= uint32_t(dimsize);
dvander@3982
   230
    if (!ke::IsUint32AddSafe(cells, dimsize))
dvander@3982
   231
      return SP_ERROR_ARRAY_TOO_BIG;
dvander@3982
   232
    cells += uint32_t(dimsize);
dvander@3982
   233
  }
dvander@3982
   234
dvander@3982
   235
  if (!ke::IsUint32MultiplySafe(cells, 4))
dvander@3982
   236
    return SP_ERROR_ARRAY_TOO_BIG;
dvander@3982
   237
dvander@3982
   238
  uint32_t bytes = cells * 4;
dvander@3991
   239
  if (!ke::IsUint32AddSafe(ctx->hp, bytes))
dvander@3982
   240
    return SP_ERROR_ARRAY_TOO_BIG;
dvander@3982
   241
dvander@3991
   242
  uint32_t new_hp = ctx->hp + bytes;
dvander@3988
   243
  cell_t *dat_hp = reinterpret_cast<cell_t *>(rt->plugin()->memory + new_hp);
dvander@3982
   244
dvander@3982
   245
  // argv, coincidentally, is STK.
dvander@3982
   246
  if (dat_hp >= argv - STACK_MARGIN)
dvander@3982
   247
    return SP_ERROR_HEAPLOW;
dvander@3982
   248
dvander@3988
   249
  if (int err = PushTracker(rt->GetBaseContext()->GetCtx(), bytes))
dvander@3982
   250
    return err;
dvander@3982
   251
dvander@3991
   252
  cell_t *base = reinterpret_cast<cell_t *>(rt->plugin()->memory + ctx->hp);
dvander@4013
   253
  cell_t offs = GenerateArrayIndirectionVectors(base, argv, argc, !!autozero);
dvander@3982
   254
  assert(size_t(offs) == cells);
dvander@3982
   255
dvander@3991
   256
  argv[argc - 1] = ctx->hp;
dvander@3991
   257
  ctx->hp = new_hp;
danderson@3977
   258
  return SP_ERROR_NONE;
dvander@157
   259
}
dvander@157
   260
danderson@3977
   261
#if !defined NDEBUG
danderson@3977
   262
static const char *
danderson@3977
   263
GetFunctionName(const sp_plugin_t *plugin, uint32_t offs)
dvander@157
   264
{
danderson@3977
   265
  if (!plugin->debug.unpacked) {
danderson@3977
   266
    uint32_t max, iter;
danderson@3977
   267
    sp_fdbg_symbol_t *sym;
danderson@3977
   268
    sp_fdbg_arraydim_t *arr;
danderson@3977
   269
    uint8_t *cursor = (uint8_t *)(plugin->debug.symbols);
dvander@157
   270
danderson@3977
   271
    max = plugin->debug.syms_num;
danderson@3977
   272
    for (iter = 0; iter < max; iter++) {
danderson@3977
   273
      sym = (sp_fdbg_symbol_t *)cursor;
dvander@157
   274
danderson@3977
   275
      if (sym->ident == SP_SYM_FUNCTION && sym->codestart <= offs && sym->codeend > offs)
danderson@3977
   276
        return plugin->debug.stringbase + sym->name;
dvander@157
   277
danderson@3977
   278
      if (sym->dimcount > 0) {
danderson@3977
   279
        cursor += sizeof(sp_fdbg_symbol_t);
danderson@3977
   280
        arr = (sp_fdbg_arraydim_t *)cursor;
danderson@3977
   281
        cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
danderson@3977
   282
        continue;
danderson@3977
   283
      }
dvander@157
   284
danderson@3977
   285
      cursor += sizeof(sp_fdbg_symbol_t);
danderson@3977
   286
    }
danderson@3977
   287
  } else {
danderson@3977
   288
    uint32_t max, iter;
danderson@3977
   289
    sp_u_fdbg_symbol_t *sym;
danderson@3977
   290
    sp_u_fdbg_arraydim_t *arr;
danderson@3977
   291
    uint8_t *cursor = (uint8_t *)(plugin->debug.symbols);
dvander@157
   292
danderson@3977
   293
    max = plugin->debug.syms_num;
danderson@3977
   294
    for (iter = 0; iter < max; iter++) {
danderson@3977
   295
      sym = (sp_u_fdbg_symbol_t *)cursor;
danderson@3977
   296
danderson@3977
   297
      if (sym->ident == SP_SYM_FUNCTION && sym->codestart <= offs && sym->codeend > offs)
danderson@3977
   298
        return plugin->debug.stringbase + sym->name;
dvander@157
   299
danderson@3977
   300
      if (sym->dimcount > 0) {
danderson@3977
   301
        cursor += sizeof(sp_u_fdbg_symbol_t);
danderson@3977
   302
        arr = (sp_u_fdbg_arraydim_t *)cursor;
danderson@3977
   303
        cursor += sizeof(sp_u_fdbg_arraydim_t) * sym->dimcount;
danderson@3977
   304
        continue;
danderson@3977
   305
      }
dvander@157
   306
danderson@3977
   307
      cursor += sizeof(sp_u_fdbg_symbol_t);
danderson@3977
   308
    }
danderson@3977
   309
  }
dvander@157
   310
danderson@3977
   311
  return NULL;
dvander@157
   312
}
danderson@3977
   313
#endif
dvander@157
   314
danderson@3977
   315
static int
danderson@3977
   316
CompileFromThunk(BaseRuntime *runtime, cell_t pcode_offs, void **addrp, char *pc)
dvander@157
   317
{
dvander@4013
   318
  // If the watchdog timer has declared a timeout, we must process it now,
dvander@4013
   319
  // and possibly refuse to compile, since otherwise we will compile a
dvander@4013
   320
  // function that is not patched for timeouts.
dvander@4013
   321
  if (!g_WatchdogTimer.HandleInterrupt())
dvander@4013
   322
    return SP_ERROR_TIMEOUT;
dvander@4013
   323
danderson@3977
   324
  JitFunction *fn = runtime->GetJittedFunctionByOffset(pcode_offs);
danderson@3977
   325
  if (!fn) {
danderson@3977
   326
    int err;
danderson@3977
   327
    fn = g_Jit.CompileFunction(runtime, pcode_offs, &err);
danderson@3977
   328
    if (!fn)
danderson@3977
   329
      return err;
danderson@3977
   330
  }
dvander@157
   331
danderson@3977
   332
#if !defined NDEBUG
danderson@3977
   333
  g_engine1.GetDebugHook()->OnDebugSpew(
danderson@3977
   334
      "Patching thunk to %s::%s\n",
danderson@3977
   335
      runtime->plugin()->name,
danderson@3977
   336
      GetFunctionName(runtime->plugin(), pcode_offs));
danderson@3977
   337
#endif
dvander@157
   338
danderson@3977
   339
  *addrp = fn->GetEntryAddress();
dvander@157
   340
danderson@3977
   341
  /* Right now, we always keep the code RWE */
danderson@3977
   342
  *(intptr_t *)(pc - 4) = intptr_t(fn->GetEntryAddress()) - intptr_t(pc);
danderson@3977
   343
  return SP_ERROR_NONE;
dvander@157
   344
}
dvander@157
   345
danderson@3977
   346
static cell_t
danderson@3977
   347
NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
dvander@157
   348
{
danderson@3977
   349
  sp_native_t *native;
danderson@3977
   350
  cell_t save_sp = ctx->sp;
danderson@3977
   351
  cell_t save_hp = ctx->hp;
danderson@3977
   352
  sp_plugin_t *pl = (sp_plugin_t *)(ctx->vm[JITVARS_PLUGIN]);
danderson@3977
   353
danderson@3977
   354
  ctx->n_idx = native_idx;
danderson@3977
   355
danderson@3977
   356
  if (ctx->hp < (cell_t)pl->data_size) {
danderson@3977
   357
    ctx->n_err = SP_ERROR_HEAPMIN;
danderson@3977
   358
    return 0;
danderson@3977
   359
  }
danderson@3977
   360
danderson@3977
   361
  if (ctx->hp + STACK_MARGIN > ctx->sp) {
danderson@3977
   362
    ctx->n_err = SP_ERROR_STACKLOW;
danderson@3977
   363
    return 0;
danderson@3977
   364
  }
danderson@3977
   365
danderson@3977
   366
  if ((uint32_t)ctx->sp >= pl->mem_size) {
danderson@3977
   367
    ctx->n_err = SP_ERROR_STACKMIN;
danderson@3977
   368
    return 0;
danderson@3977
   369
  }
danderson@3977
   370
danderson@3977
   371
  native = &pl->natives[native_idx];
danderson@3977
   372
danderson@3977
   373
  if (native->status == SP_NATIVE_UNBOUND) {
danderson@3977
   374
    ctx->n_err = SP_ERROR_INVALID_NATIVE;
danderson@3977
   375
    return 0;
danderson@3977
   376
  }
danderson@3977
   377
danderson@3977
   378
  cell_t result = native->pfn(GET_CONTEXT(ctx), params);
danderson@3977
   379
danderson@3977
   380
  if (ctx->n_err != SP_ERROR_NONE)
danderson@3977
   381
    return result;
danderson@3977
   382
danderson@3977
   383
  if (save_sp != ctx->sp) {
danderson@3977
   384
    ctx->n_err = SP_ERROR_STACKLEAK;
danderson@3977
   385
    return result;
danderson@3977
   386
  }
danderson@3977
   387
  if (save_hp != ctx->hp) {
danderson@3977
   388
    ctx->n_err = SP_ERROR_HEAPLEAK;
danderson@3977
   389
    return result;
danderson@3977
   390
  }
danderson@3977
   391
danderson@3977
   392
  return result;
dvander@157
   393
}
dvander@157
   394
danderson@3977
   395
Compiler::Compiler(BaseRuntime *rt, cell_t pcode_offs)
danderson@3977
   396
  : rt_(rt),
danderson@3977
   397
    plugin_(rt->plugin()),
danderson@3977
   398
    error_(SP_ERROR_NONE),
danderson@3977
   399
    pcode_start_(pcode_offs),
danderson@3977
   400
    code_start_(reinterpret_cast<cell_t *>(plugin_->pcode + pcode_start_)),
danderson@3977
   401
    cip_(code_start_),
danderson@3977
   402
    code_end_(reinterpret_cast<cell_t *>(plugin_->pcode + plugin_->pcode_size))
dvander@157
   403
{
danderson@3977
   404
  size_t nmaxops = plugin_->pcode_size / sizeof(cell_t) + 1;
danderson@3977
   405
  jump_map_ = new Label[nmaxops];
dvander@157
   406
}
dvander@157
   407
danderson@3977
   408
Compiler::~Compiler()
dvander@157
   409
{
danderson@3977
   410
  delete [] jump_map_;
dvander@157
   411
}
dvander@157
   412
danderson@3977
   413
JitFunction *
danderson@3977
   414
Compiler::emit(int *errp)
dvander@157
   415
{
danderson@3977
   416
  if (cip_ >= code_end_ || *cip_ != OP_PROC) {
danderson@3977
   417
    *errp = SP_ERROR_INVALID_INSTRUCTION;
danderson@3977
   418
    return NULL;
danderson@3977
   419
  }
danderson@3977
   420
danderson@3977
   421
#if !defined NDEBUG
danderson@3977
   422
  g_engine1.GetDebugHook()->OnDebugSpew(
danderson@3977
   423
      "Compiling function %s::%s\n",
danderson@3977
   424
      plugin_->name,
danderson@3977
   425
      GetFunctionName(plugin_, pcode_start_));
dvander@157
   426
danderson@3977
   427
  SpewOpcode(plugin_, code_start_, cip_);
danderson@3977
   428
#endif
danderson@3977
   429
danderson@3977
   430
  cell_t *codeseg = reinterpret_cast<cell_t *>(plugin_->pcode);
danderson@3977
   431
danderson@3977
   432
  cip_++;
danderson@3977
   433
  if (!emitOp(OP_PROC)) {
danderson@3977
   434
      *errp = (error_ == SP_ERROR_NONE) ? SP_ERROR_OUT_OF_MEMORY : error_;
danderson@3977
   435
      return NULL;
danderson@3977
   436
  }
dvander@157
   437
danderson@3977
   438
  while (cip_ < code_end_) {
danderson@3977
   439
    // If we reach the end of this function, or the beginning of a new
danderson@3977
   440
    // procedure, then stop.
danderson@3977
   441
    if (*cip_ == OP_PROC || *cip_ == OP_ENDPROC)
danderson@3977
   442
      break;
dvander@157
   443
danderson@3977
   444
#if !defined NDEBUG
danderson@3977
   445
    SpewOpcode(plugin_, code_start_, cip_);
danderson@3977
   446
#endif
danderson@3977
   447
danderson@3977
   448
    // We assume every instruction is a jump target, so before emitting
danderson@3977
   449
    // an opcode, we bind its corresponding label.
danderson@3977
   450
    __ bind(&jump_map_[cip_ - codeseg]);
dvander@157
   451
danderson@3977
   452
    OPCODE op = (OPCODE)readCell();
danderson@3977
   453
    if (!emitOp(op) || error_ != SP_ERROR_NONE) {
danderson@3977
   454
      *errp = (error_ == SP_ERROR_NONE) ? SP_ERROR_OUT_OF_MEMORY : error_;
danderson@3977
   455
      return NULL;
danderson@3977
   456
    }
danderson@3977
   457
  }
dvander@1945
   458
danderson@3977
   459
  emitCallThunks();
danderson@3977
   460
  emitErrorPaths();
dvander@1945
   461
dvander@4013
   462
  uint8_t *code = LinkCode(masm);
danderson@3977
   463
  if (!code) {
danderson@3977
   464
    *errp = SP_ERROR_OUT_OF_MEMORY;
danderson@3977
   465
    return NULL;
danderson@3977
   466
  }
danderson@3977
   467
dvander@4013
   468
  LoopEdge *edges = new LoopEdge[backward_jumps_.length()];
dvander@4013
   469
  for (size_t i = 0; i < backward_jumps_.length(); i++) {
dvander@4013
   470
    edges[i].offset = backward_jumps_[i];
dvander@4013
   471
    edges[i].disp32 = *reinterpret_cast<int32_t *>(code + edges[i].offset - 4);
dvander@4013
   472
  }
dvander@4013
   473
dvander@4013
   474
  return new JitFunction(code, pcode_start_, edges, backward_jumps_.length());
dvander@1945
   475
}
dvander@1945
   476
danderson@3977
   477
bool
danderson@3977
   478
Compiler::emitOp(OPCODE op)
dvander@157
   479
{
danderson@3977
   480
  switch (op) {
danderson@3977
   481
    case OP_MOVE_PRI:
danderson@3977
   482
      __ movl(pri, alt);
danderson@3977
   483
      break;
danderson@3977
   484
danderson@3977
   485
    case OP_MOVE_ALT:
danderson@3977
   486
      __ movl(alt, pri);
danderson@3977
   487
      break;
danderson@3977
   488
danderson@3977
   489
    case OP_XCHG:
danderson@3977
   490
      __ xchgl(pri, alt);
danderson@3977
   491
      break;
danderson@3977
   492
danderson@3977
   493
    case OP_ZERO:
danderson@3977
   494
    {
danderson@3977
   495
      cell_t offset = readCell();
danderson@3977
   496
      __ movl(Operand(dat, offset), 0);
danderson@3977
   497
      break;
danderson@3977
   498
    }
danderson@3977
   499
danderson@3977
   500
    case OP_ZERO_S:
danderson@3977
   501
    {
danderson@3977
   502
      cell_t offset = readCell();
danderson@3977
   503
      __ movl(Operand(frm, offset), 0);
danderson@3977
   504
      break;
danderson@3977
   505
    }
danderson@3977
   506
danderson@3977
   507
    case OP_PUSH_PRI:
danderson@3977
   508
    case OP_PUSH_ALT:
danderson@3977
   509
    {
danderson@3977
   510
      Register reg = (op == OP_PUSH_PRI) ? pri : alt;
danderson@3977
   511
      __ movl(Operand(stk, -4), reg);
danderson@3977
   512
      __ subl(stk, 4);
danderson@3977
   513
      break;
danderson@3977
   514
    }
danderson@3977
   515
danderson@3977
   516
    case OP_PUSH_C:
danderson@3977
   517
    case OP_PUSH2_C:
danderson@3977
   518
    case OP_PUSH3_C:
danderson@3977
   519
    case OP_PUSH4_C:
danderson@3977
   520
    case OP_PUSH5_C:
danderson@3977
   521
    {
danderson@3977
   522
      int n = 1;
danderson@3977
   523
      if (op >= OP_PUSH2_C)
danderson@3977
   524
        n = ((op - OP_PUSH2_C) / 4) + 2;
dvander@157
   525
danderson@3977
   526
      int i = 1;
danderson@3977
   527
      do {
danderson@3977
   528
        cell_t val = readCell();
danderson@3977
   529
        __ movl(Operand(stk, -(4 * i)), val);
danderson@3977
   530
      } while (i++ < n);
danderson@3977
   531
      __ subl(stk, 4 * n);
danderson@3977
   532
      break;
danderson@3977
   533
    }
danderson@3977
   534
danderson@3977
   535
    case OP_PUSH_ADR:
danderson@3977
   536
    case OP_PUSH2_ADR:
danderson@3977
   537
    case OP_PUSH3_ADR:
danderson@3977
   538
    case OP_PUSH4_ADR:
danderson@3977
   539
    case OP_PUSH5_ADR:
danderson@3977
   540
    {
danderson@3977
   541
      int n = 1;
danderson@3977
   542
      if (op >= OP_PUSH2_ADR)
danderson@3977
   543
        n = ((op - OP_PUSH2_ADR) / 4) + 2;
danderson@3977
   544
danderson@3977
   545
      int i = 1;
dvander@157
   546
danderson@3977
   547
      // We temporarily relocate FRM to be a local address instead of an
danderson@3977
   548
      // absolute address.
danderson@3977
   549
      __ subl(frm, dat);
danderson@3977
   550
      do {
danderson@3977
   551
        cell_t offset = readCell();
danderson@3977
   552
        __ lea(tmp, Operand(frm, offset));
danderson@3977
   553
        __ movl(Operand(stk, -(4 * i)), tmp);
danderson@3977
   554
      } while (i++ < n);
danderson@3977
   555
      __ subl(stk, 4 * n);
danderson@3977
   556
      __ addl(frm, dat);
danderson@3977
   557
      break;
danderson@3977
   558
    }
danderson@3977
   559
danderson@3977
   560
    case OP_PUSH_S:
danderson@3977
   561
    case OP_PUSH2_S:
danderson@3977
   562
    case OP_PUSH3_S:
danderson@3977
   563
    case OP_PUSH4_S:
danderson@3977
   564
    case OP_PUSH5_S:
danderson@3977
   565
    {
danderson@3977
   566
      int n = 1;
danderson@3977
   567
      if (op >= OP_PUSH2_S)
danderson@3977
   568
        n = ((op - OP_PUSH2_S) / 4) + 2;
danderson@3977
   569
danderson@3977
   570
      int i = 1;
danderson@3977
   571
      do {
danderson@3977
   572
        cell_t offset = readCell();
danderson@3977
   573
        __ movl(tmp, Operand(frm, offset));
danderson@3977
   574
        __ movl(Operand(stk, -(4 * i)), tmp);
danderson@3977
   575
      } while (i++ < n);
danderson@3977
   576
      __ subl(stk, 4 * n);
danderson@3977
   577
      break;
danderson@3977
   578
    }
dvander@157
   579
danderson@3977
   580
    case OP_PUSH:
danderson@3977
   581
    case OP_PUSH2:
danderson@3977
   582
    case OP_PUSH3:
danderson@3977
   583
    case OP_PUSH4:
danderson@3977
   584
    case OP_PUSH5:
danderson@3977
   585
    {
danderson@3977
   586
      int n = 1;
danderson@3977
   587
      if (op >= OP_PUSH2)
danderson@3977
   588
        n = ((op - OP_PUSH2) / 4) + 2;
danderson@3977
   589
danderson@3977
   590
      int i = 1;
danderson@3977
   591
      do {
danderson@3977
   592
        cell_t offset = readCell();
danderson@3977
   593
        __ movl(tmp, Operand(dat, offset));
danderson@3977
   594
        __ movl(Operand(stk, -(4 * i)), tmp);
danderson@3977
   595
      } while (i++ < n);
danderson@3977
   596
      __ subl(stk, 4 * n);
danderson@3977
   597
      break;
danderson@3977
   598
    }
danderson@3977
   599
danderson@3977
   600
    case OP_ZERO_PRI:
danderson@3977
   601
      __ xorl(pri, pri);
danderson@3977
   602
      break;
dvander@157
   603
danderson@3977
   604
    case OP_ZERO_ALT:
danderson@3977
   605
      __ xorl(alt, alt);
danderson@3977
   606
      break;
danderson@3977
   607
danderson@3977
   608
    case OP_ADD:
danderson@3977
   609
      __ addl(pri, alt);
danderson@3977
   610
      break;
danderson@3977
   611
danderson@3977
   612
    case OP_SUB:
danderson@3977
   613
      __ subl(pri, alt);
danderson@3977
   614
      break;
danderson@3977
   615
danderson@3977
   616
    case OP_SUB_ALT:
danderson@3977
   617
      __ movl(tmp, alt);
danderson@3977
   618
      __ subl(tmp, pri);
danderson@3977
   619
      __ movl(pri, tmp);
danderson@3977
   620
      break;
danderson@3977
   621
danderson@3977
   622
    case OP_PROC:
danderson@3977
   623
      // Push the old frame onto the stack.
dvander@3992
   624
      __ movl(tmp, Operand(frmAddr()));
danderson@3977
   625
      __ movl(Operand(stk, -4), tmp);
danderson@3977
   626
      __ subl(stk, 8);    // extra unused slot for non-existant CIP
danderson@3977
   627
danderson@3977
   628
      // Get and store the new frame.
danderson@3977
   629
      __ movl(tmp, stk);
danderson@3977
   630
      __ movl(frm, stk);
danderson@3977
   631
      __ subl(tmp, dat);
dvander@3992
   632
      __ movl(Operand(frmAddr()), tmp);
dvander@3983
   633
dvander@3983
   634
      // Align the stack to 16-bytes (each call adds 4 bytes).
dvander@3983
   635
      __ subl(esp, 12);
danderson@3977
   636
      break;
dvander@157
   637
danderson@3977
   638
    case OP_IDXADDR_B:
danderson@3977
   639
    {
danderson@3977
   640
      cell_t val = readCell();
danderson@3977
   641
      __ shll(pri, val);
danderson@3977
   642
      __ addl(pri, alt);
danderson@3977
   643
      break;
danderson@3977
   644
    }
danderson@3977
   645
danderson@3977
   646
    case OP_SHL:
danderson@3977
   647
      __ movl(ecx, alt);
danderson@3977
   648
      __ shll_cl(pri);
danderson@3977
   649
      break;
danderson@3977
   650
danderson@3977
   651
    case OP_SHR:
danderson@3977
   652
      __ movl(ecx, alt);
danderson@3977
   653
      __ shrl_cl(pri);
danderson@3977
   654
      break;
danderson@3977
   655
danderson@3977
   656
    case OP_SSHR:
danderson@3977
   657
      __ movl(ecx, alt);
danderson@3977
   658
      __ sarl_cl(pri);
danderson@3977
   659
      break;
dvander@157
   660
danderson@3977
   661
    case OP_SHL_C_PRI:
danderson@3977
   662
    case OP_SHL_C_ALT:
danderson@3977
   663
    {
danderson@3977
   664
      Register reg = (op == OP_SHL_C_PRI) ? pri : alt;
danderson@3977
   665
      cell_t val = readCell();
danderson@3977
   666
      __ shll(reg, val);
danderson@3977
   667
      break;
danderson@3977
   668
    }
danderson@3977
   669
danderson@3977
   670
    case OP_SHR_C_PRI:
danderson@3977
   671
    case OP_SHR_C_ALT:
danderson@3977
   672
    {
danderson@3977
   673
      Register reg = (op == OP_SHR_C_PRI) ? pri : alt;
danderson@3977
   674
      cell_t val = readCell();
danderson@3977
   675
      __ shrl(reg, val);
danderson@3977
   676
      break;
danderson@3977
   677
    }
danderson@3977
   678
danderson@3977
   679
    case OP_SMUL:
danderson@3977
   680
      __ imull(pri, alt);
danderson@3977
   681
      break;
danderson@3977
   682
danderson@3977
   683
    case OP_NOT:
danderson@3977
   684
      __ testl(eax, eax);
danderson@3977
   685
      __ movl(eax, 0);
danderson@3977
   686
      __ set(zero, r8_al);
danderson@3977
   687
      break;
danderson@3977
   688
danderson@3977
   689
    case OP_NEG:
danderson@3977
   690
      __ negl(eax);
danderson@3977
   691
      break;
danderson@3977
   692
danderson@3977
   693
    case OP_XOR:
danderson@3977
   694
      __ xorl(pri, alt);
danderson@3977
   695
      break;
dvander@157
   696
danderson@3977
   697
    case OP_OR:
danderson@3977
   698
      __ orl(pri, alt);
danderson@3977
   699
      break;
danderson@3977
   700
danderson@3977
   701
    case OP_AND:
danderson@3977
   702
      __ andl(pri, alt);
danderson@3977
   703
      break;
danderson@3977
   704
danderson@3977
   705
    case OP_INVERT:
danderson@3977
   706
      __ notl(pri);
danderson@3977
   707
      break;
danderson@3977
   708
danderson@3977
   709
    case OP_ADD_C:
danderson@3977
   710
    {
danderson@3977
   711
      cell_t val = readCell();
danderson@3977
   712
      __ addl(pri, val);
danderson@3977
   713
      break;
danderson@3977
   714
    }
danderson@3977
   715
danderson@3977
   716
    case OP_SMUL_C:
danderson@3977
   717
    {
danderson@3977
   718
      cell_t val = readCell();
danderson@3977
   719
      __ imull(pri, pri, val);
danderson@3977
   720
      break;
danderson@3977
   721
    }
danderson@3977
   722
danderson@3977
   723
    case OP_EQ:
danderson@3977
   724
    case OP_NEQ:
danderson@3977
   725
    case OP_SLESS:
danderson@3977
   726
    case OP_SLEQ:
danderson@3977
   727
    case OP_SGRTR:
danderson@3977
   728
    case OP_SGEQ:
danderson@3977
   729
    {
danderson@3977
   730
      ConditionCode cc = OpToCondition(op);
danderson@3977
   731
      __ cmpl(pri, alt);
danderson@3977
   732
      __ movl(pri, 0);
danderson@3977
   733
      __ set(cc, r8_al);
danderson@3977
   734
      break;
danderson@3977
   735
    }
danderson@3977
   736
danderson@3977
   737
    case OP_EQ_C_PRI:
danderson@3977
   738
    case OP_EQ_C_ALT:
danderson@3977
   739
    {
danderson@3977
   740
      Register reg = (op == OP_EQ_C_PRI) ? pri : alt;
danderson@3977
   741
      cell_t val = readCell();
danderson@3977
   742
      __ cmpl(reg, val);
danderson@3977
   743
      __ movl(pri, 0);
danderson@3977
   744
      __ set(equal, r8_al);
danderson@3977
   745
      break;
danderson@3977
   746
    }
dvander@157
   747
danderson@3977
   748
    case OP_INC_PRI:
danderson@3977
   749
    case OP_INC_ALT:
danderson@3977
   750
    {
danderson@3977
   751
      Register reg = (OP_INC_PRI) ? pri : alt;
danderson@3977
   752
      __ addl(reg, 1);
danderson@3977
   753
      break;
danderson@3977
   754
    }
danderson@3977
   755
danderson@3977
   756
    case OP_INC:
danderson@3977
   757
    case OP_INC_S:
danderson@3977
   758
    {
danderson@3977
   759
      Register base = (op == OP_INC) ? dat : frm;
danderson@3977
   760
      cell_t offset = readCell();
danderson@3977
   761
      __ addl(Operand(base, offset), 1);
danderson@3977
   762
      break;
danderson@3977
   763
    }
danderson@3977
   764
danderson@3977
   765
    case OP_INC_I:
danderson@3977
   766
      __ addl(Operand(dat, pri, NoScale), 1);
danderson@3977
   767
      break;
danderson@3977
   768
danderson@3977
   769
    case OP_DEC_PRI:
danderson@3977
   770
    case OP_DEC_ALT:
danderson@3977
   771
    {
danderson@3977
   772
      Register reg = (op == OP_DEC_PRI) ? pri : alt;
danderson@3977
   773
      __ subl(reg, 1);
danderson@3977
   774
      break;
danderson@3977
   775
    }
danderson@3977
   776
danderson@3977
   777
    case OP_DEC:
danderson@3977
   778
    case OP_DEC_S:
danderson@3977
   779
    {
danderson@3977
   780
      Register base = (op == OP_DEC) ? dat : frm;
danderson@3977
   781
      cell_t offset = readCell();
danderson@3977
   782
      __ subl(Operand(base, offset), 1);
danderson@3977
   783
      break;
danderson@3977
   784
    }
danderson@3977
   785
danderson@3977
   786
    case OP_DEC_I:
danderson@3977
   787
      __ subl(Operand(dat, pri, NoScale), 1);
danderson@3977
   788
      break;
danderson@3977
   789
danderson@3977
   790
    case OP_LOAD_PRI:
danderson@3977
   791
    case OP_LOAD_ALT:
danderson@3977
   792
    {
danderson@3977
   793
      Register reg = (op == OP_LOAD_PRI) ? pri : alt;
danderson@3977
   794
      cell_t offset = readCell();
danderson@3977
   795
      __ movl(reg, Operand(dat, offset));
danderson@3977
   796
      break;
danderson@3977
   797
    }
dvander@157
   798
danderson@3977
   799
    case OP_LOAD_BOTH:
danderson@3977
   800
    {
danderson@3977
   801
      cell_t offs1 = readCell();
danderson@3977
   802
      cell_t offs2 = readCell();
danderson@3977
   803
      __ movl(pri, Operand(dat, offs1));
danderson@3977
   804
      __ movl(alt, Operand(dat, offs2));
danderson@3977
   805
      break;
danderson@3977
   806
    }
danderson@3977
   807
danderson@3977
   808
    case OP_LOAD_S_PRI:
danderson@3977
   809
    case OP_LOAD_S_ALT:
danderson@3977
   810
    {
danderson@3977
   811
      Register reg = (op == OP_LOAD_S_PRI) ? pri : alt;
danderson@3977
   812
      cell_t offset = readCell();
danderson@3977
   813
      __ movl(reg, Operand(frm, offset));
danderson@3977
   814
      break;
danderson@3977
   815
    }
danderson@3977
   816
danderson@3977
   817
    case OP_LOAD_S_BOTH:
danderson@3977
   818
    {
danderson@3977
   819
      cell_t offs1 = readCell();
danderson@3977
   820
      cell_t offs2 = readCell();
danderson@3977
   821
      __ movl(pri, Operand(frm, offs1));
danderson@3977
   822
      __ movl(alt, Operand(frm, offs2));
danderson@3977
   823
      break;
danderson@3977
   824
    }
danderson@3977
   825
danderson@3977
   826
    case OP_LREF_S_PRI:
danderson@3977
   827
    case OP_LREF_S_ALT:
danderson@3977
   828
    {
danderson@3977
   829
      Register reg = (op == OP_LREF_S_PRI) ? pri : alt;
danderson@3977
   830
      cell_t offset = readCell();
danderson@3977
   831
      __ movl(reg, Operand(frm, offset));
danderson@3977
   832
      __ movl(reg, Operand(dat, reg, NoScale));
danderson@3977
   833
      break;
danderson@3977
   834
    }
danderson@3977
   835
danderson@3977
   836
    case OP_CONST_PRI:
danderson@3977
   837
    case OP_CONST_ALT:
danderson@3977
   838
    {
danderson@3977
   839
      Register reg = (op == OP_CONST_PRI) ? pri : alt;
danderson@3977
   840
      cell_t val = readCell();
danderson@3977
   841
      __ movl(reg, val);
danderson@3977
   842
      break;
danderson@3977
   843
    }
danderson@3977
   844
danderson@3977
   845
    case OP_ADDR_PRI:
danderson@3977
   846
    case OP_ADDR_ALT:
danderson@3977
   847
    {
danderson@3977
   848
      Register reg = (op == OP_ADDR_PRI) ? pri : alt;
danderson@3977
   849
      cell_t offset = readCell();
dvander@3992
   850
      __ movl(reg, Operand(frmAddr()));
danderson@3977
   851
      __ addl(reg, offset);
danderson@3977
   852
      break;
danderson@3977
   853
    }
danderson@3977
   854
danderson@3977
   855
    case OP_STOR_PRI:
danderson@3977
   856
    case OP_STOR_ALT:
danderson@3977
   857
    {
danderson@3977
   858
      Register reg = (op == OP_STOR_PRI) ? pri : alt;
danderson@3977
   859
      cell_t offset = readCell();
danderson@3977
   860
      __ movl(Operand(dat, offset), reg);
danderson@3977
   861
      break;
danderson@3977
   862
    }
danderson@3977
   863
danderson@3977
   864
    case OP_STOR_S_PRI:
danderson@3977
   865
    case OP_STOR_S_ALT:
danderson@3977
   866
    {
danderson@3977
   867
      Register reg = (op == OP_STOR_S_PRI) ? pri : alt;
danderson@3977
   868
      cell_t offset = readCell();
danderson@3977
   869
      __ movl(Operand(frm, offset), reg);
danderson@3977
   870
      break;
danderson@3977
   871
    }
danderson@3977
   872
danderson@3977
   873
    case OP_IDXADDR:
danderson@3977
   874
      __ lea(pri, Operand(alt, pri, ScaleFour));
danderson@3977
   875
      break;
danderson@3977
   876
danderson@3977
   877
    case OP_SREF_S_PRI:
danderson@3977
   878
    case OP_SREF_S_ALT:
danderson@3977
   879
    {
danderson@3977
   880
      Register reg = (op == OP_SREF_S_PRI) ? pri : alt;
danderson@3977
   881
      cell_t offset = readCell();
danderson@3977
   882
      __ movl(tmp, Operand(frm, offset));
danderson@3977
   883
      __ movl(Operand(dat, tmp, NoScale), reg);
danderson@3977
   884
      break;
danderson@3977
   885
    }
danderson@3977
   886
danderson@3977
   887
    case OP_POP_PRI:
danderson@3977
   888
    case OP_POP_ALT:
danderson@3977
   889
    {
danderson@3977
   890
      Register reg = (op == OP_POP_PRI) ? pri : alt;
danderson@3977
   891
      __ movl(reg, Operand(stk, 0));
danderson@3977
   892
      __ addl(stk, 4);
danderson@3977
   893
      break;
danderson@3977
   894
    }
danderson@3977
   895
danderson@3977
   896
    case OP_SWAP_PRI:
danderson@3977
   897
    case OP_SWAP_ALT:
danderson@3977
   898
    {
danderson@3977
   899
      Register reg = (op == OP_SWAP_PRI) ? pri : alt;
danderson@3977
   900
      __ movl(tmp, Operand(stk, 0));
danderson@3977
   901
      __ movl(Operand(stk, 0), reg);
danderson@3977
   902
      __ movl(reg, tmp);
danderson@3977
   903
      break;
danderson@3977
   904
    }
danderson@3977
   905
danderson@3977
   906
    case OP_LIDX:
danderson@3977
   907
      __ lea(pri, Operand(alt, pri, ScaleFour));
danderson@3977
   908
      __ movl(pri, Operand(dat, pri, NoScale));
danderson@3977
   909
      break;
dvander@157
   910
danderson@3977
   911
    case OP_LIDX_B:
danderson@3977
   912
    {
danderson@3977
   913
      cell_t val = readCell();
danderson@3977
   914
      if (val >= 0 && val <= 3) {
danderson@3977
   915
        __ lea(pri, Operand(alt, pri, Scale(val)));
danderson@3977
   916
      } else {
danderson@3977
   917
        __ shll(pri, val);
danderson@3977
   918
        __ addl(pri, alt);
danderson@3977
   919
      }
danderson@3977
   920
      emitCheckAddress(pri);
danderson@3977
   921
      __ movl(pri, Operand(dat, pri, NoScale));
danderson@3977
   922
      break;
danderson@3977
   923
    }
danderson@3977
   924
danderson@3977
   925
    case OP_CONST:
danderson@3977
   926
    case OP_CONST_S:
danderson@3977
   927
    {
danderson@3977
   928
      Register base = (op == OP_CONST) ? dat : frm;
danderson@3977
   929
      cell_t offset = readCell();
danderson@3977
   930
      cell_t val = readCell();
danderson@3977
   931
      __ movl(Operand(base, offset), val);
danderson@3977
   932
      break;
danderson@3977
   933
    }
danderson@3977
   934
danderson@3977
   935
    case OP_LOAD_I:
danderson@3977
   936
      emitCheckAddress(pri);
danderson@3977
   937
      __ movl(pri, Operand(dat, pri, NoScale));
danderson@3977
   938
      break;
danderson@3977
   939
danderson@3977
   940
    case OP_STOR_I:
danderson@3977
   941
      emitCheckAddress(alt);
danderson@3977
   942
      __ movl(Operand(dat, alt, NoScale), pri);
danderson@3977
   943
      break;
danderson@3977
   944
danderson@3977
   945
    case OP_SDIV:
danderson@3977
   946
    case OP_SDIV_ALT:
danderson@3977
   947
    {
danderson@3977
   948
      Register dividend = (op == OP_SDIV) ? pri : alt;
danderson@3977
   949
      Register divisor = (op == OP_SDIV) ? alt : pri;
danderson@3977
   950
danderson@3977
   951
      // Guard against divide-by-zero.
danderson@3977
   952
      __ testl(divisor, divisor);
danderson@3977
   953
      __ j(zero, &error_divide_by_zero_);
danderson@3977
   954
danderson@3977
   955
      // A more subtle case; -INT_MIN / -1 yields an overflow exception.
danderson@3977
   956
      Label ok;
danderson@3977
   957
      __ cmpl(divisor, -1);
danderson@3977
   958
      __ j(not_equal, &ok);
danderson@3977
   959
      __ cmpl(dividend, 0x80000000);
danderson@3977
   960
      __ j(equal, &error_integer_overflow_);
danderson@3977
   961
      __ bind(&ok);
danderson@3977
   962
danderson@3977
   963
      // Now we can actually perform the divide.
danderson@3977
   964
      __ movl(tmp, divisor);
danderson@3977
   965
      if (op == OP_SDIV)
danderson@3977
   966
        __ movl(edx, dividend);
danderson@3977
   967
      else
danderson@3977
   968
        __ movl(eax, dividend);
danderson@3977
   969
      __ sarl(edx, 31);
danderson@3977
   970
      __ idivl(tmp);
danderson@3977
   971
      break;
danderson@3977
   972
    }
danderson@3977
   973
danderson@3977
   974
    case OP_LODB_I:
danderson@3977
   975
    {
danderson@3977
   976
      cell_t val = readCell();
danderson@3977
   977
      emitCheckAddress(pri);
danderson@3977
   978
      __ movl(pri, Operand(dat, pri, NoScale));
danderson@3977
   979
      if (val == 1)
danderson@3977
   980
        __ andl(pri, 0xff);
danderson@3977
   981
      else if (val == 2)
danderson@3977
   982
        __ andl(pri, 0xffff);
danderson@3977
   983
      break;
danderson@3977
   984
    }
danderson@3977
   985
danderson@3977
   986
    case OP_STRB_I:
danderson@3977
   987
    {
danderson@3977
   988
      cell_t val = readCell();
danderson@3977
   989
      emitCheckAddress(alt);
danderson@3977
   990
      if (val == 1)
danderson@3977
   991
        __ movb(Operand(dat, alt, NoScale), pri);
danderson@3977
   992
      else if (val == 2)
danderson@3977
   993
        __ movw(Operand(dat, alt, NoScale), pri);
danderson@3977
   994
      else if (val == 4)
danderson@3977
   995
        __ movl(Operand(dat, alt, NoScale), pri);
danderson@3977
   996
      break;
danderson@3977
   997
    }
danderson@3977
   998
danderson@3977
   999
    case OP_RETN:
danderson@3977
  1000
    {
danderson@3977
  1001
      // Restore the old frame pointer.
danderson@3977
  1002
      __ movl(frm, Operand(stk, 4));              // get the old frm
danderson@3977
  1003
      __ addl(stk, 8);                            // pop stack
dvander@3992
  1004
      __ movl(Operand(frmAddr()), frm);           // store back old frm
danderson@3977
  1005
      __ addl(frm, dat);                          // relocate
danderson@3977
  1006
danderson@3977
  1007
      // Remove parameters.
danderson@3977
  1008
      __ movl(tmp, Operand(stk, 0));
danderson@3977
  1009
      __ lea(stk, Operand(stk, tmp, ScaleFour, 4));
dvander@3983
  1010
      __ addl(esp, 12);
danderson@3977
  1011
      __ ret();
danderson@3977
  1012
      break;
danderson@3977
  1013
    }
danderson@3977
  1014
danderson@3977
  1015
    case OP_MOVS:
danderson@3977
  1016
    {
danderson@3977
  1017
      cell_t val = readCell();
danderson@3977
  1018
      unsigned dwords = val / 4;
danderson@3977
  1019
      unsigned bytes = val % 4;
dvander@157
  1020
danderson@3977
  1021
      __ cld();
danderson@3977
  1022
      __ push(esi);
danderson@3977
  1023
      __ push(edi);
danderson@3977
  1024
      __ lea(esi, Operand(dat, pri, NoScale));
danderson@3977
  1025
      __ lea(edi, Operand(dat, alt, NoScale));
danderson@3977
  1026
      if (dwords) {
danderson@3977
  1027
        __ movl(ecx, dwords);
danderson@3977
  1028
        __ rep_movsd();
danderson@3977
  1029
      }
danderson@3977
  1030
      if (bytes) {
danderson@3977
  1031
        __ movl(ecx, bytes);
danderson@3977
  1032
        __ rep_movsb();
danderson@3977
  1033
      }
danderson@3977
  1034
      __ pop(edi);
danderson@3977
  1035
      __ pop(esi);
danderson@3977
  1036
      break;
danderson@3977
  1037
    }
dvander@157
  1038
danderson@3977
  1039
    case OP_FILL:
danderson@3977
  1040
    {
danderson@3977
  1041
      // eax/pri is used implicitly.
danderson@3977
  1042
      unsigned dwords = readCell() / 4;
danderson@3977
  1043
      __ push(edi);
danderson@3977
  1044
      __ lea(edi, Operand(dat, alt, NoScale));
danderson@3977
  1045
      __ movl(ecx, dwords);
danderson@3977
  1046
      __ cld();
danderson@3977
  1047
      __ rep_stosd();
danderson@3977
  1048
      __ pop(edi);
danderson@3977
  1049
      break;
danderson@3977
  1050
    }
danderson@3977
  1051
danderson@3977
  1052
    case OP_STRADJUST_PRI:
danderson@3977
  1053
      __ addl(pri, 4);
danderson@3977
  1054
      __ sarl(pri, 2);
danderson@3977
  1055
      break;
dvander@157
  1056
danderson@3977
  1057
    case OP_FABS:
danderson@3977
  1058
      __ movl(pri, Operand(stk, 0));
danderson@3977
  1059
      __ andl(pri, 0x7fffffff);
danderson@3977
  1060
      __ addl(stk, 4);
danderson@3977
  1061
      break;
danderson@3977
  1062
danderson@3977
  1063
    case OP_FLOAT:
danderson@3979
  1064
      if (MacroAssemblerX86::Features().sse2) {
danderson@3979
  1065
        __ cvtsi2ss(xmm0, Operand(edi, 0));
danderson@3979
  1066
        __ movd(pri, xmm0);
danderson@3979
  1067
      } else {
danderson@3979
  1068
        __ fild32(Operand(edi, 0));
danderson@3979
  1069
        __ subl(esp, 4);
danderson@3979
  1070
        __ fstp32(Operand(esp, 0));
danderson@3979
  1071
        __ pop(pri);
danderson@3979
  1072
      }
danderson@3977
  1073
      __ addl(stk, 4);
danderson@3977
  1074
      break;
danderson@3977
  1075
danderson@3977
  1076
    case OP_FLOATADD:
danderson@3977
  1077
    case OP_FLOATSUB:
danderson@3977
  1078
    case OP_FLOATMUL:
danderson@3977
  1079
    case OP_FLOATDIV:
danderson@3979
  1080
      if (MacroAssemblerX86::Features().sse2) {
danderson@3979
  1081
        __ movss(xmm0, Operand(stk, 0));
danderson@3979
  1082
        if (op == OP_FLOATADD)
danderson@3979
  1083
          __ addss(xmm0, Operand(stk, 4));
danderson@3979
  1084
        else if (op == OP_FLOATSUB)
danderson@3979
  1085
          __ subss(xmm0, Operand(stk, 4));
danderson@3979
  1086
        else if (op == OP_FLOATMUL)
danderson@3979
  1087
          __ mulss(xmm0, Operand(stk, 4));
danderson@3979
  1088
        else if (op == OP_FLOATDIV)
danderson@3979
  1089
          __ divss(xmm0, Operand(stk, 4));
danderson@3979
  1090
        __ movd(pri, xmm0);
danderson@3979
  1091
      } else {
danderson@3979
  1092
        __ subl(esp, 4);
danderson@3979
  1093
        __ fld32(Operand(stk, 0));
dvander@157
  1094
danderson@3979
  1095
        if (op == OP_FLOATADD)
danderson@3979
  1096
          __ fadd32(Operand(stk, 4));
danderson@3979
  1097
        else if (op == OP_FLOATSUB)
danderson@3979
  1098
          __ fsub32(Operand(stk, 4));
danderson@3979
  1099
        else if (op == OP_FLOATMUL)
danderson@3979
  1100
          __ fmul32(Operand(stk, 4));
danderson@3979
  1101
        else if (op == OP_FLOATDIV)
danderson@3979
  1102
          __ fdiv32(Operand(stk, 4));
danderson@3977
  1103
danderson@3979
  1104
        __ fstp32(Operand(esp, 0));
danderson@3979
  1105
        __ pop(pri);
danderson@3979
  1106
      }
danderson@3977
  1107
      __ addl(stk, 8);
danderson@3977
  1108
      break;
dvander@157
  1109
danderson@3977
  1110
    case OP_RND_TO_NEAREST:
danderson@3977
  1111
    {
danderson@3979
  1112
      if (MacroAssemblerX86::Features().sse) {
danderson@3979
  1113
        // Assume no one is touching MXCSR.
danderson@3979
  1114
        __ cvtss2si(pri, Operand(stk, 0));
danderson@3979
  1115
      } else {
danderson@3979
  1116
        static float kRoundToNearest = 0.5f;
danderson@3979
  1117
        // From http://wurstcaptures.untergrund.net/assembler_tricks.html#fastfloorf
danderson@3979
  1118
        __ fld32(Operand(stk, 0));
danderson@3979
  1119
        __ fadd32(st0, st0);
danderson@3979
  1120
        __ fadd32(Operand(ExternalAddress(&kRoundToNearest)));
danderson@3979
  1121
        __ subl(esp, 4);
danderson@3979
  1122
        __ fistp32(Operand(esp, 0));
danderson@3979
  1123
        __ pop(pri);
danderson@3979
  1124
        __ sarl(pri, 1);
danderson@3979
  1125
      }
danderson@3977
  1126
      __ addl(stk, 4);
danderson@3977
  1127
      break;
danderson@3977
  1128
    }
dvander@157
  1129
danderson@3977
  1130
    case OP_RND_TO_CEIL:
danderson@3977
  1131
    {
danderson@3977
  1132
      static float kRoundToCeil = -0.5f;
danderson@3977
  1133
      // From http://wurstcaptures.untergrund.net/assembler_tricks.html#fastfloorf
danderson@3979
  1134
      __ fld32(Operand(stk, 0));
danderson@3977
  1135
      __ fadd32(st0, st0);
danderson@3977
  1136
      __ fsubr32(Operand(ExternalAddress(&kRoundToCeil)));
danderson@3977
  1137
      __ subl(esp, 4);
danderson@3977
  1138
      __ fistp32(Operand(esp, 0));
danderson@3977
  1139
      __ pop(pri);
danderson@3977
  1140
      __ sarl(pri, 1);
danderson@3977
  1141
      __ negl(pri);
danderson@3977
  1142
      __ addl(stk, 4);
danderson@3977
  1143
      break;
danderson@3977
  1144
    }
dvander@157
  1145
danderson@3977
  1146
    case OP_RND_TO_ZERO:
danderson@3979
  1147
      if (MacroAssemblerX86::Features().sse) {
danderson@3979
  1148
        __ cvttss2si(pri, Operand(stk, 0));
danderson@3979
  1149
      } else {
danderson@3979
  1150
        __ fld32(Operand(stk, 0));
danderson@3979
  1151
        __ subl(esp, 8);
danderson@3979
  1152
        __ fstcw(Operand(esp, 4));
danderson@3979
  1153
        __ movl(Operand(esp, 0), 0xfff);
danderson@3979
  1154
        __ fldcw(Operand(esp, 0));
danderson@3979
  1155
        __ fistp32(Operand(esp, 0));
danderson@3979
  1156
        __ pop(pri);
danderson@3979
  1157
        __ fldcw(Operand(esp, 0));
danderson@3979
  1158
        __ addl(esp, 4);
danderson@3979
  1159
      }
danderson@3977
  1160
      __ addl(stk, 4);
danderson@3977
  1161
      break;
dvander@157
  1162
danderson@3977
  1163
    case OP_RND_TO_FLOOR:
danderson@3977
  1164
      __ fld32(Operand(stk, 0));
danderson@3977
  1165
      __ subl(esp, 8);
danderson@3977
  1166
      __ fstcw(Operand(esp, 4));
danderson@3977
  1167
      __ movl(Operand(esp, 0), 0x7ff);
danderson@3977
  1168
      __ fldcw(Operand(esp, 0));
danderson@3977
  1169
      __ fistp32(Operand(esp, 0));
danderson@3977
  1170
      __ pop(eax);
danderson@3977
  1171
      __ fldcw(Operand(esp, 0));
danderson@3977
  1172
      __ addl(esp, 4);
danderson@3977
  1173
      __ addl(stk, 4);
danderson@3977
  1174
      break;
dvander@157
  1175
danderson@3977
  1176
    case OP_FLOATCMP:
danderson@3977
  1177
    {
danderson@3977
  1178
      Label bl, ab, done;
danderson@3979
  1179
      if (MacroAssemblerX86::Features().sse) {
danderson@3979
  1180
        __ movss(xmm0, Operand(stk, 4));
danderson@3979
  1181
        __ ucomiss(xmm0, Operand(stk, 0));
danderson@3979
  1182
      } else {
danderson@3979
  1183
        __ fld32(Operand(stk, 0));
danderson@3979
  1184
        __ fld32(Operand(stk, 4));
danderson@3979
  1185
        __ fucomip(st1);
danderson@3979
  1186
        __ fstp(st0);
danderson@3979
  1187
      }
danderson@3977
  1188
      __ j(above, &ab);
danderson@3977
  1189
      __ j(below, &bl);
danderson@3977
  1190
      __ xorl(pri, pri);
danderson@3977
  1191
      __ jmp(&done);
danderson@3977
  1192
      __ bind(&ab);
danderson@3977
  1193
      __ movl(pri, -1);
danderson@3977
  1194
      __ jmp(&done);
danderson@3977
  1195
      __ bind(&bl);
danderson@3977
  1196
      __ movl(pri, 1);
danderson@3977
  1197
      __ bind(&done);
danderson@3977
  1198
      __ addl(stk, 8);
danderson@3977
  1199
      break;
danderson@3977
  1200
    }
danderson@3977
  1201
danderson@3977
  1202
    case OP_STACK:
danderson@3977
  1203
    {
danderson@3977
  1204
      cell_t amount = readCell();
danderson@3977
  1205
      __ addl(stk, amount);
danderson@3977
  1206
danderson@3977
  1207
     if (amount > 0) {
danderson@3977
  1208
       // Check if the stack went beyond the stack top - usually a compiler error.
dvander@3986
  1209
       __ cmpl(stk, intptr_t(plugin_->memory + plugin_->mem_size));
danderson@3977
  1210
       __ j(not_below, &error_stack_min_);
danderson@3977
  1211
     } else {
danderson@3977
  1212
       // Check if the stack is going to collide with the heap.
dvander@3991
  1213
       __ movl(tmp, Operand(hpAddr()));
danderson@3977
  1214
       __ lea(tmp, Operand(dat, ecx, NoScale, STACK_MARGIN));
danderson@3977
  1215
       __ cmpl(stk, tmp);
danderson@3977
  1216
       __ j(below, &error_stack_low_);
danderson@3977
  1217
     }
danderson@3977
  1218
     break;
danderson@3977
  1219
    }
dvander@157
  1220
danderson@3977
  1221
    case OP_HEAP:
danderson@3977
  1222
    {
danderson@3977
  1223
      cell_t amount = readCell();
dvander@3991
  1224
      __ movl(alt, Operand(hpAddr()));
dvander@3991
  1225
      __ addl(Operand(hpAddr()), amount);
danderson@3977
  1226
danderson@3977
  1227
      if (amount > 0) {
dvander@3991
  1228
        __ cmpl(Operand(hpAddr()), plugin_->data_size);
danderson@3977
  1229
        __ j(below, &error_heap_min_);
danderson@3977
  1230
      } else {
dvander@3991
  1231
        __ movl(tmp, Operand(hpAddr()));
danderson@3977
  1232
        __ lea(tmp, Operand(dat, ecx, NoScale, STACK_MARGIN));
danderson@3977
  1233
        __ cmpl(tmp, stk);
danderson@3977
  1234
        __ j(above, &error_heap_low_);
danderson@3977
  1235
      }
danderson@3977
  1236
      break;
danderson@3977
  1237
    }
danderson@3977
  1238
danderson@3977
  1239
    case OP_JUMP:
danderson@3977
  1240
    {
danderson@3977
  1241
      Label *target = labelAt(readCell());
danderson@3977
  1242
      if (!target)
danderson@3977
  1243
        return false;
dvander@4013
  1244
      if (target->bound()) {
dvander@4013
  1245
        __ jmp32(target);
dvander@4013
  1246
        backward_jumps_.append(masm.pc());
dvander@4013
  1247
      } else {
dvander@4013
  1248
        __ jmp(target);
dvander@4013
  1249
      }
danderson@3977
  1250
      break;
danderson@3977
  1251
    }
faluco@1166
  1252
danderson@3977
  1253
    case OP_JZER:
danderson@3977
  1254
    case OP_JNZ:
danderson@3977
  1255
    {
danderson@3977
  1256
      ConditionCode cc = (op == OP_JZER) ? zero : not_zero;
danderson@3977
  1257
      Label *target = labelAt(readCell());
danderson@3977
  1258
      if (!target)
danderson@3977
  1259
        return false;
danderson@3977
  1260
      __ testl(pri, pri);
dvander@4013
  1261
      if (target->bound()) {
dvander@4013
  1262
        __ j32(cc, target);
dvander@4013
  1263
        backward_jumps_.append(masm.pc());
dvander@4013
  1264
      } else {
dvander@4013
  1265
        __ j(cc, target);
dvander@4013
  1266
      }
danderson@3977
  1267
      break;
danderson@3977
  1268
    }
danderson@3977
  1269
danderson@3977
  1270
    case OP_JEQ:
danderson@3977
  1271
    case OP_JNEQ:
danderson@3977
  1272
    case OP_JSLESS:
danderson@3977
  1273
    case OP_JSLEQ:
danderson@3977
  1274
    case OP_JSGRTR:
danderson@3977
  1275
    case OP_JSGEQ:
danderson@3977
  1276
    {
danderson@3977
  1277
      Label *target = labelAt(readCell());
danderson@3977
  1278
      if (!target)
danderson@3977
  1279
        return false;
danderson@3977
  1280
      ConditionCode cc = OpToCondition(op);
danderson@3977
  1281
      __ cmpl(pri, alt);
dvander@4013
  1282
      if (target->bound()) {
dvander@4013
  1283
        __ j32(cc, target);
dvander@4013
  1284
        backward_jumps_.append(masm.pc());
dvander@4013
  1285
      } else {
dvander@4013
  1286
        __ j(cc, target);
dvander@4013
  1287
      }
danderson@3977
  1288
      break;
danderson@3977
  1289
    }
danderson@3977
  1290
danderson@3977
  1291
    case OP_TRACKER_PUSH_C:
danderson@3977
  1292
    {
danderson@3977
  1293
      cell_t amount = readCell();
dvander@157
  1294
danderson@3977
  1295
      __ push(pri);
danderson@3977
  1296
      __ push(alt);
danderson@3977
  1297
dvander@3982
  1298
      __ push(amount * 4);
dvander@3988
  1299
      __ push(intptr_t(rt_->GetBaseContext()->GetCtx()));
dvander@3982
  1300
      __ call(ExternalAddress((void *)PushTracker));
dvander@3982
  1301
      __ addl(esp, 8);
danderson@3977
  1302
      __ testl(eax, eax);
danderson@3977
  1303
      __ j(not_zero, &extern_error_);
danderson@3977
  1304
danderson@3977
  1305
      __ pop(alt);
danderson@3977
  1306
      __ pop(pri);
danderson@3977
  1307
      break;
danderson@3977
  1308
    }
danderson@3977
  1309
danderson@3977
  1310
    case OP_TRACKER_POP_SETHEAP:
danderson@3977
  1311
    {
danderson@3977
  1312
      // Save registers.
danderson@3977
  1313
      __ push(pri);
danderson@3977
  1314
      __ push(alt);
danderson@3977
  1315
danderson@3977
  1316
      // Get the context pointer and call the sanity checker.
dvander@3988
  1317
      __ push(intptr_t(rt_));
dvander@3982
  1318
      __ call(ExternalAddress((void *)PopTrackerAndSetHeap));
dvander@3991
  1319
      __ addl(esp, 4);
danderson@3977
  1320
      __ testl(eax, eax);
danderson@3977
  1321
      __ j(not_zero, &extern_error_);
danderson@3977
  1322
danderson@3977
  1323
      __ pop(alt);
danderson@3977
  1324
      __ pop(pri);
danderson@3977
  1325
      break;
danderson@3977
  1326
    }
dvander@157
  1327
danderson@3977
  1328
    case OP_BREAK:
danderson@3977
  1329
    {
danderson@3977
  1330
      cell_t cip = uintptr_t(cip_ - 1) - uintptr_t(plugin_->pcode);
dvander@3990
  1331
      __ movl(Operand(cipAddr()), cip);
danderson@3977
  1332
      break;
danderson@3977
  1333
    }
danderson@3977
  1334
danderson@3977
  1335
    case OP_HALT:
danderson@3977
  1336
      __ align(16);
dvander@3989
  1337
      __ movl(tmp, intptr_t(rt_->GetBaseContext()->GetCtx()));
dvander@3989
  1338
      __ movl(Operand(tmp, offsetof(sp_context_t, rval)), pri);
danderson@3977
  1339
      __ movl(pri, readCell());
danderson@3977
  1340
      __ jmp(&extern_error_);
danderson@3977
  1341
      break;
danderson@3977
  1342
danderson@3977
  1343
    case OP_BOUNDS:
danderson@3977
  1344
    {
danderson@3977
  1345
      cell_t value = readCell();
danderson@3977
  1346
      __ cmpl(eax, value);
danderson@3977
  1347
      __ j(above, &error_bounds_);
danderson@3977
  1348
      break;
danderson@3977
  1349
    }
danderson@3977
  1350
danderson@3977
  1351
    case OP_GENARRAY:
danderson@3977
  1352
    case OP_GENARRAY_Z:
danderson@3977
  1353
      emitGenArray(op == OP_GENARRAY_Z);
danderson@3977
  1354
      break;
dvander@157
  1355
danderson@3977
  1356
    case OP_CALL:
danderson@3977
  1357
      if (!emitCall())
danderson@3977
  1358
        return false;
danderson@3977
  1359
      break;
danderson@3977
  1360
danderson@3977
  1361
    case OP_SYSREQ_C:
danderson@3977
  1362
    case OP_SYSREQ_N:
danderson@3977
  1363
      if (!emitNativeCall(op))
danderson@3977
  1364
        return false;
danderson@3977
  1365
      break;
danderson@3977
  1366
danderson@3977
  1367
    case OP_SWITCH:
danderson@3977
  1368
      if (!emitSwitch())
danderson@3977
  1369
        return false;
danderson@3977
  1370
      break;
dvander@157
  1371
danderson@3977
  1372
    case OP_CASETBL:
danderson@3977
  1373
    {
danderson@3977
  1374
      size_t ncases = readCell();
danderson@3977
  1375
danderson@3977
  1376
      // Two cells per case, and one extra cell for the default address.
danderson@3977
  1377
      cip_ += (ncases * 2) + 1;
danderson@3977
  1378
      break;
danderson@3977
  1379
    }
danderson@3977
  1380
danderson@3977
  1381
    case OP_NOP:
danderson@3977
  1382
      break;
danderson@3977
  1383
danderson@3977
  1384
    default:
danderson@3977
  1385
      error_ = SP_ERROR_INVALID_INSTRUCTION;
danderson@3977
  1386
      return false;
danderson@3977
  1387
  }
danderson@3977
  1388
danderson@3977
  1389
  return true;
dvander@157
  1390
}
dvander@157
  1391
danderson@3977
  1392
Label *
danderson@3977
  1393
Compiler::labelAt(size_t offset)
dvander@157
  1394
{
danderson@3977
  1395
  if (offset % 4 != 0 ||
danderson@3977
  1396
      offset > plugin_->pcode_size ||
danderson@3977
  1397
      offset <= pcode_start_)
danderson@3977
  1398
  {
danderson@3977
  1399
    // If the jump target is misaligned, or out of pcode bounds, or is an
danderson@3977
  1400
    // address out of the function bounds, we abort. Unfortunately we can't
danderson@3977
  1401
    // test beyond the end of the function since we don't have a precursor
danderson@3977
  1402
    // pass (yet).
danderson@3977
  1403
    error_ = SP_ERROR_INSTRUCTION_PARAM;
danderson@3977
  1404
    return NULL;
danderson@3977
  1405
  }
dvander@157
  1406
danderson@3977
  1407
  return &jump_map_[offset / sizeof(cell_t)];
dvander@157
  1408
}
dvander@157
  1409
danderson@3977
  1410
void
danderson@3977
  1411
Compiler::emitCheckAddress(Register reg)
faluco@831
  1412
{
danderson@3977
  1413
  // Check if we're in memory bounds.
danderson@3977
  1414
  __ cmpl(reg, plugin_->mem_size);
danderson@3977
  1415
  __ j(not_below, &error_memaccess_);
faluco@831
  1416
danderson@3977
  1417
  // Check if we're in the invalid region between hp and sp.
danderson@3977
  1418
  Label done;
dvander@3991
  1419
  __ cmpl(reg, Operand(hpAddr()));
danderson@3977
  1420
  __ j(below, &done);
danderson@3977
  1421
  __ lea(tmp, Operand(dat, reg, NoScale));
danderson@3977
  1422
  __ cmpl(tmp, stk);
danderson@3977
  1423
  __ j(below, &error_memaccess_);
danderson@3977
  1424
  __ bind(&done);
faluco@831
  1425
}
faluco@831
  1426
danderson@3977
  1427
void
danderson@3977
  1428
Compiler::emitGenArray(bool autozero)
faluco@831
  1429
{
danderson@3977
  1430
  cell_t val = readCell();
danderson@3977
  1431
  if (val == 1)
danderson@3977
  1432
  {
danderson@3977
  1433
    // flat array; we can generate this without indirection tables.
danderson@3977
  1434
    // Note that we can overwrite ALT because technically STACK should be destroying ALT
dvander@3991
  1435
    __ movl(alt, Operand(hpAddr()));
danderson@3977
  1436
    __ movl(tmp, Operand(stk, 0));
danderson@3977
  1437
    __ movl(Operand(stk, 0), alt);    // store base of the array into the stack.
danderson@3977
  1438
    __ lea(alt, Operand(alt, tmp, ScaleFour));
dvander@3991
  1439
    __ movl(Operand(hpAddr()), alt);
danderson@3977
  1440
    __ addl(alt, dat);
danderson@3977
  1441
    __ cmpl(alt, stk);
danderson@3977
  1442
    __ j(not_below, &error_heap_low_);
faluco@831
  1443
dvander@3982
  1444
    __ shll(tmp, 2);
dvander@3982
  1445
    __ push(tmp);
dvander@3988
  1446
    __ push(intptr_t(rt_->GetBaseContext()->GetCtx()));
dvander@3982
  1447
    __ call(ExternalAddress((void *)PushTracker));
dvander@3982
  1448
    __ addl(esp, 4);
dvander@3982
  1449
    __ pop(tmp);
dvander@3982
  1450
    __ shrl(tmp, 2);
dvander@3982
  1451
    __ testl(eax, eax);
dvander@3982
  1452
    __ j(not_zero, &extern_error_);
faluco@831
  1453
danderson@3977
  1454
    if (autozero) {
dvander@3982
  1455
      // Note - tmp is ecx and still intact.
danderson@3977
  1456
      __ push(eax);
danderson@3977
  1457
      __ push(edi);
danderson@3977
  1458
      __ xorl(eax, eax);
danderson@3977
  1459
      __ movl(edi, Operand(stk, 0));
danderson@3977
  1460
      __ addl(edi, dat);
danderson@3977
  1461
      __ cld();
danderson@3977
  1462
      __ rep_stosd();
danderson@3977
  1463
      __ pop(edi);
danderson@3977
  1464
      __ pop(eax);
danderson@3977
  1465
    }
danderson@3977
  1466
  } else {
dvander@3982
  1467
    __ push(pri);
dvander@3982
  1468
dvander@3982
  1469
    // int GenerateArray(sp_plugin_t, vars[], uint32_t, cell_t *, int, unsigned *);
dvander@3982
  1470
    __ push(autozero ? 1 : 0);
dvander@3982
  1471
    __ push(stk);
dvander@3982
  1472
    __ push(val);
dvander@3988
  1473
    __ push(intptr_t(rt_));
dvander@3982
  1474
    __ call(ExternalAddress((void *)GenerateArray));
dvander@3993
  1475
    __ addl(esp, 4 * sizeof(void *));
dvander@3982
  1476
dvander@3982
  1477
    // restore pri to tmp
dvander@3982
  1478
    __ pop(tmp);
dvander@3982
  1479
dvander@3982
  1480
    __ testl(eax, eax);
dvander@3982
  1481
    __ j(not_zero, &extern_error_);
dvander@3982
  1482
dvander@3982
  1483
    // Move tmp back to pri, remove pushed args.
dvander@3982
  1484
    __ movl(pri, tmp);
dvander@3982
  1485
    __ addl(stk, (val - 1) * 4);
danderson@3977
  1486
  }
faluco@831
  1487
}
faluco@831
  1488
danderson@3977
  1489
bool
danderson@3977
  1490
Compiler::emitCall()
faluco@831
  1491
{
danderson@3977
  1492
  cell_t offset = readCell();
faluco@831
  1493
danderson@3977
  1494
  // If this offset looks crappy, i.e. not aligned or out of bounds, we just
danderson@3977
  1495
  // abort.
danderson@3977
  1496
  if (offset % 4 != 0 || uint32_t(offset) >= plugin_->pcode_size) {
danderson@3977
  1497
    error_ = SP_ERROR_INSTRUCTION_PARAM;
danderson@3977
  1498
    return false;
danderson@3977
  1499
  }
faluco@831
  1500
danderson@3977
  1501
  // eax = context
danderson@3977
  1502
  // ecx = rp
dvander@3988
  1503
  __ movl(eax, intptr_t(rt_->GetBaseContext()->GetCtx()));
danderson@3977
  1504
  __ movl(ecx, Operand(eax, offsetof(sp_context_t, rp)));
faluco@831
  1505
danderson@3977
  1506
  // Check if the return stack is used up.
danderson@3977
  1507
  __ cmpl(ecx, SP_MAX_RETURN_STACK);
danderson@3977
  1508
  __ j(not_below, &error_stack_low_);
danderson@3977
  1509
danderson@3977
  1510
  // Add to the return stack.
danderson@3977
  1511
  uintptr_t cip = uintptr_t(cip_ - 2) - uintptr_t(plugin_->pcode);
danderson@3977
  1512
  __ movl(Operand(eax, ecx, ScaleFour, offsetof(sp_context_t, rstk_cips)), cip);
faluco@831
  1513
danderson@3977
  1514
  // Increment the return stack pointer.
danderson@3977
  1515
  __ addl(Operand(eax, offsetof(sp_context_t, rp)), 1);
faluco@831
  1516
danderson@3977
  1517
  // Store the CIP of the function we're about to call.
dvander@3990
  1518
  __ movl(Operand(cipAddr()), offset);
faluco@831
  1519
danderson@3977
  1520
  JitFunction *fun = rt_->GetJittedFunctionByOffset(offset);
danderson@3977
  1521
  if (!fun) {
danderson@3977
  1522
    // Need to emit a delayed thunk.
danderson@3977
  1523
    CallThunk *thunk = new CallThunk(offset);
danderson@3977
  1524
    __ call(&thunk->call);
danderson@3977
  1525
    if (!thunks_.append(thunk))
danderson@3977
  1526
      return false;
danderson@3977
  1527
  } else {
danderson@3977
  1528
    // Function is already emitted, we can do a direct call.
danderson@3977
  1529
    __ call(ExternalAddress(fun->GetEntryAddress()));
danderson@3977
  1530
  }
faluco@831
  1531
danderson@3977
  1532
  // Restore the last cip.
dvander@3990
  1533
  __ movl(Operand(cipAddr()), cip);
faluco@831
  1534
danderson@3977
  1535
  // Mark us as leaving the last frame.
dvander@3988
  1536
  __ movl(tmp, intptr_t(rt_->GetBaseContext()->GetCtx()));
danderson@3977
  1537
  __ subl(Operand(tmp, offsetof(sp_context_t, rp)), 1);
danderson@3977
  1538
  return true;
faluco@831
  1539
}
faluco@831
  1540
danderson@3977
  1541
void
danderson@3977
  1542
Compiler::emitCallThunks()
faluco@831
  1543
{
danderson@3977
  1544
  for (size_t i = 0; i < thunks_.length(); i++) {
danderson@3977
  1545
    CallThunk *thunk = thunks_[i];
faluco@831
  1546
danderson@3977
  1547
    Label error;
danderson@3977
  1548
    __ bind(&thunk->call);
danderson@3977
  1549
    // Huge hack - get the return address, since that is the call that we
danderson@3977
  1550
    // need to patch.
danderson@3977
  1551
    __ movl(eax, Operand(esp, 0));
faluco@831
  1552
danderson@3977
  1553
    // Align the stack. Unfortunately this is a pretty careful dance based
danderson@3977
  1554
    // on the number of words we push (4 args, 1 saved esp), and someday
danderson@3977
  1555
    // we should look into automating this.
danderson@3977
  1556
    __ movl(edx, esp);
danderson@3977
  1557
    __ andl(esp, 0xfffffff0);
danderson@3977
  1558
    __ subl(esp, 12);
danderson@3977
  1559
    __ push(edx);
faluco@831
  1560
danderson@3977
  1561
    // Push arguments.
danderson@3977
  1562
    __ push(eax);
danderson@3977
  1563
    __ subl(esp, 4);
danderson@3977
  1564
    __ movl(Operand(esp, 0), esp);
danderson@3977
  1565
    __ push(thunk->pcode_offset);
danderson@3977
  1566
    __ push(intptr_t(rt_));
danderson@3977
  1567
    __ call(ExternalAddress((void *)CompileFromThunk));
danderson@3977
  1568
    __ movl(edx, Operand(esp, 8));
danderson@3977
  1569
    __ movl(esp, Operand(esp, 16));
danderson@3977
  1570
    __ testl(eax, eax);
danderson@3977
  1571
    __ j(not_zero, &error);
danderson@3977
  1572
    __ call(edx);
danderson@3977
  1573
    __ ret();
faluco@831
  1574
danderson@3977
  1575
    __ bind(&error);
dvander@3990
  1576
    __ movl(Operand(cipAddr()), thunk->pcode_offset);
danderson@3977
  1577
    __ jmp(g_Jit.GetUniversalReturn());
danderson@3977
  1578
  }
danderson@3977
  1579
}
faluco@831
  1580
danderson@3977
  1581
cell_t
danderson@3977
  1582
Compiler::readCell()
danderson@3977
  1583
{
danderson@3977
  1584
  if (cip_ >= code_end_) {
danderson@3977
  1585
    error_= SP_ERROR_INVALID_INSTRUCTION;
danderson@3977
  1586
    return 0;
danderson@3977
  1587
  }
danderson@3977
  1588
  return *cip_++;
faluco@831
  1589
}
faluco@831
  1590
danderson@3977
  1591
bool
danderson@3977
  1592
Compiler::emitNativeCall(OPCODE op)
faluco@831
  1593
{
danderson@3977
  1594
  uint32_t native_index = readCell();
faluco@831
  1595
danderson@3977
  1596
  if (native_index >= plugin_->num_natives) {
danderson@3977
  1597
    error_ = SP_ERROR_INSTRUCTION_PARAM;
danderson@3977
  1598
    return false;
danderson@3977
  1599
  }
faluco@831
  1600
danderson@3977
  1601
  uint32_t num_params;
danderson@3977
  1602
  if (op == OP_SYSREQ_N) {
danderson@3977
  1603
    num_params = readCell();
faluco@831
  1604
danderson@3977
  1605
    // See if we can get a replacement opcode. If we can, then recursively
danderson@3977
  1606
    // call emitOp() to generate it. Note: it's important that we do this
danderson@3977
  1607
    // before generating any code for the SYSREQ.N.
danderson@3977
  1608
    unsigned replacement = rt_->GetNativeReplacement(native_index);
danderson@3977
  1609
    if (replacement != OP_NOP)
danderson@3977
  1610
      return emitOp((OPCODE)replacement);
faluco@831
  1611
danderson@3977
  1612
    // Store the number of parameters.
danderson@3977
  1613
    __ movl(Operand(stk, -4), num_params);
danderson@3977
  1614
    __ subl(stk, 4);
danderson@3977
  1615
  }
faluco@831
  1616
danderson@3977
  1617
  // Save registers.
danderson@3977
  1618
  __ push(edx);
faluco@831
  1619
danderson@3977
  1620
  // Push the parameters for the C++ function.
danderson@3977
  1621
  __ push(stk);
danderson@3977
  1622
  __ push(native_index);
faluco@831
  1623
dvander@3992
  1624
  // Relocate our absolute stk to be dat-relative, and update the context's
dvander@3992
  1625
  // view.
dvander@3988
  1626
  __ movl(eax, intptr_t(rt_->GetBaseContext()->GetCtx()));
danderson@3977
  1627
  __ subl(stk, dat);
danderson@3977
  1628
  __ movl(Operand(eax, offsetof(sp_context_t, sp)), stk);
faluco@831
  1629
danderson@3977
  1630
  // Push context and make the call.
danderson@3977
  1631
  __ push(eax);
danderson@3977
  1632
  __ call(ExternalAddress((void *)NativeCallback));
faluco@831
  1633
danderson@3977
  1634
  // Check for errors.
dvander@3988
  1635
  __ movl(ecx, intptr_t(rt_->GetBaseContext()->GetCtx()));
danderson@3977
  1636
  __ movl(ecx, Operand(ecx, offsetof(sp_context_t, n_err)));
danderson@3977
  1637
  __ testl(ecx, ecx);
danderson@3977
  1638
  __ j(not_zero, &extern_error_);
danderson@3977
  1639
  
danderson@3977
  1640
  // Restore local state.
danderson@3977
  1641
  __ addl(stk, dat);
dvander@3983
  1642
  __ addl(esp, 12);
danderson@3977
  1643
  __ pop(edx);
dvander@2226
  1644
danderson@3977
  1645
  if (op == OP_SYSREQ_N) {
danderson@3977
  1646
    // Pop the stack. Do not check the margins.
danderson@3977
  1647
    __ addl(stk, (num_params + 1) * sizeof(cell_t));
danderson@3977
  1648
  }
danderson@3977
  1649
  return true;
dvander@2226
  1650
}
dvander@2226
  1651
danderson@3977
  1652
bool
danderson@3977
  1653
Compiler::emitSwitch()
dvander@2226
  1654
{
danderson@3977
  1655
  cell_t offset = readCell();
danderson@3977
  1656
  if (!labelAt(offset))
danderson@3977
  1657
    return false;
danderson@3977
  1658
danderson@3977
  1659
  cell_t *tbl = (cell_t *)((char *)plugin_->pcode + offset + sizeof(cell_t));
danderson@3977
  1660
danderson@3977
  1661
  struct Entry {
danderson@3977
  1662
    cell_t val;
danderson@3977
  1663
    cell_t offset;
danderson@3977
  1664
  };
danderson@3977
  1665
danderson@3977
  1666
  size_t ncases = *tbl++;
danderson@3977
  1667
danderson@3977
  1668
  Label *defaultCase = labelAt(*tbl);
danderson@3977
  1669
  if (!defaultCase)
danderson@3977
  1670
    return false;
danderson@3977
  1671
danderson@3977
  1672
  // Degenerate - 0 cases.
danderson@3977
  1673
  if (!ncases) {
danderson@3977
  1674
    __ jmp(defaultCase);
danderson@3977
  1675
    return true;
danderson@3977
  1676
  }
danderson@3977
  1677
danderson@3977
  1678
  Entry *cases = (Entry *)(tbl + 1);
danderson@3977
  1679
danderson@3977
  1680
  // Degenerate - 1 case.
danderson@3977
  1681
  if (ncases == 1) {
danderson@3977
  1682
    Label *maybe = labelAt(cases[0].offset);
danderson@3977
  1683
    if (!maybe)
danderson@3977
  1684
      return false;
danderson@3977
  1685
    __ cmpl(pri, cases[0].val);
danderson@3977
  1686
    __ j(equal, maybe);
danderson@3977
  1687
    __ jmp(defaultCase);
danderson@3977
  1688
    return true;
danderson@3977
  1689
  }
danderson@3977
  1690
danderson@3977
  1691
  // We have two or more cases, so let's generate a full switch. Decide
danderson@3977
  1692
  // whether we'll make an if chain, or a jump table, based on whether
danderson@3977
  1693
  // the numbers are strictly sequential.
danderson@3977
  1694
  bool sequential = true;
danderson@3977
  1695
  {
danderson@3977
  1696
    cell_t first = cases[0].val;
danderson@3977
  1697
    cell_t last = first;
danderson@3977
  1698
    for (size_t i = 1; i < ncases; i++) {
danderson@3977
  1699
      if (cases[i].val != ++last) {
danderson@3977
  1700
        sequential = false;
danderson@3977
  1701
        break;
danderson@3977
  1702
      }
danderson@3977
  1703
    }
danderson@3977
  1704
  }
danderson@3977
  1705
danderson@3977
  1706
  // First check whether the bounds are correct: if (a < LOW || a > HIGH);
danderson@3977
  1707
  // this check is valid whether or not we emit a sequential-optimized switch.
danderson@3977
  1708
  cell_t low = cases[0].val;
danderson@3977
  1709
  if (low != 0) {
danderson@3977
  1710
    // negate it so we'll get a lower bound of 0.
danderson@3977
  1711
    low = -low;
danderson@3977
  1712
    __ lea(tmp, Operand(pri, low));
danderson@3977
  1713
  } else {
danderson@3977
  1714
    __ movl(tmp, pri);
danderson@3977
  1715
  }
dvander@2226
  1716
danderson@3977
  1717
  cell_t high = abs(cases[0].val - cases[ncases - 1].val);
danderson@3977
  1718
  __ cmpl(tmp, high);
danderson@3977
  1719
  __ j(above, defaultCase);
dvander@2226
  1720
danderson@3977
  1721
  if (sequential) {
danderson@3977
  1722
    // Optimized table version. The tomfoolery below is because we only have
danderson@3977
  1723
    // one free register... it seems unlikely pri or alt will be used given
danderson@3977
  1724
    // that we're at the end of a control-flow point, but we'll play it safe.
danderson@3977
  1725
    DataLabel table;
danderson@3977
  1726
    __ push(eax);
danderson@3977
  1727
    __ movl(eax, &table);
danderson@3977
  1728
    __ movl(ecx, Operand(eax, ecx, ScaleFour));
danderson@3977
  1729
    __ pop(eax);
danderson@3977
  1730
    __ jmp(ecx);
dvander@2226
  1731
danderson@3977
  1732
    __ bind(&table);
danderson@3977
  1733
    for (size_t i = 0; i < ncases; i++) {
danderson@3977
  1734
      Label *label = labelAt(cases[i].offset);
danderson@3977
  1735
      if (!label)
danderson@3977
  1736
        return false;
danderson@3977
  1737
      __ emit_absolute_address(label);
danderson@3977
  1738
    }
danderson@3977
  1739
  } else {
danderson@3977
  1740
    // Slower version. Go through each case and generate a check.
danderson@3977
  1741
    for (size_t i = 0; i < ncases; i++) {
danderson@3977
  1742
      Label *label = labelAt(cases[i].offset);
danderson@3977
  1743
      if (!label)
danderson@3977
  1744
        return false;
danderson@3977
  1745
      __ cmpl(pri, cases[i].val);
danderson@3977
  1746
      __ j(equal, label);
danderson@3977
  1747
    }
danderson@3977
  1748
    __ jmp(defaultCase);
danderson@3977
  1749
  }
danderson@3977
  1750
  return true;
danderson@3977
  1751
}
dvander@2226
  1752
danderson@3977
  1753
void
danderson@3977
  1754
Compiler::emitErrorPath(Label *dest, int code)
danderson@3977
  1755
{
danderson@3977
  1756
  if (dest->used()) {
danderson@3977
  1757
    __ bind(dest);
danderson@3977
  1758
    __ movl(eax, code);
danderson@3977
  1759
    __ jmp(g_Jit.GetUniversalReturn());
danderson@3977
  1760
  }
danderson@3977
  1761
}
dvander@2226
  1762
danderson@3977
  1763
void
danderson@3977
  1764
Compiler::emitErrorPaths()
danderson@3977
  1765
{
danderson@3977
  1766
  emitErrorPath(&error_divide_by_zero_, SP_ERROR_DIVIDE_BY_ZERO);
danderson@3977
  1767
  emitErrorPath(&error_stack_low_, SP_ERROR_STACKLOW);
danderson@3977
  1768
  emitErrorPath(&error_stack_min_, SP_ERROR_STACKMIN);
danderson@3977
  1769
  emitErrorPath(&error_bounds_, SP_ERROR_ARRAY_BOUNDS);
danderson@3977
  1770
  emitErrorPath(&error_memaccess_, SP_ERROR_MEMACCESS);
danderson@3977
  1771
  emitErrorPath(&error_heap_low_, SP_ERROR_HEAPLOW);
danderson@3977
  1772
  emitErrorPath(&error_heap_min_, SP_ERROR_HEAPMIN);
danderson@3977
  1773
  emitErrorPath(&error_integer_overflow_, SP_ERROR_INTEGER_OVERFLOW);
dvander@2226
  1774
danderson@3977
  1775
  if (extern_error_.used()) {
danderson@3977
  1776
    __ bind(&extern_error_);
dvander@3988
  1777
    __ movl(eax, intptr_t(rt_->GetBaseContext()->GetCtx()));
danderson@3977
  1778
    __ movl(eax, Operand(eax, offsetof(sp_context_t, n_err)));
danderson@3977
  1779
    __ jmp(g_Jit.GetUniversalReturn());
danderson@3977
  1780
  }
dvander@2226
  1781
}
dvander@2226
  1782
dvander@3993
  1783
typedef int (*JIT_EXECUTE)(sp_context_t *ctx, uint8_t *memory, void *code);
dvander@3989
  1784
danderson@3977
  1785
static void *
dvander@4013
  1786
GenerateEntry(void **retp, void **timeoutp)
dvander@157
  1787
{
danderson@3977
  1788
  AssemblerX86 masm;
danderson@3977
  1789
danderson@3977
  1790
  __ push(ebp);
danderson@3977
  1791
  __ movl(ebp, esp);
danderson@3977
  1792
dvander@3993
  1793
  __ push(esi);   // ebp - 4
dvander@3993
  1794
  __ push(edi);   // ebp - 8
dvander@3993
  1795
  __ push(ebx);   // ebp - 12
dvander@3993
  1796
  __ push(esp);   // ebp - 16
danderson@3977
  1797
dvander@3993
  1798
  __ movl(ebx, Operand(ebp, 8 + 4 * 0));
dvander@3993
  1799
  __ movl(eax, Operand(ebp, 8 + 4 * 1));
dvander@3993
  1800
  __ movl(ecx, Operand(ebp, 8 + 4 * 2));
danderson@3977
  1801
danderson@3977
  1802
  // Set up run-time registers.
dvander@3992
  1803
  __ movl(edi, Operand(ebx, offsetof(sp_context_t, sp)));
danderson@3977
  1804
  __ addl(edi, eax);
dvander@3993
  1805
  __ movl(esi, eax);
danderson@3977
  1806
  __ movl(ebx, edi);
dvander@157
  1807
dvander@3983
  1808
  // Align the stack.
dvander@3983
  1809
  __ andl(esp, 0xfffffff0);
dvander@3983
  1810
dvander@3983
  1811
  // Call into plugin (align the stack first).
danderson@3977
  1812
  __ call(ecx);
faluco@853
  1813
dvander@3992
  1814
  // Get input context, store rval.
dvander@3993
  1815
  __ movl(ecx, Operand(ebp, 8 + 4 * 0));
dvander@3989
  1816
  __ movl(Operand(ecx, offsetof(sp_context_t, rval)), pri);
dvander@3989
  1817
dvander@3989
  1818
  // Set no error.
danderson@3977
  1819
  __ movl(eax, SP_ERROR_NONE);
dvander@157
  1820
dvander@3989
  1821
  // Store latest stk. If we have an error code, we'll jump directly to here,
dvander@3989
  1822
  // so eax will already be set.
dvander@3989
  1823
  Label ret;
dvander@3989
  1824
  __ bind(&ret);
danderson@3977
  1825
  __ subl(stk, dat);
dvander@3992
  1826
  __ movl(Operand(ecx, offsetof(sp_context_t, sp)), stk);
dvander@157
  1827
dvander@3993
  1828
  // Restore stack.
dvander@3993
  1829
  __ movl(esp, Operand(ebp, -16));
dvander@3993
  1830
dvander@3989
  1831
  // Restore registers and gtfo.
danderson@3977
  1832
  __ pop(ebx);
danderson@3977
  1833
  __ pop(edi);
danderson@3977
  1834
  __ pop(esi);
danderson@3977
  1835
  __ pop(ebp);
danderson@3977
  1836
  __ ret();
dvander@157
  1837
dvander@3989
  1838
  // The universal emergency return will jump to here.
dvander@3989
  1839
  Label error;
dvander@3989
  1840
  __ bind(&error);
dvander@3993
  1841
  __ movl(ecx, Operand(ebp, 8 + 4 * 0)); // ret-path expects ecx = ctx
dvander@3989
  1842
  __ jmp(&ret);
dvander@3989
  1843
dvander@4013
  1844
  Label timeout;
dvander@4013
  1845
  __ bind(&timeout);
dvander@4013
  1846
  __ movl(eax, SP_ERROR_TIMEOUT);
dvander@4013
  1847
  __ jmp(&error);
dvander@4013
  1848
danderson@3977
  1849
  void *code = LinkCode(masm);
danderson@3977
  1850
  if (!code)
danderson@3977
  1851
    return NULL;
dvander@157
  1852
danderson@3977
  1853
  *retp = reinterpret_cast<uint8_t *>(code) + error.offset();
dvander@4013
  1854
  *timeoutp = reinterpret_cast<uint8_t *>(code) + timeout.offset();
danderson@3977
  1855
  return code;
dvander@157
  1856
}
dvander@157
  1857
dvander@2226
  1858
ICompilation *JITX86::ApplyOptions(ICompilation *_IN, ICompilation *_OUT)
ds@1952
  1859
{
danderson@3977
  1860
  if (_IN == NULL)
danderson@3977
  1861
    return _OUT;
danderson@3977
  1862
danderson@3977
  1863
  CompData *_in = (CompData * )_IN;
danderson@3977
  1864
  CompData *_out = (CompData * )_OUT;
dvander@2193
  1865
danderson@3977
  1866
  _in->inline_level = _out->inline_level;
danderson@3977
  1867
  _in->profile = _out->profile;
dvander@2226
  1868
danderson@3977
  1869
  _out->Abort();
danderson@3977
  1870
  return _in;
dvander@2226
  1871
}
dvander@2226
  1872
dvander@2226
  1873
JITX86::JITX86()
dvander@2226
  1874
{
danderson@3977
  1875
  m_pJitEntry = NULL;
dvander@2226
  1876
}
dvander@2226
  1877
dvander@4013
  1878
bool
dvander@4013
  1879
JITX86::InitializeJIT()
dvander@157
  1880
{
danderson@3977
  1881
  g_pCodeCache = KE_CreateCodeCache();
dvander@2226
  1882
dvander@4013
  1883
  m_pJitEntry = GenerateEntry(&m_pJitReturn, &m_pJitTimeout);
danderson@3977
  1884
  if (!m_pJitEntry)
danderson@3977
  1885
    return false;
dvander@2226
  1886
danderson@3979
  1887
  MacroAssemblerX86 masm;
danderson@3979
  1888
  MacroAssemblerX86::GenerateFeatureDetection(masm);
danderson@3979
  1889
  void *code = LinkCode(masm);
danderson@3979
  1890
  if (!code)
danderson@3979
  1891
    return false;
danderson@3979
  1892
  MacroAssemblerX86::RunFeatureDetection(code);
danderson@3979
  1893
  KE_FreeCode(g_pCodeCache, code);
danderson@3979
  1894
danderson@3977
  1895
  return true;
dvander@2226
  1896
}
dvander@2226
  1897
danderson@3977
  1898
void
danderson@3977
  1899
JITX86::ShutdownJIT()
dvander@2226
  1900
{
danderson@3977
  1901
  KE_DestroyCodeCache(g_pCodeCache);
danderson@3977
  1902
}
danderson@3977
  1903
danderson@3977
  1904
JitFunction *
danderson@3977
  1905
JITX86::CompileFunction(BaseRuntime *prt, cell_t pcode_offs, int *err)
danderson@3977
  1906
{
danderson@3977
  1907
  Compiler cc(prt, pcode_offs);
danderson@3977
  1908
  JitFunction *fun = cc.emit(err);
danderson@3977
  1909
  if (!fun)
danderson@3977
  1910
    return NULL;
dvander@4013
  1911
dvander@4013
  1912
  // Grab the lock before linking code in, since the watchdog timer will look
dvander@4013
  1913
  // at this list on another thread.
dvander@4013
  1914
  ke::AutoLock lock(g_Jit.Mutex());
dvander@4013
  1915
danderson@3977
  1916
  prt->AddJittedFunction(fun);
danderson@3977
  1917
  return fun;
dvander@2226
  1918
}
dvander@2226
  1919
danderson@3977
  1920
void
danderson@3977
  1921
JITX86::SetupContextVars(BaseRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx)
dvander@2226
  1922
{
danderson@3977
  1923
  tracker_t *trk = new tracker_t;
faluco@831
  1924
danderson@3977
  1925
  ctx->vm[JITVARS_TRACKER] = trk;
danderson@3977
  1926
  ctx->vm[JITVARS_BASECTX] = pCtx; /* GetDefaultContext() is not constructed yet */
danderson@3977
  1927
  ctx->vm[JITVARS_PROFILER] = g_engine2.GetProfiler();
danderson@3977
  1928
  ctx->vm[JITVARS_PLUGIN] = const_cast<sp_plugin_t *>(runtime->plugin());
dvander@2226
  1929
danderson@3977
  1930
  trk->pBase = (ucell_t *)malloc(1024);
danderson@3977
  1931
  trk->pCur = trk->pBase;
danderson@3977
  1932
  trk->size = 1024 / sizeof(cell_t);
dvander@2226
  1933
}
dvander@2226
  1934
danderson@3977
  1935
SPVM_NATIVE_FUNC
danderson@3977
  1936
JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData)
dvander@2226
  1937
{
danderson@3977
  1938
  AssemblerX86 masm;
dvander@601
  1939
danderson@3977
  1940
  __ push(ebx);
danderson@3977
  1941
  __ push(edi);
danderson@3977
  1942
  __ push(esi);
danderson@3977
  1943
  __ movl(edi, Operand(esp, 16)); // store ctx
danderson@3977
  1944
  __ movl(esi, Operand(esp, 20)); // store params
danderson@3977
  1945
  __ movl(ebx, esp);
danderson@3977
  1946
  __ andl(esp, 0xfffffff0);
danderson@3977
  1947
  __ subl(esp, 4);
faluco@1166
  1948
danderson@3977
  1949
  __ push(intptr_t(pData));
danderson@3977
  1950
  __ push(esi);
danderson@3977
  1951
  __ push(edi);
danderson@3977
  1952
  __ call(ExternalAddress((void *)callback));
danderson@3977
  1953
  __ movl(esp, ebx);
danderson@3977
  1954
  __ pop(esi);
danderson@3977
  1955
  __ pop(edi);
danderson@3977
  1956
  __ pop(ebx);
danderson@3977
  1957
  __ ret();
dvander@601
  1958
danderson@3977
  1959
  return (SPVM_NATIVE_FUNC)LinkCode(masm);
dvander@601
  1960
}
dvander@601
  1961
dvander@4013
  1962
void
dvander@4013
  1963
JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func)
dvander@601
  1964
{
danderson@3977
  1965
  KE_FreeCode(g_pCodeCache, (void *)func);
dvander@157
  1966
}
dvander@157
  1967
dvander@4013
  1968
ICompilation *
dvander@4013
  1969
JITX86::StartCompilation()
dvander@157
  1970
{
danderson@3977
  1971
  return new CompData;
dvander@2193
  1972
}
dvander@2193
  1973
dvander@4013
  1974
ICompilation *
dvander@4013
  1975
JITX86::StartCompilation(BaseRuntime *runtime)
dvander@2193
  1976
{
danderson@3977
  1977
  return new CompData;
dvander@157
  1978
}
dvander@157
  1979
dvander@4013
  1980
void
dvander@4013
  1981
CompData::Abort()
dvander@157
  1982
{
danderson@3977
  1983
  delete this;
dvander@2193
  1984
}
dvander@2193
  1985
dvander@4013
  1986
void
dvander@4013
  1987
JITX86::FreeContextVars(sp_context_t *ctx)
dvander@2193
  1988
{
danderson@3977
  1989
  free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase);
danderson@3977
  1990
  delete (tracker_t *)ctx->vm[JITVARS_TRACKER];
ds@1952
  1991
}
ds@1952
  1992
dvander@4013
  1993
bool
dvander@4013
  1994
CompData::SetOption(const char *key, const char *val)
dvander@2193
  1995
{
danderson@3977
  1996
  if (strcmp(key, SP_JITCONF_DEBUG) == 0)
danderson@3977
  1997
    return true;
danderson@3977
  1998
  if (strcmp(key, SP_JITCONF_PROFILE) == 0) {
danderson@3977
  1999
    profile = atoi(val);
dvander@157
  2000
danderson@3977
  2001
    /** Callbacks must be profiled to profile functions! */
danderson@3977
  2002
    if ((profile & SP_PROF_FUNCTIONS) == SP_PROF_FUNCTIONS)
danderson@3977
  2003
      profile |= SP_PROF_CALLBACKS;
dvander@175
  2004
danderson@3977
  2005
    return true;
danderson@3977
  2006
  }
dvander@2226
  2007
danderson@3977
  2008
  return false;
dvander@344
  2009
}
dvander@344
  2010
dvander@4013
  2011
int
dvander@4013
  2012
JITX86::InvokeFunction(BaseRuntime *runtime, JitFunction *fn, cell_t *result)
dvander@344
  2013
{
dvander@3989
  2014
  sp_context_t *ctx = runtime->GetBaseContext()->GetCtx();
dvander@3989
  2015
dvander@3991
  2016
  // Note that cip, hp, sp are saved and restored by Execute2().
dvander@3990
  2017
  ctx->cip = fn->GetPCodeAddress();
dvander@3990
  2018
dvander@3989
  2019
  JIT_EXECUTE pfn = (JIT_EXECUTE)m_pJitEntry;
dvander@4013
  2020
dvander@4013
  2021
  if (level_++ == 0)
dvander@4013
  2022
    frame_id_++;
dvander@3993
  2023
  int err = pfn(ctx, runtime->plugin()->memory, fn->GetEntryAddress());
dvander@4013
  2024
  level_--;
dvander@2226
  2025
dvander@3989
  2026
  *result = ctx->rval;
danderson@3977
  2027
  return err;
dvander@175
  2028
}
dvander@175
  2029
dvander@4013
  2030
void *
dvander@4013
  2031
JITX86::AllocCode(size_t size)
dvander@175
  2032
{
danderson@3977
  2033
  return Knight::KE_AllocCode(g_pCodeCache, size);
dvander@175
  2034
}
dvander@253
  2035
dvander@4013
  2036
void
dvander@4013
  2037
JITX86::FreeCode(void *code)
dvander@253
  2038
{
danderson@3977
  2039
  KE_FreeCode(g_pCodeCache, code);
dvander@253
  2040
}
dvander@4013
  2041
dvander@4013
  2042
void
dvander@4013
  2043
JITX86::RegisterRuntime(BaseRuntime *rt)
dvander@4013
  2044
{
dvander@4013
  2045
  mutex_.AssertCurrentThreadOwns();
dvander@4013
  2046
  runtimes_.insert(rt);
dvander@4013
  2047
}
dvander@4013
  2048
dvander@4013
  2049
void
dvander@4013
  2050
JITX86::DeregisterRuntime(BaseRuntime *rt)
dvander@4013
  2051
{
dvander@4013
  2052
  mutex_.AssertCurrentThreadOwns();
dvander@4013
  2053
  runtimes_.erase(rt);
dvander@4013
  2054
}
dvander@4013
  2055
dvander@4013
  2056
void
dvander@4013
  2057
JITX86::PatchAllJumpsForTimeout()
dvander@4013
  2058
{
dvander@4013
  2059
  mutex_.AssertCurrentThreadOwns();
dvander@4013
  2060
  for (InlineList<BaseRuntime>::iterator iter = runtimes_.begin(); iter != runtimes_.end(); iter++) {
dvander@4013
  2061
    BaseRuntime *rt = *iter;
dvander@4013
  2062
    for (size_t i = 0; i < rt->NumJitFunctions(); i++) {
dvander@4013
  2063
      JitFunction *fun = rt->GetJitFunction(i);
dvander@4013
  2064
      uint8_t *base = reinterpret_cast<uint8_t *>(fun->GetEntryAddress());
dvander@4013
  2065
dvander@4013
  2066
      for (size_t j = 0; j < fun->NumLoopEdges(); j++) {
dvander@4013
  2067
        const LoopEdge &e = fun->GetLoopEdge(j);
dvander@4013
  2068
        int32_t diff = intptr_t(m_pJitTimeout) - intptr_t(base + e.offset);
dvander@4013
  2069
        *reinterpret_cast<int32_t *>(base + e.offset - 4) = diff;
dvander@4013
  2070
      }
dvander@4013
  2071
    }
dvander@4013
  2072
  }
dvander@4013
  2073
}
dvander@4013
  2074
dvander@4013
  2075
void
dvander@4013
  2076
JITX86::UnpatchAllJumpsFromTimeout()
dvander@4013
  2077
{
dvander@4013
  2078
  mutex_.AssertCurrentThreadOwns();
dvander@4013
  2079
  for (InlineList<BaseRuntime>::iterator iter = runtimes_.begin(); iter != runtimes_.end(); iter++) {
dvander@4013
  2080
    BaseRuntime *rt = *iter;
dvander@4013
  2081
    for (size_t i = 0; i < rt->NumJitFunctions(); i++) {
dvander@4013
  2082
      JitFunction *fun = rt->GetJitFunction(i);
dvander@4013
  2083
      uint8_t *base = reinterpret_cast<uint8_t *>(fun->GetEntryAddress());
dvander@4013
  2084
dvander@4013
  2085
      for (size_t j = 0; j < fun->NumLoopEdges(); j++) {
dvander@4013
  2086
        const LoopEdge &e = fun->GetLoopEdge(j);
dvander@4013
  2087
        *reinterpret_cast<int32_t *>(base + e.offset - 4) = e.disp32;
dvander@4013
  2088
      }
dvander@4013
  2089
    }
dvander@4013
  2090
  }
dvander@4013
  2091
}