2009-07-10 12:58:34 -07:00
|
|
|
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
|
|
|
|
/* ***** 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.
|
2008-06-18 19:55:26 -07:00
|
|
|
*
|
|
|
|
* 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>
|
2009-07-10 12:58:34 -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.
|
|
|
|
*
|
2008-06-18 19:55:26 -07:00
|
|
|
***** 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"
|
Bug 479258: Don't define <stdint.h> types in public headers. r=brendan
On systems that don't have <stdint.h> (i.e., Microsoft, which is
tragically underfunded and cannot spare the resources necessary to
provide and support this header: http://tinyurl.com/absoh8),
SpiderMonkey header files should not introduce definitions for these
types, as doing so may conflict with client code's attempts to provide
its own definitions for these types.
Instead, have jstypes.h define JS{Int,Uint}{8,16,32,64,Ptr} types
based on configure's results, and make jsstdint.h into an uninstalled
header for use within SpiderMonkey that does whatever is necessary to
get definitions for the <stdint.h> types.
The changes to make the appropriate SpiderMonkey .cpp files #include
"jsstdint.h" explicitly are in a separate patch, for ease of review.
2009-03-18 11:38:15 -07:00
|
|
|
#include "jsstdint.h"
|
2008-06-18 19:55:26 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
#if !defined(AVMPLUS_LITTLE_ENDIAN) && !defined(AVMPLUS_BIG_ENDIAN)
|
|
|
|
#ifdef IS_BIG_ENDIAN
|
|
|
|
#define AVMPLUS_BIG_ENDIAN
|
|
|
|
#else
|
|
|
|
#define AVMPLUS_LITTLE_ENDIAN
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
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
|
|
|
|
|
2009-07-15 12:31:26 -07:00
|
|
|
#if defined(DEBUG) || defined(MOZ_NO_VARADIC_MACROS)
|
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)
|
2009-07-10 12:58:34 -07:00
|
|
|
#define AvmAssertMsg(x, y)
|
2008-06-19 10:47:58 -07:00
|
|
|
#define AvmDebugLog(x) printf x
|
2008-06-18 19:55:26 -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;
|
|
|
|
|
2009-07-16 11:50:27 -07:00
|
|
|
namespace MMgc {
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
class GC;
|
2009-07-10 12:58:34 -07:00
|
|
|
|
|
|
|
class GCObject
|
2008-06-19 10:47:58 -07:00
|
|
|
{
|
2008-11-07 15:52:51 -08:00
|
|
|
public:
|
|
|
|
inline void*
|
|
|
|
operator new(size_t size, GC* gc)
|
|
|
|
{
|
|
|
|
return calloc(1, size);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
static void operator delete (void *gcObject)
|
|
|
|
{
|
2009-07-10 12:58:34 -07:00
|
|
|
free(gcObject);
|
2008-11-07 15:52:51 -08:00
|
|
|
}
|
|
|
|
};
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
#define MMGC_SUBCLASS_DECL : public avmplus::GCObject
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
class GCFinalizedObject : public GCObject
|
2008-06-19 15:32:40 -07:00
|
|
|
{
|
2008-11-07 15:52:51 -08:00
|
|
|
public:
|
|
|
|
static void operator delete (void *gcObject)
|
|
|
|
{
|
2009-07-10 12:58:34 -07:00
|
|
|
free(gcObject);
|
2008-11-07 15:52:51 -08:00
|
|
|
}
|
|
|
|
};
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
class GCHeap
|
2008-06-19 10:47:58 -07:00
|
|
|
{
|
2008-11-07 15:52:51 -08:00
|
|
|
public:
|
|
|
|
int32_t kNativePageSize;
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
GCHeap()
|
|
|
|
{
|
|
|
|
#if defined _SC_PAGE_SIZE
|
|
|
|
kNativePageSize = sysconf(_SC_PAGE_SIZE);
|
|
|
|
#else
|
|
|
|
kNativePageSize = 4096; // @todo: what is this?
|
|
|
|
#endif
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
inline void*
|
2009-07-10 12:58:34 -07:00
|
|
|
Alloc(uint32_t pages)
|
2008-11-07 15:52:51 -08:00
|
|
|
{
|
|
|
|
#ifdef XP_WIN
|
2009-07-10 12:58:34 -07:00
|
|
|
return VirtualAlloc(NULL,
|
2008-11-07 15:52:51 -08:00
|
|
|
pages * kNativePageSize,
|
2009-07-10 12:58:34 -07:00
|
|
|
MEM_COMMIT | MEM_RESERVE,
|
2008-11-07 15:52:51 -08:00
|
|
|
PAGE_EXECUTE_READWRITE);
|
|
|
|
#elif defined AVMPLUS_UNIX
|
|
|
|
/**
|
|
|
|
* Don't use normal heap with mprotect+PROT_EXEC for executable code.
|
|
|
|
* SELinux and friends don't allow this.
|
|
|
|
*/
|
2009-07-10 12:58:34 -07:00
|
|
|
return mmap(NULL,
|
2008-11-07 15:52:51 -08:00
|
|
|
pages * kNativePageSize,
|
|
|
|
PROT_READ | PROT_WRITE | PROT_EXEC,
|
|
|
|
MAP_PRIVATE | MAP_ANON,
|
|
|
|
-1,
|
|
|
|
0);
|
|
|
|
#else
|
2009-07-10 12:58:34 -07:00
|
|
|
return valloc(pages * kNativePageSize);
|
2008-11-07 15:52:51 -08:00
|
|
|
#endif
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
inline void
|
|
|
|
Free(void* p, uint32_t pages)
|
|
|
|
{
|
|
|
|
#ifdef XP_WIN
|
|
|
|
VirtualFree(p, 0, MEM_RELEASE);
|
|
|
|
#elif defined AVMPLUS_UNIX
|
|
|
|
#if defined SOLARIS
|
2009-07-10 12:58:34 -07:00
|
|
|
munmap((char*)p, pages * kNativePageSize);
|
2008-11-07 15:52:51 -08:00
|
|
|
#else
|
2009-07-10 12:58:34 -07:00
|
|
|
munmap(p, pages * kNativePageSize);
|
2008-11-07 15:52:51 -08:00
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
free(p);
|
|
|
|
#endif
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
};
|
2009-07-10 12:58:34 -07:00
|
|
|
|
|
|
|
class GC
|
2008-06-19 10:47:58 -07:00
|
|
|
{
|
2008-11-07 15:52:51 -08:00
|
|
|
static GCHeap heap;
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
public:
|
2009-07-10 12:58:34 -07:00
|
|
|
/**
|
|
|
|
* flags to be passed as second argument to alloc
|
|
|
|
*/
|
|
|
|
enum AllocFlags
|
|
|
|
{
|
|
|
|
kZero=1,
|
|
|
|
kContainsPointers=2,
|
|
|
|
kFinalize=4,
|
|
|
|
kRCObject=8
|
|
|
|
};
|
2008-12-10 17:25:46 -08:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
static inline void*
|
2008-12-10 17:25:46 -08:00
|
|
|
Alloc(uint32_t bytes, int flags=kZero)
|
2008-11-07 15:52:51 -08:00
|
|
|
{
|
2008-12-10 17:25:46 -08:00
|
|
|
if (flags & kZero)
|
2008-11-07 15:52:51 -08:00
|
|
|
return calloc(1, bytes);
|
2008-12-10 17:25:46 -08:00
|
|
|
else
|
|
|
|
return malloc(bytes);
|
2008-11-07 15:52:51 -08:00
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
static inline void
|
|
|
|
Free(void* p)
|
|
|
|
{
|
|
|
|
free(p);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
static inline GCHeap*
|
|
|
|
GetGCHeap()
|
|
|
|
{
|
|
|
|
return &heap;
|
|
|
|
}
|
|
|
|
};
|
2009-07-16 11:50:27 -07:00
|
|
|
}
|
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-10-13 13:29:18 -07:00
|
|
|
#define WB(gc, container, addr, value) do { *(addr) = (value); } while(0)
|
|
|
|
#define WBRC(gc, container, addr, value) do { *(addr) = (value); } while(0)
|
2008-06-18 21:11:15 -07:00
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
#define MMGC_MEM_TYPE(x)
|
|
|
|
|
2009-07-15 09:34:17 -07:00
|
|
|
#define VMPI_strlen strlen
|
|
|
|
#define VMPI_strcat strcat
|
|
|
|
#define VMPI_strcpy strcpy
|
|
|
|
#define VMPI_sprintf sprintf
|
|
|
|
|
2009-07-15 16:50:01 -07:00
|
|
|
extern void VMPI_setPageProtection(void *address,
|
|
|
|
size_t size,
|
|
|
|
bool executableFlag,
|
|
|
|
bool writeableFlag);
|
|
|
|
|
2009-07-16 11:50:27 -07:00
|
|
|
namespace avmplus {
|
|
|
|
|
|
|
|
using namespace MMgc;
|
|
|
|
|
2008-11-07 15:52:51 -08:00
|
|
|
typedef int FunctionID;
|
2008-06-19 10:47:58 -07:00
|
|
|
|
2009-07-15 16:50:01 -07:00
|
|
|
extern void AvmLog(char const *msg, ...);
|
|
|
|
|
2008-06-19 15:32:40 -07:00
|
|
|
class String
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
2008-06-30 15:33:41 -07:00
|
|
|
typedef class String AvmString;
|
2009-07-10 12:58:34 -07:00
|
|
|
|
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;
|
|
|
|
|
2008-12-10 17:19:40 -08:00
|
|
|
class Config
|
2008-06-19 10:47:58 -07:00
|
|
|
{
|
|
|
|
public:
|
2008-12-10 17:19:40 -08:00
|
|
|
Config() {
|
|
|
|
memset(this, 0, sizeof(Config));
|
2008-06-19 15:32:40 -07:00
|
|
|
#ifdef DEBUG
|
2009-06-24 20:32:00 -07:00
|
|
|
verbose = false;
|
2008-06-19 15:32:40 -07:00
|
|
|
verbose_addrs = 1;
|
|
|
|
verbose_exits = 1;
|
|
|
|
verbose_live = 1;
|
|
|
|
show_stats = 1;
|
|
|
|
#endif
|
2008-06-19 10:47:58 -07:00
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
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;
|
2008-12-10 17:19:40 -08:00
|
|
|
|
2009-06-10 15:21:10 -07:00
|
|
|
#if defined (AVMPLUS_IA32)
|
2009-07-10 12:58:34 -07:00
|
|
|
// Whether or not we can use SSE2 instructions and conditional moves.
|
2009-03-20 15:53:33 -07:00
|
|
|
bool sse2;
|
|
|
|
bool use_cmov;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (AVMPLUS_ARM)
|
2009-05-09 13:14:38 -07:00
|
|
|
// Whether or not to generate VFP instructions.
|
2009-03-20 15:53:33 -07:00
|
|
|
# if defined (NJ_FORCE_SOFTFLOAT)
|
|
|
|
static const bool vfp = false;
|
|
|
|
# else
|
|
|
|
bool vfp;
|
|
|
|
# endif
|
|
|
|
|
2009-05-09 13:14:38 -07:00
|
|
|
// The ARM architecture version.
|
|
|
|
# if defined (NJ_FORCE_ARM_ARCH_VERSION)
|
|
|
|
static const unsigned int arch = NJ_FORCE_ARM_ARCH_VERSION;
|
2009-03-20 15:53:33 -07:00
|
|
|
# else
|
2009-05-09 13:14:38 -07:00
|
|
|
unsigned int arch;
|
2009-03-20 15:53:33 -07:00
|
|
|
# endif
|
2009-05-09 13:14:38 -07:00
|
|
|
|
|
|
|
// Support for Thumb, even if it isn't used by nanojit. This is used to
|
|
|
|
// determine whether or not to generate interworking branches.
|
|
|
|
# if defined (NJ_FORCE_NO_ARM_THUMB)
|
|
|
|
static const bool thumb = false;
|
|
|
|
# else
|
|
|
|
bool thumb;
|
|
|
|
# endif
|
|
|
|
|
|
|
|
// Support for Thumb2, even if it isn't used by nanojit. This is used to
|
|
|
|
// determine whether or not to use some of the ARMv6T2 instructions.
|
|
|
|
# if defined (NJ_FORCE_NO_ARM_THUMB2)
|
|
|
|
static const bool thumb2 = false;
|
|
|
|
# else
|
|
|
|
bool thumb2;
|
|
|
|
# endif
|
|
|
|
|
2009-03-20 15:53:33 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (NJ_FORCE_SOFTFLOAT)
|
|
|
|
static const bool soft_float = true;
|
|
|
|
#else
|
|
|
|
bool soft_float;
|
|
|
|
#endif
|
2008-06-19 15:32:40 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
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
|
|
|
};
|
2009-07-10 12:58:34 -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;
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-12-10 17:19:40 -08:00
|
|
|
static Config config;
|
2008-06-19 10:47:58 -07:00
|
|
|
static GC* gc;
|
2008-06-19 15:32:40 -07:00
|
|
|
static String* k_str[];
|
|
|
|
|
2009-06-10 15:21:10 -07:00
|
|
|
#ifdef AVMPLUS_IA32
|
2008-06-19 15:32:40 -07:00
|
|
|
static inline bool
|
|
|
|
use_sse2()
|
2008-06-19 10:47:58 -07:00
|
|
|
{
|
2008-12-10 17:19:40 -08:00
|
|
|
return config.sse2;
|
2008-06-19 10:47:58 -07:00
|
|
|
}
|
2009-06-10 15:21:10 -07:00
|
|
|
#endif
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-09-26 20:39:21 -07:00
|
|
|
static inline bool
|
|
|
|
use_cmov()
|
|
|
|
{
|
2009-06-10 15:21:10 -07:00
|
|
|
#ifdef AVMPLUS_IA32
|
2008-12-10 17:19:40 -08:00
|
|
|
return config.use_cmov;
|
2009-06-10 15:21:10 -07:00
|
|
|
#else
|
2009-07-10 12:58:34 -07:00
|
|
|
return true;
|
2008-12-11 13:50:55 -08:00
|
|
|
#endif
|
2009-06-10 15:21:10 -07:00
|
|
|
}
|
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*
|
2009-07-10 12:58:34 -07:00
|
|
|
GetGC()
|
2008-06-19 10:47:58 -07:00
|
|
|
{
|
|
|
|
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
|
|
|
};
|
2009-07-10 12:58:34 -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.
|
2009-07-10 12:58:34 -07:00
|
|
|
*
|
|
|
|
* Elements can be added to the end, modified in the middle,
|
2008-06-18 19:55:26 -07:00
|
|
|
* 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
|
2009-07-10 12:58:34 -07:00
|
|
|
* array use the [] operators.
|
2008-06-18 19:55:26 -07:00
|
|
|
*/
|
|
|
|
|
2008-11-14 12:46:35 -08:00
|
|
|
enum ListElementType {
|
|
|
|
LIST_NonGCObjects = 0,
|
|
|
|
LIST_GCObjects = 1,
|
|
|
|
LIST_RCObjects = 2
|
|
|
|
};
|
2008-06-18 19:55:26 -07:00
|
|
|
|
|
|
|
template <typename T, ListElementType kElementType>
|
|
|
|
class List
|
|
|
|
{
|
|
|
|
public:
|
2009-07-10 12:58:34 -07:00
|
|
|
enum { kInitialCapacity = 128 };
|
2008-06-18 19:55:26 -07:00
|
|
|
|
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);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
~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-11-14 12:46:35 -08:00
|
|
|
|
|
|
|
const T *getData() const { return data; }
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
// 'this' steals the guts of 'that' and 'that' gets reset.
|
2009-08-06 13:40:05 -07:00
|
|
|
void become(List& that)
|
2008-06-19 10:47:58 -07:00
|
|
|
{
|
|
|
|
this->destroy();
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
this->data = that.data;
|
|
|
|
this->len = that.len;
|
2009-07-10 12:58:34 -07:00
|
|
|
this->capacity = that.capacity;
|
|
|
|
|
2008-06-19 10:47:58 -07:00
|
|
|
that.data = 0;
|
|
|
|
that.len = 0;
|
2009-07-10 12:58:34 -07:00
|
|
|
that.capacity = 0;
|
2008-06-19 10:47:58 -07:00
|
|
|
}
|
2009-08-06 13:40:05 -07:00
|
|
|
uint32_t add(T value)
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
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;
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
inline bool isEmpty() const
|
|
|
|
{
|
|
|
|
return len == 0;
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
inline uint32_t size() const
|
|
|
|
{
|
|
|
|
return len;
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
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
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-08-06 13:40:05 -07:00
|
|
|
void set(uint32_t index, T value)
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
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);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-14 12:46:35 -08:00
|
|
|
void add(const List<T, kElementType>& l)
|
|
|
|
{
|
|
|
|
ensureCapacity(len+l.size());
|
|
|
|
// FIXME: make RCObject version
|
|
|
|
AvmAssert(kElementType != LIST_RCObjects);
|
|
|
|
arraycopy(l.getData(), 0, data, len, l.size());
|
|
|
|
len += l.size();
|
|
|
|
}
|
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
inline void clear()
|
|
|
|
{
|
|
|
|
zero_range(0, len);
|
|
|
|
len = 0;
|
|
|
|
}
|
|
|
|
|
2009-08-06 13:40:05 -07:00
|
|
|
int indexOf(T value) const
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
|
|
|
for(uint32_t i=0; i<len; i++)
|
|
|
|
if (get(i) == value)
|
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-08-06 13:40:05 -07:00
|
|
|
int lastIndexOf(T value) const
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
|
|
|
for(int32_t i=len-1; i>=0; i--)
|
|
|
|
if (get(i) == value)
|
|
|
|
return i;
|
|
|
|
return -1;
|
2009-07-10 12:58:34 -07:00
|
|
|
}
|
|
|
|
|
2008-11-14 12:46:35 -08:00
|
|
|
inline T last() const
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
|
|
|
return get(len-1);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-08-06 13:40:05 -07:00
|
|
|
T removeLast()
|
2009-07-10 12:58:34 -07:00
|
|
|
{
|
2008-06-18 19:55:26 -07:00
|
|
|
if(isEmpty())
|
|
|
|
return undef_list_val();
|
|
|
|
T t = get(len-1);
|
|
|
|
set(len-1, undef_list_val());
|
|
|
|
len--;
|
|
|
|
return t;
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
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);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-08-06 13:40:05 -07:00
|
|
|
void ensureCapacity(uint32_t cap)
|
2009-07-10 12:58:34 -07:00
|
|
|
{
|
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
|
|
|
}
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-08-06 13:40:05 -07:00
|
|
|
void insert(uint32_t index, T value, uint32_t count = 1)
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-08-06 13:40:05 -07:00
|
|
|
T removeAt(uint32_t index)
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
private:
|
2009-08-06 13:40:05 -07:00
|
|
|
void grow()
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
|
|
|
// 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;
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
ensureCapacity(newMax);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-11-14 12:46:35 -08:00
|
|
|
void arraycopy(const T* src, int srcStart, T* dst, int dstStart, int nbr)
|
|
|
|
{
|
|
|
|
// we have 2 cases, either closing a gap or opening it.
|
|
|
|
if ((src == dst) && (srcStart > dstStart) )
|
|
|
|
{
|
|
|
|
for(int i=0; i<nbr; i++)
|
2009-07-10 12:58:34 -07:00
|
|
|
dst[i+dstStart] = src[i+srcStart];
|
2008-11-14 12:46:35 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(int i=nbr-1; i>=0; i--)
|
|
|
|
dst[i+dstStart] = src[i+srcStart];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-07 02:59:20 -07:00
|
|
|
inline void do_wb_nongc(T* slot, T value)
|
2009-07-10 12:58:34 -07:00
|
|
|
{
|
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)
|
2009-07-10 12:58:34 -07:00
|
|
|
{
|
2008-06-18 21:23:53 -07:00
|
|
|
*slot = (GCObject*)*value;
|
2008-06-18 19:55:26 -07:00
|
|
|
}
|
|
|
|
|
2009-08-06 13:40:05 -07:00
|
|
|
void wb(uint32_t index, T value)
|
2009-07-10 12:58:34 -07:00
|
|
|
{
|
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);
|
2009-08-06 13:40:05 -07:00
|
|
|
void wbzm(uint32_t index, uint32_t index_end, T value)
|
2009-07-10 12:58:34 -07:00
|
|
|
{
|
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
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
inline uint32_t factor(uint32_t index) const
|
|
|
|
{
|
|
|
|
return index * sizeof(T);
|
|
|
|
}
|
|
|
|
|
2009-08-06 13:40:05 -07:00
|
|
|
void zero_range(uint32_t _first, uint32_t _count)
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
|
|
|
memset(data + _first, 0, factor(_count));
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
// 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
|
2009-07-10 12:58:34 -07:00
|
|
|
template<typename T, ListElementType kElementType>
|
2008-06-18 19:55:26 -07:00
|
|
|
/* 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
|
2009-07-10 12:58:34 -07:00
|
|
|
* 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
|
2008-06-18 19:55:26 -07:00
|
|
|
* key; O(logN) if the key already exists,
|
2009-07-10 12:58:34 -07:00
|
|
|
* and O(N) otherwise.
|
2008-06-18 19:55:26 -07:00
|
|
|
* get() is an O(logN) binary search.
|
2009-07-10 12:58:34 -07:00
|
|
|
*
|
2008-06-18 19:55:26 -07:00
|
|
|
* 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 };
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
SortedMap(GC* gc, int _capacity=kInitialCapacity)
|
|
|
|
: keys(gc, _capacity), values(gc, _capacity)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isEmpty() const
|
|
|
|
{
|
|
|
|
return keys.size() == 0;
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
int size() const
|
|
|
|
{
|
|
|
|
return keys.size();
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
void clear()
|
|
|
|
{
|
|
|
|
keys.clear();
|
|
|
|
values.clear();
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
void destroy()
|
|
|
|
{
|
|
|
|
keys.destroy();
|
|
|
|
values.destroy();
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
T put(K k, T v)
|
|
|
|
{
|
2009-07-10 12:58:34 -07:00
|
|
|
if (keys.size() == 0 || k > keys.last())
|
2008-06-18 19:55:26 -07:00
|
|
|
{
|
|
|
|
keys.add(k);
|
|
|
|
values.add(v);
|
|
|
|
return (T)v;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-07-10 12:58:34 -07:00
|
|
|
int i = find(k);
|
2008-06-18 19:55:26 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
T get(K k) const
|
|
|
|
{
|
|
|
|
int i = find(k);
|
|
|
|
return i >= 0 ? values[i] : 0;
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
bool get(K k, T& v) const
|
|
|
|
{
|
|
|
|
int i = find(k);
|
|
|
|
if (i >= 0)
|
|
|
|
{
|
|
|
|
v = values[i];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
bool containsKey(K k) const
|
|
|
|
{
|
|
|
|
int i = find(k);
|
|
|
|
return (i >= 0) ? true : false;
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
T remove(K k)
|
|
|
|
{
|
|
|
|
int i = find(k);
|
|
|
|
return removeAt(i);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
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]; }
|
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
// iterator
|
2008-06-18 19:55:26 -07:00
|
|
|
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;
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 19:55:26 -07:00
|
|
|
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
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 20:29:01 -07:00
|
|
|
/**
|
2009-07-10 12:58:34 -07:00
|
|
|
* Bit vectors are an efficent method of keeping True/False information
|
|
|
|
* on a set of items or conditions. Class BitSet provides functions
|
2008-06-18 20:29:01 -07:00
|
|
|
* 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
|
2009-07-10 12:58:34 -07:00
|
|
|
* then an array is allocated dynamically outside of this object.
|
|
|
|
*
|
2008-06-18 20:29:01 -07:00
|
|
|
* This object is not optimized for a fixed sized bit vector
|
|
|
|
* it instead allows for dynamically growing the bit vector.
|
2009-07-10 12:58:34 -07:00
|
|
|
*/
|
2008-06-18 20:29:01 -07:00
|
|
|
class BitSet
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum { kUnit = 8*sizeof(long),
|
|
|
|
kDefaultCapacity = 4 };
|
|
|
|
|
|
|
|
BitSet()
|
|
|
|
{
|
|
|
|
capacity = kDefaultCapacity;
|
|
|
|
reset();
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2008-06-18 20:29:01 -07:00
|
|
|
~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;
|
|
|
|
}
|
|
|
|
|
2009-07-30 14:23:35 -07:00
|
|
|
void set(GC *gc, int bitNbr)
|
2008-06-18 20:29:01 -07:00
|
|
|
{
|
|
|
|
int index = bitNbr / kUnit;
|
|
|
|
int bit = bitNbr % kUnit;
|
|
|
|
if (index >= capacity)
|
2009-07-30 14:23:35 -07:00
|
|
|
grow(gc, index+1);
|
2008-06-18 20:29:01 -07:00
|
|
|
|
|
|
|
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
|
2009-07-30 14:23:35 -07:00
|
|
|
void grow(GC *gc, int newCapacity)
|
2008-06-18 20:29:01 -07:00
|
|
|
{
|
2009-07-10 12:58:34 -07:00
|
|
|
// create vector that is 2x bigger than requested
|
2008-06-18 20:29:01 -07:00
|
|
|
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
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
// copy the old one
|
2008-06-18 20:29:01 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
// by default we use the array, but if the vector
|
2008-06-18 20:29:01 -07:00
|
|
|
// 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
|