mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
Compare commits
12 commits
master
...
compressio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
205b5f35bd | ||
|
|
d1535b2088 | ||
|
|
a771419d0c | ||
|
|
dfba6d6bd5 | ||
|
|
e80a414017 | ||
|
|
af79291159 | ||
|
|
0eaf50714b | ||
|
|
b51839b7b9 | ||
|
|
73e5e66b4a | ||
|
|
bcdbaa4bac | ||
|
|
31cf4200f9 | ||
|
|
e3fe51cf14 |
13 changed files with 369 additions and 81 deletions
|
|
@ -144,13 +144,14 @@ ELSEIF (${ESCARGOT_HOST} STREQUAL "tizen_obs")
|
||||||
SET (ESCARGOT_CXXFLAGS ${ESCARGOT_CXXFLAGS} ${DLOG_CFLAGS_OTHER})
|
SET (ESCARGOT_CXXFLAGS ${ESCARGOT_CXXFLAGS} ${DLOG_CFLAGS_OTHER})
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_COMPRESSIBLE_STRING)
|
IF (ESCARGOT_SOURCE_COMPRESSION)
|
||||||
|
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_COMPRESSIBLE_STRING)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
IF (ESCARGOT_SMALL_CONFIG)
|
IF (ESCARGOT_SMALL_CONFIG)
|
||||||
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DLZ4_MEMORY_USAGE=16 -DLZ4_HEAPMODE=1)
|
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DLZ4_MEMORY_USAGE=16 -DLZ4_HEAPMODE=1)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_RELOADABLE_STRING)
|
|
||||||
|
|
||||||
IF (ESCARGOT_CODE_CACHE)
|
IF (ESCARGOT_CODE_CACHE)
|
||||||
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_CODE_CACHE)
|
SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_CODE_CACHE)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
|
||||||
|
|
@ -511,6 +511,12 @@ StringRef* StringRef::createFromUTF8(const char* s, size_t len, bool maybeASCII)
|
||||||
return toRef(String::fromUTF8(s, len, maybeASCII));
|
return toRef(String::fromUTF8(s, len, maybeASCII));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringRef* StringRef::createFromUTF8(ContextRef* context, const char* src, size_t len, bool maybeASCII)
|
||||||
|
{
|
||||||
|
auto s = utf8StringToUTF16String(src, len);
|
||||||
|
return toRef(new UTF16StringFinalizer(toImpl(context), std::move(s)));
|
||||||
|
}
|
||||||
|
|
||||||
StringRef* StringRef::createFromUTF16(const char16_t* s, size_t len)
|
StringRef* StringRef::createFromUTF16(const char16_t* s, size_t len)
|
||||||
{
|
{
|
||||||
return toRef(new UTF16String(s, len));
|
return toRef(new UTF16String(s, len));
|
||||||
|
|
@ -521,6 +527,11 @@ StringRef* StringRef::createFromLatin1(const unsigned char* s, size_t len)
|
||||||
return toRef(new Latin1String(s, len));
|
return toRef(new Latin1String(s, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringRef* StringRef::createFromLatin1(ContextRef* context, const unsigned char* s, size_t len)
|
||||||
|
{
|
||||||
|
return toRef(new Latin1StringFinalizer(toImpl(context), s, len));
|
||||||
|
}
|
||||||
|
|
||||||
StringRef* StringRef::createExternalFromASCII(const char* s, size_t len)
|
StringRef* StringRef::createExternalFromASCII(const char* s, size_t len)
|
||||||
{
|
{
|
||||||
return toRef(new ASCIIStringFromExternalMemory(s, len));
|
return toRef(new ASCIIStringFromExternalMemory(s, len));
|
||||||
|
|
@ -1101,6 +1112,11 @@ void VMInstanceRef::unregisterErrorCreationCallback()
|
||||||
toImpl(this)->unregisterErrorCreationCallback();
|
toImpl(this)->unregisterErrorCreationCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t VMInstanceRef::validSourceSize()
|
||||||
|
{
|
||||||
|
return toImpl(this)->validSourceSize();
|
||||||
|
}
|
||||||
|
|
||||||
void VMInstanceRef::registerPromiseHook(PromiseHook promiseHook)
|
void VMInstanceRef::registerPromiseHook(PromiseHook promiseHook)
|
||||||
{
|
{
|
||||||
toImpl(this)->registerPromiseHook([](ExecutionState& state, VMInstance::PromiseHookType type, PromiseObject* promise, const Value& parent, void* hook) -> void {
|
toImpl(this)->registerPromiseHook([](ExecutionState& state, VMInstance::PromiseHookType type, PromiseObject* promise, const Value& parent, void* hook) -> void {
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,11 @@ public:
|
||||||
return *m_holder;
|
return *m_holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isInitialized() const
|
||||||
|
{
|
||||||
|
return m_holder != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initHolderSpace(T* initialValue)
|
void initHolderSpace(T* initialValue)
|
||||||
{
|
{
|
||||||
|
|
@ -639,6 +644,8 @@ public:
|
||||||
void registerErrorCreationCallback(ErrorCreationCallback cb);
|
void registerErrorCreationCallback(ErrorCreationCallback cb);
|
||||||
void unregisterErrorCreationCallback();
|
void unregisterErrorCreationCallback();
|
||||||
|
|
||||||
|
size_t validSourceSize();
|
||||||
|
|
||||||
enum PromiseHookType {
|
enum PromiseHookType {
|
||||||
Init,
|
Init,
|
||||||
Resolve,
|
Resolve,
|
||||||
|
|
@ -859,8 +866,11 @@ public:
|
||||||
return createFromUTF8(str, N - 1);
|
return createFromUTF8(str, N - 1);
|
||||||
}
|
}
|
||||||
static StringRef* createFromUTF8(const char* s, size_t byteLength, bool maybeASCII = true);
|
static StringRef* createFromUTF8(const char* s, size_t byteLength, bool maybeASCII = true);
|
||||||
|
static StringRef* createFromUTF8(ContextRef* context, const char* s, size_t len, bool maybeASCII);
|
||||||
|
|
||||||
static StringRef* createFromUTF16(const char16_t* s, size_t stringLength);
|
static StringRef* createFromUTF16(const char16_t* s, size_t stringLength);
|
||||||
static StringRef* createFromLatin1(const unsigned char* s, size_t stringLength);
|
static StringRef* createFromLatin1(const unsigned char* s, size_t stringLength);
|
||||||
|
static StringRef* createFromLatin1(ContextRef* context, const unsigned char* s, size_t len);
|
||||||
|
|
||||||
static StringRef* createExternalFromASCII(const char* s, size_t stringLength);
|
static StringRef* createExternalFromASCII(const char* s, size_t stringLength);
|
||||||
static StringRef* createExternalFromLatin1(const unsigned char* s, size_t stringLength);
|
static StringRef* createExternalFromLatin1(const unsigned char* s, size_t stringLength);
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include "CompressibleString.h"
|
#include "CompressibleString.h"
|
||||||
#include "runtime/Context.h"
|
#include "runtime/Context.h"
|
||||||
#include "runtime/VMInstance.h"
|
#include "runtime/VMInstance.h"
|
||||||
|
#include "runtime/Global.h"
|
||||||
#include "lz4.h"
|
#include "lz4.h"
|
||||||
|
|
||||||
namespace Escargot {
|
namespace Escargot {
|
||||||
|
|
@ -33,7 +34,9 @@ void* CompressibleString::operator new(size_t size)
|
||||||
static MAY_THREAD_LOCAL GC_descr descr;
|
static MAY_THREAD_LOCAL GC_descr descr;
|
||||||
if (!typeInited) {
|
if (!typeInited) {
|
||||||
GC_word obj_bitmap[GC_BITMAP_SIZE(CompressibleString)] = { 0 };
|
GC_word obj_bitmap[GC_BITMAP_SIZE(CompressibleString)] = { 0 };
|
||||||
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(CompressibleString, m_bufferData.buffer));
|
||||||
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(CompressibleString, m_vmInstance));
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(CompressibleString, m_vmInstance));
|
||||||
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(CompressibleString, m_compressedData));
|
||||||
descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(CompressibleString));
|
descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(CompressibleString));
|
||||||
typeInited = true;
|
typeInited = true;
|
||||||
}
|
}
|
||||||
|
|
@ -44,6 +47,7 @@ CompressibleString::CompressibleString(VMInstance* instance)
|
||||||
: String()
|
: String()
|
||||||
, m_isOwnerMayFreed(false)
|
, m_isOwnerMayFreed(false)
|
||||||
, m_isCompressed(false)
|
, m_isCompressed(false)
|
||||||
|
, m_refCount(0)
|
||||||
, m_vmInstance(instance)
|
, m_vmInstance(instance)
|
||||||
, m_lastUsedTickcount(fastTickCount())
|
, m_lastUsedTickcount(fastTickCount())
|
||||||
{
|
{
|
||||||
|
|
@ -53,14 +57,18 @@ CompressibleString::CompressibleString(VMInstance* instance)
|
||||||
v.push_back(this);
|
v.push_back(this);
|
||||||
GC_REGISTER_FINALIZER_NO_ORDER(this, [](void* obj, void*) {
|
GC_REGISTER_FINALIZER_NO_ORDER(this, [](void* obj, void*) {
|
||||||
CompressibleString* self = (CompressibleString*)obj;
|
CompressibleString* self = (CompressibleString*)obj;
|
||||||
|
ASSERT(self->refCount() == 0);
|
||||||
|
size_t strLength = self->m_bufferData.length * (self->m_bufferData.has8BitContent ? 1 : 2);
|
||||||
|
|
||||||
if (self->isCompressed()) {
|
if (self->isCompressed()) {
|
||||||
self->m_compressedData.~CompressedDataVector();
|
self->clearCompressedData();
|
||||||
} else {
|
} else {
|
||||||
deallocateStringDataBuffer(const_cast<void*>(self->m_bufferData.buffer), self->m_bufferData.length * (self->m_bufferData.has8BitContent ? 1 : 2));
|
deallocateStringDataBuffer(const_cast<void*>(self->m_bufferData.buffer), strLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self->m_isOwnerMayFreed) {
|
if (!self->m_isOwnerMayFreed) {
|
||||||
self->m_vmInstance->compressibleStringsUncomressedBufferSize() -= self->decomressedBufferSize();
|
self->m_vmInstance->compressibleStringsUncomressedBufferSize() -= self->decomressedBufferSize();
|
||||||
|
self->m_vmInstance->decreaseSourceSize(strLength);
|
||||||
|
|
||||||
auto& v = self->m_vmInstance->compressibleStrings();
|
auto& v = self->m_vmInstance->compressibleStrings();
|
||||||
v.erase(std::find(v.begin(), v.end(), self));
|
v.erase(std::find(v.begin(), v.end(), self));
|
||||||
|
|
@ -75,6 +83,7 @@ CompressibleString::CompressibleString(VMInstance* instance, const char* str, si
|
||||||
char* buf = (char*)allocateStringDataBuffer(sizeof(char) * len);
|
char* buf = (char*)allocateStringDataBuffer(sizeof(char) * len);
|
||||||
memcpy(buf, str, len);
|
memcpy(buf, str, len);
|
||||||
initBufferAccessData(buf, len, true);
|
initBufferAccessData(buf, len, true);
|
||||||
|
instance->increaseSourceSize(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompressibleString::CompressibleString(VMInstance* instance, const LChar* str, size_t len)
|
CompressibleString::CompressibleString(VMInstance* instance, const LChar* str, size_t len)
|
||||||
|
|
@ -83,6 +92,7 @@ CompressibleString::CompressibleString(VMInstance* instance, const LChar* str, s
|
||||||
char* buf = (char*)allocateStringDataBuffer(sizeof(char) * len);
|
char* buf = (char*)allocateStringDataBuffer(sizeof(char) * len);
|
||||||
memcpy(buf, str, len);
|
memcpy(buf, str, len);
|
||||||
initBufferAccessData(buf, len, true);
|
initBufferAccessData(buf, len, true);
|
||||||
|
instance->increaseSourceSize(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompressibleString::CompressibleString(VMInstance* instance, const char16_t* str, size_t len)
|
CompressibleString::CompressibleString(VMInstance* instance, const char16_t* str, size_t len)
|
||||||
|
|
@ -91,11 +101,13 @@ CompressibleString::CompressibleString(VMInstance* instance, const char16_t* str
|
||||||
char* buf = (char*)allocateStringDataBuffer(sizeof(char) * len * 2);
|
char* buf = (char*)allocateStringDataBuffer(sizeof(char) * len * 2);
|
||||||
memcpy(buf, str, len * 2);
|
memcpy(buf, str, len * 2);
|
||||||
initBufferAccessData(buf, len, false);
|
initBufferAccessData(buf, len, false);
|
||||||
|
instance->increaseSourceSize(len * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompressibleString::CompressibleString(VMInstance* instance, void* buffer, size_t stringLength, bool is8bit)
|
CompressibleString::CompressibleString(VMInstance* instance, void* buffer, size_t stringLength, bool is8bit)
|
||||||
: CompressibleString(instance)
|
: CompressibleString(instance)
|
||||||
{
|
{
|
||||||
|
RELEASE_ASSERT_NOT_REACHED();
|
||||||
initBufferAccessData(buffer, stringLength, is8bit);
|
initBufferAccessData(buffer, stringLength, is8bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,26 +147,36 @@ UTF16StringData CompressibleString::toUTF16StringData() const
|
||||||
|
|
||||||
void* CompressibleString::allocateStringDataBuffer(size_t byteLength)
|
void* CompressibleString::allocateStringDataBuffer(size_t byteLength)
|
||||||
{
|
{
|
||||||
return malloc(byteLength);
|
return GC_MALLOC_ATOMIC(byteLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompressibleString::deallocateStringDataBuffer(void* ptr, size_t byteLength)
|
void CompressibleString::deallocateStringDataBuffer(void* ptr, size_t byteLength)
|
||||||
{
|
{
|
||||||
free(ptr);
|
GC_FREE(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompressibleString::clearCompressedData()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m_compressedData.size(); i++) {
|
||||||
|
GC_FREE(m_compressedData[i].compressedBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_compressedData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompressibleString::compress()
|
bool CompressibleString::compress()
|
||||||
{
|
{
|
||||||
ASSERT(!m_isCompressed);
|
ASSERT(!m_isCompressed);
|
||||||
if (UNLIKELY(!m_bufferData.length)) {
|
if (UNLIKELY(!m_bufferData.length || !!m_refCount)) {
|
||||||
|
ESCARGOT_LOG_INFO("Compression Failed due to string usage in stack\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has8Bit = m_bufferData.has8BitContent;
|
bool has8Bit = m_bufferData.has8BitContent;
|
||||||
if (has8Bit) {
|
if (has8Bit) {
|
||||||
return compressWorker<LChar>(currentStackPointer());
|
return compressWorker<LChar>();
|
||||||
} else {
|
} else {
|
||||||
return compressWorker<char16_t>(currentStackPointer());
|
return compressWorker<char16_t>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,75 +185,79 @@ void CompressibleString::decompress()
|
||||||
ASSERT(m_isCompressed);
|
ASSERT(m_isCompressed);
|
||||||
ASSERT(m_bufferData.length);
|
ASSERT(m_bufferData.length);
|
||||||
|
|
||||||
|
uint64_t currentTick = fastTickCount();
|
||||||
|
|
||||||
bool has8Bit = m_bufferData.has8BitContent;
|
bool has8Bit = m_bufferData.has8BitContent;
|
||||||
if (has8Bit) {
|
if (has8Bit) {
|
||||||
decompressWorker<LChar>();
|
decompressWorker<LChar>();
|
||||||
} else {
|
} else {
|
||||||
decompressWorker<char16_t>();
|
decompressWorker<char16_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Global::addHeapProfileDecompTime(fastTickCount() - currentTick);
|
||||||
|
Global::increaseHeapProfileDecompCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static const size_t g_compressChunkSize = 1044465;
|
constexpr static const size_t g_compressChunkSize = 1044465;
|
||||||
static_assert(LZ4_COMPRESSBOUND(g_compressChunkSize) == 1024 * 1024, "");
|
static_assert(LZ4_COMPRESSBOUND(g_compressChunkSize) == 1024 * 1024, "");
|
||||||
|
|
||||||
static ATTRIBUTE_NO_SANITIZE_ADDRESS bool testPointerExistsOnStack(size_t* start, size_t* end, const void* ptr)
|
|
||||||
{
|
|
||||||
while (start != end) {
|
|
||||||
if (UNLIKELY(*start == (size_t)ptr)) {
|
|
||||||
// if there is reference on stack, we cannot compress string.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename StringType>
|
template <typename StringType>
|
||||||
bool CompressibleString::compressWorker(void* callerSP)
|
bool CompressibleString::compressWorker()
|
||||||
{
|
{
|
||||||
ASSERT(!m_isCompressed);
|
ASSERT(!m_isCompressed && !m_refCount);
|
||||||
ASSERT(m_bufferData.length > 0);
|
ASSERT(m_bufferData.length > 0);
|
||||||
|
ASSERT(!GC_is_disabled());
|
||||||
|
|
||||||
#if defined(STACK_GROWS_DOWN)
|
uint64_t currentTick = fastTickCount();
|
||||||
size_t* start = (size_t*)((size_t)callerSP & ~(sizeof(size_t) - 1));
|
|
||||||
size_t* end = (size_t*)m_vmInstance->stackStartAddress();
|
|
||||||
#else
|
|
||||||
size_t* start = (size_t*)m_vmInstance->stackStartAddress();
|
|
||||||
size_t* end = (size_t*)((size_t)callerSP & ~(sizeof(size_t) - 1));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (testPointerExistsOnStack(start, end, m_bufferData.buffer)) {
|
GC_disable();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t originByteLength = m_bufferData.length * sizeof(StringType);
|
size_t originByteLength = m_bufferData.length * sizeof(StringType);
|
||||||
|
size_t totalDecompLength = 0;
|
||||||
int lastBoundLength = 0;
|
int lastBoundLength = 0;
|
||||||
std::unique_ptr<char[]> compBuffer;
|
char* tempBuffer = nullptr;
|
||||||
|
|
||||||
|
ESCARGOT_LOG_INFO("COMPRESS TICK: %" PRIu64 " Size: %zu\n", currentTick, originByteLength);
|
||||||
|
|
||||||
for (size_t srcIndex = 0; srcIndex < originByteLength; srcIndex += g_compressChunkSize) {
|
for (size_t srcIndex = 0; srcIndex < originByteLength; srcIndex += g_compressChunkSize) {
|
||||||
int srcSize = (int)std::min(g_compressChunkSize, originByteLength - srcIndex);
|
int srcSize = (int)std::min(g_compressChunkSize, originByteLength - srcIndex);
|
||||||
int boundLength = LZ4::LZ4_compressBound(srcSize);
|
int boundLength = LZ4::LZ4_compressBound(srcSize);
|
||||||
if (boundLength > lastBoundLength) {
|
if (boundLength > lastBoundLength) {
|
||||||
compBuffer.reset(new char[boundLength]);
|
delete[] tempBuffer;
|
||||||
|
tempBuffer = new char[boundLength];
|
||||||
lastBoundLength = boundLength;
|
lastBoundLength = boundLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
int compressedLength = LZ4::LZ4_compress_default(m_bufferData.bufferAs8Bit + srcIndex, (char*)compBuffer.get(), srcSize, boundLength);
|
int compressedLength = LZ4::LZ4_compress_default(m_bufferData.bufferAs8Bit + srcIndex, (char*)tempBuffer, srcSize, boundLength);
|
||||||
if (!compressedLength) {
|
if (!compressedLength) {
|
||||||
// compression fail
|
// compression fail
|
||||||
|
ESCARGOT_LOG_ERROR("Compression Failed\n");
|
||||||
|
delete[] tempBuffer;
|
||||||
|
|
||||||
|
GC_enable();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(compressedLength > 0);
|
ASSERT(compressedLength > 0);
|
||||||
m_compressedData.push_back(std::vector<char>(compBuffer.get(), compBuffer.get() + compressedLength));
|
totalDecompLength += compressedLength;
|
||||||
|
|
||||||
|
char* compBuffer = reinterpret_cast<char*>(GC_MALLOC_ATOMIC(compressedLength));
|
||||||
|
memcpy(compBuffer, tempBuffer, compressedLength);
|
||||||
|
m_compressedData.push_back(CompressedElement(compBuffer, compressedLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete[] tempBuffer;
|
||||||
|
|
||||||
m_vmInstance->compressibleStringsUncomressedBufferSize() -= decomressedBufferSize();
|
m_vmInstance->compressibleStringsUncomressedBufferSize() -= decomressedBufferSize();
|
||||||
|
ASSERT(originByteLength > totalDecompLength);
|
||||||
|
m_vmInstance->decreaseSourceSize(originByteLength - totalDecompLength);
|
||||||
|
|
||||||
|
GC_enable();
|
||||||
|
|
||||||
// immediately free the original string after compression when there is no reference on stack
|
// immediately free the original string after compression when there is no reference on stack
|
||||||
deallocateStringDataBuffer(const_cast<void*>(m_bufferData.buffer), m_bufferData.length * (m_bufferData.has8BitContent ? 1 : 2));
|
deallocateStringDataBuffer(const_cast<void*>(m_bufferData.buffer), m_bufferData.length * (m_bufferData.has8BitContent ? 1 : 2));
|
||||||
|
|
||||||
m_bufferData.bufferAs8Bit = nullptr;
|
m_bufferData.buffer = nullptr;
|
||||||
m_isCompressed = true;
|
m_isCompressed = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -242,6 +268,8 @@ bool CompressibleString::compressWorker(void* callerSP)
|
||||||
ESCARGOT_LOG_INFO("CompressibleString::compressWorker %fKB -> %fKB\n", originByteLength / 1024.f, compressedSize / 1024.f);
|
ESCARGOT_LOG_INFO("CompressibleString::compressWorker %fKB -> %fKB\n", originByteLength / 1024.f, compressedSize / 1024.f);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
Global::addHeapProfileCompTime(fastTickCount() - currentTick);
|
||||||
|
Global::increaseHeapProfileCompCount();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,6 +280,7 @@ void CompressibleString::decompressWorker()
|
||||||
ASSERT(m_isCompressed);
|
ASSERT(m_isCompressed);
|
||||||
|
|
||||||
size_t originByteLength = m_bufferData.length * sizeof(StringType);
|
size_t originByteLength = m_bufferData.length * sizeof(StringType);
|
||||||
|
size_t totalDecompLength = 0;
|
||||||
|
|
||||||
char* dstBuffer = (char*)allocateStringDataBuffer(originByteLength);
|
char* dstBuffer = (char*)allocateStringDataBuffer(originByteLength);
|
||||||
int dstIndex = 0;
|
int dstIndex = 0;
|
||||||
|
|
@ -259,7 +288,9 @@ void CompressibleString::decompressWorker()
|
||||||
for (size_t srcIndex = 0, bufIndex = 0; srcIndex < originByteLength; srcIndex += g_compressChunkSize, bufIndex++) {
|
for (size_t srcIndex = 0, bufIndex = 0; srcIndex < originByteLength; srcIndex += g_compressChunkSize, bufIndex++) {
|
||||||
int srcSize = (int)std::min(g_compressChunkSize, originByteLength - srcIndex);
|
int srcSize = (int)std::min(g_compressChunkSize, originByteLength - srcIndex);
|
||||||
|
|
||||||
int decompressedLength = LZ4::LZ4_decompress_safe(m_compressedData[bufIndex].data(), dstBuffer + dstIndex, m_compressedData[bufIndex].size(), srcSize);
|
totalDecompLength += m_compressedData[bufIndex].compressedLength;
|
||||||
|
|
||||||
|
int decompressedLength = LZ4::LZ4_decompress_safe(m_compressedData[bufIndex].compressedBuffer, dstBuffer + dstIndex, m_compressedData[bufIndex].compressedLength, srcSize);
|
||||||
if (!decompressedLength) {
|
if (!decompressedLength) {
|
||||||
// decompress fail
|
// decompress fail
|
||||||
RELEASE_ASSERT_NOT_REACHED();
|
RELEASE_ASSERT_NOT_REACHED();
|
||||||
|
|
@ -268,12 +299,16 @@ void CompressibleString::decompressWorker()
|
||||||
dstIndex += srcSize;
|
dstIndex += srcSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompressedDataVector().swap(m_compressedData);
|
clearCompressedData();
|
||||||
|
|
||||||
m_bufferData.bufferAs8Bit = const_cast<const char*>(dstBuffer);
|
m_bufferData.bufferAs8Bit = const_cast<const char*>(dstBuffer);
|
||||||
m_isCompressed = false;
|
m_isCompressed = false;
|
||||||
|
|
||||||
m_vmInstance->compressibleStringsUncomressedBufferSize() += decomressedBufferSize();
|
m_vmInstance->compressibleStringsUncomressedBufferSize() += decomressedBufferSize();
|
||||||
|
ASSERT(originByteLength > totalDecompLength);
|
||||||
|
m_vmInstance->increaseSourceSize(originByteLength - totalDecompLength);
|
||||||
|
|
||||||
|
ESCARGOT_LOG_INFO("DECOMPRESS TICK: %" PRIu64 " Size: %zu\n", fastTickCount(), originByteLength);
|
||||||
}
|
}
|
||||||
} // namespace Escargot
|
} // namespace Escargot
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,17 @@ namespace Escargot {
|
||||||
|
|
||||||
class VMInstance;
|
class VMInstance;
|
||||||
|
|
||||||
|
struct CompressedElement {
|
||||||
|
CompressedElement(char* buffer, size_t length)
|
||||||
|
: compressedBuffer(buffer)
|
||||||
|
, compressedLength(length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
char* compressedBuffer;
|
||||||
|
size_t compressedLength;
|
||||||
|
};
|
||||||
|
|
||||||
class CompressibleString : public String {
|
class CompressibleString : public String {
|
||||||
friend class VMInstance;
|
friend class VMInstance;
|
||||||
|
|
||||||
|
|
@ -67,7 +78,8 @@ public:
|
||||||
if (isCompressed()) {
|
if (isCompressed()) {
|
||||||
decompress();
|
decompress();
|
||||||
}
|
}
|
||||||
return StringBufferAccessData(m_bufferData.has8BitContent, m_bufferData.length, const_cast<void*>(m_bufferData.buffer));
|
|
||||||
|
return StringBufferAccessData(m_bufferData.has8BitContent, m_bufferData.length, const_cast<void*>(m_bufferData.buffer), &m_refCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isCompressed()
|
bool isCompressed()
|
||||||
|
|
@ -75,12 +87,18 @@ public:
|
||||||
return m_isCompressed;
|
return m_isCompressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t refCount()
|
||||||
|
{
|
||||||
|
return m_refCount;
|
||||||
|
}
|
||||||
|
|
||||||
void* operator new(size_t);
|
void* operator new(size_t);
|
||||||
void* operator new[](size_t) = delete;
|
void* operator new[](size_t) = delete;
|
||||||
void operator delete[](void*) = delete;
|
void operator delete[](void*) = delete;
|
||||||
|
|
||||||
static void* allocateStringDataBuffer(size_t byteLength);
|
static void* allocateStringDataBuffer(size_t byteLength);
|
||||||
static void deallocateStringDataBuffer(void* ptr, size_t byteLength);
|
static void deallocateStringDataBuffer(void* ptr, size_t byteLength);
|
||||||
|
void clearCompressedData();
|
||||||
|
|
||||||
bool compress();
|
bool compress();
|
||||||
void decompress();
|
void decompress();
|
||||||
|
|
@ -100,15 +118,16 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename StringType>
|
template <typename StringType>
|
||||||
NEVER_INLINE bool compressWorker(void* callerSP);
|
NEVER_INLINE bool compressWorker();
|
||||||
template <typename StringType>
|
template <typename StringType>
|
||||||
NEVER_INLINE void decompressWorker();
|
NEVER_INLINE void decompressWorker();
|
||||||
|
|
||||||
bool m_isOwnerMayFreed;
|
bool m_isOwnerMayFreed;
|
||||||
bool m_isCompressed;
|
bool m_isCompressed;
|
||||||
|
size_t m_refCount; // reference count representing the usage of this CompressibleString
|
||||||
VMInstance* m_vmInstance;
|
VMInstance* m_vmInstance;
|
||||||
uint64_t m_lastUsedTickcount;
|
uint64_t m_lastUsedTickcount;
|
||||||
typedef std::vector<std::vector<char>> CompressedDataVector;
|
typedef Vector<CompressedElement, GCUtil::gc_malloc_allocator<CompressedElement>> CompressedDataVector;
|
||||||
CompressedDataVector m_compressedData;
|
CompressedDataVector m_compressedData;
|
||||||
};
|
};
|
||||||
} // namespace Escargot
|
} // namespace Escargot
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include "runtime/Platform.h"
|
#include "runtime/Platform.h"
|
||||||
#include "runtime/PointerValue.h"
|
#include "runtime/PointerValue.h"
|
||||||
#include "runtime/ArrayObject.h"
|
#include "runtime/ArrayObject.h"
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
namespace Escargot {
|
namespace Escargot {
|
||||||
|
|
||||||
|
|
@ -34,6 +35,7 @@ SpinLock Global::g_atomicsLock;
|
||||||
std::mutex Global::g_waiterMutex;
|
std::mutex Global::g_waiterMutex;
|
||||||
std::vector<Global::Waiter*> Global::g_waiter;
|
std::vector<Global::Waiter*> Global::g_waiter;
|
||||||
#endif
|
#endif
|
||||||
|
Global::HeapProfile* Global::g_heapProfile;
|
||||||
|
|
||||||
void Global::initialize(Platform* platform)
|
void Global::initialize(Platform* platform)
|
||||||
{
|
{
|
||||||
|
|
@ -51,6 +53,8 @@ void Global::initialize(Platform* platform)
|
||||||
PointerValue::g_objectRareDataTag = ObjectRareData(nullptr).getTag();
|
PointerValue::g_objectRareDataTag = ObjectRareData(nullptr).getTag();
|
||||||
PointerValue::g_doubleInEncodedValueTag = DoubleInEncodedValue(0).getTag();
|
PointerValue::g_doubleInEncodedValueTag = DoubleInEncodedValue(0).getTag();
|
||||||
|
|
||||||
|
g_heapProfile = new HeapProfile();
|
||||||
|
|
||||||
called_once = false;
|
called_once = false;
|
||||||
inited = true;
|
inited = true;
|
||||||
}
|
}
|
||||||
|
|
@ -72,6 +76,9 @@ void Global::finalize()
|
||||||
delete g_platform;
|
delete g_platform;
|
||||||
g_platform = nullptr;
|
g_platform = nullptr;
|
||||||
|
|
||||||
|
g_heapProfile->printResult();
|
||||||
|
delete g_heapProfile;
|
||||||
|
|
||||||
called_once = false;
|
called_once = false;
|
||||||
inited = false;
|
inited = false;
|
||||||
}
|
}
|
||||||
|
|
@ -82,6 +89,19 @@ Platform* Global::platform()
|
||||||
return g_platform;
|
return g_platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Global::HeapProfile::printResult()
|
||||||
|
{
|
||||||
|
ESCARGOT_LOG_INFO("=== HeapProfile Result ===\n");
|
||||||
|
ESCARGOT_LOG_INFO("GC_Count: %zu\nComp_Count: %zu\nDecomp_Count: %zu\n", gcCount, compCount, decompCount);
|
||||||
|
ESCARGOT_LOG_INFO("GC_Time: %" PRIu64 "\nComp_Time: %" PRIu64 "\nDecomp_Time:%" PRIu64 "\n", gcTime, compTime, decompTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
Global::HeapProfile* Global::heapProfile()
|
||||||
|
{
|
||||||
|
ASSERT(inited && !!g_heapProfile);
|
||||||
|
return g_heapProfile;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(ENABLE_THREADING)
|
#if defined(ENABLE_THREADING)
|
||||||
Global::Waiter* Global::waiter(void* blockAddress)
|
Global::Waiter* Global::waiter(void* blockAddress)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,50 @@ public:
|
||||||
static std::vector<Waiter*> g_waiter;
|
static std::vector<Waiter*> g_waiter;
|
||||||
static Waiter* waiter(void* blockAddress);
|
static Waiter* waiter(void* blockAddress);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct HeapProfile {
|
||||||
|
HeapProfile()
|
||||||
|
: gcCount(0)
|
||||||
|
, compCount(0)
|
||||||
|
, decompCount(0)
|
||||||
|
, lastGCMarkTime(0)
|
||||||
|
, gcTime(0)
|
||||||
|
, compTime(0)
|
||||||
|
, decompTime(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t gcCount;
|
||||||
|
size_t compCount;
|
||||||
|
size_t decompCount;
|
||||||
|
uint64_t lastGCMarkTime;
|
||||||
|
uint64_t gcTime;
|
||||||
|
uint64_t compTime;
|
||||||
|
uint64_t decompTime;
|
||||||
|
|
||||||
|
void printResult();
|
||||||
|
};
|
||||||
|
|
||||||
|
static HeapProfile* g_heapProfile;
|
||||||
|
static HeapProfile* heapProfile();
|
||||||
|
|
||||||
|
// Heap Profile Functions
|
||||||
|
static void increaseHeapProfileGCCount() { g_heapProfile->gcCount++; }
|
||||||
|
static void increaseHeapProfileCompCount() { g_heapProfile->compCount++; }
|
||||||
|
static void increaseHeapProfileDecompCount() { g_heapProfile->decompCount++; }
|
||||||
|
static void markHeapProfileGCMarkStartTime(uint64_t time)
|
||||||
|
{
|
||||||
|
ASSERT(g_heapProfile->lastGCMarkTime == 0);
|
||||||
|
g_heapProfile->lastGCMarkTime = time;
|
||||||
|
}
|
||||||
|
static void markHeapProfileGCReclaimEndTime(uint64_t time)
|
||||||
|
{
|
||||||
|
ASSERT(time >= g_heapProfile->lastGCMarkTime);
|
||||||
|
g_heapProfile->gcTime += (time - g_heapProfile->lastGCMarkTime);
|
||||||
|
g_heapProfile->lastGCMarkTime = 0;
|
||||||
|
}
|
||||||
|
static void addHeapProfileCompTime(uint64_t time) { g_heapProfile->compTime += time; }
|
||||||
|
static void addHeapProfileDecompTime(uint64_t time) { g_heapProfile->decompTime += time; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Escargot
|
} // namespace Escargot
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@
|
||||||
|
|
||||||
#include "fast-dtoa.h"
|
#include "fast-dtoa.h"
|
||||||
#include "bignum-dtoa.h"
|
#include "bignum-dtoa.h"
|
||||||
|
#include "runtime/VMInstance.h"
|
||||||
|
|
||||||
namespace Escargot {
|
namespace Escargot {
|
||||||
|
|
||||||
|
|
@ -623,6 +624,32 @@ String* String::fromDouble(double v)
|
||||||
return new ASCIIString(std::move(s));
|
return new ASCIIString(std::move(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UTF16StringFinalizer::UTF16StringFinalizer(Context* context, UTF16StringData&& src)
|
||||||
|
: UTF16String(std::forward<UTF16StringData>(src))
|
||||||
|
, m_context(context)
|
||||||
|
{
|
||||||
|
context->vmInstance()->increaseSourceSize(length() * 2);
|
||||||
|
GC_REGISTER_FINALIZER_NO_ORDER(this, [](void* obj, void*) {
|
||||||
|
UTF16StringFinalizer* self = (UTF16StringFinalizer*)obj;
|
||||||
|
self->m_context->vmInstance()->decreaseSourceSize((self->length()) * 2);
|
||||||
|
},
|
||||||
|
nullptr, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* UTF16StringFinalizer::operator new(size_t size)
|
||||||
|
{
|
||||||
|
static MAY_THREAD_LOCAL bool typeInited = false;
|
||||||
|
static MAY_THREAD_LOCAL GC_descr descr;
|
||||||
|
if (!typeInited) {
|
||||||
|
GC_word obj_bitmap[GC_BITMAP_SIZE(UTF16StringFinalizer)] = { 0 };
|
||||||
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(UTF16StringFinalizer, m_bufferData.buffer));
|
||||||
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(UTF16StringFinalizer, m_context));
|
||||||
|
descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(UTF16StringFinalizer));
|
||||||
|
typeInited = true;
|
||||||
|
}
|
||||||
|
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
|
||||||
|
}
|
||||||
|
|
||||||
String* String::fromUTF8(const char* src, size_t len, bool maybeASCII)
|
String* String::fromUTF8(const char* src, size_t len, bool maybeASCII)
|
||||||
{
|
{
|
||||||
if (maybeASCII && isAllASCII(src, len)) {
|
if (maybeASCII && isAllASCII(src, len)) {
|
||||||
|
|
@ -637,6 +664,7 @@ String* String::fromUTF8(const char* src, size_t len, bool maybeASCII)
|
||||||
String* String::fromUTF8ToCompressibleString(VMInstance* instance, const char* src, size_t len, bool maybeASCII)
|
String* String::fromUTF8ToCompressibleString(VMInstance* instance, const char* src, size_t len, bool maybeASCII)
|
||||||
{
|
{
|
||||||
if (maybeASCII && isAllASCII(src, len)) {
|
if (maybeASCII && isAllASCII(src, len)) {
|
||||||
|
RELEASE_ASSERT_NOT_REACHED();
|
||||||
return new CompressibleString(instance, src, len);
|
return new CompressibleString(instance, src, len);
|
||||||
} else {
|
} else {
|
||||||
auto s = utf8StringToUTF16StringNonGC(src, len);
|
auto s = utf8StringToUTF16StringNonGC(src, len);
|
||||||
|
|
@ -927,6 +955,32 @@ void* Latin1String::operator new(size_t size)
|
||||||
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
|
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Latin1StringFinalizer::Latin1StringFinalizer(Context* context, const LChar* str, size_t len)
|
||||||
|
: Latin1String(str, len)
|
||||||
|
, m_context(context)
|
||||||
|
{
|
||||||
|
context->vmInstance()->increaseSourceSize(length());
|
||||||
|
GC_REGISTER_FINALIZER_NO_ORDER(this, [](void* obj, void*) {
|
||||||
|
Latin1StringFinalizer* self = (Latin1StringFinalizer*)obj;
|
||||||
|
self->m_context->vmInstance()->decreaseSourceSize(self->length());
|
||||||
|
},
|
||||||
|
nullptr, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Latin1StringFinalizer::operator new(size_t size)
|
||||||
|
{
|
||||||
|
static MAY_THREAD_LOCAL bool typeInited = false;
|
||||||
|
static MAY_THREAD_LOCAL GC_descr descr;
|
||||||
|
if (!typeInited) {
|
||||||
|
GC_word obj_bitmap[GC_BITMAP_SIZE(Latin1StringFinalizer)] = { 0 };
|
||||||
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(Latin1StringFinalizer, m_bufferData.buffer));
|
||||||
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(Latin1StringFinalizer, m_context));
|
||||||
|
descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(Latin1StringFinalizer));
|
||||||
|
typeInited = true;
|
||||||
|
}
|
||||||
|
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
|
||||||
|
}
|
||||||
|
|
||||||
void* UTF16String::operator new(size_t size)
|
void* UTF16String::operator new(size_t size)
|
||||||
{
|
{
|
||||||
static MAY_THREAD_LOCAL bool typeInited = false;
|
static MAY_THREAD_LOCAL bool typeInited = false;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
namespace Escargot {
|
namespace Escargot {
|
||||||
|
|
||||||
|
class Context;
|
||||||
|
|
||||||
// A type to hold a single Latin-1 character.
|
// A type to hold a single Latin-1 character.
|
||||||
typedef unsigned char LChar;
|
typedef unsigned char LChar;
|
||||||
|
|
||||||
|
|
@ -100,12 +102,27 @@ struct StringBufferAccessData {
|
||||||
};
|
};
|
||||||
void* extraData;
|
void* extraData;
|
||||||
|
|
||||||
StringBufferAccessData(bool has8Bit, size_t len, void* buffer, void* extraDataKeepInStack = nullptr)
|
StringBufferAccessData(bool has8Bit, size_t len, void* buffer, void* extraDataToKeep = nullptr)
|
||||||
: has8BitContent(has8Bit)
|
: has8BitContent(has8Bit)
|
||||||
, length(len)
|
, length(len)
|
||||||
, buffer(buffer)
|
, buffer(buffer)
|
||||||
, extraData(extraDataKeepInStack)
|
, extraData(extraDataToKeep)
|
||||||
{
|
{
|
||||||
|
if (extraData) {
|
||||||
|
// increase refCount in CompressibleString
|
||||||
|
size_t& count = *reinterpret_cast<size_t*>(extraData);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~StringBufferAccessData()
|
||||||
|
{
|
||||||
|
if (extraData) {
|
||||||
|
// decrease refCount in CompressibleString
|
||||||
|
size_t& count = *reinterpret_cast<size_t*>(extraData);
|
||||||
|
ASSERT(count > 0);
|
||||||
|
count--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char16_t uncheckedCharAtFor8Bit(size_t idx) const
|
char16_t uncheckedCharAtFor8Bit(size_t idx) const
|
||||||
|
|
@ -759,6 +776,16 @@ public:
|
||||||
void* operator new[](size_t size) = delete;
|
void* operator new[](size_t size) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Latin1StringFinalizer : public Latin1String {
|
||||||
|
public:
|
||||||
|
Latin1StringFinalizer(Context* context, const LChar* str, size_t len);
|
||||||
|
|
||||||
|
Context* m_context;
|
||||||
|
|
||||||
|
void* operator new(size_t size);
|
||||||
|
void* operator new[](size_t size) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
class Latin1StringFromExternalMemory : public Latin1String {
|
class Latin1StringFromExternalMemory : public Latin1String {
|
||||||
public:
|
public:
|
||||||
Latin1StringFromExternalMemory(const unsigned char* str, size_t len)
|
Latin1StringFromExternalMemory(const unsigned char* str, size_t len)
|
||||||
|
|
@ -825,6 +852,16 @@ public:
|
||||||
void* operator new[](size_t size) = delete;
|
void* operator new[](size_t size) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class UTF16StringFinalizer : public UTF16String {
|
||||||
|
public:
|
||||||
|
explicit UTF16StringFinalizer(Context* context, UTF16StringData&& src);
|
||||||
|
|
||||||
|
Context* m_context;
|
||||||
|
|
||||||
|
void* operator new(size_t size);
|
||||||
|
void* operator new[](size_t size) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
class UTF16StringFromExternalMemory : public UTF16String {
|
class UTF16StringFromExternalMemory : public UTF16String {
|
||||||
public:
|
public:
|
||||||
UTF16StringFromExternalMemory(const char16_t* str, size_t len)
|
UTF16StringFromExternalMemory(const char16_t* str, size_t len)
|
||||||
|
|
|
||||||
|
|
@ -139,9 +139,6 @@ protected:
|
||||||
ASSERT(m_bufferData.hasSpecialImpl);
|
ASSERT(m_bufferData.hasSpecialImpl);
|
||||||
|
|
||||||
StringBufferAccessData r = m_bufferData.bufferAsString->bufferAccessData();
|
StringBufferAccessData r = m_bufferData.bufferAsString->bufferAccessData();
|
||||||
// keep original buffer pointer in stack
|
|
||||||
// without this, compressible string can free this pointer
|
|
||||||
r.extraData = const_cast<void*>(r.buffer);
|
|
||||||
r.length = m_bufferData.length;
|
r.length = m_bufferData.length;
|
||||||
if (r.has8BitContent) {
|
if (r.has8BitContent) {
|
||||||
r.bufferAs8Bit += m_start;
|
r.bufferAs8Bit += m_start;
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,8 @@ void* VMInstance::operator new(size_t size)
|
||||||
void vmMarkStartCallback(void* data)
|
void vmMarkStartCallback(void* data)
|
||||||
{
|
{
|
||||||
VMInstance* self = (VMInstance*)data;
|
VMInstance* self = (VMInstance*)data;
|
||||||
|
Global::increaseHeapProfileGCCount();
|
||||||
|
Global::markHeapProfileGCMarkStartTime(fastTickCount());
|
||||||
|
|
||||||
#ifdef ESCARGOT_DEBUGGER
|
#ifdef ESCARGOT_DEBUGGER
|
||||||
if (!self->m_debuggerEnabled) {
|
if (!self->m_debuggerEnabled) {
|
||||||
|
|
@ -266,6 +268,11 @@ void vmReclaimEndCallback(void* data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Global::markHeapProfileGCReclaimEndTime(fastTickCount());
|
||||||
|
|
||||||
|
// disabled in default due to massive logs
|
||||||
|
//ESCARGOT_LOG_INFO("Heap After GC: %f MB\n", GC_get_heap_size() / 1024.f / 1024.f);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (t == GC_EventType::GC_EVENT_RECLAIM_END) {
|
if (t == GC_EventType::GC_EVENT_RECLAIM_END) {
|
||||||
printf("Done GC: HeapSize: [%f MB , %f MB]\n", GC_get_memory_use() / 1024.f / 1024.f, GC_get_heap_size() / 1024.f / 1024.f);
|
printf("Done GC: HeapSize: [%f MB , %f MB]\n", GC_get_memory_use() / 1024.f / 1024.f, GC_get_heap_size() / 1024.f / 1024.f);
|
||||||
|
|
@ -342,6 +349,7 @@ VMInstance::VMInstance(const char* locale, const char* timezone, const char* bas
|
||||||
, m_debuggerEnabled(false)
|
, m_debuggerEnabled(false)
|
||||||
#endif /* ESCARGOT_DEBUGGER */
|
#endif /* ESCARGOT_DEBUGGER */
|
||||||
, m_compiledByteCodeSize(0)
|
, m_compiledByteCodeSize(0)
|
||||||
|
, m_validSourceSize(0)
|
||||||
#if defined(ENABLE_COMPRESSIBLE_STRING)
|
#if defined(ENABLE_COMPRESSIBLE_STRING)
|
||||||
, m_lastCompressibleStringsTestTime(0)
|
, m_lastCompressibleStringsTestTime(0)
|
||||||
, m_compressibleStringsUncomressedBufferSize(0)
|
, m_compressibleStringsUncomressedBufferSize(0)
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,22 @@ public:
|
||||||
return m_compiledByteCodeSize;
|
return m_compiledByteCodeSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t validSourceSize()
|
||||||
|
{
|
||||||
|
return m_validSourceSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void increaseSourceSize(size_t size)
|
||||||
|
{
|
||||||
|
m_validSourceSize += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decreaseSourceSize(size_t size)
|
||||||
|
{
|
||||||
|
ASSERT(m_validSourceSize >= size);
|
||||||
|
m_validSourceSize -= size;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(ENABLE_COMPRESSIBLE_STRING)
|
#if defined(ENABLE_COMPRESSIBLE_STRING)
|
||||||
std::vector<CompressibleString*>& compressibleStrings()
|
std::vector<CompressibleString*>& compressibleStrings()
|
||||||
{
|
{
|
||||||
|
|
@ -328,6 +344,7 @@ private:
|
||||||
|
|
||||||
std::vector<ByteCodeBlock*> m_compiledByteCodeBlocks;
|
std::vector<ByteCodeBlock*> m_compiledByteCodeBlocks;
|
||||||
size_t m_compiledByteCodeSize;
|
size_t m_compiledByteCodeSize;
|
||||||
|
size_t m_validSourceSize;
|
||||||
|
|
||||||
#if defined(ENABLE_COMPRESSIBLE_STRING)
|
#if defined(ENABLE_COMPRESSIBLE_STRING)
|
||||||
uint64_t m_lastCompressibleStringsTestTime;
|
uint64_t m_lastCompressibleStringsTestTime;
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,13 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "api/EscargotPublic.h"
|
#include "api/EscargotPublic.h"
|
||||||
#include "malloc.h"
|
#include "malloc.h"
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
#if defined(ESCARGOT_ENABLE_TEST)
|
#if defined(ESCARGOT_ENABLE_TEST)
|
||||||
// these header & function below are used for Escargot internal development
|
// these header & function below are used for Escargot internal development
|
||||||
// general client doesn't need this
|
// general client doesn't need this
|
||||||
|
|
@ -188,24 +192,27 @@ static OptionalRef<StringRef> builtinHelperFileRead(OptionalRef<ExecutionStateRe
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
if (StringRef::isCompressibleStringEnabled()) {
|
if (StringRef::isCompressibleStringEnabled()) {
|
||||||
if (state) {
|
//if (state) {
|
||||||
if (hasNonLatin1Content) {
|
if (hasNonLatin1Content) {
|
||||||
src = StringRef::createFromUTF8ToCompressibleString(state->context()->vmInstance(), utf8Str.data(), utf8Str.length(), false);
|
src = StringRef::createFromUTF8ToCompressibleString(state->context()->vmInstance(), utf8Str.data(), utf8Str.length(), false);
|
||||||
} else {
|
|
||||||
src = StringRef::createFromLatin1ToCompressibleString(state->context()->vmInstance(), str.data(), str.length());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
src = StringRef::createFromLatin1ToCompressibleString(state->context()->vmInstance(), str.data(), str.length());
|
||||||
|
}
|
||||||
|
//}
|
||||||
|
/*
|
||||||
|
else {
|
||||||
if (hasNonLatin1Content) {
|
if (hasNonLatin1Content) {
|
||||||
src = StringRef::createFromUTF8(utf8Str.data(), utf8Str.length(), false);
|
src = StringRef::createFromUTF8(utf8Str.data(), utf8Str.length(), false);
|
||||||
} else {
|
} else {
|
||||||
src = StringRef::createFromLatin1(str.data(), str.length());
|
src = StringRef::createFromLatin1(str.data(), str.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
} else {
|
} else {
|
||||||
if (hasNonLatin1Content) {
|
if (hasNonLatin1Content) {
|
||||||
src = StringRef::createFromUTF8(utf8Str.data(), utf8Str.length(), false);
|
src = StringRef::createFromUTF8(state->context(), utf8Str.data(), utf8Str.length(), false);
|
||||||
} else {
|
} else {
|
||||||
src = StringRef::createFromLatin1(str.data(), str.length());
|
src = StringRef::createFromLatin1(state->context(), str.data(), str.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return src;
|
return src;
|
||||||
|
|
@ -921,6 +928,30 @@ PersistentRefHolder<ContextRef> createEscargotContext(VMInstanceRef* instance, b
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t g_lastTick = 0;
|
||||||
|
static uint64_t g_dumpInterval = 1000; // default interval is set to 1 second
|
||||||
|
|
||||||
|
static uint64_t fastTickCount()
|
||||||
|
{
|
||||||
|
#if defined(CLOCK_MONOTONIC_COARSE)
|
||||||
|
timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
|
||||||
|
return (uint64_t)ts.tv_sec * 1000UL + ts.tv_nsec / 1000000UL;
|
||||||
|
#else
|
||||||
|
return tickCount();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printGCMemory(void* data)
|
||||||
|
{
|
||||||
|
uint64_t currentTick = fastTickCount();
|
||||||
|
if (currentTick - g_lastTick >= g_dumpInterval) {
|
||||||
|
g_lastTick = currentTick;
|
||||||
|
VMInstanceRef* vm = static_cast<VMInstanceRef*>(data);
|
||||||
|
printf("Tick %" PRIu64 ": %f MB %lu \n", currentTick, Memory::heapSize() / 1024.f / 1024.f, vm->validSourceSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
@ -941,7 +972,7 @@ int main(int argc, char* argv[])
|
||||||
Memory::setGCFrequency(24);
|
Memory::setGCFrequency(24);
|
||||||
|
|
||||||
PersistentRefHolder<VMInstanceRef> instance = VMInstanceRef::create();
|
PersistentRefHolder<VMInstanceRef> instance = VMInstanceRef::create();
|
||||||
PersistentRefHolder<ContextRef> context = createEscargotContext(instance.get());
|
PersistentRefHolder<ContextRef> context;
|
||||||
|
|
||||||
if (getenv("GC_FREE_SPACE_DIVISOR") && strlen(getenv("GC_FREE_SPACE_DIVISOR"))) {
|
if (getenv("GC_FREE_SPACE_DIVISOR") && strlen(getenv("GC_FREE_SPACE_DIVISOR"))) {
|
||||||
int d = atoi(getenv("GC_FREE_SPACE_DIVISOR"));
|
int d = atoi(getenv("GC_FREE_SPACE_DIVISOR"));
|
||||||
|
|
@ -951,6 +982,7 @@ int main(int argc, char* argv[])
|
||||||
bool runShell = true;
|
bool runShell = true;
|
||||||
bool seenModule = false;
|
bool seenModule = false;
|
||||||
std::string fileName;
|
std::string fileName;
|
||||||
|
bool memoryUsageLog = false;
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
if (strlen(argv[i]) >= 2 && argv[i][0] == '-') { // parse command line option
|
if (strlen(argv[i]) >= 2 && argv[i][0] == '-') { // parse command line option
|
||||||
|
|
@ -971,32 +1003,20 @@ int main(int argc, char* argv[])
|
||||||
fileName = argv[i] + sizeof("--filename-as=") - 1;
|
fileName = argv[i] + sizeof("--filename-as=") - 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strcmp(argv[i], "--start-debug-server") == 0) {
|
if (strcmp(argv[i], "--dump-memory-usage") == 0) {
|
||||||
context->initDebugger(nullptr);
|
memoryUsageLog = true;
|
||||||
|
g_lastTick = fastTickCount();
|
||||||
|
printf("Tick %" PRIu64 ": Start Measure\n", g_lastTick);
|
||||||
|
Memory::removeGCEventListener(Memory::RECLAIM_END, printGCMemory, instance.get());
|
||||||
|
Memory::addGCEventListener(Memory::RECLAIM_END, printGCMemory, instance.get());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strcmp(argv[i], "--debugger-wait-source") == 0) {
|
if (strstr(argv[i], "--dump-memory-interval=") == argv[i]) {
|
||||||
StringRef* sourceName;
|
std::string interval = argv[i] + sizeof("--dump-memory-interval=") - 1;
|
||||||
while (true) {
|
g_dumpInterval = atoi(interval.c_str());
|
||||||
StringRef* clientSourceRef = context->getClientSource(&sourceName);
|
|
||||||
if (!clientSourceRef) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!evalScript(context, clientSourceRef, sourceName, false, false))
|
|
||||||
return 3;
|
|
||||||
runShell = false;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else { // `-option` case
|
} else { // `-option` case
|
||||||
if (strcmp(argv[i], "-e") == 0) {
|
|
||||||
runShell = false;
|
|
||||||
i++;
|
|
||||||
StringRef* src = StringRef::createFromUTF8(argv[i], strlen(argv[i]));
|
|
||||||
if (!evalScript(context, src, StringRef::createFromASCII("shell input"), false, false))
|
|
||||||
return 3;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (strcmp(argv[i], "-f") == 0) {
|
if (strcmp(argv[i], "-f") == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1006,6 +1026,13 @@ int main(int argc, char* argv[])
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!context.isInitialized()) {
|
||||||
|
// postpone allocation of Context to here
|
||||||
|
// initialization of Context triggers several GC
|
||||||
|
// so, register of gc event with `--dump-memory-usage` should be done before Context creation
|
||||||
|
context.reset(createEscargotContext(instance.get()));
|
||||||
|
}
|
||||||
|
|
||||||
FILE* fp = fopen(argv[i], "r");
|
FILE* fp = fopen(argv[i], "r");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
@ -1024,6 +1051,7 @@ int main(int argc, char* argv[])
|
||||||
if (!evalScript(context, src, StringRef::createFromUTF8(fileName.data(), fileName.length()), false, seenModule)) {
|
if (!evalScript(context, src, StringRef::createFromUTF8(fileName.data(), fileName.length()), false, seenModule)) {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
seenModule = false;
|
seenModule = false;
|
||||||
fileName.clear();
|
fileName.clear();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1076,6 +1104,8 @@ int main(int argc, char* argv[])
|
||||||
instance.release();
|
instance.release();
|
||||||
|
|
||||||
Globals::finalize();
|
Globals::finalize();
|
||||||
|
if (memoryUsageLog) {
|
||||||
|
printf("Tick %" PRIu64 ": End Measure\n", fastTickCount());
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue