mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
Add custom allocator for precise marking and add more tools
* CustomAllocator : Supports precise marking for specified objects.
(also supports iteration of specific typed objects)
* HeapVisualizer : Track and visualize heap usage info.
* GCLeakChecker : Shows where the false reference came from.
(Developer should specify the location of false reference)
* Add support for incremental build of bdwgc
This commit is contained in:
parent
ac9b7b10f5
commit
1a56fe4e48
22 changed files with 1056 additions and 475 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -56,4 +56,4 @@ android/obj
|
|||
android/libs
|
||||
#test/chakracore/chakracorelog.verbose.txt
|
||||
*.gen.txt
|
||||
bdwgc_log
|
||||
bdwgcUsage.dat
|
||||
|
|
|
|||
3
Makefile
3
Makefile
|
|
@ -195,11 +195,12 @@ endif
|
|||
|
||||
SRC=
|
||||
SRC += $(foreach dir, src , $(wildcard $(dir)/*.cpp))
|
||||
SRC += $(foreach dir, src/heap , $(wildcard $(dir)/*.cpp))
|
||||
SRC += $(foreach dir, src/interpreter , $(wildcard $(dir)/*.cpp))
|
||||
SRC += $(foreach dir, src/parser , $(wildcard $(dir)/*.cpp))
|
||||
SRC += $(foreach dir, src/parser/ast , $(wildcard $(dir)/*.cpp))
|
||||
SRC += $(foreach dir, src/parser/esprima_cpp , $(wildcard $(dir)/*.cpp))
|
||||
SRC += $(foreach dir, src/runtime , $(wildcard $(dir)/*.cpp))
|
||||
SRC += $(foreach dir, src/interpreter , $(wildcard $(dir)/*.cpp))
|
||||
SRC += $(foreach dir, src/util , $(wildcard $(dir)/*.cpp))
|
||||
ifeq ($(OUTPUT), bin)
|
||||
SRC += $(foreach dir, src/shell , $(wildcard $(dir)/*.cpp))
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@ if [ ! -f /proc/cpuinfo ]; then
|
|||
fi
|
||||
NUMPROC=$(grep 'processor' /proc/cpuinfo | wc -l)
|
||||
|
||||
INCREMENTAL=false
|
||||
if [[ $1 == incremental ]]; then
|
||||
INCREMENTAL=true
|
||||
fi
|
||||
|
||||
#LTO=true
|
||||
LTO=false
|
||||
#COMPILER_VERSION_MAJOR=4.9
|
||||
|
|
@ -18,10 +23,12 @@ COMPILER_VERSION_MINOR=4.6.4
|
|||
# GC build
|
||||
###########################################################
|
||||
cd third_party/bdwgc/
|
||||
autoreconf -vif
|
||||
automake --add-missing
|
||||
#./autogen.sh
|
||||
#make distclean
|
||||
if [[ $INCREMENTAL == false ]]; then
|
||||
autoreconf -vif
|
||||
automake --add-missing
|
||||
#./autogen.sh
|
||||
#make distclean
|
||||
fi
|
||||
|
||||
# Common flags --------------------------------------------
|
||||
|
||||
|
|
@ -70,10 +77,20 @@ function build_gc_for_linux() {
|
|||
for mode in debug release; do
|
||||
for libtype in shared static; do
|
||||
echo =========================================================================
|
||||
echo Building bdwgc for $host $arch $mode $libtype
|
||||
|
||||
if ([ "$ARCH" != "" ] && [ "$ARCH" != $arch ]) ||
|
||||
([ "$MODE" != "" ] && [ "$MODE" != $mode ]) ||
|
||||
([ "$LIBTYPE" != "" ] && [ "$LIBTYPE" != $libtype ]); then
|
||||
echo Skipping bdwgc build for $host $arch $mode $libtype
|
||||
continue
|
||||
else
|
||||
echo Building bdwgc for $host $arch $mode $libtype
|
||||
fi
|
||||
|
||||
BUILDDIR=out/$host/$arch/$mode.$libtype
|
||||
rm -rf $BUILDDIR
|
||||
if [[ $INCREMENTAL == false ]]; then
|
||||
rm -rf $BUILDDIR
|
||||
fi
|
||||
mkdir -p $BUILDDIR
|
||||
cd $BUILDDIR
|
||||
|
||||
|
|
@ -86,7 +103,9 @@ function build_gc_for_linux() {
|
|||
CFLAGS="$CFLAGS_COMMON ${!CFLAGS_HOST} ${!CFLAGS_ARCH} ${!CFLAGS_MODE} ${!CFLAGS_LIBTYPE}"
|
||||
LDFLAGS="$LDFLAGS_COMMON ${!LDFLAGS_HOST} ${!LDFLAGS_ARCH} ${!LDFLAGS_MODE} ${!LDFLAGS_LIBTYPE}"
|
||||
|
||||
../../../../configure $GCCONFFLAGS CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS $CFLAGS" > /dev/null
|
||||
if [[ $INCREMENTAL == false ]]; then
|
||||
../../../../configure $GCCONFFLAGS CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS $CFLAGS" > /dev/null
|
||||
fi
|
||||
make -j$NUMPROC > /dev/null
|
||||
|
||||
echo Building bdwgc for $host $arch $mode $libtype done
|
||||
|
|
@ -215,6 +234,7 @@ if [[ $1 == tizen_obs_arm ]]; then
|
|||
build_gc_for_tizen_obs arm $2
|
||||
elif [[ $1 == tizen_obs_i386 ]]; then
|
||||
build_gc_for_tizen_obs i386 $2
|
||||
|
||||
else # full build
|
||||
|
||||
build_gc_for_linux
|
||||
|
|
|
|||
330
src/Escargot.h
330
src/Escargot.h
|
|
@ -26,337 +26,8 @@
|
|||
|
||||
#include <unicode/locid.h>
|
||||
#include <unicode/uchar.h>
|
||||
|
||||
// #define PROFILE_MASSIF
|
||||
|
||||
#ifndef PROFILE_MASSIF
|
||||
|
||||
#include <gc_allocator.h>
|
||||
#include <gc_cpp.h>
|
||||
|
||||
#include <unicode/locid.h>
|
||||
#include <unicode/datefmt.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <gc.h>
|
||||
|
||||
void* GC_malloc_hook(size_t siz);
|
||||
void* GC_malloc_atomic_hook(size_t siz);
|
||||
void GC_free_hook(void* address);
|
||||
|
||||
#undef GC_MALLOC
|
||||
#define GC_MALLOC(X) GC_malloc_hook(X)
|
||||
|
||||
#undef GC_MALLOC_ATOMIC
|
||||
#define GC_MALLOC_ATOMIC(X) GC_malloc_atomic_hook(X)
|
||||
|
||||
#undef GC_FREE
|
||||
#define GC_FREE(X) GC_free_hook(X)
|
||||
|
||||
#undef GC_REGISTER_FINALIZER_NO_ORDER
|
||||
#define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) GC_register_finalizer_no_order(p, f, d, of, od)
|
||||
|
||||
|
||||
#include <gc_allocator.h>
|
||||
#include <gc_cpp.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
template <class GC_Tp>
|
||||
class gc_malloc_allocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef GC_Tp* pointer;
|
||||
typedef const GC_Tp* const_pointer;
|
||||
typedef GC_Tp& reference;
|
||||
typedef const GC_Tp& const_reference;
|
||||
typedef GC_Tp value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_allocator<GC_Tp1> other;
|
||||
};
|
||||
|
||||
gc_malloc_allocator() throw() {}
|
||||
gc_malloc_allocator(const gc_malloc_allocator&) throw() {}
|
||||
#if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
|
||||
// MSVC++ 6.0 do not support member templates
|
||||
template <class GC_Tp1>
|
||||
gc_malloc_allocator(const gc_malloc_allocator<GC_Tp1>&) throw() {}
|
||||
#endif
|
||||
~gc_malloc_allocator() throw()
|
||||
{
|
||||
}
|
||||
|
||||
pointer address(reference GC_x) const { return &GC_x; }
|
||||
const_pointer address(const_reference GC_x) const { return &GC_x; }
|
||||
// GC_n is permitted to be 0. The C++ standard says nothing about what
|
||||
// the return value is when GC_n == 0.
|
||||
GC_Tp* allocate(size_type GC_n, const void* = 0)
|
||||
{
|
||||
return (GC_Tp*)GC_MALLOC(sizeof(GC_Tp) * GC_n);
|
||||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n) { GC_FREE(__p); }
|
||||
size_type max_size() const throw() { return size_t(-1) / sizeof(GC_Tp); }
|
||||
void construct(pointer __p, const GC_Tp& __val) { new (__p) GC_Tp(__val); }
|
||||
void destroy(pointer __p) { __p->~GC_Tp(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class gc_malloc_allocator<void> {
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
typedef void value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_allocator<GC_Tp1> other;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator==(const gc_malloc_allocator<GC_T1>&, const gc_malloc_allocator<GC_T2>&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator!=(const gc_malloc_allocator<GC_T1>&, const gc_malloc_allocator<GC_T2>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class GC_Tp>
|
||||
class gc_malloc_pointer_free_allocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef GC_Tp* pointer;
|
||||
typedef const GC_Tp* const_pointer;
|
||||
typedef GC_Tp& reference;
|
||||
typedef const GC_Tp& const_reference;
|
||||
typedef GC_Tp value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_pointer_free_allocator<GC_Tp1> other;
|
||||
};
|
||||
|
||||
gc_malloc_pointer_free_allocator() throw() {}
|
||||
gc_malloc_pointer_free_allocator(const gc_malloc_pointer_free_allocator&) throw() {}
|
||||
#if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
|
||||
// MSVC++ 6.0 do not support member templates
|
||||
template <class GC_Tp1>
|
||||
gc_malloc_pointer_free_allocator(const gc_malloc_pointer_free_allocator<GC_Tp1>&) throw() {}
|
||||
#endif
|
||||
~gc_malloc_pointer_free_allocator() throw()
|
||||
{
|
||||
}
|
||||
|
||||
pointer address(reference GC_x) const { return &GC_x; }
|
||||
const_pointer address(const_reference GC_x) const { return &GC_x; }
|
||||
// GC_n is permitted to be 0. The C++ standard says nothing about what
|
||||
// the return value is when GC_n == 0.
|
||||
GC_Tp* allocate(size_type GC_n, const void* = 0)
|
||||
{
|
||||
return (GC_Tp*)GC_MALLOC_ATOMIC(sizeof(GC_Tp) * GC_n);
|
||||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n) { GC_FREE(__p); }
|
||||
size_type max_size() const throw() { return size_t(-1) / sizeof(GC_Tp); }
|
||||
void construct(pointer __p, const GC_Tp& __val) { new (__p) GC_Tp(__val); }
|
||||
void destroy(pointer __p) { __p->~GC_Tp(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class gc_malloc_pointer_free_allocator<void> {
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
typedef void value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_pointer_free_allocator<GC_Tp1> other;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator==(const gc_malloc_pointer_free_allocator<GC_T1>&, const gc_malloc_pointer_free_allocator<GC_T2>&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator!=(const gc_malloc_pointer_free_allocator<GC_T1>&, const gc_malloc_pointer_free_allocator<GC_T2>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template <class GC_Tp>
|
||||
class gc_malloc_ignore_off_page_allocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef GC_Tp* pointer;
|
||||
typedef const GC_Tp* const_pointer;
|
||||
typedef GC_Tp& reference;
|
||||
typedef const GC_Tp& const_reference;
|
||||
typedef GC_Tp value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_ignore_off_page_allocator<GC_Tp1> other;
|
||||
};
|
||||
|
||||
gc_malloc_ignore_off_page_allocator() throw() {}
|
||||
gc_malloc_ignore_off_page_allocator(const gc_malloc_ignore_off_page_allocator&) throw() {}
|
||||
#if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
|
||||
// MSVC++ 6.0 do not support member templates
|
||||
template <class GC_Tp1>
|
||||
gc_malloc_ignore_off_page_allocator(const gc_malloc_ignore_off_page_allocator<GC_Tp1>&) throw() {}
|
||||
#endif
|
||||
~gc_malloc_ignore_off_page_allocator() throw()
|
||||
{
|
||||
}
|
||||
|
||||
pointer address(reference GC_x) const { return &GC_x; }
|
||||
const_pointer address(const_reference GC_x) const { return &GC_x; }
|
||||
// GC_n is permitted to be 0. The C++ standard says nothing about what
|
||||
// the return value is when GC_n == 0.
|
||||
GC_Tp* allocate(size_type GC_n, const void* = 0)
|
||||
{
|
||||
if (sizeof(GC_Tp) * GC_n > 1024) {
|
||||
return (GC_Tp*)GC_MALLOC_IGNORE_OFF_PAGE(sizeof(GC_Tp) * GC_n);
|
||||
} else {
|
||||
return (GC_Tp*)GC_MALLOC(sizeof(GC_Tp) * GC_n);
|
||||
}
|
||||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n) { GC_FREE(__p); }
|
||||
size_type max_size() const throw() { return size_t(-1) / sizeof(GC_Tp); }
|
||||
void construct(pointer __p, const GC_Tp& __val) { new (__p) GC_Tp(__val); }
|
||||
void destroy(pointer __p) { __p->~GC_Tp(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class gc_malloc_ignore_off_page_allocator<void> {
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
typedef void value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_ignore_off_page_allocator<GC_Tp1> other;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator==(const gc_malloc_ignore_off_page_allocator<GC_T1>&, const gc_malloc_ignore_off_page_allocator<GC_T2>&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator!=(const gc_malloc_ignore_off_page_allocator<GC_T1>&, const gc_malloc_ignore_off_page_allocator<GC_T2>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class GC_Tp>
|
||||
class gc_malloc_atomic_ignore_off_page_allocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef GC_Tp* pointer;
|
||||
typedef const GC_Tp* const_pointer;
|
||||
typedef GC_Tp& reference;
|
||||
typedef const GC_Tp& const_reference;
|
||||
typedef GC_Tp value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_atomic_ignore_off_page_allocator<GC_Tp1> other;
|
||||
};
|
||||
|
||||
gc_malloc_atomic_ignore_off_page_allocator() throw() {}
|
||||
gc_malloc_atomic_ignore_off_page_allocator(const gc_malloc_atomic_ignore_off_page_allocator&) throw() {}
|
||||
#if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
|
||||
// MSVC++ 6.0 do not support member templates
|
||||
template <class GC_Tp1>
|
||||
gc_malloc_atomic_ignore_off_page_allocator(const gc_malloc_atomic_ignore_off_page_allocator<GC_Tp1>&) throw() {}
|
||||
#endif
|
||||
~gc_malloc_atomic_ignore_off_page_allocator() throw()
|
||||
{
|
||||
}
|
||||
|
||||
pointer address(reference GC_x) const { return &GC_x; }
|
||||
const_pointer address(const_reference GC_x) const { return &GC_x; }
|
||||
// GC_n is permitted to be 0. The C++ standard says nothing about what
|
||||
// the return value is when GC_n == 0.
|
||||
GC_Tp* allocate(size_type GC_n, const void* = 0)
|
||||
{
|
||||
if (sizeof(GC_Tp) * GC_n > 1024) {
|
||||
return (GC_Tp*)GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sizeof(GC_Tp) * GC_n);
|
||||
} else {
|
||||
return (GC_Tp*)GC_MALLOC_ATOMIC(sizeof(GC_Tp) * GC_n);
|
||||
}
|
||||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n) { GC_FREE(__p); }
|
||||
size_type max_size() const throw() { return size_t(-1) / sizeof(GC_Tp); }
|
||||
void construct(pointer __p, const GC_Tp& __val) { new (__p) GC_Tp(__val); }
|
||||
void destroy(pointer __p) { __p->~GC_Tp(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class gc_malloc_atomic_ignore_off_page_allocator<void> {
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
typedef void value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_atomic_ignore_off_page_allocator<GC_Tp1> other;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator==(const gc_malloc_atomic_ignore_off_page_allocator<GC_T1>&, const gc_malloc_atomic_ignore_off_page_allocator<GC_T2>&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator!=(const gc_malloc_atomic_ignore_off_page_allocator<GC_T1>&, const gc_malloc_atomic_ignore_off_page_allocator<GC_T2>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* COMPILER() - the compiler being used to build the project */
|
||||
#define COMPILER(FEATURE) (defined COMPILER_##FEATURE && COMPILER_##FEATURE)
|
||||
|
||||
|
|
@ -531,6 +202,7 @@ inline bool operator!=(const gc_malloc_atomic_ignore_off_page_allocator<GC_T1>&,
|
|||
|
||||
#define ALLOCA(bytes, typenameWithoutPointer, ec) (typenameWithoutPointer*)alloca(bytes)
|
||||
|
||||
#include "heap/Heap.h"
|
||||
#include "CheckedArithmetic.h"
|
||||
#include "runtime/String.h"
|
||||
|
||||
|
|
|
|||
213
src/heap/Allocator.cpp
Normal file
213
src/heap/Allocator.cpp
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Samsung Electronics Co., Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Escargot.h"
|
||||
#include "Allocator.h"
|
||||
|
||||
#include "runtime/Value.h"
|
||||
#include "runtime/ArrayObject.h"
|
||||
|
||||
|
||||
#ifdef PROFILE_MASSIF
|
||||
std::unordered_map<void*, void*> g_addressTable;
|
||||
std::vector<void*> g_freeList;
|
||||
|
||||
void unregisterGCAddress(void* address)
|
||||
{
|
||||
// ASSERT(g_addressTable.find(address) != g_addressTable.end());
|
||||
if (g_addressTable.find(address) != g_addressTable.end()) {
|
||||
auto iter = g_addressTable.find(address);
|
||||
free(iter->second);
|
||||
g_addressTable.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void registerGCAddress(void* address, size_t siz)
|
||||
{
|
||||
if (g_addressTable.find(address) != g_addressTable.end()) {
|
||||
unregisterGCAddress(address);
|
||||
}
|
||||
g_addressTable[address] = malloc(siz);
|
||||
}
|
||||
|
||||
void* GC_malloc_hook(size_t siz)
|
||||
{
|
||||
void* ptr;
|
||||
#ifdef NDEBUG
|
||||
ptr = GC_malloc(siz);
|
||||
#else
|
||||
ptr = GC_malloc(siz);
|
||||
#endif
|
||||
registerGCAddress(ptr, siz);
|
||||
return ptr;
|
||||
}
|
||||
void* GC_malloc_atomic_hook(size_t siz)
|
||||
{
|
||||
void* ptr;
|
||||
#ifdef NDEBUG
|
||||
ptr = GC_malloc_atomic(siz);
|
||||
#else
|
||||
ptr = GC_malloc_atomic(siz);
|
||||
#endif
|
||||
registerGCAddress(ptr, siz);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* GC_generic_malloc_ignore_off_page_hook(size_t siz, int kind)
|
||||
{
|
||||
void* ptr;
|
||||
#ifdef NDEBUG
|
||||
ptr = GC_generic_malloc(siz, kind);
|
||||
#else
|
||||
ptr = GC_generic_malloc(siz, kind);
|
||||
#endif
|
||||
registerGCAddress(ptr, siz);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* GC_malloc_ignore_off_page_hook(size_t siz)
|
||||
{
|
||||
void* ptr;
|
||||
#ifdef NDEBUG
|
||||
ptr = GC_malloc_ignore_off_page(siz);
|
||||
#else
|
||||
ptr = GC_malloc_ignore_off_page(siz);
|
||||
#endif
|
||||
registerGCAddress(ptr, siz);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* GC_malloc_atomic_ignore_off_page_hook(size_t siz)
|
||||
{
|
||||
void* ptr;
|
||||
#ifdef NDEBUG
|
||||
ptr = GC_malloc_atomic_ignore_off_page_hook(siz);
|
||||
#else
|
||||
ptr = GC_malloc_atomic_ignore_off_page_hook(siz);
|
||||
#endif
|
||||
registerGCAddress(ptr, siz);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void GC_free_hook(void* address)
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
GC_free(address);
|
||||
#else
|
||||
GC_free(address);
|
||||
#endif
|
||||
unregisterGCAddress(address);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
static int s_gcKinds[HeapObjectKind::NumberOfKind];
|
||||
|
||||
template<GC_get_next_pointer_proc proc>
|
||||
static struct GC_ms_entry* markAndPushCustom(GC_word* addr,
|
||||
struct GC_ms_entry *mark_stack_ptr,
|
||||
struct GC_ms_entry *mark_stack_limit,
|
||||
GC_word env) {
|
||||
return GC_mark_and_push_custom(addr, mark_stack_ptr, mark_stack_limit, proc);
|
||||
}
|
||||
|
||||
static GC_word* getNextValidValue(GC_word** iterator) {
|
||||
Value* current = (*(Value**)iterator)++;
|
||||
if (*current && current->isPointerValue())
|
||||
return (GC_word*)current->asPointerValue();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void initializeCustomAllocators() {
|
||||
s_gcKinds[HeapObjectKind::ValueVectorKind] =
|
||||
GC_new_kind(GC_new_free_list(),
|
||||
GC_MAKE_PROC(GC_new_proc(markAndPushCustom<getNextValidValue>), 0),
|
||||
FALSE,
|
||||
TRUE);
|
||||
|
||||
s_gcKinds[HeapObjectKind::ArrayObjectKind] =
|
||||
GC_new_kind(GC_new_free_list(),
|
||||
0 | GC_DS_LENGTH,
|
||||
TRUE,
|
||||
TRUE);
|
||||
|
||||
#ifdef PROFILE_MASSIF
|
||||
GC_is_valid_displacement_print_proc = [](void* ptr) {
|
||||
g_freeList.push_back(ptr);
|
||||
};
|
||||
GC_set_on_collection_event([](GC_EventType evtType) {
|
||||
if (GC_EVENT_PRE_START_WORLD == evtType) {
|
||||
auto iter = g_addressTable.begin();
|
||||
while (iter != g_addressTable.end()) {
|
||||
GC_is_valid_displacement(iter->first);
|
||||
iter++;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < g_freeList.size(); i++) {
|
||||
unregisterGCAddress(g_freeList[i]);
|
||||
}
|
||||
|
||||
g_freeList.clear();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void iterateSpecificKindOfObject(ExecutionState& state, HeapObjectKind kind, HeapObjectIteratorCallback callback) {
|
||||
|
||||
struct HeapObjectIteratorData {
|
||||
int kind;
|
||||
ExecutionState& state;
|
||||
HeapObjectIteratorCallback callback;
|
||||
};
|
||||
|
||||
HeapObjectIteratorData data { s_gcKinds[kind], state, callback };
|
||||
|
||||
GC_gcollect(); // Update mark status
|
||||
GC_enumerate_reachable_objects_inner([](void* obj, size_t bytes, void* cd) {
|
||||
size_t size;
|
||||
int kind = GC_get_kind_and_size(obj, &size);
|
||||
ASSERT(size == bytes);
|
||||
|
||||
HeapObjectIteratorData* data = (HeapObjectIteratorData*) cd;
|
||||
if (kind == data->kind) {
|
||||
data->callback(data->state, obj);
|
||||
}
|
||||
}, (void*)(&data));
|
||||
}
|
||||
|
||||
template <>
|
||||
Value* CustomAllocator<Value>::allocate(size_type GC_n, const void*) {
|
||||
// Un-comment this to use default allocator
|
||||
// return (Value*)GC_MALLOC_IGNORE_OFF_PAGE(sizeof(Value) * GC_n);
|
||||
int kind = s_gcKinds[HeapObjectKind::ValueVectorKind];
|
||||
return (Value*)GC_GENERIC_MALLOC_IGNORE_OFF_PAGE(sizeof(Value) * GC_n, kind);
|
||||
}
|
||||
|
||||
template <>
|
||||
ArrayObject* CustomAllocator<ArrayObject>::allocate(size_type GC_n, const void*) {
|
||||
// Un-comment this to use default allocator
|
||||
// return (ArrayObject*)GC_MALLOC(sizeof(ArrayObject));
|
||||
ASSERT(GC_n == 1);
|
||||
int kind = s_gcKinds[HeapObjectKind::ArrayObjectKind];
|
||||
return (ArrayObject*)GC_GENERIC_MALLOC(sizeof(ArrayObject), kind);
|
||||
}
|
||||
|
||||
}
|
||||
400
src/heap/Allocator.h
Normal file
400
src/heap/Allocator.h
Normal file
|
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Samsung Electronics Co., Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __Allocator__
|
||||
#define __Allocator__
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
class ExecutionState;
|
||||
|
||||
enum HeapObjectKind {
|
||||
ValueVectorKind = 0,
|
||||
ArrayObjectKind,
|
||||
NumberOfKind,
|
||||
};
|
||||
|
||||
void initializeCustomAllocators();
|
||||
|
||||
typedef std::function<void(ExecutionState& state, void* obj)> HeapObjectIteratorCallback;
|
||||
|
||||
/*
|
||||
* This Function will iterate over every objects of given kind.
|
||||
* It has to call GC_gcollect() since it needs precise mark status.
|
||||
* So don't call this in performance-critical path.
|
||||
*/
|
||||
void iterateSpecificKindOfObject(ExecutionState& state, HeapObjectKind kind, HeapObjectIteratorCallback callback);
|
||||
|
||||
template <class GC_Tp>
|
||||
class CustomAllocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef GC_Tp* pointer;
|
||||
typedef const GC_Tp* const_pointer;
|
||||
typedef GC_Tp& reference;
|
||||
typedef const GC_Tp& const_reference;
|
||||
typedef GC_Tp value_type;
|
||||
|
||||
template <class GC_Tp1> struct rebind {
|
||||
typedef CustomAllocator<GC_Tp1> other;
|
||||
};
|
||||
|
||||
CustomAllocator() throw() { }
|
||||
CustomAllocator(const CustomAllocator&) throw() { }
|
||||
# if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
|
||||
// MSVC++ 6.0 do not support member templates
|
||||
template <class GC_Tp1> CustomAllocator
|
||||
(const CustomAllocator<GC_Tp1>&) throw() { }
|
||||
# endif
|
||||
~CustomAllocator() throw() { }
|
||||
|
||||
pointer address(reference GC_x) const { return &GC_x; }
|
||||
const_pointer address(const_reference GC_x) const { return &GC_x; }
|
||||
|
||||
// GC_n is permitted to be 0. The C++ standard says nothing about what
|
||||
// the return value is when GC_n == 0.
|
||||
GC_Tp* allocate(size_type GC_n, const void* = 0);
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n)
|
||||
{ GC_FREE(__p); }
|
||||
|
||||
size_type max_size() const throw()
|
||||
{ return size_t(-1) / sizeof(GC_Tp); }
|
||||
|
||||
void construct(pointer __p, const GC_Tp& __val) { new(__p) GC_Tp(__val); }
|
||||
void destroy(pointer __p) { __p->~GC_Tp(); }
|
||||
};
|
||||
|
||||
template<>
|
||||
class CustomAllocator<void> {
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
typedef void value_type;
|
||||
|
||||
template <class GC_Tp1> struct rebind {
|
||||
typedef CustomAllocator<GC_Tp1> other;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator==(const CustomAllocator<GC_T1>&, const CustomAllocator<GC_T2>&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator!=(const CustomAllocator<GC_T1>&, const CustomAllocator<GC_T2>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class GC_Tp>
|
||||
class gc_malloc_allocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef GC_Tp* pointer;
|
||||
typedef const GC_Tp* const_pointer;
|
||||
typedef GC_Tp& reference;
|
||||
typedef const GC_Tp& const_reference;
|
||||
typedef GC_Tp value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_allocator<GC_Tp1> other;
|
||||
};
|
||||
|
||||
gc_malloc_allocator() throw() {}
|
||||
gc_malloc_allocator(const gc_malloc_allocator&) throw() {}
|
||||
#if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
|
||||
// MSVC++ 6.0 do not support member templates
|
||||
template <class GC_Tp1>
|
||||
gc_malloc_allocator(const gc_malloc_allocator<GC_Tp1>&) throw() {}
|
||||
#endif
|
||||
~gc_malloc_allocator() throw()
|
||||
{
|
||||
}
|
||||
|
||||
pointer address(reference GC_x) const { return &GC_x; }
|
||||
const_pointer address(const_reference GC_x) const { return &GC_x; }
|
||||
// GC_n is permitted to be 0. The C++ standard says nothing about what
|
||||
// the return value is when GC_n == 0.
|
||||
GC_Tp* allocate(size_type GC_n, const void* = 0)
|
||||
{
|
||||
return (GC_Tp*)GC_MALLOC(sizeof(GC_Tp) * GC_n);
|
||||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n) { GC_FREE(__p); }
|
||||
size_type max_size() const throw() { return size_t(-1) / sizeof(GC_Tp); }
|
||||
void construct(pointer __p, const GC_Tp& __val) { new (__p) GC_Tp(__val); }
|
||||
void destroy(pointer __p) { __p->~GC_Tp(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class gc_malloc_allocator<void> {
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
typedef void value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_allocator<GC_Tp1> other;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator==(const gc_malloc_allocator<GC_T1>&, const gc_malloc_allocator<GC_T2>&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator!=(const gc_malloc_allocator<GC_T1>&, const gc_malloc_allocator<GC_T2>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class GC_Tp>
|
||||
class gc_malloc_pointer_free_allocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef GC_Tp* pointer;
|
||||
typedef const GC_Tp* const_pointer;
|
||||
typedef GC_Tp& reference;
|
||||
typedef const GC_Tp& const_reference;
|
||||
typedef GC_Tp value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_pointer_free_allocator<GC_Tp1> other;
|
||||
};
|
||||
|
||||
gc_malloc_pointer_free_allocator() throw() {}
|
||||
gc_malloc_pointer_free_allocator(const gc_malloc_pointer_free_allocator&) throw() {}
|
||||
#if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
|
||||
// MSVC++ 6.0 do not support member templates
|
||||
template <class GC_Tp1>
|
||||
gc_malloc_pointer_free_allocator(const gc_malloc_pointer_free_allocator<GC_Tp1>&) throw() {}
|
||||
#endif
|
||||
~gc_malloc_pointer_free_allocator() throw()
|
||||
{
|
||||
}
|
||||
|
||||
pointer address(reference GC_x) const { return &GC_x; }
|
||||
const_pointer address(const_reference GC_x) const { return &GC_x; }
|
||||
// GC_n is permitted to be 0. The C++ standard says nothing about what
|
||||
// the return value is when GC_n == 0.
|
||||
GC_Tp* allocate(size_type GC_n, const void* = 0)
|
||||
{
|
||||
return (GC_Tp*)GC_MALLOC_ATOMIC(sizeof(GC_Tp) * GC_n);
|
||||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n) { GC_FREE(__p); }
|
||||
size_type max_size() const throw() { return size_t(-1) / sizeof(GC_Tp); }
|
||||
void construct(pointer __p, const GC_Tp& __val) { new (__p) GC_Tp(__val); }
|
||||
void destroy(pointer __p) { __p->~GC_Tp(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class gc_malloc_pointer_free_allocator<void> {
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
typedef void value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_pointer_free_allocator<GC_Tp1> other;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator==(const gc_malloc_pointer_free_allocator<GC_T1>&, const gc_malloc_pointer_free_allocator<GC_T2>&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator!=(const gc_malloc_pointer_free_allocator<GC_T1>&, const gc_malloc_pointer_free_allocator<GC_T2>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template <class GC_Tp>
|
||||
class gc_malloc_ignore_off_page_allocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef GC_Tp* pointer;
|
||||
typedef const GC_Tp* const_pointer;
|
||||
typedef GC_Tp& reference;
|
||||
typedef const GC_Tp& const_reference;
|
||||
typedef GC_Tp value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_ignore_off_page_allocator<GC_Tp1> other;
|
||||
};
|
||||
|
||||
gc_malloc_ignore_off_page_allocator() throw() {}
|
||||
gc_malloc_ignore_off_page_allocator(const gc_malloc_ignore_off_page_allocator&) throw() {}
|
||||
#if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
|
||||
// MSVC++ 6.0 do not support member templates
|
||||
template <class GC_Tp1>
|
||||
gc_malloc_ignore_off_page_allocator(const gc_malloc_ignore_off_page_allocator<GC_Tp1>&) throw() {}
|
||||
#endif
|
||||
~gc_malloc_ignore_off_page_allocator() throw()
|
||||
{
|
||||
}
|
||||
|
||||
pointer address(reference GC_x) const { return &GC_x; }
|
||||
const_pointer address(const_reference GC_x) const { return &GC_x; }
|
||||
// GC_n is permitted to be 0. The C++ standard says nothing about what
|
||||
// the return value is when GC_n == 0.
|
||||
GC_Tp* allocate(size_type GC_n, const void* = 0)
|
||||
{
|
||||
if (sizeof(GC_Tp) * GC_n > 1024) {
|
||||
return (GC_Tp*)GC_MALLOC_IGNORE_OFF_PAGE(sizeof(GC_Tp) * GC_n);
|
||||
} else {
|
||||
return (GC_Tp*)GC_MALLOC(sizeof(GC_Tp) * GC_n);
|
||||
}
|
||||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n) { GC_FREE(__p); }
|
||||
size_type max_size() const throw() { return size_t(-1) / sizeof(GC_Tp); }
|
||||
void construct(pointer __p, const GC_Tp& __val) { new (__p) GC_Tp(__val); }
|
||||
void destroy(pointer __p) { __p->~GC_Tp(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class gc_malloc_ignore_off_page_allocator<void> {
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
typedef void value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_ignore_off_page_allocator<GC_Tp1> other;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator==(const gc_malloc_ignore_off_page_allocator<GC_T1>&, const gc_malloc_ignore_off_page_allocator<GC_T2>&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator!=(const gc_malloc_ignore_off_page_allocator<GC_T1>&, const gc_malloc_ignore_off_page_allocator<GC_T2>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class GC_Tp>
|
||||
class gc_malloc_atomic_ignore_off_page_allocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef GC_Tp* pointer;
|
||||
typedef const GC_Tp* const_pointer;
|
||||
typedef GC_Tp& reference;
|
||||
typedef const GC_Tp& const_reference;
|
||||
typedef GC_Tp value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_atomic_ignore_off_page_allocator<GC_Tp1> other;
|
||||
};
|
||||
|
||||
gc_malloc_atomic_ignore_off_page_allocator() throw() {}
|
||||
gc_malloc_atomic_ignore_off_page_allocator(const gc_malloc_atomic_ignore_off_page_allocator&) throw() {}
|
||||
#if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
|
||||
// MSVC++ 6.0 do not support member templates
|
||||
template <class GC_Tp1>
|
||||
gc_malloc_atomic_ignore_off_page_allocator(const gc_malloc_atomic_ignore_off_page_allocator<GC_Tp1>&) throw() {}
|
||||
#endif
|
||||
~gc_malloc_atomic_ignore_off_page_allocator() throw()
|
||||
{
|
||||
}
|
||||
|
||||
pointer address(reference GC_x) const { return &GC_x; }
|
||||
const_pointer address(const_reference GC_x) const { return &GC_x; }
|
||||
// GC_n is permitted to be 0. The C++ standard says nothing about what
|
||||
// the return value is when GC_n == 0.
|
||||
GC_Tp* allocate(size_type GC_n, const void* = 0)
|
||||
{
|
||||
if (sizeof(GC_Tp) * GC_n > 1024) {
|
||||
return (GC_Tp*)GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sizeof(GC_Tp) * GC_n);
|
||||
} else {
|
||||
return (GC_Tp*)GC_MALLOC_ATOMIC(sizeof(GC_Tp) * GC_n);
|
||||
}
|
||||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n) { GC_FREE(__p); }
|
||||
size_type max_size() const throw() { return size_t(-1) / sizeof(GC_Tp); }
|
||||
void construct(pointer __p, const GC_Tp& __val) { new (__p) GC_Tp(__val); }
|
||||
void destroy(pointer __p) { __p->~GC_Tp(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class gc_malloc_atomic_ignore_off_page_allocator<void> {
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
typedef void value_type;
|
||||
|
||||
template <class GC_Tp1>
|
||||
struct rebind {
|
||||
typedef gc_malloc_atomic_ignore_off_page_allocator<GC_Tp1> other;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator==(const gc_malloc_atomic_ignore_off_page_allocator<GC_T1>&, const gc_malloc_atomic_ignore_off_page_allocator<GC_T2>&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator!=(const gc_malloc_atomic_ignore_off_page_allocator<GC_T1>&, const gc_malloc_atomic_ignore_off_page_allocator<GC_T2>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
30
src/heap/Heap.cpp
Normal file
30
src/heap/Heap.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include "Escargot.h"
|
||||
|
||||
#include "Heap.h"
|
||||
#include "HeapProfiler.h"
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
void Heap::initialize()
|
||||
{
|
||||
GC_set_free_space_divisor(24);
|
||||
GC_set_force_unmap_on_gcollect(1);
|
||||
// GC_set_full_freq(1);
|
||||
// GC_set_time_limit(GC_TIME_UNLIMITED);
|
||||
|
||||
initializeCustomAllocators();
|
||||
|
||||
#ifdef PROFILE_BDWGC
|
||||
Escargot::HeapUsageVisualizer::initialize();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void Heap::finalize()
|
||||
{
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
GC_gcollect_and_unmap();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
56
src/heap/Heap.h
Normal file
56
src/heap/Heap.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#ifndef __Heap__
|
||||
#define __Heap__
|
||||
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
class Heap {
|
||||
public:
|
||||
static void initialize();
|
||||
static void finalize();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
//#define PROFILE_MASSIF
|
||||
#ifdef PROFILE_MASSIF
|
||||
|
||||
#ifndef ESCARGOT_SHELL
|
||||
#error `PROFILE_MASSIF` can only be enabled in escargot shell
|
||||
#endif
|
||||
|
||||
#include <gc.h>
|
||||
|
||||
void* GC_malloc_hook(size_t siz);
|
||||
void* GC_malloc_atomic_hook(size_t siz);
|
||||
void* GC_generic_malloc_ignore_off_page_hook(size_t siz, int kind);
|
||||
void GC_free_hook(void* address);
|
||||
|
||||
#undef GC_MALLOC
|
||||
#define GC_MALLOC(X) GC_malloc_hook(X)
|
||||
|
||||
#undef GC_MALLOC_ATOMIC
|
||||
#define GC_MALLOC_ATOMIC(X) GC_malloc_atomic_hook(X)
|
||||
|
||||
#undef GC_GENERIC_MALLOC_IGNORE_OFF_PAGE
|
||||
#define GC_GENERIC_MALLOC_IGNORE_OFF_PAGE(siz, kind) GC_generic_malloc_ignore_off_page_hook(siz, kind)
|
||||
|
||||
#undef GC_FREE
|
||||
#define GC_FREE(X) GC_free_hook(X)
|
||||
|
||||
#undef GC_REGISTER_FINALIZER_NO_ORDER
|
||||
#define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) GC_register_finalizer_no_order(p, f, d, of, od)
|
||||
|
||||
#endif
|
||||
|
||||
#include <gc_allocator.h>
|
||||
#include <gc_cpp.h>
|
||||
#include <gc_mark.h>
|
||||
#ifdef GC_DEBUG
|
||||
#include <gc_backptr.h>
|
||||
#endif
|
||||
|
||||
#include "Allocator.h"
|
||||
|
||||
#endif
|
||||
121
src/heap/HeapProfiler.cpp
Normal file
121
src/heap/HeapProfiler.cpp
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
#include "Escargot.h"
|
||||
|
||||
#include "HeapProfiler.h"
|
||||
#include "heap/Allocator.h"
|
||||
#include "runtime/ErrorObject.h"
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
#ifdef PROFILE_BDWGC
|
||||
|
||||
std::string HeapUsageVisualizer::m_outputFile = "bdwgcUsage.dat";
|
||||
|
||||
size_t GCLeakChecker::m_totalFreed = 0;
|
||||
std::vector<GCLeakChecker::LeakCheckedAddr> GCLeakChecker::m_leakCheckedAddrs;
|
||||
|
||||
static std::string s_gcLogPhaseName = "initial phase";
|
||||
|
||||
void HeapUsageVisualizer::initialize()
|
||||
{
|
||||
remove(HeapUsageVisualizer::m_outputFile.c_str());
|
||||
FILE* fp = fopen(HeapUsageVisualizer::m_outputFile.c_str(), "a");
|
||||
if (fp) {
|
||||
fprintf(fp, "GC_no PeakRSS TotalHeap Marked # Phase\n");
|
||||
fclose(fp);
|
||||
}
|
||||
GC_set_on_collection_event([](GC_EventType evtType) {
|
||||
if (GC_EVENT_RECLAIM_START == evtType) {
|
||||
GC_dump_for_graph(HeapUsageVisualizer::m_outputFile.c_str(),
|
||||
s_gcLogPhaseName.c_str());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void GCLeakChecker::registerAddress(void* ptr, std::string description)
|
||||
{
|
||||
RELEASE_ASSERT(ptr);
|
||||
m_leakCheckedAddrs.push_back(LeakCheckedAddr { ptr, description, false });
|
||||
|
||||
printf("GCLeakChecker::registerAddress %p (%zu - %zu = %zu)\n", ptr,
|
||||
m_leakCheckedAddrs.size(), m_totalFreed, m_leakCheckedAddrs.size() - m_totalFreed);
|
||||
|
||||
GC_REGISTER_FINALIZER_NO_ORDER(ptr, [] (void* obj, void* cd) {
|
||||
GCLeakChecker::unregisterAddress(obj);
|
||||
}, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void GCLeakChecker::unregisterAddress(void* ptr)
|
||||
{
|
||||
RELEASE_ASSERT(ptr);
|
||||
m_totalFreed++;
|
||||
|
||||
printf("GCLeakChecker::unregisterAddress %p (%zu - %zu = %zu)\n", ptr,
|
||||
m_leakCheckedAddrs.size(), m_totalFreed, m_leakCheckedAddrs.size() - m_totalFreed);
|
||||
|
||||
for (auto& it: m_leakCheckedAddrs) {
|
||||
if (it.ptr == ptr) {
|
||||
it.deallocated = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void GCLeakChecker::dumpBackTrace(ExecutionState& state, const char* phase)
|
||||
{
|
||||
if (phase)
|
||||
s_gcLogPhaseName = phase;
|
||||
|
||||
#ifdef GC_DEBUG
|
||||
auto stream = stderr;
|
||||
fprintf(stderr, "GCLeakChecker::dumpBackTrace %s start >>>>>>>>>>\n", s_gcLogPhaseName.c_str());
|
||||
for (const auto& it: m_leakCheckedAddrs) {
|
||||
if (it.deallocated) {
|
||||
fprintf(stderr, "%s (%p) deallocated\n", it.description.c_str(), it.ptr);
|
||||
} else {
|
||||
fprintf(stderr, "Backtrace of %s (%p):\n", it.description.c_str(), it.ptr);
|
||||
GC_print_backtrace(it.ptr);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "GCLeakChecker::dumpBackTrace %s end <<<<<<<<<<\n", s_gcLogPhaseName.c_str());
|
||||
#else
|
||||
fprintf(stderr, "Cannot print the backtrace of leaked address.\n");
|
||||
fprintf(stderr, "Please re-configure bdwgc with `--enable-gc-debug`, ");
|
||||
fprintf(stderr, "and re-build escargot with `-DGC_DEBUG`.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Usage in JS: registerLeakCheck( object: PointerValue, description: String ); */
|
||||
Value builtinRegisterLeakCheck(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
|
||||
{
|
||||
if (!argv[0].isPointerValue())
|
||||
state.throwException(new ErrorObject(state, new ASCIIString("builtinRegisterLeakCheck should get pointer-type argument")));
|
||||
|
||||
PointerValue* ptr = argv[0].asPointerValue();
|
||||
std::string description = argv[1].toString(state)->toUTF8StringData().data();
|
||||
RELEASE_ASSERT(ptr);
|
||||
|
||||
GCLeakChecker::registerAddress(ptr, description);
|
||||
|
||||
return Value();
|
||||
}
|
||||
|
||||
/* Usage in JS: dumpBackTrace( phase: String ); */
|
||||
Value builtinDumpBackTrace(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
|
||||
{
|
||||
GCLeakChecker::dumpBackTrace(state, argv[0].toString(state)->toUTF8StringData().data());
|
||||
return Value();
|
||||
}
|
||||
|
||||
/* Usage in JS: setPhaseName( phase: String ); */
|
||||
Value builtinSetGCPhaseName(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression)
|
||||
{
|
||||
s_gcLogPhaseName = argv[0].toString(state)->toUTF8StringData().data();
|
||||
return Value();
|
||||
}
|
||||
|
||||
#endif // PROFILE_BDWGC
|
||||
|
||||
}
|
||||
|
||||
45
src/heap/HeapProfiler.h
Normal file
45
src/heap/HeapProfiler.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef __HeapProfiler__
|
||||
#define __HeapProfiler__
|
||||
|
||||
//#define PROFILE_BDWGC
|
||||
#ifdef PROFILE_BDWGC
|
||||
|
||||
#include "runtime/Value.h"
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
class ExecutionState;
|
||||
|
||||
class HeapUsageVisualizer {
|
||||
public:
|
||||
static void initialize();
|
||||
private:
|
||||
static std::string m_outputFile;
|
||||
};
|
||||
|
||||
class GCLeakChecker {
|
||||
public:
|
||||
static void registerAddress(void* ptr, std::string description);
|
||||
static void dumpBackTrace(ExecutionState& state, const char* phase = NULL);
|
||||
|
||||
private:
|
||||
static void unregisterAddress(void* ptr);
|
||||
|
||||
struct LeakCheckedAddr {
|
||||
void* ptr;
|
||||
std::string description;
|
||||
bool deallocated;
|
||||
};
|
||||
static size_t m_totalFreed;
|
||||
static std::vector<LeakCheckedAddr> m_leakCheckedAddrs;
|
||||
};
|
||||
|
||||
Value builtinRegisterLeakCheck(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression);
|
||||
Value builtinDumpBackTrace(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression);
|
||||
Value builtinSetGCPhaseName(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression);
|
||||
|
||||
}
|
||||
|
||||
#endif // PROFILE_BDWGC
|
||||
|
||||
#endif // __HeapProfiler__
|
||||
|
|
@ -1147,7 +1147,7 @@ struct EnumerateObjectData : public gc {
|
|||
ObjectStructureChain m_hiddenClassChain;
|
||||
Object* m_object;
|
||||
size_t m_idx;
|
||||
Vector<Value, gc_malloc_ignore_off_page_allocator<Value>> m_keys;
|
||||
ValueVector m_keys;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -90,4 +90,15 @@ void ArrayObject::sort(ExecutionState& state, std::function<bool(const Value& a,
|
|||
}
|
||||
Object::sort(state, comp);
|
||||
}
|
||||
|
||||
void* ArrayObject::operator new(size_t size)
|
||||
{
|
||||
return CustomAllocator<ArrayObject>().allocate(1);
|
||||
}
|
||||
|
||||
void ArrayObject::iterateArrays(ExecutionState& state, HeapObjectIteratorCallback callback)
|
||||
{
|
||||
iterateSpecificKindOfObject(state, HeapObjectKind::ArrayObjectKind, callback);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint32_t getLength(ExecutionState& state)
|
||||
{
|
||||
if (LIKELY(isPlainObject())) {
|
||||
|
|
@ -50,6 +49,12 @@ public:
|
|||
}
|
||||
virtual void sort(ExecutionState& state, std::function<bool(const Value& a, const Value& b)> comp);
|
||||
|
||||
// Use custom allocator for Array object (for Badtime)
|
||||
void* operator new(size_t size);
|
||||
void* operator new[](size_t size) = delete;
|
||||
|
||||
static void iterateArrays(ExecutionState& state, HeapObjectIteratorCallback callback);
|
||||
|
||||
protected:
|
||||
Value getLengthSlowCase(ExecutionState& state);
|
||||
bool setLengthSlowCase(ExecutionState& state, const Value& value);
|
||||
|
|
@ -156,7 +161,7 @@ protected:
|
|||
return false;
|
||||
}
|
||||
|
||||
Vector<Value, gc_malloc_ignore_off_page_allocator<Value>> m_fastModeData;
|
||||
ValueVector m_fastModeData;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "NumberObject.h"
|
||||
#include "parser/ScriptParser.h"
|
||||
#include "parser/esprima_cpp/esprima.h"
|
||||
#include "heap/HeapProfiler.h"
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
|
|
@ -202,6 +203,24 @@ void GlobalObject::installOthers(ExecutionState& state)
|
|||
NativeFunctionInfo(state.context()->staticStrings().gc, builtinGc, 0, nullptr, NativeFunctionInfo::Strict), false),
|
||||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
|
||||
|
||||
#ifdef PROFILE_BDWGC
|
||||
AtomicString dumpBackTrace(state, "dumpBackTrace");
|
||||
defineOwnProperty(state, ObjectPropertyName(dumpBackTrace),
|
||||
ObjectPropertyDescriptor(new FunctionObject(state,
|
||||
NativeFunctionInfo(dumpBackTrace, builtinDumpBackTrace, 1, nullptr, NativeFunctionInfo::Strict), false),
|
||||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
|
||||
AtomicString registerLeakCheck(state, "registerLeakCheck");
|
||||
defineOwnProperty(state, ObjectPropertyName(registerLeakCheck),
|
||||
ObjectPropertyDescriptor(new FunctionObject(state,
|
||||
NativeFunctionInfo(registerLeakCheck, builtinRegisterLeakCheck, 2, nullptr, NativeFunctionInfo::Strict), false),
|
||||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
|
||||
AtomicString setPhaseName(state, "setPhaseName");
|
||||
defineOwnProperty(state, ObjectPropertyName(setPhaseName),
|
||||
ObjectPropertyDescriptor(new FunctionObject(state,
|
||||
NativeFunctionInfo(setPhaseName, builtinSetGCPhaseName, 1, nullptr, NativeFunctionInfo::Strict), false),
|
||||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent)));
|
||||
#endif
|
||||
|
||||
m_stringProxyObject = new StringObject(state);
|
||||
m_numberProxyObject = new NumberObject(state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ private:
|
|||
#include "runtime/ValueInlines.h"
|
||||
|
||||
namespace Escargot {
|
||||
typedef Vector<Value, gc_malloc_ignore_off_page_allocator<Value>> ValueVector;
|
||||
typedef Vector<Value, CustomAllocator<Value>> ValueVector;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,92 +31,6 @@ void __attribute__((optimize("O0"))) fillStack(size_t siz)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef PROFILE_MASSIF
|
||||
std::unordered_map<void*, void*> g_addressTable;
|
||||
std::vector<void*> g_freeList;
|
||||
|
||||
void unregisterGCAddress(void* address)
|
||||
{
|
||||
// ASSERT(g_addressTable.find(address) != g_addressTable.end());
|
||||
if (g_addressTable.find(address) != g_addressTable.end()) {
|
||||
auto iter = g_addressTable.find(address);
|
||||
free(iter->second);
|
||||
g_addressTable.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void registerGCAddress(void* address, size_t siz)
|
||||
{
|
||||
if (g_addressTable.find(address) != g_addressTable.end()) {
|
||||
unregisterGCAddress(address);
|
||||
}
|
||||
g_addressTable[address] = malloc(siz);
|
||||
}
|
||||
|
||||
void* GC_malloc_hook(size_t siz)
|
||||
{
|
||||
void* ptr;
|
||||
#ifdef NDEBUG
|
||||
ptr = GC_malloc(siz);
|
||||
#else
|
||||
ptr = GC_malloc(siz);
|
||||
#endif
|
||||
registerGCAddress(ptr, siz);
|
||||
return ptr;
|
||||
}
|
||||
void* GC_malloc_atomic_hook(size_t siz)
|
||||
{
|
||||
void* ptr;
|
||||
#ifdef NDEBUG
|
||||
ptr = GC_malloc_atomic(siz);
|
||||
#else
|
||||
ptr = GC_malloc_atomic(siz);
|
||||
#endif
|
||||
registerGCAddress(ptr, siz);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* GC_malloc_ignore_off_page_hook(size_t siz)
|
||||
{
|
||||
void* ptr;
|
||||
#ifdef NDEBUG
|
||||
ptr = GC_malloc_ignore_off_page(siz);
|
||||
#else
|
||||
ptr = GC_malloc_ignore_off_page(siz);
|
||||
#endif
|
||||
registerGCAddress(ptr, siz);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* GC_malloc_atomic_ignore_off_page_hook(size_t siz)
|
||||
{
|
||||
void* ptr;
|
||||
#ifdef NDEBUG
|
||||
ptr = GC_malloc_atomic_ignore_off_page_hook(siz);
|
||||
#else
|
||||
ptr = GC_malloc_atomic_ignore_off_page_hook(siz);
|
||||
#endif
|
||||
registerGCAddress(ptr, siz);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void GC_free_hook(void* address)
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
GC_free(address);
|
||||
#else
|
||||
GC_free(address);
|
||||
#endif
|
||||
unregisterGCAddress(address);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef PROFILE_BDWGC
|
||||
const char* bdwgc_log_filename = "bdwgc_log";
|
||||
const char* bdwgc_log_phase = "initial phase";
|
||||
#endif
|
||||
|
||||
void eval(Escargot::Context* context, Escargot::String* str, Escargot::String* fileName, bool shouldPrintScriptResult)
|
||||
{
|
||||
auto result = context->scriptParser().parse(str, fileName);
|
||||
|
|
@ -154,43 +68,9 @@ int main(int argc, char* argv[])
|
|||
GC_gcollect();
|
||||
GC_gcollect();
|
||||
*/
|
||||
GC_set_free_space_divisor(24);
|
||||
GC_set_force_unmap_on_gcollect(1);
|
||||
// GC_set_full_freq(1);
|
||||
// GC_set_time_limit(GC_TIME_UNLIMITED);
|
||||
#ifdef PROFILE_MASSIF
|
||||
GC_is_valid_displacement_print_proc = [](void* ptr) {
|
||||
g_freeList.push_back(ptr);
|
||||
};
|
||||
GC_set_on_collection_event([](GC_EventType evtType) {
|
||||
if (GC_EVENT_PRE_START_WORLD == evtType) {
|
||||
auto iter = g_addressTable.begin();
|
||||
while (iter != g_addressTable.end()) {
|
||||
GC_is_valid_displacement(iter->first);
|
||||
iter++;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < g_freeList.size(); i++) {
|
||||
unregisterGCAddress(g_freeList[i]);
|
||||
}
|
||||
Escargot::Heap::initialize();
|
||||
|
||||
g_freeList.clear();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#ifdef PROFILE_BDWGC
|
||||
remove(bdwgc_log_filename);
|
||||
FILE* fp = fopen(bdwgc_log_filename, "a");
|
||||
if (fp) {
|
||||
fprintf(fp, "GC_no PeakRSS TotalHeap Marked # Phase\n");
|
||||
fclose(fp);
|
||||
}
|
||||
GC_set_on_collection_event([](GC_EventType evtType) {
|
||||
if (GC_EVENT_RECLAIM_START == evtType) {
|
||||
GC_dump_for_graph(bdwgc_log_filename, bdwgc_log_phase);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
setbuf(stdout, NULL);
|
||||
setbuf(stderr, NULL);
|
||||
|
|
@ -234,12 +114,9 @@ int main(int argc, char* argv[])
|
|||
|
||||
delete context;
|
||||
delete instance;
|
||||
GC_gcollect_and_unmap();
|
||||
GC_gcollect_and_unmap();
|
||||
GC_gcollect_and_unmap();
|
||||
GC_gcollect_and_unmap();
|
||||
GC_gcollect_and_unmap();
|
||||
GC_gcollect_and_unmap();
|
||||
|
||||
Escargot::Heap::finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -279,3 +156,19 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/* Custom allocator & Array iterator test
|
||||
|
||||
#include "runtime/ArrayObject.h"
|
||||
|
||||
size_t counter = 0;
|
||||
Escargot::HeapObjectIteratorCallback callback =
|
||||
[&counter](Escargot::ExecutionState& state, void* obj) {
|
||||
Escargot::ArrayObject* arr = (Escargot::ArrayObject*) obj;
|
||||
printf("ArrayObject %p with length %zu\n", obj, arr->getLength(state));
|
||||
counter++;
|
||||
};
|
||||
Escargot::ExecutionState state(context);
|
||||
Escargot::ArrayObject::iterateArrays(state, callback);
|
||||
printf("Array total count %zu\n", counter);
|
||||
*/
|
||||
|
|
|
|||
31
third_party/bdwgc/dbg_mlc.c
vendored
31
third_party/bdwgc/dbg_mlc.c
vendored
|
|
@ -189,6 +189,11 @@
|
|||
void *base;
|
||||
#ifdef ESCARGOT
|
||||
ptr_t object_start;
|
||||
|
||||
if (GC_base(current) == 0) {
|
||||
GC_err_printf("GC_base(%p) == 0\n", current);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
GC_print_heap_obj(GC_base(current));
|
||||
|
|
@ -585,7 +590,11 @@ GC_API GC_ATTR_MALLOC void * GC_CALL
|
|||
return (GC_store_debug_info(result, (word)lb, s, i));
|
||||
}
|
||||
|
||||
#ifdef ESCARGOT // To expose API
|
||||
GC_API GC_ATTR_MALLOC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
|
||||
#else
|
||||
STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
|
||||
#endif
|
||||
{
|
||||
void * result = GC_generic_malloc(lb + DEBUG_BYTES, knd);
|
||||
|
||||
|
|
@ -966,6 +975,28 @@ GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS)
|
|||
return(result);
|
||||
}
|
||||
|
||||
#ifdef ESCARGOT // To expose API
|
||||
|
||||
GC_API GC_ATTR_MALLOC void * GC_CALL
|
||||
GC_debug_generic_malloc_ignore_off_page(size_t lb, int k, GC_EXTRA_PARAMS)
|
||||
{
|
||||
void * result = GC_generic_malloc_inner_ignore_off_page(
|
||||
lb + DEBUG_BYTES, k);
|
||||
|
||||
if (result == 0) {
|
||||
GC_err_printf("GC internal allocation (%lu bytes) returning NULL (%s:%d)\n",
|
||||
(unsigned long) lb, s, i);
|
||||
return(0);
|
||||
}
|
||||
if (!GC_debugging_started) {
|
||||
GC_start_debugging_inner();
|
||||
}
|
||||
ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
|
||||
return (GC_store_debug_info(result, (word)lb, s, i));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
GC_API GC_ATTR_MALLOC void * GC_CALL
|
||||
GC_debug_generic_or_special_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
|
||||
{
|
||||
|
|
|
|||
39
third_party/bdwgc/include/gc_mark.h
vendored
39
third_party/bdwgc/include/gc_mark.h
vendored
|
|
@ -204,6 +204,32 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
|||
/* first page of the resulting object */
|
||||
/* are ignored. */
|
||||
|
||||
#ifdef ESCARGOT // To expose API
|
||||
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||
GC_debug_generic_malloc(
|
||||
size_t /* lb */,
|
||||
int /* knd */,
|
||||
GC_EXTRA_PARAMS);
|
||||
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||
GC_debug_generic_malloc_ignore_off_page(
|
||||
size_t /* lb */, int /* knd */,
|
||||
GC_EXTRA_PARAMS);
|
||||
|
||||
#ifndef GC_GENERIC_MALLOC
|
||||
#ifdef GC_DEBUG
|
||||
# define GC_GENERIC_MALLOC(sz, knd) \
|
||||
GC_debug_generic_malloc(sz, knd, GC_EXTRAS)
|
||||
# define GC_GENERIC_MALLOC_IGNORE_OFF_PAGE(sz, knd) \
|
||||
GC_debug_generic_malloc_ignore_off_page(sz, knd, GC_EXTRAS)
|
||||
#else /* GC_DEBUG */
|
||||
# define GC_GENERIC_MALLOC(sz, knd) \
|
||||
GC_generic_malloc(sz, knd)
|
||||
# define GC_GENERIC_MALLOC_IGNORE_OFF_PAGE(sz, knd) \
|
||||
GC_generic_malloc_ignore_off_page(sz, knd)
|
||||
#endif /* GC_DEBUG */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Same as above but primary for allocating an object of the same kind */
|
||||
/* as an existing one (kind obtained by GC_get_kind_and_size). */
|
||||
/* Not suitable for GCJ and typed-malloc kinds. */
|
||||
|
|
@ -272,6 +298,19 @@ GC_API int GC_CALL GC_is_marked(const void *) GC_ATTR_NONNULL(1);
|
|||
GC_API void GC_CALL GC_clear_mark_bit(const void *) GC_ATTR_NONNULL(1);
|
||||
GC_API void GC_CALL GC_set_mark_bit(const void *) GC_ATTR_NONNULL(1);
|
||||
|
||||
#ifdef ESCARGOT
|
||||
/* To use mark function, we should choose between:
|
||||
* 1. include private header or 2. do some work inside bdwgc
|
||||
* Currently second choice is adopted,
|
||||
* but it can be changed in future for better performance.
|
||||
*/
|
||||
typedef GC_word* (GC_get_next_pointer_proc)(GC_word** iterator);
|
||||
GC_API struct GC_ms_entry* GC_mark_and_push_custom(GC_word* addr,
|
||||
struct GC_ms_entry *mark_stack_ptr,
|
||||
struct GC_ms_entry *mark_stack_limit,
|
||||
const GC_get_next_pointer_proc proc);
|
||||
#endif
|
||||
|
||||
/* Push everything in the given range onto the mark stack. */
|
||||
/* (GC_push_conditional pushes either all or only dirty pages depending */
|
||||
/* on the third argument.) GC_push_all_eager also ensures that stack */
|
||||
|
|
|
|||
23
third_party/bdwgc/mark.c
vendored
23
third_party/bdwgc/mark.c
vendored
|
|
@ -869,6 +869,29 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
|
|||
return mark_stack_top;
|
||||
}
|
||||
|
||||
#ifdef ESCARGOT
|
||||
GC_API mse * GC_mark_and_push_custom(GC_word *addr, mse *mark_stack_ptr, mse *mark_stack_limit,
|
||||
const GC_get_next_pointer_proc proc) {
|
||||
DECLARE_HDR_CACHE;
|
||||
|
||||
INIT_HDR_CACHE;
|
||||
|
||||
const char* start = GC_USR_PTR_FROM_BASE(addr);
|
||||
const char* end = ((char*)addr) + GC_size(addr) - 8;
|
||||
|
||||
GC_word* iterator = (GC_word*)start;
|
||||
while (TRUE) {
|
||||
GC_word* points = proc(&iterator);
|
||||
if (points) {
|
||||
PUSH_CONTENTS((ptr_t)points, mark_stack_ptr, mark_stack_limit, iterator, exit);
|
||||
}
|
||||
if (iterator >= (GC_word*)end)
|
||||
break;
|
||||
}
|
||||
return (mark_stack_ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PARALLEL_MARK
|
||||
|
||||
STATIC GC_bool GC_help_wanted = FALSE; /* Protected by mark lock */
|
||||
|
|
|
|||
2
third_party/bdwgc/misc.c
vendored
2
third_party/bdwgc/misc.c
vendored
|
|
@ -1311,8 +1311,10 @@ GC_API void GC_CALL GC_init(void)
|
|||
# endif
|
||||
RESTORE_CANCEL(cancel_state);
|
||||
#ifdef ESCARGOT
|
||||
/* These variables are not initialized properly */
|
||||
GC_heapsize = 0;
|
||||
GC_unmapped_bytes = 0;
|
||||
GC_debug_header_size = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
8
third_party/bdwgc/reclaim.c
vendored
8
third_party/bdwgc/reclaim.c
vendored
|
|
@ -698,15 +698,15 @@ GC_API void GC_CALL GC_dump_for_graph(const char* log_file_name,
|
|||
getrusage(RUSAGE_SELF, &ru);
|
||||
size_t peak_rss = ru.ru_maxrss;
|
||||
|
||||
GC_printf("[%d] %s : PeakRSS %zu KB, TotalHeap %lu KB, MarkedHeap %lu KB\n",
|
||||
GC_get_gc_no(), phase_name, peak_rss,
|
||||
GC_printf("[%lu] %s : PeakRSS %zu KB, TotalHeap %lu KB, MarkedHeap %lu KB\n",
|
||||
(unsigned long) GC_get_gc_no(), phase_name, peak_rss,
|
||||
(unsigned long) pstats.total_bytes / 1024,
|
||||
(unsigned long) pstats.marked_bytes / 1024);
|
||||
|
||||
FILE* fp = fopen(log_file_name, "a");
|
||||
if (fp) {
|
||||
fprintf(fp, "%5d %9lu %9lu %9zu # %s\n",
|
||||
GC_get_gc_no(),
|
||||
fprintf(fp, "%5lu %9zu %9lu %9lu # %s\n",
|
||||
(unsigned long) GC_get_gc_no(),
|
||||
peak_rss,
|
||||
(unsigned long) pstats.total_bytes / 1024,
|
||||
(unsigned long) pstats.marked_bytes / 1024,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
import subprocess
|
||||
import os
|
||||
|
||||
BDWGC_LOGFILE="bdwgc_log"
|
||||
BDWGC_LOGFILE="bdwgcUsage.dat"
|
||||
GNUPLOT_DISPLAY_STYLE="lines"
|
||||
|
||||
def make_plot_subcmd(col, name):
|
||||
|
|
@ -26,7 +26,7 @@ def make_plot_subcmd(col, name):
|
|||
def draw_bdwgc_plot():
|
||||
if not os.path.exists(BDWGC_LOGFILE):
|
||||
print 'Cannot draw plot! No input file %s' % BDWGC_LOGFILE
|
||||
print 'Re-build escargot with `-DPROFILE_BDWGC`'
|
||||
print 'Please re-build escargot with `-DPROFILE_BDWGC` and run again.'
|
||||
exit(1)
|
||||
|
||||
plot_cmd = 'plot '
|
||||
Loading…
Add table
Add a link
Reference in a new issue