mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
137 lines
3.5 KiB
C++
137 lines
3.5 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: set ts=8 sw=4 et tw=99:
|
|
*/
|
|
|
|
#include "tests.h"
|
|
#include "jsstr.h"
|
|
|
|
static JSGCCallback oldGCCallback;
|
|
|
|
static void **checkPointers;
|
|
static jsuint checkPointersLength;
|
|
static size_t checkPointersStaticStrings;
|
|
|
|
static JSBool
|
|
TestAboutToBeFinalizedCallback(JSContext *cx, JSGCStatus status)
|
|
{
|
|
if (status == JSGC_MARK_END && checkPointers) {
|
|
for (jsuint i = 0; i != checkPointersLength; ++i) {
|
|
void *p = checkPointers[i];
|
|
JS_ASSERT(p);
|
|
if (JS_IsAboutToBeFinalized(cx, p))
|
|
checkPointers[i] = NULL;
|
|
}
|
|
}
|
|
|
|
return !oldGCCallback || oldGCCallback(cx, status);
|
|
}
|
|
|
|
/*
|
|
* NativeFrameCleaner write to sink so a compiler nwould not be able to optimze out
|
|
* the buffer memset there.
|
|
*/
|
|
volatile void *ptrSink;
|
|
|
|
static JS_NEVER_INLINE void
|
|
NativeFrameCleaner()
|
|
{
|
|
char buffer[1 << 16];
|
|
memset(buffer, 0, sizeof buffer);
|
|
ptrSink = buffer;
|
|
}
|
|
|
|
BEGIN_TEST(testIsAboutToBeFinalized_bug528645)
|
|
{
|
|
/*
|
|
* Due to the conservative GC we use separated never-inline function to
|
|
* test rooted elements.
|
|
*/
|
|
CHECK(createAndTestRooted());
|
|
NativeFrameCleaner();
|
|
|
|
JS_GC(cx);
|
|
|
|
/* Everything is unrooted except unit strings. */
|
|
for (jsuint i = 0; i != checkPointersLength; ++i) {
|
|
void *p = checkPointers[i];
|
|
if (p) {
|
|
CHECK(JSString::isStatic(p));
|
|
CHECK(checkPointersStaticStrings != 0);
|
|
--checkPointersStaticStrings;
|
|
}
|
|
}
|
|
CHECK(checkPointersStaticStrings == 0);
|
|
|
|
free(checkPointers);
|
|
checkPointers = NULL;
|
|
JS_SetGCCallback(cx, oldGCCallback);
|
|
|
|
return true;
|
|
}
|
|
|
|
JS_NEVER_INLINE bool createAndTestRooted();
|
|
|
|
END_TEST(testIsAboutToBeFinalized_bug528645)
|
|
|
|
JS_NEVER_INLINE bool
|
|
cls_testIsAboutToBeFinalized_bug528645::createAndTestRooted()
|
|
{
|
|
jsvalRoot root(cx);
|
|
|
|
/*
|
|
* Check various types of GC things against JS_IsAboutToBeFinalized.
|
|
* Make sure to include unit and numeric strings to the set.
|
|
*/
|
|
EVAL("var x = 1.1; "
|
|
"[''+x, 'a', '123456789', 'something'.substring(1), "
|
|
"{}, [], new Function('return 10;'), <xml/>];",
|
|
root.addr());
|
|
|
|
JSObject *array = JSVAL_TO_OBJECT(root.value());
|
|
JS_ASSERT(JS_IsArrayObject(cx, array));
|
|
|
|
JSBool ok = JS_GetArrayLength(cx, array, &checkPointersLength);
|
|
CHECK(ok);
|
|
|
|
checkPointers = (void **) malloc(sizeof(void *) * checkPointersLength);
|
|
CHECK(checkPointers);
|
|
|
|
checkPointersStaticStrings = 0;
|
|
for (jsuint i = 0; i != checkPointersLength; ++i) {
|
|
jsval v;
|
|
ok = JS_GetElement(cx, array, i, &v);
|
|
CHECK(ok);
|
|
JS_ASSERT(JSVAL_IS_GCTHING(v));
|
|
JS_ASSERT(!JSVAL_IS_NULL(v));
|
|
checkPointers[i] = JSVAL_TO_GCTHING(v);
|
|
if (JSString::isStatic(checkPointers[i]))
|
|
++checkPointersStaticStrings;
|
|
}
|
|
|
|
oldGCCallback = JS_SetGCCallback(cx, TestAboutToBeFinalizedCallback);
|
|
JS_GC(cx);
|
|
|
|
/*
|
|
* All GC things are rooted via the root holding the array containing them
|
|
* and TestAboutToBeFinalizedCallback must keep them as is.
|
|
*/
|
|
for (jsuint i = 0; i != checkPointersLength; ++i)
|
|
CHECK(checkPointers[i]);
|
|
|
|
/*
|
|
* Overwrite the registers and stack with new GC things to avoid false
|
|
* positives with the finalization test.
|
|
*/
|
|
EVAL("[]", root.addr());
|
|
|
|
array = JSVAL_TO_OBJECT(root.value());
|
|
JS_ASSERT(JS_IsArrayObject(cx, array));
|
|
|
|
jsuint tmp;
|
|
CHECK(JS_GetArrayLength(cx, array, &tmp));
|
|
CHECK(ok);
|
|
|
|
return true;
|
|
}
|
|
|