2008-06-18 19:55:26 -07:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
|
|
|
* "License"); you may not use this file except in compliance with the License. You may obtain
|
|
|
|
* a copy of the License at http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
|
|
|
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
|
|
|
* language governing rights and limitations under the License.
|
|
|
|
*
|
|
|
|
* The Original Code is [Open Source Virtual Machine.]
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
|
|
|
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
|
|
|
* Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s): Adobe AS3 Team
|
2008-06-28 09:58:15 -07:00
|
|
|
* Andreas Gal <gal@mozilla.com>
|
2008-09-02 10:15:26 -07:00
|
|
|
* Asko Tontti <atontti@cc.hut.fi>
|
2008-06-18 19:55:26 -07:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
|
|
|
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
|
|
|
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
|
|
|
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
|
|
|
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
|
|
|
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
|
|
|
* above and replace them with the notice and other provisions required by the GPL or the
|
|
|
|
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
|
|
|
* under the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#ifndef avm_h___
|
|
|
|
#define avm_h___
|
|
|
|
|
|
|
|
#include <assert.h>
|
2008-06-18 20:29:01 -07:00
|
|
|
#include <string.h>
|
2008-06-19 10:47:58 -07:00
|
|
|
#include <stdio.h>
|
2008-07-10 07:03:45 -07:00
|
|
|
#include <stdlib.h>
|
2008-09-02 10:15:26 -07:00
|
|
|
|
2008-09-05 15:15:00 -07:00
|
|
|
#if defined(AVMPLUS_UNIX)
|
2008-09-02 10:15:26 -07:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#endif
|
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
#include "jstypes.h"
|
|
|
|
|
2008-08-10 00:39:18 -07:00
|
|
|
#define FASTCALL JS_FASTCALL
|
|
|
|
|
2008-09-02 11:43:55 -07:00
|
|
|
#if defined(JS_NO_FASTCALL)
|
|
|
|
#define NJ_NO_FASTCALL
|
|
|
|
#if defined(AVMPLUS_IA32)
|
|
|
|
#define SIMULATE_FASTCALL(lr, state_ptr, frag_ptr, func_addr) \
|
|
|
|
asm volatile( \
|
|
|
|
"call *%%esi" \
|
|
|
|
: "=a" (lr) \
|
|
|
|
: "c" (state_ptr), "d" (frag_ptr), "S" (func_addr) \
|
|
|
|
: "memory", "cc" \
|
|
|
|
);
|
|
|
|
#endif /* defined(AVMPLUS_IA32) */
|
|
|
|
#endif /* defined(JS_NO_FASTCALL) */
|
|
|
|
|
2008-09-02 10:28:14 -07:00
|
|
|
#ifdef WIN32
|
2008-07-10 15:39:51 -07:00
|
|
|
#include <windows.h>
|
2008-06-18 20:45:37 -07:00
|
|
|
#endif
|
|
|
|
|
2008-09-24 10:21:49 -07:00
|
|
|
#if defined(DEBUG) || defined(_MSC_VER) && _MSC_VER < 1400
|
2008-07-29 17:19:51 -07:00
|
|
|
#if !defined _DEBUG
|
2008-06-19 15:32:40 -07:00
|
|
|
#define _DEBUG
|
2008-07-29 17:19:51 -07:00
|
|
|
#endif
|
2008-09-24 10:21:49 -07:00
|
|
|
#define NJ_VERBOSE 1
|
|
|
|
#define NJ_PROFILE 1
|
2008-06-19 15:32:40 -07:00
|
|
|
#include <stdarg.h>
|
|
|
|
#endif
|
2008-06-19 10:47:58 -07:00
|
|
|
|
2008-08-28 19:07:49 -07:00
|
|
|
#ifdef _DEBUG
|
|
|
|
void NanoAssertFail();
|
|
|
|
#endif
|
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
#define AvmAssert(x) assert(x)
|
2008-06-19 10:47:58 -07:00
|
|
|
#define AvmAssertMsg(x, y)
|
|
|
|
#define AvmDebugLog(x) printf x
|
2008-06-18 19:55:26 -07:00
|
|
|
|
2008-07-10 06:52:34 -07:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
/*
|
|
|
|
* Can we just take a moment to think about what it means that MSVC doesn't have stdint.h in 2008?
|
|
|
|
* Thanks for your time.
|
|
|
|
*/
|
2008-07-10 17:25:57 -07:00
|
|
|
typedef JSUint8 uint8_t;
|
|
|
|
typedef JSInt8 int8_t;
|
2008-07-10 06:52:34 -07:00
|
|
|
typedef JSUint16 uint16_t;
|
2008-07-10 17:25:57 -07:00
|
|
|
typedef JSInt16 int16_t;
|
2008-07-10 06:52:34 -07:00
|
|
|
typedef JSUint32 uint32_t;
|
2008-07-10 13:58:08 -07:00
|
|
|
typedef JSInt32 int32_t;
|
2008-07-10 06:52:34 -07:00
|
|
|
typedef JSUint64 uint64_t;
|
2008-07-10 17:25:57 -07:00
|
|
|
typedef JSInt64 int64_t;
|
2008-07-10 07:18:22 -07:00
|
|
|
#else
|
|
|
|
#include <stdint.h>
|
|
|
|
#endif
|
2008-07-10 06:52:34 -07:00
|
|
|
|
2008-09-05 16:56:03 -07:00
|
|
|
#if defined(AVMPLUS_IA32)
|
|
|
|
#if defined(_MSC_VER)
|
2008-07-29 17:19:51 -07:00
|
|
|
__declspec(naked) static inline __int64 rdtsc()
|
|
|
|
{
|
|
|
|
__asm
|
|
|
|
{
|
|
|
|
rdtsc;
|
|
|
|
ret;
|
|
|
|
}
|
|
|
|
}
|
2008-09-05 16:56:03 -07:00
|
|
|
#elif defined(SOLARIS)
|
|
|
|
static inline unsigned long long rdtsc(void)
|
|
|
|
{
|
|
|
|
unsigned long long int x;
|
|
|
|
asm volatile (".byte 0x0f, 0x31" : "=A" (x));
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
#elif defined(__i386__)
|
2008-07-01 02:37:07 -07:00
|
|
|
static __inline__ unsigned long long rdtsc(void)
|
|
|
|
{
|
|
|
|
unsigned long long int x;
|
|
|
|
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
|
|
|
|
return x;
|
|
|
|
}
|
2008-09-05 16:56:03 -07:00
|
|
|
#endif /* compilers */
|
|
|
|
|
2008-07-01 02:37:07 -07:00
|
|
|
#elif defined(__x86_64__)
|
|
|
|
|
2008-08-18 12:41:55 -07:00
|
|
|
static __inline__ uint64_t rdtsc(void)
|
2008-07-01 02:37:07 -07:00
|
|
|
{
|
|
|
|
unsigned hi, lo;
|
|
|
|
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
|
2008-08-18 12:41:55 -07:00
|
|
|
return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 );
|
2008-07-01 02:37:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(__powerpc__)
|
|
|
|
|
|
|
|
typedef unsigned long long int unsigned long long;
|
|
|
|
|
|
|
|
static __inline__ unsigned long long rdtsc(void)
|
|
|
|
{
|
|
|
|
unsigned long long int result=0;
|
|
|
|
unsigned long int upper, lower,tmp;
|
|
|
|
__asm__ volatile(
|
|
|
|
"0: \n"
|
|
|
|
"\tmftbu %0 \n"
|
|
|
|
"\tmftb %1 \n"
|
|
|
|
"\tmftbu %2 \n"
|
|
|
|
"\tcmpw %2,%0 \n"
|
|
|
|
"\tbne 0b \n"
|
|
|
|
: "=r"(upper),"=r"(lower),"=r"(tmp)
|
|
|
|
);
|
|
|
|
result = upper;
|
|
|
|
result = result<<32;
|
|
|
|
result = result|lower;
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2008-09-05 16:56:03 -07:00
|
|
|
#endif /* architecture */
|
2008-07-01 02:37:07 -07:00
|
|
|
|
2008-07-08 17:16:51 -07:00
|
|
|
struct JSContext;
|
|
|
|
|
|
|
|
namespace nanojit
|
|
|
|
{
|
|
|
|
class Fragment;
|
|
|
|
|
2008-07-27 16:18:53 -07:00
|
|
|
enum ExitType {
|
2008-08-08 15:26:31 -07:00
|
|
|
BRANCH_EXIT,
|
|
|
|
LOOP_EXIT,
|
|
|
|
NESTED_EXIT,
|
2008-08-11 15:40:04 -07:00
|
|
|
MISMATCH_EXIT,
|
|
|
|
OOM_EXIT,
|
2008-08-19 23:28:13 -07:00
|
|
|
OVERFLOW_EXIT
|
2008-07-27 16:18:53 -07:00
|
|
|
};
|
|
|
|
|
2008-07-08 17:16:51 -07:00
|
|
|
struct SideExit
|
|
|
|
{
|
2008-07-14 19:12:50 -07:00
|
|
|
intptr_t ip_adj;
|
2008-07-30 00:15:07 -07:00
|
|
|
intptr_t sp_adj;
|
|
|
|
intptr_t rp_adj;
|
|
|
|
Fragment *target;
|
2008-07-08 17:16:51 -07:00
|
|
|
Fragment *from;
|
2008-07-30 00:15:07 -07:00
|
|
|
int32_t calldepth;
|
|
|
|
uint32 numGlobalSlots;
|
2008-08-12 20:18:29 -07:00
|
|
|
uint32 numStackSlots;
|
2008-08-26 01:00:53 -07:00
|
|
|
uint32 numStackSlotsBelowCurrentFrame;
|
2008-07-08 17:16:51 -07:00
|
|
|
uint8 *typeMap;
|
2008-07-27 16:18:53 -07:00
|
|
|
ExitType exitType;
|
2008-07-08 17:16:51 -07:00
|
|
|
#if defined NJ_VERBOSE
|
|
|
|
uint32_t sid;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
class LIns;
|
|
|
|
|
|
|
|
struct GuardRecord
|
|
|
|
{
|
|
|
|
Fragment *target;
|
|
|
|
Fragment *from;
|
|
|
|
void *jmp;
|
|
|
|
void *origTarget;
|
|
|
|
SideExit *exit;
|
|
|
|
GuardRecord *outgoing;
|
|
|
|
GuardRecord *next;
|
|
|
|
LIns *guard;
|
|
|
|
int32_t calldepth;
|
|
|
|
#if defined NJ_VERBOSE
|
|
|
|
uint32_t compileNbr;
|
|
|
|
uint32_t sid;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
#define GuardRecordSize(g) sizeof(GuardRecord)
|
2008-07-09 00:13:35 -07:00
|
|
|
#define SideExitSize(e) sizeof(SideExit)
|
2008-07-08 17:16:51 -07:00
|
|
|
}
|
|
|
|
|
2008-09-23 18:12:53 -07:00
|
|
|
class GC;
|
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
class GCObject
|
2008-06-18 20:45:37 -07:00
|
|
|
{
|
2008-08-11 16:01:21 -07:00
|
|
|
public:
|
2008-09-23 18:12:53 -07:00
|
|
|
inline void*
|
|
|
|
operator new(size_t size, GC* gc)
|
|
|
|
{
|
|
|
|
return calloc(1, size);
|
|
|
|
}
|
|
|
|
|
2008-08-11 16:01:21 -07:00
|
|
|
static void operator delete (void *gcObject)
|
|
|
|
{
|
|
|
|
free(gcObject);
|
|
|
|
}
|
2008-06-18 20:45:37 -07:00
|
|
|
};
|
|
|
|
|
2008-08-11 16:01:21 -07:00
|
|
|
#define MMGC_SUBCLASS_DECL : public GCObject
|
2008-07-15 13:06:05 -07:00
|
|
|
|
2008-08-11 16:01:21 -07:00
|
|
|
class GCFinalizedObject : public GCObject
|
2008-06-18 21:23:53 -07:00
|
|
|
{
|
2008-08-11 16:01:21 -07:00
|
|
|
public:
|
|
|
|
static void operator delete (void *gcObject)
|
|
|
|
{
|
|
|
|
free(gcObject);
|
|
|
|
}
|
2008-06-18 21:23:53 -07:00
|
|
|
};
|
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
class GCHeap
|
2008-06-18 21:11:15 -07:00
|
|
|
{
|
2008-06-19 10:47:58 -07:00
|
|
|
public:
|
2008-06-19 15:32:40 -07:00
|
|
|
int32_t kNativePageSize;
|
|
|
|
|
|
|
|
GCHeap()
|
2008-06-19 10:47:58 -07:00
|
|
|
{
|
2008-09-02 10:15:26 -07:00
|
|
|
#if defined _SC_PAGE_SIZE
|
|
|
|
kNativePageSize = sysconf(_SC_PAGE_SIZE);
|
|
|
|
#else
|
2008-06-19 10:47:58 -07:00
|
|
|
kNativePageSize = 4096; // @todo: what is this?
|
2008-09-02 10:15:26 -07:00
|
|
|
#endif
|
2008-06-19 10:47:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void*
|
|
|
|
Alloc(uint32_t pages)
|
|
|
|
{
|
2008-07-10 15:39:51 -07:00
|
|
|
#ifdef XP_WIN
|
2008-09-02 10:15:26 -07:00
|
|
|
return VirtualAlloc(NULL,
|
|
|
|
pages * kNativePageSize,
|
|
|
|
MEM_COMMIT | MEM_RESERVE,
|
|
|
|
PAGE_EXECUTE_READWRITE);
|
2008-09-05 15:15:00 -07:00
|
|
|
#elif defined AVMPLUS_UNIX
|
2008-09-02 10:15:26 -07:00
|
|
|
/**
|
|
|
|
* Don't use normal heap with mprotect+PROT_EXEC for executable code.
|
|
|
|
* SELinux and friends don't allow this.
|
|
|
|
*/
|
|
|
|
return mmap(NULL,
|
|
|
|
pages * kNativePageSize,
|
|
|
|
PROT_READ | PROT_WRITE | PROT_EXEC,
|
|
|
|
MAP_PRIVATE | MAP_ANON,
|
|
|
|
-1,
|
|
|
|
0);
|
2008-07-10 15:39:51 -07:00
|
|
|
#else
|
2008-09-02 10:15:26 -07:00
|
|
|
return valloc(pages * kNativePageSize);
|
2008-07-10 15:39:51 -07:00
|
|
|
#endif
|
2008-06-19 10:47:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2008-09-02 10:15:26 -07:00
|
|
|
Free(void* p, uint32_t pages)
|
2008-06-19 10:47:58 -07:00
|
|
|
{
|
2008-07-10 15:39:51 -07:00
|
|
|
#ifdef XP_WIN
|
2008-09-02 10:15:26 -07:00
|
|
|
VirtualFree(p, 0, MEM_RELEASE);
|
2008-09-05 15:15:00 -07:00
|
|
|
#elif defined AVMPLUS_UNIX
|
2008-09-05 16:56:03 -07:00
|
|
|
#if defined SOLARIS
|
|
|
|
munmap((char*)p, pages * kNativePageSize);
|
|
|
|
#else
|
2008-09-02 10:15:26 -07:00
|
|
|
munmap(p, pages * kNativePageSize);
|
2008-09-05 16:56:03 -07:00
|
|
|
#endif
|
2008-07-10 15:39:51 -07:00
|
|
|
#else
|
2008-06-20 14:26:43 -07:00
|
|
|
free(p);
|
2008-07-10 15:39:51 -07:00
|
|
|
#endif
|
2008-06-19 10:47:58 -07:00
|
|
|
}
|
|
|
|
|
2008-06-18 21:11:15 -07:00
|
|
|
};
|
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
class GC
|
2008-06-18 21:11:15 -07:00
|
|
|
{
|
2008-06-19 10:47:58 -07:00
|
|
|
static GCHeap heap;
|
|
|
|
|
|
|
|
public:
|
2008-06-19 15:32:40 -07:00
|
|
|
static inline void*
|
|
|
|
Alloc(uint32_t bytes)
|
|
|
|
{
|
2008-06-20 14:26:43 -07:00
|
|
|
return calloc(1, bytes);
|
2008-06-19 15:32:40 -07:00
|
|
|
}
|
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
static inline void
|
|
|
|
Free(void* p)
|
|
|
|
{
|
2008-06-20 14:26:43 -07:00
|
|
|
free(p);
|
2008-06-19 10:47:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline GCHeap*
|
|
|
|
GetGCHeap()
|
|
|
|
{
|
|
|
|
return &heap;
|
|
|
|
}
|
2008-06-18 21:11:15 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
#define DWB(x) x
|
2008-06-19 15:32:40 -07:00
|
|
|
#define DRCWB(x) x
|
2008-06-18 21:11:15 -07:00
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
#define MMGC_MEM_TYPE(x)
|
|
|
|
|
|
|
|
typedef int FunctionID;
|
|
|
|
|
2008-06-18 20:45:37 -07:00
|
|
|
namespace avmplus
|
|
|
|
{
|
2008-06-29 20:56:06 -07:00
|
|
|
struct InterpState
|
2008-06-18 21:23:53 -07:00
|
|
|
{
|
2008-08-13 17:12:55 -07:00
|
|
|
void* sp; /* native stack pointer, stack[0] is spbase[0] */
|
|
|
|
void* rp; /* call stack pointer */
|
|
|
|
void* gp; /* global frame pointer */
|
|
|
|
JSContext *cx; /* current VM context handle */
|
|
|
|
void* eos; /* first unusable word after the native stack */
|
|
|
|
void* eor; /* first unusable word after the call stack */
|
2008-09-19 18:45:57 -07:00
|
|
|
nanojit::GuardRecord* lastTreeExitGuard; /* guard we exited on during a tree call */
|
|
|
|
nanojit::GuardRecord* lastTreeCallGuard; /* guard we want to grow from if the tree
|
|
|
|
call exit guard mismatched */
|
2008-06-18 21:23:53 -07:00
|
|
|
};
|
|
|
|
|
2008-06-19 15:32:40 -07:00
|
|
|
class String
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
2008-06-30 15:33:41 -07:00
|
|
|
typedef class String AvmString;
|
|
|
|
|
2008-06-19 15:32:40 -07:00
|
|
|
class StringNullTerminatedUTF8
|
|
|
|
{
|
|
|
|
const char* cstr;
|
|
|
|
|
|
|
|
public:
|
|
|
|
StringNullTerminatedUTF8(GC* gc, String* s)
|
|
|
|
{
|
|
|
|
cstr = strdup((const char*)s);
|
|
|
|
}
|
|
|
|
|
|
|
|
~StringNullTerminatedUTF8()
|
|
|
|
{
|
|
|
|
free((void*)cstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
|
|
|
const char* c_str()
|
|
|
|
{
|
|
|
|
return cstr;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef String* Stringp;
|
|
|
|
|
|
|
|
class AvmConfiguration
|
2008-06-19 10:47:58 -07:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
AvmConfiguration() {
|
|
|
|
memset(this, 0, sizeof(AvmConfiguration));
|
2008-06-19 15:32:40 -07:00
|
|
|
#ifdef DEBUG
|
2008-08-20 10:15:42 -07:00
|
|
|
verbose = getenv("TRACEMONKEY") && strstr(getenv("TRACEMONKEY"), "verbose");
|
2008-06-19 15:32:40 -07:00
|
|
|
verbose_addrs = 1;
|
|
|
|
verbose_exits = 1;
|
|
|
|
verbose_live = 1;
|
|
|
|
show_stats = 1;
|
|
|
|
#endif
|
2008-07-30 21:40:21 -07:00
|
|
|
tree_opt = 0;
|
2008-06-19 10:47:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t tree_opt:1;
|
2008-06-19 15:32:40 -07:00
|
|
|
uint32_t quiet_opt:1;
|
|
|
|
uint32_t verbose:1;
|
|
|
|
uint32_t verbose_addrs:1;
|
|
|
|
uint32_t verbose_live:1;
|
|
|
|
uint32_t verbose_exits:1;
|
|
|
|
uint32_t show_stats:1;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const int kstrconst_emptyString = 0;
|
|
|
|
|
|
|
|
class AvmInterpreter
|
|
|
|
{
|
|
|
|
class Labels {
|
|
|
|
public:
|
2008-07-07 02:47:40 -07:00
|
|
|
const char* format(const void* ip)
|
2008-06-19 15:32:40 -07:00
|
|
|
{
|
|
|
|
static char buf[33];
|
|
|
|
sprintf(buf, "%p", ip);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Labels _labels;
|
|
|
|
public:
|
|
|
|
Labels* labels;
|
|
|
|
|
|
|
|
AvmInterpreter()
|
|
|
|
{
|
|
|
|
labels = &_labels;
|
|
|
|
}
|
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
};
|
|
|
|
|
2008-06-19 15:32:40 -07:00
|
|
|
class AvmConsole
|
2008-06-18 20:29:01 -07:00
|
|
|
{
|
2008-06-19 10:47:58 -07:00
|
|
|
public:
|
2008-06-19 15:32:40 -07:00
|
|
|
AvmConsole& operator<<(const char* s)
|
|
|
|
{
|
2008-07-18 14:13:31 -07:00
|
|
|
fprintf(stdout, "%s", s);
|
2008-06-19 15:32:40 -07:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class AvmCore
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AvmInterpreter interp;
|
|
|
|
AvmConsole console;
|
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
static AvmConfiguration config;
|
|
|
|
static GC* gc;
|
2008-06-19 15:32:40 -07:00
|
|
|
static String* k_str[];
|
2008-08-22 12:21:27 -07:00
|
|
|
static bool sse2_available;
|
2008-06-19 15:32:40 -07:00
|
|
|
|
|
|
|
static inline bool
|
|
|
|
use_sse2()
|
2008-06-19 10:47:58 -07:00
|
|
|
{
|
2008-08-22 12:21:27 -07:00
|
|
|
return sse2_available;
|
2008-06-19 10:47:58 -07:00
|
|
|
}
|
|
|
|
|
2008-06-19 15:32:40 -07:00
|
|
|
static inline bool
|
|
|
|
quiet_opt()
|
|
|
|
{
|
|
|
|
return config.quiet_opt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
verbose()
|
|
|
|
{
|
|
|
|
return config.verbose;
|
|
|
|
}
|
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
static inline GC*
|
|
|
|
GetGC()
|
|
|
|
{
|
|
|
|
return gc;
|
|
|
|
}
|
2008-06-19 15:32:40 -07:00
|
|
|
|
|
|
|
static inline String* newString(const char* cstr) {
|
|
|
|
return (String*)strdup(cstr);
|
|
|
|
}
|
2008-09-05 16:05:13 -07:00
|
|
|
|
|
|
|
static inline void freeString(String* str) {
|
|
|
|
return free((char*)str);
|
|
|
|
}
|
2008-06-18 20:29:01 -07:00
|
|
|
};
|
2008-06-19 15:32:40 -07:00
|
|
|
|
2008-06-18 20:29:01 -07:00
|
|
|
class OSDep
|
|
|
|
{
|
2008-06-19 10:47:58 -07:00
|
|
|
public:
|
|
|
|
static inline void
|
|
|
|
getDate()
|
|
|
|
{
|
|
|
|
}
|
2008-06-18 20:29:01 -07:00
|
|
|
};
|
2008-06-18 19:55:26 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The List<T> template implements a simple List, which can
|
|
|
|
* be templated to support different types.
|
|
|
|
*
|
|
|
|
* Elements can be added to the end, modified in the middle,
|
|
|
|
* but no holes are allowed. That is for set(n, v) to work
|
|
|
|
* size() > n
|
|
|
|
*
|
|
|
|
* Note that [] operators are provided and you can violate the
|
|
|
|
* set properties using these operators, if you want a real
|
|
|
|
* list dont use the [] operators, if you want a general purpose
|
|
|
|
* array use the [] operators.
|
|
|
|
*/
|
|
|
|
|
|
|
|
enum ListElementType { LIST_NonGCObjects, LIST_GCObjects };
|
|
|
|
|
|
|
|
template <typename T, ListElementType kElementType>
|
|
|
|
class List
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum { kInitialCapacity = 128 };
|
|
|
|
|
2008-06-19 19:19:39 -07:00
|
|
|
List(GC *_gc, uint32_t _capacity=kInitialCapacity) : data(NULL), len(0), capacity(0)
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
|
|
|
ensureCapacity(_capacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
~List()
|
|
|
|
{
|
|
|
|
//clear();
|
|
|
|
destroy();
|
|
|
|
// zero out in case we are part of an RCObject
|
|
|
|
len = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void destroy()
|
|
|
|
{
|
|
|
|
if (data)
|
2008-06-23 18:00:03 -07:00
|
|
|
free(data);
|
2008-06-18 19:55:26 -07:00
|
|
|
}
|
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
// 'this' steals the guts of 'that' and 'that' gets reset.
|
|
|
|
void FASTCALL become(List& that)
|
|
|
|
{
|
|
|
|
this->destroy();
|
|
|
|
|
|
|
|
this->data = that.data;
|
|
|
|
this->len = that.len;
|
2008-07-16 23:11:17 -07:00
|
|
|
this->capacity = that.capacity;
|
2008-06-19 10:47:58 -07:00
|
|
|
|
|
|
|
that.data = 0;
|
|
|
|
that.len = 0;
|
2008-07-16 23:11:17 -07:00
|
|
|
that.capacity = 0;
|
2008-06-19 10:47:58 -07:00
|
|
|
}
|
2008-06-18 19:55:26 -07:00
|
|
|
uint32_t FASTCALL add(T value)
|
|
|
|
{
|
2008-06-18 21:23:53 -07:00
|
|
|
if (len >= capacity) {
|
2008-06-18 19:55:26 -07:00
|
|
|
grow();
|
|
|
|
}
|
|
|
|
wb(len++, value);
|
|
|
|
return len-1;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool isEmpty() const
|
|
|
|
{
|
|
|
|
return len == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline uint32_t size() const
|
|
|
|
{
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline T get(uint32_t index) const
|
|
|
|
{
|
|
|
|
AvmAssert(index < len);
|
2008-06-18 21:23:53 -07:00
|
|
|
return *(T*)(data + index);
|
2008-06-18 19:55:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void FASTCALL set(uint32_t index, T value)
|
|
|
|
{
|
2008-06-18 21:23:53 -07:00
|
|
|
AvmAssert(index < capacity);
|
2008-06-18 19:55:26 -07:00
|
|
|
if (index >= len)
|
|
|
|
{
|
|
|
|
len = index+1;
|
|
|
|
}
|
2008-06-18 21:23:53 -07:00
|
|
|
AvmAssert(len <= capacity);
|
2008-06-18 19:55:26 -07:00
|
|
|
wb(index, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void clear()
|
|
|
|
{
|
|
|
|
zero_range(0, len);
|
|
|
|
len = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int FASTCALL indexOf(T value) const
|
|
|
|
{
|
|
|
|
for(uint32_t i=0; i<len; i++)
|
|
|
|
if (get(i) == value)
|
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int FASTCALL lastIndexOf(T value) const
|
|
|
|
{
|
|
|
|
for(int32_t i=len-1; i>=0; i--)
|
|
|
|
if (get(i) == value)
|
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline T last()
|
|
|
|
{
|
|
|
|
return get(len-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
T FASTCALL removeLast()
|
|
|
|
{
|
|
|
|
if(isEmpty())
|
|
|
|
return undef_list_val();
|
|
|
|
T t = get(len-1);
|
|
|
|
set(len-1, undef_list_val());
|
|
|
|
len--;
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline T operator[](uint32_t index) const
|
|
|
|
{
|
2008-06-18 21:23:53 -07:00
|
|
|
AvmAssert(index < capacity);
|
2008-06-18 19:55:26 -07:00
|
|
|
return get(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FASTCALL ensureCapacity(uint32_t cap)
|
|
|
|
{
|
2008-06-18 21:23:53 -07:00
|
|
|
if (cap > capacity) {
|
2008-06-18 19:55:26 -07:00
|
|
|
if (data == NULL) {
|
2008-07-01 02:37:07 -07:00
|
|
|
data = (T*)calloc(1, factor(cap));
|
2008-06-18 19:55:26 -07:00
|
|
|
} else {
|
|
|
|
data = (T*)realloc(data, factor(cap));
|
2008-06-18 21:23:53 -07:00
|
|
|
zero_range(capacity, cap - capacity);
|
2008-06-18 19:55:26 -07:00
|
|
|
}
|
2008-06-18 21:23:53 -07:00
|
|
|
capacity = cap;
|
2008-06-18 19:55:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FASTCALL insert(uint32_t index, T value, uint32_t count = 1)
|
|
|
|
{
|
|
|
|
AvmAssert(index <= len);
|
|
|
|
AvmAssert(count > 0);
|
|
|
|
ensureCapacity(len+count);
|
|
|
|
memmove(data + index + count, data + index, factor(len - index));
|
|
|
|
wbzm(index, index+count, value);
|
|
|
|
len += count;
|
|
|
|
}
|
|
|
|
|
|
|
|
T FASTCALL removeAt(uint32_t index)
|
|
|
|
{
|
|
|
|
T old = get(index);
|
|
|
|
// dec the refcount on the one we're removing
|
|
|
|
wb(index, undef_list_val());
|
|
|
|
memmove(data + index, data + index + 1, factor(len - index - 1));
|
|
|
|
len--;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void FASTCALL grow()
|
|
|
|
{
|
|
|
|
// growth is fast at first, then slows at larger list sizes.
|
|
|
|
uint32_t newMax = 0;
|
2008-06-18 21:23:53 -07:00
|
|
|
const uint32_t curMax = capacity;
|
2008-06-18 19:55:26 -07:00
|
|
|
if (curMax == 0)
|
|
|
|
newMax = kInitialCapacity;
|
|
|
|
else if(curMax > 15)
|
|
|
|
newMax = curMax * 3/2;
|
|
|
|
else
|
|
|
|
newMax = curMax * 2;
|
|
|
|
|
|
|
|
ensureCapacity(newMax);
|
|
|
|
}
|
|
|
|
|
2008-07-07 02:59:20 -07:00
|
|
|
inline void do_wb_nongc(T* slot, T value)
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
|
|
|
*slot = value;
|
|
|
|
}
|
|
|
|
|
2008-07-07 02:59:20 -07:00
|
|
|
inline void do_wb_gc(GCObject** slot, const GCObject** value)
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
2008-06-18 21:23:53 -07:00
|
|
|
*slot = (GCObject*)*value;
|
2008-06-18 19:55:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void FASTCALL wb(uint32_t index, T value)
|
|
|
|
{
|
2008-06-18 21:23:53 -07:00
|
|
|
AvmAssert(index < capacity);
|
2008-06-18 19:55:26 -07:00
|
|
|
AvmAssert(data != NULL);
|
2008-06-18 21:23:53 -07:00
|
|
|
T* slot = &data[index];
|
2008-07-15 15:58:43 -07:00
|
|
|
do_wb_nongc(slot, value);
|
2008-06-18 19:55:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// multiple wb call with the same value, and assumption that existing value is all zero bits,
|
|
|
|
// like
|
|
|
|
// for (uint32_t u = index; u < index_end; ++u)
|
|
|
|
// wb(u, value);
|
|
|
|
void FASTCALL wbzm(uint32_t index, uint32_t index_end, T value)
|
|
|
|
{
|
2008-06-18 21:23:53 -07:00
|
|
|
AvmAssert(index < capacity);
|
|
|
|
AvmAssert(index_end <= capacity);
|
2008-06-18 19:55:26 -07:00
|
|
|
AvmAssert(index < index_end);
|
|
|
|
AvmAssert(data != NULL);
|
|
|
|
T* slot = data + index;
|
2008-07-15 15:58:43 -07:00
|
|
|
for ( ; index < index_end; ++index, ++slot)
|
|
|
|
do_wb_nongc(slot, value);
|
2008-06-18 19:55:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline uint32_t factor(uint32_t index) const
|
|
|
|
{
|
|
|
|
return index * sizeof(T);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FASTCALL zero_range(uint32_t _first, uint32_t _count)
|
|
|
|
{
|
|
|
|
memset(data + _first, 0, factor(_count));
|
|
|
|
}
|
|
|
|
|
|
|
|
// stuff that needs specialization based on the type
|
|
|
|
static inline T undef_list_val();
|
|
|
|
|
|
|
|
private:
|
|
|
|
List(const List& toCopy); // unimplemented
|
|
|
|
void operator=(const List& that); // unimplemented
|
|
|
|
|
|
|
|
// ------------------------ DATA SECTION BEGIN
|
|
|
|
private:
|
|
|
|
T* data;
|
|
|
|
uint32_t len;
|
2008-06-18 21:23:53 -07:00
|
|
|
uint32_t capacity;
|
2008-06-18 19:55:26 -07:00
|
|
|
// ------------------------ DATA SECTION END
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
// stuff that needs specialization based on the type
|
|
|
|
template<typename T, ListElementType kElementType>
|
|
|
|
/* static */ inline T List<T, kElementType>::undef_list_val() { return T(0); }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The SortedMap<K,T> template implements an object that
|
|
|
|
* maps keys to values. The keys are sorted
|
|
|
|
* from smallest to largest in the map. Time of operations
|
|
|
|
* is as follows:
|
|
|
|
* put() is O(1) if the key is higher than any existing
|
|
|
|
* key; O(logN) if the key already exists,
|
|
|
|
* and O(N) otherwise.
|
|
|
|
* get() is an O(logN) binary search.
|
|
|
|
*
|
|
|
|
* no duplicates are allowed.
|
|
|
|
*/
|
|
|
|
template <class K, class T, ListElementType valType>
|
2008-09-23 18:12:53 -07:00
|
|
|
class SortedMap : public GCObject
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum { kInitialCapacity= 64 };
|
|
|
|
|
|
|
|
SortedMap(GC* gc, int _capacity=kInitialCapacity)
|
|
|
|
: keys(gc, _capacity), values(gc, _capacity)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isEmpty() const
|
|
|
|
{
|
|
|
|
return keys.size() == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int size() const
|
|
|
|
{
|
|
|
|
return keys.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear()
|
|
|
|
{
|
|
|
|
keys.clear();
|
|
|
|
values.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void destroy()
|
|
|
|
{
|
|
|
|
keys.destroy();
|
|
|
|
values.destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
T put(K k, T v)
|
|
|
|
{
|
|
|
|
if (keys.size() == 0 || k > keys.last())
|
|
|
|
{
|
|
|
|
keys.add(k);
|
|
|
|
values.add(v);
|
|
|
|
return (T)v;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i = find(k);
|
|
|
|
if (i >= 0)
|
|
|
|
{
|
|
|
|
T old = values[i];
|
|
|
|
keys.set(i, k);
|
|
|
|
values.set(i, v);
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
i = -i - 1; // recover the insertion point
|
|
|
|
AvmAssert(keys.size() != (uint32_t)i);
|
|
|
|
keys.insert(i, k);
|
|
|
|
values.insert(i, v);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
T get(K k) const
|
|
|
|
{
|
|
|
|
int i = find(k);
|
|
|
|
return i >= 0 ? values[i] : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool get(K k, T& v) const
|
|
|
|
{
|
|
|
|
int i = find(k);
|
|
|
|
if (i >= 0)
|
|
|
|
{
|
|
|
|
v = values[i];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool containsKey(K k) const
|
|
|
|
{
|
|
|
|
int i = find(k);
|
|
|
|
return (i >= 0) ? true : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
T remove(K k)
|
|
|
|
{
|
|
|
|
int i = find(k);
|
|
|
|
return removeAt(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
T removeAt(int i)
|
|
|
|
{
|
|
|
|
T old = values.removeAt(i);
|
|
|
|
keys.removeAt(i);
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
T removeFirst() { return isEmpty() ? (T)0 : removeAt(0); }
|
|
|
|
T removeLast() { return isEmpty() ? (T)0 : removeAt(keys.size()-1); }
|
|
|
|
T first() const { return isEmpty() ? (T)0 : values[0]; }
|
|
|
|
T last() const { return isEmpty() ? (T)0 : values[keys.size()-1]; }
|
|
|
|
|
|
|
|
K firstKey() const { return isEmpty() ? 0 : keys[0]; }
|
|
|
|
K lastKey() const { return isEmpty() ? 0 : keys[keys.size()-1]; }
|
|
|
|
|
|
|
|
// iterator
|
|
|
|
T at(int i) const { return values[i]; }
|
|
|
|
K keyAt(int i) const { return keys[i]; }
|
|
|
|
|
|
|
|
int findNear(K k) const {
|
|
|
|
int i = find(k);
|
|
|
|
return i >= 0 ? i : -i-2;
|
|
|
|
}
|
|
|
|
protected:
|
|
|
|
List<K, LIST_NonGCObjects> keys;
|
|
|
|
List<T, valType> values;
|
|
|
|
|
|
|
|
int find(K k) const
|
|
|
|
{
|
|
|
|
int lo = 0;
|
|
|
|
int hi = keys.size()-1;
|
|
|
|
|
|
|
|
while (lo <= hi)
|
|
|
|
{
|
|
|
|
int i = (lo + hi)/2;
|
|
|
|
K m = keys[i];
|
|
|
|
if (k > m)
|
|
|
|
lo = i + 1;
|
|
|
|
else if (k < m)
|
|
|
|
hi = i - 1;
|
|
|
|
else
|
|
|
|
return i; // key found
|
|
|
|
}
|
|
|
|
return -(lo + 1); // key not found, low is the insertion point
|
|
|
|
}
|
|
|
|
};
|
2008-07-15 13:06:05 -07:00
|
|
|
|
|
|
|
#define GCSortedMap SortedMap
|
2008-06-18 20:29:01 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Bit vectors are an efficent method of keeping True/False information
|
|
|
|
* on a set of items or conditions. Class BitSet provides functions
|
|
|
|
* to manipulate individual bits in the vector.
|
|
|
|
*
|
|
|
|
* Since most vectors are rather small an array of longs is used by
|
|
|
|
* default to house the value of the bits. If more bits are needed
|
|
|
|
* then an array is allocated dynamically outside of this object.
|
|
|
|
*
|
|
|
|
* This object is not optimized for a fixed sized bit vector
|
|
|
|
* it instead allows for dynamically growing the bit vector.
|
|
|
|
*/
|
|
|
|
class BitSet
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum { kUnit = 8*sizeof(long),
|
|
|
|
kDefaultCapacity = 4 };
|
|
|
|
|
|
|
|
BitSet()
|
|
|
|
{
|
|
|
|
capacity = kDefaultCapacity;
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
~BitSet()
|
|
|
|
{
|
|
|
|
if (capacity > kDefaultCapacity)
|
2008-09-23 18:12:53 -07:00
|
|
|
free(bits.ptr);
|
2008-06-18 20:29:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
if (capacity > kDefaultCapacity)
|
|
|
|
for(int i=0; i<capacity; i++)
|
|
|
|
bits.ptr[i] = 0;
|
|
|
|
else
|
|
|
|
for(int i=0; i<capacity; i++)
|
|
|
|
bits.ar[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set(GC *gc, int bitNbr)
|
|
|
|
{
|
|
|
|
int index = bitNbr / kUnit;
|
|
|
|
int bit = bitNbr % kUnit;
|
|
|
|
if (index >= capacity)
|
|
|
|
grow(gc, index+1);
|
|
|
|
|
|
|
|
if (capacity > kDefaultCapacity)
|
|
|
|
bits.ptr[index] |= (1<<bit);
|
|
|
|
else
|
|
|
|
bits.ar[index] |= (1<<bit);
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear(int bitNbr)
|
|
|
|
{
|
|
|
|
int index = bitNbr / kUnit;
|
|
|
|
int bit = bitNbr % kUnit;
|
|
|
|
if (index < capacity)
|
|
|
|
{
|
|
|
|
if (capacity > kDefaultCapacity)
|
|
|
|
bits.ptr[index] &= ~(1<<bit);
|
|
|
|
else
|
|
|
|
bits.ar[index] &= ~(1<<bit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool get(int bitNbr) const
|
|
|
|
{
|
|
|
|
int index = bitNbr / kUnit;
|
|
|
|
int bit = bitNbr % kUnit;
|
|
|
|
bool value = false;
|
|
|
|
if (index < capacity)
|
|
|
|
{
|
|
|
|
if (capacity > kDefaultCapacity)
|
|
|
|
value = ( bits.ptr[index] & (1<<bit) ) ? true : false;
|
|
|
|
else
|
|
|
|
value = ( bits.ar[index] & (1<<bit) ) ? true : false;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Grow the array until at least newCapacity big
|
|
|
|
void grow(GC *gc, int newCapacity)
|
|
|
|
{
|
|
|
|
// create vector that is 2x bigger than requested
|
|
|
|
newCapacity *= 2;
|
|
|
|
//MEMTAG("BitVector::Grow - long[]");
|
2008-07-01 02:37:07 -07:00
|
|
|
long* newBits = (long*)calloc(1, newCapacity * sizeof(long));
|
|
|
|
//memset(newBits, 0, newCapacity * sizeof(long));
|
2008-06-18 20:29:01 -07:00
|
|
|
|
|
|
|
// copy the old one
|
|
|
|
if (capacity > kDefaultCapacity)
|
|
|
|
for(int i=0; i<capacity; i++)
|
|
|
|
newBits[i] = bits.ptr[i];
|
|
|
|
else
|
|
|
|
for(int i=0; i<capacity; i++)
|
|
|
|
newBits[i] = bits.ar[i];
|
|
|
|
|
|
|
|
// in with the new out with the old
|
|
|
|
if (capacity > kDefaultCapacity)
|
2008-07-01 02:37:07 -07:00
|
|
|
free(bits.ptr);
|
2008-06-18 20:29:01 -07:00
|
|
|
|
|
|
|
bits.ptr = newBits;
|
|
|
|
capacity = newCapacity;
|
|
|
|
}
|
|
|
|
|
|
|
|
// by default we use the array, but if the vector
|
|
|
|
// size grows beyond kDefaultCapacity we allocate
|
|
|
|
// space dynamically.
|
|
|
|
int capacity;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
long ar[kDefaultCapacity];
|
|
|
|
long* ptr;
|
|
|
|
}
|
|
|
|
bits;
|
|
|
|
};
|
2008-06-18 19:55:26 -07:00
|
|
|
}
|
|
|
|
|
2008-06-18 20:29:01 -07:00
|
|
|
#endif
|