mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 624878 - Remove dangerous uses of vanilla (throw-on-failure) |operator new|. r=lw.
This commit is contained in:
parent
cc51b5ed72
commit
ed55695802
80
config/find_vanilla_new_calls
Executable file
80
config/find_vanilla_new_calls
Executable file
@ -0,0 +1,80 @@
|
||||
# /bin/bash
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# We must avoid using the vanilla new/new[] operators (and consequently, the
|
||||
# vanilla delete/delete[] operators) in SpiderMonkey, see bug 624878 for why.
|
||||
#
|
||||
# This script:
|
||||
# - Detects if any of the vanilla new/new[] operators are used in a file.
|
||||
# Its exit code is 1 if it found some, and 0 if it didn't.
|
||||
# - Doesn't detect delete/delete[] because it appears they can be present
|
||||
# somehow due to virtual destructors, but this is ok because vanilla
|
||||
# delete/delete[] calls don't make sense without corresponding new/new[]
|
||||
# calls, and any explicit calls will be caught by Valgrind's mismatched
|
||||
# alloc/free checking.
|
||||
# - Doesn't detect the 'nothrow' variants, which are ok but probably still
|
||||
# best avoided.
|
||||
# - Is designed to only run on Linux (though it may also work on Mac); one
|
||||
# platform will be enough to catch any violations.
|
||||
#
|
||||
# If this script fails:
|
||||
# - You need to find the uses of vanilla new/delete and replace them with
|
||||
# js_new()/js_delete().
|
||||
# - Run this script on each of the .o files, that should narrow it down.
|
||||
# - After that, one way to find them is to run 'objdump -r -C' on the
|
||||
# relevant .o files. For example, you might search for 'operator new' and
|
||||
# find a record like this:
|
||||
#
|
||||
# RELOCATION RECORDS FOR [.text._ZN3JSC14ExecutablePool6createEj]:
|
||||
# OFFSET TYPE VALUE
|
||||
# 00000009 R_386_PC32 __i686.get_pc_thunk.bx
|
||||
# 0000000f R_386_GOTPC _GLOBAL_OFFSET_TABLE_
|
||||
# 0000001b R_386_PLT32 operator new(unsigned int)
|
||||
# 0000002e R_386_PC32 JSC::ExecutablePool::ExecutablePool(unsigned int)
|
||||
# 0000004a R_386_PC32 JSC::ExecutablePool::~ExecutablePool()
|
||||
# 00000052 R_386_PLT32 operator delete(void*)
|
||||
#
|
||||
# This says that vanilla 'new' and 'delete' are both used in
|
||||
# JSC::ExecutablePool::create(unsigned int). This doesn't always work,
|
||||
# though. (Nb: use 'c++filt' to demangle names like
|
||||
# _ZN3JSC14ExecutablePool6createEj.)
|
||||
#
|
||||
# If that doesn't work, use grep.
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
if [ -z $1 ] ; then
|
||||
echo "usage: find_vanilla_new_calls <file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
file=$1
|
||||
|
||||
if [ ! -f $file ] ; then
|
||||
echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | file '$file' not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tmpfile1=`mktemp`
|
||||
tmpfile2=`mktemp`
|
||||
nm -C $file > $tmpfile1
|
||||
|
||||
# Need to double-escape '[' and ']' to stop grep from interpreting them
|
||||
# specially.
|
||||
grep 'operator new(unsigned int)' $tmpfile1 >> $tmpfile2
|
||||
grep 'operator new(unsigned long)' $tmpfile1 >> $tmpfile2
|
||||
grep 'operator new\\[\\](unsigned int)' $tmpfile1 >> $tmpfile2
|
||||
grep 'operator new\\[\\](unsigned long)' $tmpfile1 >> $tmpfile2
|
||||
rm -f $tmpfile1
|
||||
|
||||
if [ -s $tmpfile2 ] ; then
|
||||
echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | found calls are listed below"
|
||||
cat $tmpfile2
|
||||
echo
|
||||
rm -f $tmpfile2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "TEST-PASS | find_vanilla_new_calls | ok"
|
||||
echo
|
||||
|
||||
exit 0
|
@ -572,6 +572,14 @@ check-valgrind::
|
||||
$(check-sync-dirs) $(srcdir)/build $(MOZ_SYNC_BUILD_FILES)/build
|
||||
endif
|
||||
|
||||
# The "find any vanilla new/new[] calls" script is tailored to Linux, so
|
||||
# only run it there. That should be enough to catch any such calls that
|
||||
# creep in.
|
||||
ifeq ($(OS_ARCH),Linux)
|
||||
check::
|
||||
$(srcdir)/config/find_vanilla_new_calls $(LIBRARY)
|
||||
endif
|
||||
|
||||
ifdef ENABLE_TRACEJIT
|
||||
ifndef WINCE
|
||||
check::
|
||||
|
@ -113,7 +113,7 @@ private:
|
||||
RChunk* chunk;
|
||||
#endif
|
||||
};
|
||||
typedef js::Vector<Allocation, 2 ,js::SystemAllocPolicy > AllocationList;
|
||||
typedef js::Vector<Allocation, 2, js::SystemAllocPolicy> AllocationList;
|
||||
|
||||
// Reference count for automatic reclamation.
|
||||
unsigned m_refCount;
|
||||
@ -132,14 +132,16 @@ public:
|
||||
{
|
||||
JS_ASSERT(m_refCount != 0);
|
||||
if (--m_refCount == 0)
|
||||
delete this;
|
||||
js_delete(this);
|
||||
}
|
||||
|
||||
static ExecutablePool* create(size_t n)
|
||||
{
|
||||
ExecutablePool *pool = new ExecutablePool(n);
|
||||
if (!pool->m_freePtr) {
|
||||
delete pool;
|
||||
/* We can't (easily) use js_new() here because the constructor is private. */
|
||||
void *memory = js_malloc(sizeof(ExecutablePool));
|
||||
ExecutablePool *pool = memory ? new(memory) ExecutablePool(n) : NULL;
|
||||
if (!pool || !pool->m_freePtr) {
|
||||
js_delete(pool);
|
||||
return NULL;
|
||||
}
|
||||
return pool;
|
||||
@ -207,7 +209,9 @@ public:
|
||||
// Returns NULL on OOM.
|
||||
static ExecutableAllocator *create()
|
||||
{
|
||||
ExecutableAllocator *allocator = new ExecutableAllocator();
|
||||
/* We can't (easily) use js_new() here because the constructor is private. */
|
||||
void *memory = js_malloc(sizeof(ExecutableAllocator));
|
||||
ExecutableAllocator *allocator = memory ? new(memory) ExecutableAllocator() : NULL;
|
||||
if (!allocator)
|
||||
return allocator;
|
||||
|
||||
@ -215,7 +219,7 @@ public:
|
||||
intializePageSize();
|
||||
ExecutablePool *pool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE);
|
||||
if (!pool) {
|
||||
delete allocator;
|
||||
js_delete(allocator);
|
||||
return NULL;
|
||||
}
|
||||
JS_ASSERT(allocator->m_smallAllocationPools.empty());
|
||||
@ -226,7 +230,7 @@ public:
|
||||
~ExecutableAllocator()
|
||||
{
|
||||
for (size_t i = 0; i < m_smallAllocationPools.length(); i++)
|
||||
delete m_smallAllocationPools[i];
|
||||
js_delete(m_smallAllocationPools[i]);
|
||||
}
|
||||
|
||||
// poolForSize returns reference-counted objects. The caller owns a reference
|
||||
|
80
js/src/config/find_vanilla_new_calls
Executable file
80
js/src/config/find_vanilla_new_calls
Executable file
@ -0,0 +1,80 @@
|
||||
# /bin/bash
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# We must avoid using the vanilla new/new[] operators (and consequently, the
|
||||
# vanilla delete/delete[] operators) in SpiderMonkey, see bug 624878 for why.
|
||||
#
|
||||
# This script:
|
||||
# - Detects if any of the vanilla new/new[] operators are used in a file.
|
||||
# Its exit code is 1 if it found some, and 0 if it didn't.
|
||||
# - Doesn't detect delete/delete[] because it appears they can be present
|
||||
# somehow due to virtual destructors, but this is ok because vanilla
|
||||
# delete/delete[] calls don't make sense without corresponding new/new[]
|
||||
# calls, and any explicit calls will be caught by Valgrind's mismatched
|
||||
# alloc/free checking.
|
||||
# - Doesn't detect the 'nothrow' variants, which are ok but probably still
|
||||
# best avoided.
|
||||
# - Is designed to only run on Linux (though it may also work on Mac); one
|
||||
# platform will be enough to catch any violations.
|
||||
#
|
||||
# If this script fails:
|
||||
# - You need to find the uses of vanilla new/delete and replace them with
|
||||
# js_new()/js_delete().
|
||||
# - Run this script on each of the .o files, that should narrow it down.
|
||||
# - After that, one way to find them is to run 'objdump -r -C' on the
|
||||
# relevant .o files. For example, you might search for 'operator new' and
|
||||
# find a record like this:
|
||||
#
|
||||
# RELOCATION RECORDS FOR [.text._ZN3JSC14ExecutablePool6createEj]:
|
||||
# OFFSET TYPE VALUE
|
||||
# 00000009 R_386_PC32 __i686.get_pc_thunk.bx
|
||||
# 0000000f R_386_GOTPC _GLOBAL_OFFSET_TABLE_
|
||||
# 0000001b R_386_PLT32 operator new(unsigned int)
|
||||
# 0000002e R_386_PC32 JSC::ExecutablePool::ExecutablePool(unsigned int)
|
||||
# 0000004a R_386_PC32 JSC::ExecutablePool::~ExecutablePool()
|
||||
# 00000052 R_386_PLT32 operator delete(void*)
|
||||
#
|
||||
# This says that vanilla 'new' and 'delete' are both used in
|
||||
# JSC::ExecutablePool::create(unsigned int). This doesn't always work,
|
||||
# though. (Nb: use 'c++filt' to demangle names like
|
||||
# _ZN3JSC14ExecutablePool6createEj.)
|
||||
#
|
||||
# If that doesn't work, use grep.
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
if [ -z $1 ] ; then
|
||||
echo "usage: find_vanilla_new_calls <file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
file=$1
|
||||
|
||||
if [ ! -f $file ] ; then
|
||||
echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | file '$file' not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tmpfile1=`mktemp`
|
||||
tmpfile2=`mktemp`
|
||||
nm -C $file > $tmpfile1
|
||||
|
||||
# Need to double-escape '[' and ']' to stop grep from interpreting them
|
||||
# specially.
|
||||
grep 'operator new(unsigned int)' $tmpfile1 >> $tmpfile2
|
||||
grep 'operator new(unsigned long)' $tmpfile1 >> $tmpfile2
|
||||
grep 'operator new\\[\\](unsigned int)' $tmpfile1 >> $tmpfile2
|
||||
grep 'operator new\\[\\](unsigned long)' $tmpfile1 >> $tmpfile2
|
||||
rm -f $tmpfile1
|
||||
|
||||
if [ -s $tmpfile2 ] ; then
|
||||
echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | found calls are listed below"
|
||||
cat $tmpfile2
|
||||
echo
|
||||
rm -f $tmpfile2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "TEST-PASS | find_vanilla_new_calls | ok"
|
||||
echo
|
||||
|
||||
exit 0
|
@ -1844,7 +1844,7 @@ ImplicitConvert(JSContext* cx,
|
||||
return false;
|
||||
|
||||
char** charBuffer = static_cast<char**>(buffer);
|
||||
*charBuffer = new char[nbytes + 1];
|
||||
*charBuffer = js_array_new<char>(nbytes + 1);
|
||||
if (!*charBuffer) {
|
||||
JS_ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
@ -1861,7 +1861,7 @@ ImplicitConvert(JSContext* cx,
|
||||
// JSString's buffer, but this approach is safer if the caller happens
|
||||
// to modify the string.)
|
||||
jschar** jscharBuffer = static_cast<jschar**>(buffer);
|
||||
*jscharBuffer = new jschar[sourceLength + 1];
|
||||
*jscharBuffer = js_array_new<jschar>(sourceLength + 1);
|
||||
if (!*jscharBuffer) {
|
||||
JS_ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
@ -1946,7 +1946,7 @@ ImplicitConvert(JSContext* cx,
|
||||
// Convert into an intermediate, in case of failure.
|
||||
size_t elementSize = CType::GetSize(cx, baseType);
|
||||
size_t arraySize = elementSize * targetLength;
|
||||
AutoPtr<char>::Array intermediate(new char[arraySize]);
|
||||
AutoPtr<char>::Array intermediate(js_array_new<char>(arraySize));
|
||||
if (!intermediate) {
|
||||
JS_ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
@ -1983,7 +1983,7 @@ ImplicitConvert(JSContext* cx,
|
||||
|
||||
// Convert into an intermediate, in case of failure.
|
||||
size_t structSize = CType::GetSize(cx, targetType);
|
||||
AutoPtr<char>::Array intermediate(new char[structSize]);
|
||||
AutoPtr<char>::Array intermediate(js_array_new<char>(structSize));
|
||||
if (!intermediate) {
|
||||
JS_ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
@ -2702,7 +2702,7 @@ CType::Finalize(JSContext* cx, JSObject* obj)
|
||||
// Free the FunctionInfo.
|
||||
ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FNINFO, &slot));
|
||||
if (!JSVAL_IS_VOID(slot))
|
||||
delete static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot));
|
||||
js_delete(static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot)));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2711,7 +2711,7 @@ CType::Finalize(JSContext* cx, JSObject* obj)
|
||||
ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FIELDINFO, &slot));
|
||||
if (!JSVAL_IS_VOID(slot)) {
|
||||
void* info = JSVAL_TO_PRIVATE(slot);
|
||||
delete static_cast<FieldInfoHash*>(info);
|
||||
js_delete(static_cast<FieldInfoHash*>(info));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2721,8 +2721,8 @@ CType::Finalize(JSContext* cx, JSObject* obj)
|
||||
ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FFITYPE, &slot));
|
||||
if (!JSVAL_IS_VOID(slot)) {
|
||||
ffi_type* ffiType = static_cast<ffi_type*>(JSVAL_TO_PRIVATE(slot));
|
||||
delete[] ffiType->elements;
|
||||
delete ffiType;
|
||||
js_array_delete(ffiType->elements);
|
||||
js_delete(ffiType);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -3700,7 +3700,7 @@ ArrayType::BuildFFIType(JSContext* cx, JSObject* obj)
|
||||
// values. It would be nice to not do all the work of setting up 'elements',
|
||||
// but some libffi platforms currently require that it be meaningful. I'm
|
||||
// looking at you, x86_64.
|
||||
AutoPtr<ffi_type> ffiType(new ffi_type);
|
||||
AutoPtr<ffi_type> ffiType(js_new<ffi_type>());
|
||||
if (!ffiType) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
@ -3709,7 +3709,7 @@ ArrayType::BuildFFIType(JSContext* cx, JSObject* obj)
|
||||
ffiType->type = FFI_TYPE_STRUCT;
|
||||
ffiType->size = CType::GetSize(cx, obj);
|
||||
ffiType->alignment = CType::GetAlignment(cx, obj);
|
||||
ffiType->elements = new ffi_type*[length + 1];
|
||||
ffiType->elements = js_array_new<ffi_type*>(length + 1);
|
||||
if (!ffiType->elements) {
|
||||
JS_ReportAllocationOverflow(cx);
|
||||
return NULL;
|
||||
@ -4032,7 +4032,7 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj
|
||||
// its constituents. (We cannot simply stash the hash in a reserved slot now
|
||||
// to get GC safety for free, since if anything in this function fails we
|
||||
// do not want to mutate 'typeObj'.)
|
||||
AutoPtr<FieldInfoHash> fields(new FieldInfoHash);
|
||||
AutoPtr<FieldInfoHash> fields(js_new<FieldInfoHash>());
|
||||
Array<jsval, 16> fieldRootsArray;
|
||||
if (!fields || !fields->init(len) || !fieldRootsArray.appendN(JSVAL_VOID, len)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
@ -4141,7 +4141,7 @@ StructType::BuildFFIType(JSContext* cx, JSObject* obj)
|
||||
size_t structSize = CType::GetSize(cx, obj);
|
||||
size_t structAlign = CType::GetAlignment(cx, obj);
|
||||
|
||||
AutoPtr<ffi_type> ffiType(new ffi_type);
|
||||
AutoPtr<ffi_type> ffiType(js_new<ffi_type>());
|
||||
if (!ffiType) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
@ -4150,7 +4150,7 @@ StructType::BuildFFIType(JSContext* cx, JSObject* obj)
|
||||
|
||||
AutoPtr<ffi_type*>::Array elements;
|
||||
if (len != 0) {
|
||||
elements = new ffi_type*[len + 1];
|
||||
elements = js_array_new<ffi_type*>(len + 1);
|
||||
if (!elements) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
@ -4169,7 +4169,7 @@ StructType::BuildFFIType(JSContext* cx, JSObject* obj)
|
||||
// Represent an empty struct as having a size of 1 byte, just like C++.
|
||||
JS_ASSERT(structSize == 1);
|
||||
JS_ASSERT(structAlign == 1);
|
||||
elements = new ffi_type*[2];
|
||||
elements = js_array_new<ffi_type*>(2);
|
||||
if (!elements) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
@ -4510,14 +4510,14 @@ struct AutoValue
|
||||
|
||||
~AutoValue()
|
||||
{
|
||||
delete[] static_cast<char*>(mData);
|
||||
js_array_delete(static_cast<char*>(mData));
|
||||
}
|
||||
|
||||
bool SizeToType(JSContext* cx, JSObject* type)
|
||||
{
|
||||
// Allocate a minimum of sizeof(ffi_arg) to handle small integers.
|
||||
size_t size = Align(CType::GetSize(cx, type), sizeof(ffi_arg));
|
||||
mData = new char[size];
|
||||
mData = js_array_new<char>(size);
|
||||
if (mData)
|
||||
memset(mData, 0, size);
|
||||
return mData != NULL;
|
||||
@ -4722,7 +4722,7 @@ NewFunctionInfo(JSContext* cx,
|
||||
jsval* argTypes,
|
||||
uintN argLength)
|
||||
{
|
||||
AutoPtr<FunctionInfo> fninfo(new FunctionInfo());
|
||||
AutoPtr<FunctionInfo> fninfo(js_new<FunctionInfo>());
|
||||
if (!fninfo) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
@ -5198,7 +5198,7 @@ CClosure::Create(JSContext* cx,
|
||||
JS_ASSERT(!fninfo->mIsVariadic);
|
||||
JS_ASSERT(GetABICode(cx, fninfo->mABI) != ABI_WINAPI);
|
||||
|
||||
AutoPtr<ClosureInfo> cinfo(new ClosureInfo());
|
||||
AutoPtr<ClosureInfo> cinfo(js_new<ClosureInfo>());
|
||||
if (!cinfo) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
@ -5311,7 +5311,7 @@ CClosure::Finalize(JSContext* cx, JSObject* obj)
|
||||
if (cinfo->closure)
|
||||
ffi_closure_free(cinfo->closure);
|
||||
|
||||
delete cinfo;
|
||||
js_delete(cinfo);
|
||||
}
|
||||
|
||||
void
|
||||
@ -5488,7 +5488,7 @@ CData::Create(JSContext* cx,
|
||||
|
||||
// attach the buffer. since it might not be 2-byte aligned, we need to
|
||||
// allocate an aligned space for it and store it there. :(
|
||||
char** buffer = new char*;
|
||||
char** buffer = js_new<char*>();
|
||||
if (!buffer) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
@ -5500,11 +5500,11 @@ CData::Create(JSContext* cx,
|
||||
} else {
|
||||
// Initialize our own buffer.
|
||||
size_t size = CType::GetSize(cx, typeObj);
|
||||
data = new char[size];
|
||||
data = js_array_new<char>(size);
|
||||
if (!data) {
|
||||
// Report a catchable allocation error.
|
||||
JS_ReportAllocationOverflow(cx);
|
||||
delete buffer;
|
||||
js_delete(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -5517,8 +5517,8 @@ CData::Create(JSContext* cx,
|
||||
*buffer = data;
|
||||
if (!JS_SetReservedSlot(cx, dataObj, SLOT_DATA, PRIVATE_TO_JSVAL(buffer))) {
|
||||
if (ownResult)
|
||||
delete[] data;
|
||||
delete buffer;
|
||||
js_array_delete(data);
|
||||
js_delete(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -5540,8 +5540,8 @@ CData::Finalize(JSContext* cx, JSObject* obj)
|
||||
char** buffer = static_cast<char**>(JSVAL_TO_PRIVATE(slot));
|
||||
|
||||
if (owns)
|
||||
delete[] *buffer;
|
||||
delete buffer;
|
||||
js_array_delete(*buffer);
|
||||
js_delete(buffer);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
@ -5825,14 +5825,14 @@ Int64Base::Construct(JSContext* cx,
|
||||
js::AutoObjectRooter root(cx, result);
|
||||
|
||||
// attach the Int64's data
|
||||
JSUint64* buffer = new JSUint64(data);
|
||||
JSUint64* buffer = js_new<JSUint64>(data);
|
||||
if (!buffer) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!JS_SetReservedSlot(cx, result, SLOT_INT64, PRIVATE_TO_JSVAL(buffer))) {
|
||||
delete buffer;
|
||||
js_delete(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -5849,7 +5849,7 @@ Int64Base::Finalize(JSContext* cx, JSObject* obj)
|
||||
if (!JS_GetReservedSlot(cx, obj, SLOT_INT64, &slot) || JSVAL_IS_VOID(slot))
|
||||
return;
|
||||
|
||||
delete static_cast<JSUint64*>(JSVAL_TO_PRIVATE(slot));
|
||||
js_delete(static_cast<JSUint64*>(JSVAL_TO_PRIVATE(slot)));
|
||||
}
|
||||
|
||||
JSUint64
|
||||
|
@ -56,25 +56,25 @@ template<class T>
|
||||
class OperatorDelete
|
||||
{
|
||||
public:
|
||||
static void destroy(T* ptr) { delete ptr; }
|
||||
static void destroy(T* ptr) { js_delete(ptr); }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class OperatorArrayDelete
|
||||
{
|
||||
public:
|
||||
static void destroy(T* ptr) { delete[] ptr; }
|
||||
static void destroy(T* ptr) { js_array_delete(ptr); }
|
||||
};
|
||||
|
||||
// Class that takes ownership of a pointer T*, and calls operator delete or
|
||||
// operator delete[] upon destruction.
|
||||
// Class that takes ownership of a pointer T*, and calls js_delete() or
|
||||
// js_array_delete() upon destruction.
|
||||
template<class T, class DeleteTraits = OperatorDelete<T> >
|
||||
class AutoPtr {
|
||||
private:
|
||||
typedef AutoPtr<T, DeleteTraits> self_type;
|
||||
|
||||
public:
|
||||
// An AutoPtr variant that calls operator delete[] instead.
|
||||
// An AutoPtr variant that calls js_array_delete() instead.
|
||||
typedef AutoPtr<T, OperatorArrayDelete<T> > Array;
|
||||
|
||||
AutoPtr() : mPtr(NULL) { }
|
||||
|
@ -638,7 +638,7 @@ JSRuntime::init(uint32 maxbytes)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(atomsCompartment = new JSCompartment(this)) ||
|
||||
if (!(atomsCompartment = js_new<JSCompartment>(this)) ||
|
||||
!atomsCompartment->init() ||
|
||||
!compartments.append(atomsCompartment)) {
|
||||
return false;
|
||||
@ -1161,11 +1161,11 @@ JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
JS_ASSERT(target);
|
||||
AutoCompartment *call = new AutoCompartment(cx, target);
|
||||
AutoCompartment *call = js_new<AutoCompartment>(cx, target);
|
||||
if (!call)
|
||||
return NULL;
|
||||
if (!call->enter()) {
|
||||
delete call;
|
||||
js_delete(call);
|
||||
return NULL;
|
||||
}
|
||||
return reinterpret_cast<JSCrossCompartmentCall *>(call);
|
||||
@ -1193,7 +1193,7 @@ JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
|
||||
AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
|
||||
CHECK_REQUEST(realcall->context);
|
||||
realcall->leave();
|
||||
delete realcall;
|
||||
js_delete(realcall);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -76,17 +76,17 @@ JSCompartment::JSCompartment(JSRuntime *rt)
|
||||
JSCompartment::~JSCompartment()
|
||||
{
|
||||
#if ENABLE_YARR_JIT
|
||||
delete regExpAllocator;
|
||||
js_delete(regExpAllocator);
|
||||
#endif
|
||||
|
||||
#if defined JS_TRACER
|
||||
FinishJIT(&traceMonitor);
|
||||
#endif
|
||||
#ifdef JS_METHODJIT
|
||||
delete jaegerCompartment;
|
||||
js_delete(jaegerCompartment);
|
||||
#endif
|
||||
|
||||
delete mathCache;
|
||||
js_delete(mathCache);
|
||||
|
||||
#ifdef DEBUG
|
||||
for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
|
||||
@ -121,7 +121,7 @@ JSCompartment::init()
|
||||
#endif
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
if (!(jaegerCompartment = new mjit::JaegerCompartment)) {
|
||||
if (!(jaegerCompartment = js_new<mjit::JaegerCompartment>())) {
|
||||
#ifdef JS_TRACER
|
||||
FinishJIT(&traceMonitor);
|
||||
#endif
|
||||
@ -492,7 +492,7 @@ MathCache *
|
||||
JSCompartment::allocMathCache(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(!mathCache);
|
||||
mathCache = new MathCache;
|
||||
mathCache = js_new<MathCache>();
|
||||
if (!mathCache)
|
||||
js_ReportOutOfMemory(cx);
|
||||
return mathCache;
|
||||
|
@ -858,7 +858,7 @@ js_FinishGC(JSRuntime *rt)
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
|
||||
JSCompartment *comp = *c;
|
||||
comp->finishArenaLists();
|
||||
delete comp;
|
||||
js_delete(comp);
|
||||
}
|
||||
rt->compartments.clear();
|
||||
rt->atomsCompartment = NULL;
|
||||
@ -2207,7 +2207,7 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
|
||||
(void) callback(cx, compartment, JSCOMPARTMENT_DESTROY);
|
||||
if (compartment->principals)
|
||||
JSPRINCIPALS_DROP(cx, compartment->principals);
|
||||
delete compartment;
|
||||
js_delete(compartment);
|
||||
} else {
|
||||
compartment->marked = false;
|
||||
*write++ = compartment;
|
||||
@ -2864,9 +2864,9 @@ JSCompartment *
|
||||
NewCompartment(JSContext *cx, JSPrincipals *principals)
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
JSCompartment *compartment = new JSCompartment(rt);
|
||||
JSCompartment *compartment = js_new<JSCompartment>(rt);
|
||||
if (!compartment || !compartment->init()) {
|
||||
delete compartment;
|
||||
js_delete(compartment);
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1002,11 +1002,11 @@ struct JSFunctionBoxQueue {
|
||||
|
||||
bool init(uint32 count) {
|
||||
lengthMask = JS_BITMASK(JS_CeilingLog2(count));
|
||||
vector = new JSFunctionBox*[length()];
|
||||
vector = js_array_new<JSFunctionBox*>(length());
|
||||
return !!vector;
|
||||
}
|
||||
|
||||
~JSFunctionBoxQueue() { delete[] vector; }
|
||||
~JSFunctionBoxQueue() { js_array_delete(vector); }
|
||||
|
||||
void push(JSFunctionBox *funbox) {
|
||||
if (!funbox->queued) {
|
||||
|
@ -2240,6 +2240,9 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag
|
||||
guardedShapeTable(cx),
|
||||
initDepth(0),
|
||||
hadNewInit(false),
|
||||
#ifdef DEBUG
|
||||
addPropShapeBefore(NULL),
|
||||
#endif
|
||||
rval_ins(NULL),
|
||||
native_rval_ins(NULL),
|
||||
newobj_ins(NULL),
|
||||
@ -2439,12 +2442,14 @@ TraceRecorder::finishSuccessfully()
|
||||
AUDIT(traceCompleted);
|
||||
mark.commit();
|
||||
|
||||
/* Grab local copies of members needed after |delete this|. */
|
||||
/* Grab local copies of members needed after destruction of |this|. */
|
||||
JSContext* localcx = cx;
|
||||
TraceMonitor* localtm = traceMonitor;
|
||||
|
||||
localtm->recorder = NULL;
|
||||
delete this;
|
||||
/* We can't (easily) use js_delete() here because the constructor is private. */
|
||||
this->~TraceRecorder();
|
||||
js_free(this);
|
||||
|
||||
/* Catch OOM that occurred during recording. */
|
||||
if (localtm->outOfMemory() || OverfullJITCache(localcx, localtm)) {
|
||||
@ -2492,12 +2497,16 @@ TraceRecorder::finishAbort(const char* reason)
|
||||
fragment->root->sideExits.setLength(numSideExitsBefore);
|
||||
}
|
||||
|
||||
/* Grab local copies of members needed after |delete this|. */
|
||||
/* Grab local copies of members needed after destruction of |this|. */
|
||||
JSContext* localcx = cx;
|
||||
TraceMonitor* localtm = traceMonitor;
|
||||
|
||||
localtm->recorder = NULL;
|
||||
delete this;
|
||||
/* We can't (easily) use js_delete() here because the constructor is private. */
|
||||
this->~TraceRecorder();
|
||||
js_free(this);
|
||||
|
||||
/* Catch OOM that occurred during recording. */
|
||||
if (localtm->outOfMemory() || OverfullJITCache(localcx, localtm)) {
|
||||
ResetJIT(localcx, FR_OOM);
|
||||
return JIT_RESET;
|
||||
@ -5564,9 +5573,13 @@ TraceRecorder::startRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* f,
|
||||
JS_ASSERT(!tm->needFlush);
|
||||
JS_ASSERT_IF(cx->fp()->hasImacropc(), f->root != f);
|
||||
|
||||
tm->recorder = new TraceRecorder(cx, anchor, f, stackSlots, ngslots, typeMap,
|
||||
expectedInnerExit, outerScript, outerPC, outerArgc,
|
||||
speculate);
|
||||
/* We can't (easily) use js_new() here because the constructor is private. */
|
||||
void *memory = js_malloc(sizeof(TraceRecorder));
|
||||
tm->recorder = memory
|
||||
? new(memory) TraceRecorder(cx, anchor, f, stackSlots, ngslots, typeMap,
|
||||
expectedInnerExit, outerScript, outerPC, outerArgc,
|
||||
speculate)
|
||||
: NULL;
|
||||
|
||||
if (!tm->recorder || tm->outOfMemory() || OverfullJITCache(cx, tm)) {
|
||||
ResetJIT(cx, FR_OOM);
|
||||
@ -7619,7 +7632,8 @@ InitJIT(TraceMonitor *tm)
|
||||
}
|
||||
/* Set up fragprofiling, if required. */
|
||||
if (LogController.lcbits & LC_FragProfile) {
|
||||
tm->profAlloc = new VMAllocator();
|
||||
tm->profAlloc = js_new<VMAllocator>();
|
||||
JS_ASSERT(tm->profAlloc);
|
||||
tm->profTab = new (*tm->profAlloc) FragStatsMap(*tm->profAlloc);
|
||||
}
|
||||
tm->lastFragID = 0;
|
||||
@ -7653,27 +7667,30 @@ InitJIT(TraceMonitor *tm)
|
||||
did_we_check_processor_features = true;
|
||||
}
|
||||
|
||||
tm->oracle = new Oracle();
|
||||
#define CHECK_ALLOC(lhs, rhs) \
|
||||
do { lhs = (rhs); if (!lhs) return false; } while (0)
|
||||
|
||||
CHECK_ALLOC(tm->oracle, js_new<Oracle>());
|
||||
|
||||
tm->profile = NULL;
|
||||
|
||||
tm->recordAttempts = new RecordAttemptMap;
|
||||
CHECK_ALLOC(tm->recordAttempts, js_new<RecordAttemptMap>());
|
||||
if (!tm->recordAttempts->init(PC_HASH_COUNT))
|
||||
abort();
|
||||
return false;
|
||||
|
||||
tm->loopProfiles = new LoopProfileMap;
|
||||
CHECK_ALLOC(tm->loopProfiles, js_new<LoopProfileMap>());
|
||||
if (!tm->loopProfiles->init(PC_HASH_COUNT))
|
||||
abort();
|
||||
return false;
|
||||
|
||||
tm->flushEpoch = 0;
|
||||
|
||||
tm->dataAlloc = new VMAllocator();
|
||||
tm->traceAlloc = new VMAllocator();
|
||||
tm->tempAlloc = new VMAllocator();
|
||||
tm->codeAlloc = new CodeAlloc();
|
||||
tm->frameCache = new FrameInfoCache(tm->dataAlloc);
|
||||
tm->storage = new TraceNativeStorage();
|
||||
tm->cachedTempTypeMap = new TypeMap(0);
|
||||
CHECK_ALLOC(tm->dataAlloc, js_new<VMAllocator>());
|
||||
CHECK_ALLOC(tm->traceAlloc, js_new<VMAllocator>());
|
||||
CHECK_ALLOC(tm->tempAlloc, js_new<VMAllocator>());
|
||||
CHECK_ALLOC(tm->codeAlloc, js_new<CodeAlloc>());
|
||||
CHECK_ALLOC(tm->frameCache, js_new<FrameInfoCache>(tm->dataAlloc));
|
||||
CHECK_ALLOC(tm->storage, js_new<TraceNativeStorage>());
|
||||
CHECK_ALLOC(tm->cachedTempTypeMap, js_new<TypeMap>((Allocator*)NULL));
|
||||
tm->flush();
|
||||
verbose_only( tm->branches = NULL; )
|
||||
|
||||
@ -7747,9 +7764,9 @@ FinishJIT(TraceMonitor *tm)
|
||||
}
|
||||
#endif
|
||||
|
||||
delete tm->recordAttempts;
|
||||
delete tm->loopProfiles;
|
||||
delete tm->oracle;
|
||||
js_delete(tm->recordAttempts);
|
||||
js_delete(tm->loopProfiles);
|
||||
js_delete(tm->oracle);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Recover profiling data from expiring Fragments, and display
|
||||
@ -7772,7 +7789,7 @@ FinishJIT(TraceMonitor *tm)
|
||||
}
|
||||
|
||||
FragProfiling_showResults(tm);
|
||||
delete tm->profAlloc;
|
||||
js_delete(tm->profAlloc);
|
||||
|
||||
} else {
|
||||
NanoAssert(!tm->profTab);
|
||||
@ -7782,37 +7799,25 @@ FinishJIT(TraceMonitor *tm)
|
||||
|
||||
PodArrayZero(tm->vmfragments);
|
||||
|
||||
if (tm->frameCache) {
|
||||
delete tm->frameCache;
|
||||
tm->frameCache = NULL;
|
||||
}
|
||||
js_delete(tm->frameCache);
|
||||
tm->frameCache = NULL;
|
||||
|
||||
if (tm->codeAlloc) {
|
||||
delete tm->codeAlloc;
|
||||
tm->codeAlloc = NULL;
|
||||
}
|
||||
js_delete(tm->codeAlloc);
|
||||
tm->codeAlloc = NULL;
|
||||
|
||||
if (tm->dataAlloc) {
|
||||
delete tm->dataAlloc;
|
||||
tm->dataAlloc = NULL;
|
||||
}
|
||||
js_delete(tm->dataAlloc);
|
||||
tm->dataAlloc = NULL;
|
||||
|
||||
if (tm->traceAlloc) {
|
||||
delete tm->traceAlloc;
|
||||
tm->traceAlloc = NULL;
|
||||
}
|
||||
js_delete(tm->traceAlloc);
|
||||
tm->traceAlloc = NULL;
|
||||
|
||||
if (tm->tempAlloc) {
|
||||
delete tm->tempAlloc;
|
||||
tm->tempAlloc = NULL;
|
||||
}
|
||||
js_delete(tm->tempAlloc);
|
||||
tm->tempAlloc = NULL;
|
||||
|
||||
if (tm->storage) {
|
||||
delete tm->storage;
|
||||
tm->storage = NULL;
|
||||
}
|
||||
js_delete(tm->storage);
|
||||
tm->storage = NULL;
|
||||
|
||||
delete tm->cachedTempTypeMap;
|
||||
js_delete(tm->cachedTempTypeMap);
|
||||
tm->cachedTempTypeMap = NULL;
|
||||
}
|
||||
|
||||
|
@ -1575,9 +1575,6 @@ class TraceRecorder
|
||||
# include "jsopcode.tbl"
|
||||
#undef OPDEF
|
||||
|
||||
inline void* operator new(size_t size) { return js_calloc(size); }
|
||||
inline void operator delete(void *p) { js_free(p); }
|
||||
|
||||
JS_REQUIRES_STACK
|
||||
TraceRecorder(JSContext* cx, VMSideExit*, VMFragment*,
|
||||
unsigned stackSlots, unsigned ngslots, JSValueType* typeMap,
|
||||
|
@ -226,6 +226,93 @@ JS_END_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/*
|
||||
* Using vanilla new/new[] is unsafe in SpiderMonkey because they throw on
|
||||
* failure instead of returning NULL, which is what SpiderMonkey expects.
|
||||
* js_new()/js_array_new() should be used instead, and memory allocated with
|
||||
* them should be deallocated with js_delete()/js_array_delete().
|
||||
*
|
||||
* If you have a class with a private constructor or destructor, you can
|
||||
* make js_new/js_delete a friend. This can be fiddly, and the interaction of
|
||||
* template functions, friend functions and namespaces can overwhelm even
|
||||
* modern compilers. Manual inlining is probably easier.
|
||||
*
|
||||
* (If you're wondering why we can't just use the 'nothrow' variant of
|
||||
* new/new[], it's because we want to mediate *all* allocations within
|
||||
* SpiderMonkey, to satisfy any embedders using JS_USE_CUSTOM_ALLOCATOR.)
|
||||
*/
|
||||
|
||||
#define JS_NEW_BODY(t, parms) \
|
||||
void *memory = js_malloc(sizeof(t)); \
|
||||
return memory ? new(memory) t parms : NULL;
|
||||
|
||||
template <class T>
|
||||
JS_ALWAYS_INLINE T *js_new() {
|
||||
JS_NEW_BODY(T, ())
|
||||
}
|
||||
|
||||
template <class T, class P1>
|
||||
JS_ALWAYS_INLINE T *js_new(const P1 &p1) {
|
||||
JS_NEW_BODY(T, (p1))
|
||||
}
|
||||
|
||||
template <class T, class P1, class P2>
|
||||
JS_ALWAYS_INLINE T *js_new(const P1 &p1, const P2 &p2) {
|
||||
JS_NEW_BODY(T, (p1, p2))
|
||||
}
|
||||
|
||||
template <class T, class P1, class P2, class P3>
|
||||
JS_ALWAYS_INLINE T *js_new(const P1 &p1, const P2 &p2, const P3 &p3) {
|
||||
JS_NEW_BODY(T, (p1, p2, p3))
|
||||
}
|
||||
|
||||
template <class T, class P1, class P2, class P3, class P4>
|
||||
JS_ALWAYS_INLINE T *js_new(const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) {
|
||||
JS_NEW_BODY(T, (p1, p2, p3, p4))
|
||||
}
|
||||
|
||||
/* ...add additional js_new()s as necessary... */
|
||||
|
||||
#undef JS_NEW_BODY
|
||||
|
||||
template <class T>
|
||||
JS_ALWAYS_INLINE void js_delete(T *p) {
|
||||
if (p) {
|
||||
p->~T();
|
||||
js_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
static const int JSMinAlignment = 8;
|
||||
|
||||
template <class T>
|
||||
JS_ALWAYS_INLINE T *js_array_new(size_t n) {
|
||||
/* The length is stored just before the vector memory. */
|
||||
uint64 numBytes64 = uint64(JSMinAlignment) + uint64(sizeof(T)) * uint64(n);
|
||||
size_t numBytes = size_t(numBytes64);
|
||||
if (numBytes64 != numBytes) {
|
||||
JS_ASSERT(0); /* we want to know if this happens in debug builds */
|
||||
return NULL;
|
||||
}
|
||||
void *memory = js_malloc(numBytes);
|
||||
if (!memory)
|
||||
return NULL;
|
||||
*(size_t *)memory = n;
|
||||
memory = (void*)(uintptr_t(memory) + JSMinAlignment);
|
||||
return new(memory) T[n];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
JS_ALWAYS_INLINE void js_array_delete(T *p) {
|
||||
if (p) {
|
||||
void* p0 = (void *)(uintptr_t(p) - JSMinAlignment);
|
||||
size_t n = *(size_t *)p0;
|
||||
for (size_t i = 0; i < n; i++)
|
||||
(p + i)->~T();
|
||||
js_free(p0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The following classes are designed to cause assertions to detect
|
||||
* inadvertent use of guard objects as temporaries. In other words,
|
||||
|
@ -712,7 +712,7 @@ void
|
||||
JaegerCompartment::Finish()
|
||||
{
|
||||
TrampolineCompiler::release(&trampolines);
|
||||
delete execAlloc;
|
||||
js_delete(execAlloc);
|
||||
#ifdef JS_METHODJIT_PROFILE_STUBS
|
||||
FILE *fp = fopen("/tmp/stub-profiling", "wt");
|
||||
# define OPDEF(op,val,name,image,length,nuses,ndefs,prec,format) \
|
||||
|
@ -157,7 +157,7 @@ class BasePolyIC : public BaseIC {
|
||||
~BasePolyIC() {
|
||||
releasePools();
|
||||
if (areMultiplePools())
|
||||
delete multiplePools();
|
||||
js_delete(multiplePools());
|
||||
}
|
||||
|
||||
void reset() {
|
||||
@ -192,11 +192,11 @@ class BasePolyIC : public BaseIC {
|
||||
if (isOnePool()) {
|
||||
JSC::ExecutablePool *oldPool = u.execPool;
|
||||
JS_ASSERT(!isTagged(oldPool));
|
||||
ExecPoolVector *execPools = new ExecPoolVector(SystemAllocPolicy());
|
||||
ExecPoolVector *execPools = js_new<ExecPoolVector>(SystemAllocPolicy());
|
||||
if (!execPools)
|
||||
return false;
|
||||
if (!execPools->append(oldPool) || !execPools->append(pool)) {
|
||||
delete execPools;
|
||||
js_delete(execPools);
|
||||
return false;
|
||||
}
|
||||
u.taggedExecPools = tag(execPools);
|
||||
|
@ -63,7 +63,7 @@ pm_construct(JSContext* cx, uintN argc, jsval* vp)
|
||||
if (!JS_FreezeObject(cx, obj))
|
||||
return JS_FALSE;
|
||||
|
||||
PerfMeasurement* p = new PerfMeasurement(PerfMeasurement::EventMask(mask));
|
||||
PerfMeasurement* p = js_new<PerfMeasurement>(PerfMeasurement::EventMask(mask));
|
||||
if (!p) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
@ -77,7 +77,7 @@ pm_construct(JSContext* cx, uintN argc, jsval* vp)
|
||||
static void
|
||||
pm_finalize(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
delete (PerfMeasurement*) JS_GetPrivate(cx, obj);
|
||||
js_delete((PerfMeasurement*) JS_GetPrivate(cx, obj));
|
||||
}
|
||||
|
||||
// Property access
|
||||
|
@ -45,6 +45,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/perf_event.h>
|
||||
#include <new>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
@ -264,7 +265,7 @@ namespace JS {
|
||||
#define initCtr(flag) ((eventsMeasured & flag) ? 0 : -1)
|
||||
|
||||
PerfMeasurement::PerfMeasurement(PerfMeasurement::EventMask toMeasure)
|
||||
: impl(new Impl),
|
||||
: impl(js_new<Impl>()),
|
||||
eventsMeasured(impl ? static_cast<Impl*>(impl)->init(toMeasure)
|
||||
: EventMask(0)),
|
||||
cpu_cycles(initCtr(CPU_CYCLES)),
|
||||
@ -285,7 +286,7 @@ PerfMeasurement::PerfMeasurement(PerfMeasurement::EventMask toMeasure)
|
||||
|
||||
PerfMeasurement::~PerfMeasurement()
|
||||
{
|
||||
delete static_cast<Impl*>(impl);
|
||||
js_delete(static_cast<Impl*>(impl));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -52,20 +52,6 @@
|
||||
typedef jschar UChar;
|
||||
typedef JSLinearString UString;
|
||||
|
||||
template <typename T>
|
||||
class ValueDeleter
|
||||
{
|
||||
public:
|
||||
void operator()(T &t) { delete t; }
|
||||
};
|
||||
|
||||
template<typename T, size_t N, class AP>
|
||||
static inline void
|
||||
deleteAllValues(js::Vector<T,N,AP> &vector)
|
||||
{
|
||||
js::ForEach(vector.begin(), vector.end(), ValueDeleter<T>());
|
||||
}
|
||||
|
||||
class Unicode {
|
||||
public:
|
||||
static UChar toUpper(UChar c) { return JS_TOUPPER(c); }
|
||||
|
@ -2588,7 +2588,8 @@ JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength,
|
||||
return returnError(ERR16, error);
|
||||
|
||||
size_t size = length + sizeof(JSRegExp);
|
||||
JSRegExp* re = reinterpret_cast<JSRegExp*>(new char[size]);
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
JSRegExp* re = reinterpret_cast<JSRegExp*>(js_array_new<char>(size));
|
||||
|
||||
if (!re)
|
||||
return returnError(ERR13, error);
|
||||
@ -2644,7 +2645,7 @@ JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength,
|
||||
/* Failed to compile, or error while post-processing */
|
||||
|
||||
if (errorcode != ERR0) {
|
||||
delete [] reinterpret_cast<char*>(re);
|
||||
js_array_delete(reinterpret_cast<char*>(re));
|
||||
return returnError(errorcode, error);
|
||||
}
|
||||
|
||||
@ -2699,5 +2700,5 @@ JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength,
|
||||
|
||||
void jsRegExpFree(JSRegExp* re)
|
||||
{
|
||||
delete [] reinterpret_cast<char*>(re);
|
||||
js_array_delete(reinterpret_cast<char*>(re));
|
||||
}
|
||||
|
@ -388,7 +388,8 @@ struct MatchStack {
|
||||
MatchFrame* allocateNextFrame() {
|
||||
if (canUseStackBufferForNextFrame())
|
||||
return currentFrame + 1;
|
||||
MatchFrame *frame = new MatchFrame;
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
MatchFrame *frame = js_new<MatchFrame>();
|
||||
frame->init(regExpPool);
|
||||
return frame;
|
||||
}
|
||||
@ -412,7 +413,7 @@ struct MatchStack {
|
||||
MatchFrame* oldFrame = currentFrame;
|
||||
currentFrame = currentFrame->previousFrame;
|
||||
if (size > numFramesOnStack)
|
||||
delete oldFrame;
|
||||
js_delete(oldFrame);
|
||||
size--;
|
||||
}
|
||||
|
||||
|
@ -2629,14 +2629,16 @@ static const char _wordcharData[65536] = {
|
||||
|
||||
CharacterClass* digitsCreate()
|
||||
{
|
||||
CharacterClass* characterClass = new CharacterClass(0);
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
CharacterClass* characterClass = js_new<CharacterClass>((CharacterClassTable*)NULL);
|
||||
characterClass->m_ranges.append(CharacterRange(0x30, 0x39));
|
||||
return characterClass;
|
||||
}
|
||||
|
||||
CharacterClass* nondigitsCreate()
|
||||
{
|
||||
CharacterClass* characterClass = new CharacterClass(0);
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
CharacterClass* characterClass = js_new<CharacterClass>((CharacterClassTable*)NULL);
|
||||
characterClass->m_ranges.append(CharacterRange(0x00, 0x2f));
|
||||
characterClass->m_ranges.append(CharacterRange(0x3a, 0x7f));
|
||||
characterClass->m_rangesUnicode.append(CharacterRange(0x0080, 0xffff));
|
||||
@ -2645,7 +2647,8 @@ CharacterClass* nondigitsCreate()
|
||||
|
||||
CharacterClass* newlineCreate()
|
||||
{
|
||||
CharacterClass* characterClass = new CharacterClass(0);
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
CharacterClass* characterClass = js_new<CharacterClass>((CharacterClassTable*)NULL);
|
||||
characterClass->m_matches.append(0x0a);
|
||||
characterClass->m_matches.append(0x0d);
|
||||
characterClass->m_matchesUnicode.append(0x2028);
|
||||
@ -2655,7 +2658,8 @@ CharacterClass* newlineCreate()
|
||||
|
||||
CharacterClass* spacesCreate()
|
||||
{
|
||||
CharacterClass* characterClass = new CharacterClass(CharacterClassTable::create(_spacesData, false));
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
CharacterClass* characterClass = js_new<CharacterClass>(CharacterClassTable::create(_spacesData, false));
|
||||
characterClass->m_ranges.append(CharacterRange(0x09, 0x0d));
|
||||
characterClass->m_matches.append(0x20);
|
||||
characterClass->m_matchesUnicode.append(0x00a0);
|
||||
@ -2672,7 +2676,8 @@ CharacterClass* spacesCreate()
|
||||
|
||||
CharacterClass* nonspacesCreate()
|
||||
{
|
||||
CharacterClass* characterClass = new CharacterClass(CharacterClassTable::create(_spacesData, true));
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
CharacterClass* characterClass = js_new<CharacterClass>(CharacterClassTable::create(_spacesData, true));
|
||||
characterClass->m_ranges.append(CharacterRange(0x00, 0x08));
|
||||
characterClass->m_ranges.append(CharacterRange(0x0e, 0x1f));
|
||||
characterClass->m_ranges.append(CharacterRange(0x21, 0x7f));
|
||||
@ -2690,7 +2695,8 @@ CharacterClass* nonspacesCreate()
|
||||
|
||||
CharacterClass* nonwordcharCreate()
|
||||
{
|
||||
CharacterClass* characterClass = new CharacterClass(CharacterClassTable::create(_wordcharData, true));
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
CharacterClass* characterClass = js_new<CharacterClass>(CharacterClassTable::create(_wordcharData, true));
|
||||
characterClass->m_ranges.append(CharacterRange(0x00, 0x2f));
|
||||
characterClass->m_ranges.append(CharacterRange(0x3a, 0x40));
|
||||
characterClass->m_ranges.append(CharacterRange(0x5b, 0x5e));
|
||||
@ -2702,7 +2708,8 @@ CharacterClass* nonwordcharCreate()
|
||||
|
||||
CharacterClass* wordcharCreate()
|
||||
{
|
||||
CharacterClass* characterClass = new CharacterClass(CharacterClassTable::create(_wordcharData, false));
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
CharacterClass* characterClass = js_new<CharacterClass>(CharacterClassTable::create(_wordcharData, false));
|
||||
characterClass->m_ranges.append(CharacterRange(0x30, 0x39));
|
||||
characterClass->m_ranges.append(CharacterRange(0x41, 0x5a));
|
||||
characterClass->m_matches.append(0x5f);
|
||||
|
@ -139,7 +139,8 @@ public:
|
||||
|
||||
CharacterClass* charClass()
|
||||
{
|
||||
CharacterClass* characterClass = new CharacterClass(0);
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
CharacterClass* characterClass = js_new<CharacterClass>((CharacterClassTable*)NULL);
|
||||
|
||||
characterClass->m_matches.append(m_matches);
|
||||
characterClass->m_ranges.append(m_ranges);
|
||||
@ -344,7 +345,8 @@ public:
|
||||
if (capture)
|
||||
m_pattern.m_numSubpatterns++;
|
||||
|
||||
PatternDisjunction* parenthesesDisjunction = new PatternDisjunction(m_alternative);
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
PatternDisjunction* parenthesesDisjunction = js_new<PatternDisjunction>(m_alternative);
|
||||
m_pattern.m_disjunctions.append(parenthesesDisjunction);
|
||||
m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture));
|
||||
m_alternative = parenthesesDisjunction->addNewAlternative();
|
||||
@ -352,7 +354,8 @@ public:
|
||||
|
||||
void atomParentheticalAssertionBegin(bool invert = false)
|
||||
{
|
||||
PatternDisjunction* parenthesesDisjunction = new PatternDisjunction(m_alternative);
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
PatternDisjunction* parenthesesDisjunction = js_new<PatternDisjunction>(m_alternative);
|
||||
m_pattern.m_disjunctions.append(parenthesesDisjunction);
|
||||
m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, invert));
|
||||
m_alternative = parenthesesDisjunction->addNewAlternative();
|
||||
@ -397,7 +400,8 @@ public:
|
||||
|
||||
PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction)
|
||||
{
|
||||
PatternDisjunction* newDisjunction = new PatternDisjunction();
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
PatternDisjunction* newDisjunction = js_new<PatternDisjunction>();
|
||||
|
||||
newDisjunction->m_parent = disjunction->m_parent;
|
||||
for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) {
|
||||
@ -467,7 +471,8 @@ public:
|
||||
|
||||
void regexBegin()
|
||||
{
|
||||
m_pattern.m_body = new PatternDisjunction();
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
m_pattern.m_body = js_new<PatternDisjunction>();
|
||||
m_alternative = m_pattern.m_body->addNewAlternative();
|
||||
m_pattern.m_disjunctions.append(m_pattern.m_body);
|
||||
}
|
||||
|
@ -66,11 +66,15 @@ struct CharacterClassTable {
|
||||
/* Ownership transferred to caller. */
|
||||
static CharacterClassTable *create(const char* table, bool inverted)
|
||||
{
|
||||
return new CharacterClassTable(table, inverted);
|
||||
// FIXME: bug 574459 -- no NULL checks done by any of the callers, all
|
||||
// of which are in RegExpJitTables.h.
|
||||
/* We can't (easily) use js_new() here because the constructor is private. */
|
||||
void *memory = js_malloc(sizeof(CharacterClassTable));
|
||||
return memory ? new(memory) CharacterClassTable(table, inverted) : NULL;
|
||||
}
|
||||
|
||||
void incref() { JS_ATOMIC_INCREMENT(&m_refcount); }
|
||||
void decref() { if (JS_ATOMIC_DECREMENT(&m_refcount) == 0) delete this; }
|
||||
void decref() { if (JS_ATOMIC_DECREMENT(&m_refcount) == 0) js_delete(this); }
|
||||
|
||||
private:
|
||||
CharacterClassTable(const char* table, bool inverted)
|
||||
@ -263,6 +267,14 @@ struct PatternAlternative {
|
||||
bool m_containsBOL : 1;
|
||||
};
|
||||
|
||||
template<typename T, size_t N, class AP>
|
||||
static inline void
|
||||
deleteAllValues(js::Vector<T*,N,AP> &vector)
|
||||
{
|
||||
for (T** t = vector.begin(); t < vector.end(); ++t)
|
||||
js_delete(*t);
|
||||
}
|
||||
|
||||
struct PatternDisjunction {
|
||||
PatternDisjunction(PatternAlternative* parent = 0)
|
||||
: m_parent(parent)
|
||||
@ -277,7 +289,8 @@ struct PatternDisjunction {
|
||||
|
||||
PatternAlternative* addNewAlternative()
|
||||
{
|
||||
PatternAlternative* alternative = new PatternAlternative(this);
|
||||
// FIXME: bug 574459 -- no NULL check
|
||||
PatternAlternative* alternative = js_new<PatternAlternative>(this);
|
||||
m_alternatives.append(alternative);
|
||||
return alternative;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user