Source code drop for the Actionscript virtual machine in the Adobe Flash Player for December 2013
272 lines
6.5 KiB
C++
272 lines
6.5 KiB
C++
/* -*- 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) */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "VMPI.h"
|
|
|
|
#include <sys/time.h>
|
|
#include <math.h>
|
|
#include <sys/mman.h>
|
|
#include "SymbianJITHeap.h"
|
|
#include <e32std.h>
|
|
#include <f32file.h>
|
|
#include <hal.h>
|
|
|
|
#define kMsecPerDay 86400000
|
|
#define kMsecPerHour 3600000
|
|
#define kMsecPerSecond 1000
|
|
#define kMsecPerMinute 60000
|
|
|
|
#define DIVCLOCK ( CLOCKS_PER_SEC / 1000 )
|
|
|
|
#define kMicroPerSec 1000000.0
|
|
|
|
/**
|
|
* Logging code
|
|
*/
|
|
|
|
void DebugTrace(const TDesC8& aBuffer)
|
|
{
|
|
RFile file;
|
|
RFs fs;
|
|
|
|
if (fs.Connect() != KErrNone)
|
|
{
|
|
return;
|
|
}
|
|
|
|
TInt err = file.Open(fs, _L("c:\\data\\vmpi_debug.txt"), EFileWrite);
|
|
if (err == KErrNotFound)
|
|
{
|
|
err = file.Create(fs, _L("c:\\data\\vmpi_debug.txt"), EFileWrite);
|
|
}
|
|
if (err == KErrNone)
|
|
{
|
|
TInt pos = 0;
|
|
file.Seek(ESeekEnd, pos);
|
|
file.Write(aBuffer);
|
|
file.Close();
|
|
}
|
|
|
|
fs.Close();
|
|
}
|
|
|
|
_LIT8(kNewline, "\n");
|
|
_LIT8(kNullString, "NULL STRING");
|
|
|
|
void DebugTraceString(const char* aString)
|
|
{
|
|
if (aString == NULL)
|
|
{
|
|
DebugTrace(kNullString);
|
|
}
|
|
else
|
|
{
|
|
TPtrC8 tstr((const TUint8*)aString);
|
|
DebugTrace(tstr);
|
|
DebugTrace(kNewline);
|
|
}
|
|
}
|
|
/**
|
|
* Logging code ends
|
|
*/
|
|
|
|
double VMPI_getLocalTimeOffset()
|
|
{
|
|
struct tm* t;
|
|
time_t current, localSec, globalSec;
|
|
|
|
// The win32 implementation ignores the passed in time
|
|
// and uses current time instead, so to keep similar
|
|
// behaviour we will do the same
|
|
time( ¤t );
|
|
|
|
t = localtime( ¤t );
|
|
localSec = mktime( t );
|
|
|
|
t = gmtime( ¤t );
|
|
globalSec = mktime( t );
|
|
|
|
return double( localSec - globalSec ) * 1000.0;
|
|
}
|
|
|
|
double VMPI_getDate()
|
|
{
|
|
struct timeval tv;
|
|
struct timezone tz; // Unused
|
|
|
|
gettimeofday(&tv, &tz);
|
|
double v = (tv.tv_sec + (tv.tv_usec/kMicroPerSec)) * kMsecPerSecond;
|
|
double ip;
|
|
::modf(v, &ip); // strip fractional part
|
|
return ip;
|
|
}
|
|
|
|
//time is passed in as milliseconds from UTC.
|
|
double VMPI_getDaylightSavingsTA(double newtime)
|
|
{
|
|
struct tm *broken_down_time;
|
|
|
|
//convert time from milliseconds
|
|
newtime=newtime/kMsecPerSecond;
|
|
|
|
time_t time_t_time=(time_t)newtime;
|
|
|
|
//pull out a struct tm
|
|
broken_down_time = localtime( &time_t_time );
|
|
|
|
if (!broken_down_time)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (broken_down_time->tm_isdst > 0)
|
|
{
|
|
//daylight saving is definitely in effect.
|
|
return kMsecPerHour;
|
|
}
|
|
|
|
//either daylight saving is not in effect, or we don't know (if tm_isdst is negative).
|
|
return 0;
|
|
}
|
|
|
|
uint64_t VMPI_getTime()
|
|
{
|
|
struct timeval tv;
|
|
::gettimeofday(&tv, NULL);
|
|
uint64_t result = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
|
|
return result;
|
|
}
|
|
|
|
void* VMPI_alloc(size_t size)
|
|
{
|
|
void* ptr = malloc(size);
|
|
if(ptr) memset(ptr, 0, size);
|
|
return ptr;
|
|
}
|
|
|
|
void VMPI_free(void* ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
size_t VMPI_size(void *ptr)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void VMPI_log(const char* message)
|
|
{
|
|
DebugTraceString(message);
|
|
}
|
|
|
|
bool VMPI_isMemoryProfilingEnabled()
|
|
{
|
|
//read the mmgc profiling option switch
|
|
const char *env = getenv("MMGC_PROFILE");
|
|
return (env && (VMPI_strncmp(env, "1", 1) == 0));
|
|
}
|
|
|
|
static SymbianJITHeap* symbianJITHeap = 0;
|
|
|
|
void *VMPI_allocateCodeMemory(size_t nbytes)
|
|
{
|
|
// Our custom SymbianJITHeap class can allocate only one page a time (=4k) per design.
|
|
// If NJ starts allocating more than 4k a time on ARM platforms, we have to change this,
|
|
// probably just to use RHeap directly (and manually page align the memory it returns).
|
|
|
|
// FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=571407
|
|
// This really should be a runtime check, not an assertion
|
|
AvmAssert( nbytes == VMPI_getVMPageSize() );
|
|
if(!symbianJITHeap)
|
|
{
|
|
symbianJITHeap = new SymbianJITHeap();
|
|
if(symbianJITHeap && !symbianJITHeap->IsInitialized())
|
|
{
|
|
delete symbianJITHeap;
|
|
symbianJITHeap = 0;
|
|
}
|
|
}
|
|
|
|
if(symbianJITHeap)
|
|
{
|
|
return symbianJITHeap->Alloc();
|
|
}
|
|
else
|
|
{
|
|
// FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=571407
|
|
// The documentation for VMPI_allocateCodeMemory states specifically that the
|
|
// function never returns NULL, so this is wrong and must be fixed.
|
|
// Being landed temporarily to sync various code lines.
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void VMPI_freeCodeMemory(void* address, size_t nbytes)
|
|
{
|
|
// FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=571407
|
|
// This really should be a runtime check, not an assertion
|
|
AvmAssert( nbytes == VMPI_getVMPageSize() );
|
|
if(symbianJITHeap)
|
|
{
|
|
symbianJITHeap->Free(address);
|
|
if(symbianJITHeap->GetNumAllocs() == 0)
|
|
{
|
|
delete symbianJITHeap;
|
|
symbianJITHeap = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void VMPI_makeCodeMemoryExecutable(void *address, size_t nbytes, bool makeItSo)
|
|
{
|
|
// See VMPI.h for documentation about the semantics of this method
|
|
|
|
// See PosixPortUtils.cpp for many useful comments about constraints
|
|
// that you may wish to implement in this function
|
|
|
|
(void)address;
|
|
(void)nbytes;
|
|
(void)makeItSo;
|
|
AvmAssert(!"Unimplemented: VMPI_freeCodeMemory");
|
|
}
|
|
|
|
const char *VMPI_getenv(const char *name)
|
|
{
|
|
return getenv(name);
|
|
}
|
|
|
|
uint64_t VMPI_getPerformanceFrequency()
|
|
{
|
|
TInt tickPeriod;
|
|
HAL::Get(HALData::EFastCounterFrequency, tickPeriod);
|
|
return (uint64_t)tickPeriod;
|
|
}
|
|
|
|
uint64_t VMPI_getPerformanceCounter()
|
|
{
|
|
// Alternative way:
|
|
/*
|
|
TTime t;
|
|
t.UniversalTime ();
|
|
TInt64 lt = t.Int64 ();
|
|
return (uint64_t) (lt & 0x7FFFFFFF);
|
|
*/
|
|
TUint32 counter = User::FastCounter();
|
|
return counter;
|
|
}
|
|
|
|
// Defined in GenericPortUtils.cpp to prevent them from being inlined below
|
|
extern void CallWithRegistersSaved2(void (*fn)(void* stackPointer, void* arg), void* arg, void* buf);
|
|
extern void CallWithRegistersSaved3(void (*fn)(void* stackPointer, void* arg), void* arg, void* buf);
|
|
|
|
void AVMPI_callWithRegistersSaved(void (*fn)(void* stackPointer, void* arg), void* arg)
|
|
{
|
|
jmp_buf buf;
|
|
VMPI_setjmpNoUnwind(buf); // Save registers
|
|
CallWithRegistersSaved2(fn, arg, &buf); // Computes the stack pointer, calls fn
|
|
CallWithRegistersSaved3(fn, &arg, &buf); // Probably prevents the previous call from being a tail call
|
|
}
|