Hi all!

I rewrote the ExternalResource benchmark using two types of Point
objects: a 'classic' Point with two integer member and one with 18
integer member. The results are attached to this mail as well as the
source files. I created test cases with 100000, 200000, 500000 and
1000000 objects. All *.result file consist tests for both Point-types.
I used the '--trace_gc' flag. I have also played with other flags but
none of them had provided any additional information I could have
used. In every test case the ExternalResource approach resulted in
more objects freed by the GC without explicitly calling it and the
heap size never exceeded above 1.0 MB. The MakeWeak approach tended to
use much more (even 6.9 MB with 1000000 objects). It is quite
interesting that with the '18 dimension-Point-object' the GC used the
mark-sweep collector instead of scavenging. I think the
ExternalResorce approach is definitely faster and less memory
consuming than the MakeWeak approach.

Best regards,
Gabor Ballabas





----------------------------------------------------------------
This message was sent using IMP, the Internet Messaging Program.

*** Begin MeasureExternalResource - external-resource-point ***

Scavenge 0.9 -> 0.5 MB, 5 ms.
Scavenge 0.9 -> 0.5 MB, 5 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.

Number of Point objects before IdleNotification: 16112

Scavenge 0.7 -> 0.5 MB, 3 ms.
Mark-sweep 0.5 -> 0.4 MB, 0 ms.
Mark-compact 0.4 -> 0.4 MB, 2 ms.

*** End MeasureExternalResource - external-resource-point ***

*** Begin MeasureMakeWeak - external-resource-point ***

Scavenge 0.9 -> 0.9 MB, 2 ms.
Scavenge 1.3 -> 1.3 MB, 2 ms.

Number of Point objects before IdleNotification: 100000

Scavenge 1.9 -> 1.9 MB, 4 ms.
Mark-sweep 1.9 -> 1.9 MB, 15 / 22 ms.
Mark-compact 1.9 -> 0.4 MB, 3 ms.

*** End MeasureMakeWeak - external-resource-point ***


*** Begin MeasureExternalResource - external-resource-bigpoint ***

Mark-sweep 0.9 -> 0.4 MB, 6 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.

Number of Point objects before IdleNotification: 10573

Scavenge 0.6 -> 0.4 MB, 2 ms.
Mark-sweep 0.4 -> 0.4 MB, 0 ms.
Mark-compact 0.4 -> 0.4 MB, 2 ms.

*** End MeasureExternalResource - external-resource-bigpoint ***

*** Begin MeasureMakeWeak - external-resource-bigpoint ***

Mark-sweep 0.9 -> 0.9 MB, 5 / 9 ms.
Mark-sweep 1.4 -> 0.9 MB, 5 / 9 ms.

Number of Point objects before IdleNotification: 35033

Scavenge 1.4 -> 1.4 MB, 2 ms.
Mark-sweep 1.4 -> 0.9 MB, 5 / 9 ms.
Mark-compact 0.9 -> 0.4 MB, 2 ms.

*** End MeasureMakeWeak - external-resource-bigpoint ***

*** Begin MeasureExternalResource - external-resource-point ***

Scavenge 0.9 -> 0.5 MB, 5 ms.
Scavenge 0.9 -> 0.5 MB, 5 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.

Number of Point objects before IdleNotification: 17811

Scavenge 0.7 -> 0.5 MB, 3 ms.
Mark-sweep 0.5 -> 0.4 MB, 0 ms.
Mark-compact 0.4 -> 0.4 MB, 2 ms.

*** End MeasureExternalResource - external-resource-point ***

*** Begin MeasureMakeWeak - external-resource-point ***

Scavenge 0.9 -> 0.9 MB, 2 ms.
Scavenge 1.3 -> 1.3 MB, 2 ms.
Scavenge 2.0 -> 2.0 MB, 5 ms.
Mark-sweep 2.8 -> 2.8 MB, 23 / 36 ms.

Number of Point objects before IdleNotification: 44849

Scavenge 3.4 -> 3.4 MB, 2 ms.
Mark-sweep 3.4 -> 1.1 MB, 6 / 12 ms.
Mark-compact 1.1 -> 0.4 MB, 2 ms.

*** End MeasureMakeWeak - external-resource-point ***


*** Begin MeasureExternalResource - external-resource-bigpoint ***

Mark-sweep 0.9 -> 0.4 MB, 6 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.

Number of Point objects before IdleNotification: 12479

Scavenge 0.6 -> 0.4 MB, 2 ms.
Mark-sweep 0.4 -> 0.4 MB, 0 ms.
Mark-compact 0.4 -> 0.4 MB, 2 ms.

*** End MeasureExternalResource - external-resource-bigpoint ***

*** Begin MeasureMakeWeak - external-resource-bigpoint ***

Mark-sweep 0.9 -> 0.9 MB, 5 / 9 ms.
Mark-sweep 1.4 -> 0.9 MB, 5 / 9 ms.
Scavenge 1.9 -> 1.9 MB, 4 ms.
Mark-sweep 2.6 -> 2.1 MB, 22 / 33 ms.

Number of Point objects before IdleNotification: 20414

Scavenge 2.4 -> 2.4 MB, 1 ms.
Mark-sweep 2.4 -> 0.7 MB, 4 / 8 ms.
Mark-compact 0.7 -> 0.4 MB, 2 ms.

*** End MeasureMakeWeak - external-resource-bigpoint ***

*** Begin MeasureExternalResource - external-resource-point ***

Scavenge 0.9 -> 0.5 MB, 5 ms.
Scavenge 0.9 -> 0.5 MB, 5 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.

Number of Point objects before IdleNotification: 22908

Scavenge 0.8 -> 0.5 MB, 4 ms.
Mark-sweep 0.5 -> 0.4 MB, 0 ms.
Mark-compact 0.4 -> 0.4 MB, 2 ms.

*** End MeasureExternalResource - external-resource-point ***

*** Begin MeasureMakeWeak - external-resource-point ***

Scavenge 0.9 -> 0.9 MB, 2 ms.
Scavenge 1.3 -> 1.3 MB, 2 ms.
Scavenge 2.0 -> 2.0 MB, 5 ms.
Mark-sweep 2.8 -> 2.8 MB, 23 / 37 ms.
Scavenge 4.8 -> 4.8 MB, 9 ms.
Scavenge 6.3 -> 6.3 MB, 9 ms.

Number of Point objects before IdleNotification: 344849

Scavenge 8.0 -> 8.0 MB, 14 ms.
Mark-sweep 8.0 -> 5.6 MB, 52 / 79 ms.
Mark-compact 5.6 -> 0.4 MB, 5 ms.

*** End MeasureMakeWeak - external-resource-point ***


*** Begin MeasureExternalResource - external-resource-bigpoint ***

Mark-sweep 0.9 -> 0.4 MB, 6 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 8 ms.
Mark-sweep 0.9 -> 0.4 MB, 10 ms.
Mark-sweep 0.9 -> 0.4 MB, 8 ms.

Number of Point objects before IdleNotification: 18197

Scavenge 0.7 -> 0.4 MB, 3 ms.
Mark-sweep 0.4 -> 0.4 MB, 0 ms.
Mark-compact 0.4 -> 0.4 MB, 2 ms.

*** End MeasureExternalResource - external-resource-bigpoint ***

*** Begin MeasureMakeWeak - external-resource-bigpoint ***

Mark-sweep 0.9 -> 0.9 MB, 6 / 10 ms.
Mark-sweep 1.4 -> 0.9 MB, 5 / 9 ms.
Scavenge 1.9 -> 1.9 MB, 4 ms.
Mark-sweep 2.6 -> 2.1 MB, 19 / 30 ms.
Mark-sweep 4.1 -> 2.4 MB, 22 / 37 ms.
Mark-sweep 4.4 -> 2.4 MB, 23 / 38 ms.

Number of Point objects before IdleNotification: 58410

Scavenge 3.3 -> 3.3 MB, 3 ms.
Mark-sweep 3.3 -> 1.3 MB, 10 / 18 ms.
Mark-compact 1.3 -> 0.4 MB, 3 ms.

*** End MeasureMakeWeak - external-resource-bigpoint ***

*** Begin MeasureExternalResource - external-resource-point ***

Scavenge 0.9 -> 0.5 MB, 5 ms.
Scavenge 0.9 -> 0.5 MB, 5 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.
Scavenge 1.0 -> 0.5 MB, 6 ms.

Number of Point objects before IdleNotification: 31403

Scavenge 0.9 -> 0.5 MB, 6 ms.
Mark-sweep 0.5 -> 0.4 MB, 0 ms.
Mark-compact 0.4 -> 0.4 MB, 2 ms.

*** End MeasureExternalResource - external-resource-point ***

*** Begin MeasureMakeWeak - external-resource-point ***

Scavenge 0.9 -> 0.9 MB, 2 ms.
Scavenge 1.3 -> 1.3 MB, 2 ms.
Scavenge 2.0 -> 2.0 MB, 5 ms.
Mark-sweep 2.8 -> 2.8 MB, 24 / 38 ms.
Scavenge 4.8 -> 4.8 MB, 9 ms.
Scavenge 6.3 -> 6.3 MB, 9 ms.
Scavenge 9.3 -> 9.3 MB, 20 ms.
Mark-sweep 12.3 -> 9.9 MB, 98 / 150 ms.

Number of Point objects before IdleNotification: 222324

Scavenge 13.3 -> 13.3 MB, 15 ms.
Mark-sweep 13.3 -> 3.8 MB, 34 / 60 ms.
Mark-compact 3.8 -> 0.4 MB, 6 ms.

*** End MeasureMakeWeak - external-resource-point ***


*** Begin MeasureExternalResource - external-resource-bigpoint ***

Mark-sweep 0.9 -> 0.4 MB, 6 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 8 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 8 ms.
Mark-sweep 0.9 -> 0.4 MB, 8 ms.
Mark-sweep 0.9 -> 0.4 MB, 10 ms.
Mark-sweep 0.9 -> 0.4 MB, 11 ms.
Mark-sweep 0.9 -> 0.4 MB, 10 ms.
Mark-sweep 0.9 -> 0.4 MB, 8 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 7 ms.
Mark-sweep 0.9 -> 0.4 MB, 8 ms.
Mark-sweep 0.9 -> 0.4 MB, 8 ms.

Number of Point objects before IdleNotification: 27727

Mark-sweep 0.8 -> 0.4 MB, 7 ms.
Mark-sweep 0.4 -> 0.4 MB, 0 ms.
Mark-compact 0.4 -> 0.4 MB, 2 ms.

*** End MeasureExternalResource - external-resource-bigpoint ***

*** Begin MeasureMakeWeak - external-resource-bigpoint ***

Mark-sweep 0.9 -> 0.9 MB, 5 / 10 ms.
Mark-sweep 1.4 -> 0.9 MB, 5 / 9 ms.
Scavenge 1.9 -> 1.9 MB, 5 ms.
Mark-sweep 2.6 -> 2.1 MB, 21 / 32 ms.
Mark-sweep 4.1 -> 2.4 MB, 22 / 37 ms.
Mark-sweep 4.4 -> 2.4 MB, 28 / 43 ms.
Mark-sweep 6.4 -> 4.4 MB, 45 / 77 ms.
Mark-sweep 6.9 -> 2.9 MB, 28 / 47 ms.

Number of Point objects before IdleNotification: 130763

Mark-sweep 4.9 -> 2.4 MB, 22 / 37 ms.
Mark-sweep 2.4 -> 0.4 MB, 2 ms.
Mark-compact 0.4 -> 0.4 MB, 2 ms.

*** End MeasureMakeWeak - external-resource-bigpoint ***

/*
 * Benchmark - ExternalResource
 * Usage: external-resource-tester [number_of_tests]
 * 
 */

#include <v8.h>
#include <cassert>
#include <cstdlib>
#include <cstring>


using namespace v8;
using namespace std;


void ExecuteString(v8::Handle<v8::String> source, bool print_result)
{
    v8::HandleScope handle_scope;
    v8::TryCatch try_catch;
    v8::Handle<v8::Script> script = v8::Script::Compile(source);
    assert(!script.IsEmpty());
    v8::Handle<v8::Value> result = script->Run();
    assert(!result.IsEmpty());
    if (print_result) {
        v8::String::Utf8Value str(result);
        printf("%s\n", *str);
    }
}


class Point {
public:
    static int counter;

    Point()
    {
        a = b = c = d = e = f = g = h = i = j = k = l = m = n = o = p = q = r = 0;
        ++counter;
    }

    ~Point()
    {
        --counter;
    }

    int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r;
};

int Point::counter = 0;


class V8ObjectResource : public v8::Object::ExternalResource {
public:
    V8ObjectResource() {}
    enum ResourceType { POINT_TYPE, SOME_OTHER_TYPE };
    virtual ResourceType getResourceType() const = 0;
};


class V8PointResource : public V8ObjectResource {
public:
    V8PointResource(Point* p) : point(p) {}
    ~V8PointResource()
    {
        delete point;
        V8::AdjustAmountOfExternalAllocatedMemory(-int(sizeof(V8PointResource) + sizeof(Point)));
    }
    
    enum { V8_RESOURCE_TYPE = V8ObjectResource::POINT_TYPE };
    
    V8ObjectResource::ResourceType getResourceType() const
    {
        return V8ObjectResource::POINT_TYPE;
    }

//private:
    Point* point;
};


template <class T>
inline T* v8_resource_cast(Handle<Object> object)
{
    V8ObjectResource* resource = static_cast<V8ObjectResource*>(object->GetExternalResource());
    return (resource && 
            (uint32_t)resource->getResourceType() == (uint32_t)T::V8_RESOURCE_TYPE) ? static_cast<T*>(resource) : 0;
}


static Handle<Value> makeResourcePoint(const Arguments& args)
{
    assert(args.IsConstructCall());
    Local<Object> self = args.This();
    Point* p = new Point();
    V8PointResource* point_resource = new V8PointResource(p);
    V8::AdjustAmountOfExternalAllocatedMemory(int(sizeof(V8PointResource) + sizeof(Point)));
    self->SetExternalResource(point_resource);
    return v8::Undefined();
}


static Handle<Value> getResourcePointX(Local<String>, const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    V8PointResource *res = v8_resource_cast<V8PointResource>(self);
    assert(res != 0);
    return v8::Int32::New(666);
}


static Handle<Value> getResourcePointY(Local<String>, const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    V8PointResource *res = v8_resource_cast<V8PointResource>(self);
    assert(res != 0);
    return v8::Int32::New(777);
}



void weakPointCallback(Persistent<Value> object, void* parameter)
{
    Point* point = static_cast<Point*>(parameter);
    delete point;
    object.Dispose();
    object.Clear();
    V8::AdjustAmountOfExternalAllocatedMemory(-int(sizeof(Point)));
}


static Handle<Value> makeWeakPoint(const Arguments& args)
{
    assert(args.IsConstructCall());
    Local<Object> self = args.This();
    assert(self->InternalFieldCount() == 1);
    Point *point = new Point();
    self->SetPointerInInternalField(0, point);
    V8::AdjustAmountOfExternalAllocatedMemory(int(sizeof(Point)));
    Persistent<Object> weakSelf = Persistent<Object>::New(self);
    weakSelf.MakeWeak(point, weakPointCallback);
    return weakSelf;
}


static Handle<Value> getWeakPointX(Local<String>, const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    Point *point = static_cast<Point*>(self->GetPointerFromInternalField(0));
    return v8::Int32::New(666);
}


static Handle<Value> getWeakPointY(Local<String>, const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    Point *point = static_cast<Point*>(self->GetPointerFromInternalField(0));
    return v8::Int32::New(777);
}


void MeasureExternalResource(int number_of_objects)
{
    printf("\n*** Begin MeasureExternalResource - external-resource-bigpoint ***\n\n");

    v8::Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(makeResourcePoint);
    v8::Handle<v8::ObjectTemplate> point_templ = fun_templ->InstanceTemplate();
    point_templ->SetHasExternalResource(true);
    point_templ->SetAccessor(v8::String::New("x"), getResourcePointX);
    point_templ->SetAccessor(v8::String::New("y"), getResourcePointY);

    v8::Context::GetEntered()->Global()->Set(v8::String::New("Point"), fun_templ->GetFunction());
    v8::Context::GetEntered()->Global()->Set(v8::String::New("counter"), v8::Int32::New(number_of_objects));

    ExecuteString(v8::String::New("for (i = 0; i < counter; ++i) { new Point(); }"), false);

    printf("\nNumber of Point objects before IdleNotification: %d\n\n", Point::counter);

    while (!V8::IdleNotification()) { }
    assert(Point::counter == 0);

    printf("\n*** End MeasureExternalResource - external-resource-bigpoint ***\n");
}


void MeasureMakeWeak(int number_of_objects)
{
    printf("\n*** Begin MeasureMakeWeak - external-resource-bigpoint ***\n\n");

    v8::Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(makeWeakPoint);
    v8::Handle<v8::ObjectTemplate> point_templ = fun_templ->InstanceTemplate();
    point_templ->SetInternalFieldCount(1);
    point_templ->SetAccessor(v8::String::New("x"), getWeakPointX);
    point_templ->SetAccessor(v8::String::New("y"), getWeakPointY);

    v8::Context::GetEntered()->Global()->Set(v8::String::New("Point"), fun_templ->GetFunction());
    v8::Context::GetEntered()->Global()->Set(v8::String::New("counter"), v8::Int32::New(number_of_objects));

    ExecuteString(v8::String::New("for (i = 0; i < counter; ++i) { new Point(); }"), false);

    printf("\nNumber of Point objects before IdleNotification: %d\n\n", Point::counter);

    while (!V8::IdleNotification()) { }
    assert(Point::counter == 0);

    printf("\n*** End MeasureMakeWeak - external-resource-bigpoint ***\n\n");
}


int main(int argc, char* argv[])
{
    if (argc > 2) {
        return 666;
    }

    int number_of_objects = 100000;
    if (argc == 2) {
        int num = atoi(argv[1]);
        if (num) {
            number_of_objects = num;
        } else {
            return 666;
        }
    }

    const char* v8args = "--trace_gc";
    if (v8args)
        v8::V8::SetFlagsFromString(v8args, strlen(v8args));

    HandleScope handle_scope;
    
    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();

    Persistent<Context> context = Context::New(NULL, global);
    Context::Scope context_scope(context);

    MeasureExternalResource(number_of_objects);
    MeasureMakeWeak(number_of_objects);

    context.Dispose();

    return 0;
}


/*
 * Benchmark - ExternalResource
 * Usage: external-resource-tester [number_of_objects]
 * 
 */

#include <v8.h>
#include <cassert>
#include <cstdlib>
#include <cstring>


using namespace v8;
using namespace std;


void ExecuteString(v8::Handle<v8::String> source, bool print_result)
{
    v8::HandleScope handle_scope;
    v8::TryCatch try_catch;
    v8::Handle<v8::Script> script = v8::Script::Compile(source);
    assert(!script.IsEmpty());
    v8::Handle<v8::Value> result = script->Run();
    assert(!result.IsEmpty());
    if (print_result) {
        v8::String::Utf8Value str(result);
        printf("%s\n", *str);
    }
}


class Point {
public:
    static int counter;

    Point(int x, int y) : x_(x), y_(y)
    {
        ++counter;
    }

    ~Point()
    {
        --counter;
    }

    int x_;
    int y_;
};


int Point::counter = 0;


class V8ObjectResource : public v8::Object::ExternalResource {
public:
    V8ObjectResource() {}
    enum ResourceType { POINT_TYPE, SOME_OTHER_TYPE };
    virtual ResourceType getResourceType() const = 0;
};


class V8PointResource : public V8ObjectResource {
public:
    V8PointResource(Point* p) : point(p) {}
    ~V8PointResource()
    {
        delete point;
        V8::AdjustAmountOfExternalAllocatedMemory(-int(sizeof(V8PointResource) + sizeof(Point)));
    }
    
    enum { V8_RESOURCE_TYPE = V8ObjectResource::POINT_TYPE };
    
    V8ObjectResource::ResourceType getResourceType() const
    {
        return V8ObjectResource::POINT_TYPE;
    }

//private:
    Point* point;
};


template <class T>
inline T* v8_resource_cast(Handle<Object> object)
{
    V8ObjectResource* resource = static_cast<V8ObjectResource*>(object->GetExternalResource());
    return (resource && 
            (uint32_t)resource->getResourceType() == (uint32_t)T::V8_RESOURCE_TYPE) ? static_cast<T*>(resource) : 0;
}


static Handle<Value> makeResourcePoint(const Arguments& args)
{
    assert(args.IsConstructCall());
    Local<Object> self = args.This();
    Point* p = new Point(10, 20);
    V8PointResource* point_resource = new V8PointResource(p);
    V8::AdjustAmountOfExternalAllocatedMemory(int(sizeof(V8PointResource) + sizeof(Point)));
    self->SetExternalResource(point_resource);
    return v8::Undefined();
}


static Handle<Value> getResourcePointX(Local<String>, const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    V8PointResource *res = v8_resource_cast<V8PointResource>(self);
    assert(res != 0);
    return v8::Int32::New(res->point->x_);
}


static Handle<Value> getResourcePointY(Local<String>, const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    V8PointResource *res = v8_resource_cast<V8PointResource>(self);
    assert(res != 0);
    return v8::Int32::New(res->point->y_);
}


void weakPointCallback(Persistent<Value> object, void* parameter)
{
    Point* point = static_cast<Point*>(parameter);
    delete point;
    object.Dispose();
    object.Clear();
    V8::AdjustAmountOfExternalAllocatedMemory(-int(sizeof(Point)));
}


static Handle<Value> makeWeakPoint(const Arguments& args)
{
    assert(args.IsConstructCall());
    Local<Object> self = args.This();
    assert(self->InternalFieldCount() == 1);
    Point *point = new Point(10, 20);
    self->SetPointerInInternalField(0, point);
    V8::AdjustAmountOfExternalAllocatedMemory(int(sizeof(Point)));
    Persistent<Object> weakSelf = Persistent<Object>::New(self);
    weakSelf.MakeWeak(point, weakPointCallback);
    return weakSelf;
}


static Handle<Value> getWeakPointX(Local<String>, const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    Point *point = static_cast<Point*>(self->GetPointerFromInternalField(0));
    return v8::Int32::New(point->x_);
}


static Handle<Value> getWeakPointY(Local<String>, const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    Point *point = static_cast<Point*>(self->GetPointerFromInternalField(0));
    return v8::Int32::New(point->y_);
}


void MeasureExternalResource(int number_of_objects)
{
    printf("\n*** Begin MeasureExternalResource - external-resource-point ***\n\n");

    v8::Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(makeResourcePoint);
    v8::Handle<v8::ObjectTemplate> point_templ = fun_templ->InstanceTemplate();
    point_templ->SetHasExternalResource(true);
    point_templ->SetAccessor(v8::String::New("x"), getResourcePointX);
    point_templ->SetAccessor(v8::String::New("y"), getResourcePointY);

    v8::Context::GetEntered()->Global()->Set(v8::String::New("Point"), fun_templ->GetFunction());
    v8::Context::GetEntered()->Global()->Set(v8::String::New("counter"), v8::Int32::New(number_of_objects));

    ExecuteString(v8::String::New("for (i = 0; i < counter; ++i) { new Point(); }"), false);

    printf("\nNumber of Point objects before IdleNotification: %d\n\n", Point::counter);

    while (!V8::IdleNotification()) { }
    assert(Point::counter == 0);

    printf("\n*** End MeasureExternalResource - external-resource-point ***\n");
}


void MeasureMakeWeak(int number_of_objects)
{
    printf("\n*** Begin MeasureMakeWeak - external-resource-point ***\n\n");

    v8::Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(makeWeakPoint);
    v8::Handle<v8::ObjectTemplate> point_templ = fun_templ->InstanceTemplate();
    point_templ->SetInternalFieldCount(1);
    point_templ->SetAccessor(v8::String::New("x"), getWeakPointX);
    point_templ->SetAccessor(v8::String::New("y"), getWeakPointY);

    v8::Context::GetEntered()->Global()->Set(v8::String::New("Point"), fun_templ->GetFunction());
    v8::Context::GetEntered()->Global()->Set(v8::String::New("counter"), v8::Int32::New(number_of_objects));

    ExecuteString(v8::String::New("for (i = 0; i < counter; ++i) { new Point(); }"), false);

    printf("\nNumber of Point objects before IdleNotification: %d\n\n", Point::counter);

    while (!V8::IdleNotification()) { }
    assert(Point::counter == 0);

    printf("\n*** End MeasureMakeWeak - external-resource-point ***\n\n");
}


int main(int argc, char* argv[])
{
    if (argc > 2) {
        return 666;
    }

    int number_of_objects = 100000;
    if (argc == 2) {
        int num = atoi(argv[1]);
        if (num) {
            number_of_objects = num;
        } else {
            return 666;
        }
    }

    const char* v8args = "--trace_gc";
    if (v8args)
        v8::V8::SetFlagsFromString(v8args, strlen(v8args));

    HandleScope handle_scope;
    
    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();

    Persistent<Context> context = Context::New(NULL, global);
    Context::Scope context_scope(context);

    MeasureExternalResource(number_of_objects);
    MeasureMakeWeak(number_of_objects);

    context.Dispose();

    return 0;
}


_______________________________________________
Qt-script mailing list
[email protected]
http://lists.qt.nokia.com/mailman/listinfo/qt-script

Reply via email to