mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
Port a ton of the original ext classes
You can now create a JS object from Ruby-land without segfaulting
This commit is contained in:
parent
1f7192ca85
commit
d1e9088cf0
21 changed files with 844 additions and 8 deletions
50
ext/v8/backref.cc
Normal file
50
ext/v8/backref.cc
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include "rr.h"
|
||||
|
||||
namespace rr {
|
||||
|
||||
VALUE Backref::Storage;
|
||||
ID Backref::_new;
|
||||
ID Backref::object;
|
||||
|
||||
void Backref::Init() {
|
||||
Storage = rb_eval_string("V8::Weak::Ref");
|
||||
rb_gc_register_address(&Storage);
|
||||
_new = rb_intern("new");
|
||||
object = rb_intern("object");
|
||||
}
|
||||
|
||||
Backref::Backref(VALUE initial) {
|
||||
set(initial);
|
||||
rb_gc_register_address(&storage);
|
||||
}
|
||||
|
||||
Backref::~Backref() {
|
||||
rb_gc_unregister_address(&storage);
|
||||
}
|
||||
|
||||
VALUE Backref::set(VALUE data) {
|
||||
this->storage = rb_funcall(Storage, _new, 1, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
VALUE Backref::get() {
|
||||
return rb_funcall(storage, object, 0);
|
||||
}
|
||||
|
||||
v8::Handle<v8::External> Backref::toExternal() {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
|
||||
v8::Local<v8::External> wrapper = v8::External::New(isolate, this);
|
||||
(new v8::Persistent<v8::External>(isolate, wrapper))->SetWeak(this, &release);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
void Backref::release(const v8::WeakCallbackData<v8::External, Backref>& data) {
|
||||
// TODO: Since data.GetValue() is Local<v8::External> make sure
|
||||
// the Persistent is disposed of (or will be) at this point.
|
||||
|
||||
delete data.GetParameter();
|
||||
}
|
||||
|
||||
}
|
29
ext/v8/backref.h
Normal file
29
ext/v8/backref.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef RR_BACKREF
|
||||
#define RR_BACKREF
|
||||
|
||||
namespace rr {
|
||||
|
||||
class Backref {
|
||||
public:
|
||||
static void Init();
|
||||
|
||||
Backref(VALUE value);
|
||||
|
||||
virtual ~Backref();
|
||||
|
||||
VALUE get();
|
||||
VALUE set(VALUE value);
|
||||
|
||||
v8::Handle<v8::External> toExternal();
|
||||
|
||||
static void release(const v8::WeakCallbackData<v8::External, Backref>& data);
|
||||
private:
|
||||
VALUE storage;
|
||||
static VALUE Storage;
|
||||
static ID _new;
|
||||
static ID object;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
19
ext/v8/bool.h
Normal file
19
ext/v8/bool.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef RR_BOOL
|
||||
#define RR_BOOL
|
||||
|
||||
namespace rr {
|
||||
|
||||
class Bool : public Equiv {
|
||||
public:
|
||||
Bool(VALUE val) : Equiv(val) {}
|
||||
Bool(bool b) : Equiv(b ? Qtrue : Qfalse) {}
|
||||
Bool(v8::Handle<v8::Boolean> b) : Equiv(b->Value() ? Qtrue : Qfalse) {}
|
||||
|
||||
inline operator bool() {
|
||||
return RTEST(value);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
64
ext/v8/context.cc
Normal file
64
ext/v8/context.cc
Normal file
|
@ -0,0 +1,64 @@
|
|||
#include "rr.h"
|
||||
|
||||
namespace rr {
|
||||
|
||||
void Context::Init() {
|
||||
ClassBuilder("Context").
|
||||
defineSingletonMethod("New", &New).
|
||||
|
||||
defineMethod("Dispose", &Dispose).
|
||||
defineMethod("Enter", &Enter).
|
||||
defineMethod("Exit", &Exit).
|
||||
|
||||
store(&Class);
|
||||
|
||||
// TODO
|
||||
// ClassBuilder("ExtensionConfiguration").
|
||||
// defineSingletonMethod("new", &ExtensionConfiguration::initialize).
|
||||
// store(&ExtensionConfiguration::Class);
|
||||
}
|
||||
|
||||
VALUE Context::New(int argc, VALUE argv[], VALUE self) {
|
||||
VALUE isolate, extension_configuration, global_template, global_object;
|
||||
rb_scan_args(argc, argv, "13", &isolate, &extension_configuration, &global_template, &global_object);
|
||||
|
||||
// TODO: Is this needed?
|
||||
// v8::Persistent<v8::Context> context(
|
||||
return Context(v8::Context::New(
|
||||
Isolate(isolate)
|
||||
// TODO
|
||||
// ,
|
||||
// ExtensionConfiguration(extension_configuration),
|
||||
// *ObjectTemplate(global_template),
|
||||
// *Object(global_object)
|
||||
));
|
||||
//);
|
||||
|
||||
// TODO: Is this needed?
|
||||
// Context reference(context);
|
||||
// context.Reset();
|
||||
//
|
||||
// return reference;
|
||||
}
|
||||
|
||||
VALUE Context::Dispose(VALUE self) {
|
||||
Context(self).dispose();
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE Context::Enter(VALUE self) {
|
||||
Context(self)->Enter();
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE Context::Exit(VALUE self) {
|
||||
Context(self)->Exit();
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// template <> void Pointer<v8::ExtensionConfiguration>::unwrap(VALUE value) {
|
||||
// Data_Get_Struct(value, class v8::ExtensionConfiguration, pointer);
|
||||
// }
|
||||
|
||||
}
|
39
ext/v8/context.h
Normal file
39
ext/v8/context.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef RR_CONTEXT
|
||||
#define RR_CONTEXT
|
||||
|
||||
namespace rr {
|
||||
|
||||
class Context : public Ref<v8::Context> {
|
||||
public:
|
||||
static void Init();
|
||||
|
||||
static VALUE New(int argc, VALUE argv[], VALUE self);
|
||||
static VALUE Dispose(VALUE self);
|
||||
|
||||
static VALUE Enter(VALUE self);
|
||||
static VALUE Exit(VALUE self);
|
||||
|
||||
// TODO
|
||||
// static VALUE Global(VALUE self);
|
||||
// static VALUE DetachGlobal(VALUE self);
|
||||
// static VALUE ReattachGlobal(VALUE self, VALUE global);
|
||||
// static VALUE GetEntered(VALUE self);
|
||||
// static VALUE GetCurrent(VALUE self);
|
||||
// static VALUE GetCalling(VALUE self);
|
||||
// static VALUE SetSecurityToken(VALUE self, VALUE token);
|
||||
// static VALUE UseDefaultSecurityToken(VALUE self);
|
||||
// static VALUE GetSecurityToken(VALUE self);
|
||||
// static VALUE HasOutOfMemoryException(VALUE self);
|
||||
// static VALUE InContext(VALUE self);
|
||||
// static VALUE SetEmbedderData(VALUE self, VALUE index, VALUE data);
|
||||
// static VALUE GetEmbedderData(VALUE self, VALUE index);
|
||||
// static VALUE AllowCodeGenerationFromStrings(VALUE self, VALUE allow);
|
||||
// static VALUE IsCodeGenerationFromStringsAllowed(VALUE self);
|
||||
|
||||
inline Context(VALUE value) : Ref<v8::Context>(value) {}
|
||||
inline Context(v8::Handle<v8::Context> cxt) : Ref<v8::Context>(cxt) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
17
ext/v8/equiv.h
Normal file
17
ext/v8/equiv.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef RR_EQUIV
|
||||
#define RR_EQUIV
|
||||
|
||||
namespace rr {
|
||||
|
||||
class Equiv {
|
||||
public:
|
||||
Equiv(VALUE val) : value(val) {}
|
||||
inline operator VALUE() { return value; }
|
||||
|
||||
protected:
|
||||
VALUE value;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -11,13 +11,15 @@ extern "C" {
|
|||
V8::Init();
|
||||
Isolate::Init();
|
||||
Handles::Init();
|
||||
Context::Init();
|
||||
Backref::Init();
|
||||
Value::Init();
|
||||
Object::Init();
|
||||
// v8::Locker lock();
|
||||
// GC::Init();
|
||||
// Accessor::Init();
|
||||
// Context::Init();
|
||||
// Invocation::Init();
|
||||
// Signature::Init();
|
||||
// Value::Init();
|
||||
// Primitive::Init();
|
||||
// String::Init();
|
||||
// Object::Init();
|
||||
|
@ -35,6 +37,5 @@ extern "C" {
|
|||
// Locker::Init();
|
||||
// ResourceConstraints::Init();
|
||||
// HeapStatistics::Init();
|
||||
// Backref::Init();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,11 @@ namespace rr {
|
|||
void Isolate::Init() {
|
||||
ClassBuilder("Isolate").
|
||||
defineSingletonMethod("New", &New).
|
||||
defineSingletonMethod("GetCurrent", &GetCurrent).
|
||||
|
||||
defineMethod("Enter", &Enter).
|
||||
defineMethod("Exit", &Exit).
|
||||
|
||||
store(&Class);
|
||||
}
|
||||
|
||||
|
@ -12,6 +17,26 @@ namespace rr {
|
|||
return Isolate(v8::Isolate::New());
|
||||
}
|
||||
|
||||
VALUE Isolate::Enter(VALUE self) {
|
||||
Isolate(self)->Enter();
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
VALUE Isolate::Exit(VALUE self) {
|
||||
Isolate(self)->Exit();
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
VALUE Isolate::GetCurrent(VALUE self) {
|
||||
v8::Isolate* currentIsolate = v8::Isolate::GetCurrent();
|
||||
|
||||
if (!currentIsolate) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
return Isolate(currentIsolate);
|
||||
}
|
||||
|
||||
template <>
|
||||
void Pointer<v8::Isolate>::unwrap(VALUE value) {
|
||||
Data_Get_Struct(value, class v8::Isolate, pointer);
|
||||
|
|
|
@ -7,6 +7,9 @@ namespace rr {
|
|||
public:
|
||||
static void Init();
|
||||
static VALUE New(VALUE self);
|
||||
static VALUE Enter(VALUE self);
|
||||
static VALUE Exit(VALUE self);
|
||||
static VALUE GetCurrent(VALUE self);
|
||||
|
||||
inline Isolate(v8::Isolate* isolate) : Pointer<v8::Isolate>(isolate) {}
|
||||
inline Isolate(VALUE value) : Pointer<v8::Isolate>(value) {}
|
||||
|
@ -22,7 +25,7 @@ namespace rr {
|
|||
// TODO: Do we want to dispose of the isolate when the object itself
|
||||
// is garbage-collected?
|
||||
// Can the isolate be used without it having a reference in ruby world?
|
||||
isolate->Dispose();
|
||||
// isolate->Dispose();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
99
ext/v8/object.cc
Normal file
99
ext/v8/object.cc
Normal file
|
@ -0,0 +1,99 @@
|
|||
#include "rr.h"
|
||||
|
||||
namespace rr {
|
||||
|
||||
void Object::Init() {
|
||||
ClassBuilder("Object", Value::Class).
|
||||
defineSingletonMethod("New", &New).
|
||||
|
||||
defineMethod("Set", &Set).
|
||||
defineMethod("Get", &Get).
|
||||
|
||||
store(&Class);
|
||||
}
|
||||
|
||||
VALUE Object::New(VALUE self) {
|
||||
return Object(v8::Object::New(v8::Isolate::GetCurrent()));
|
||||
}
|
||||
|
||||
// TODO: Allow setting of property attributes
|
||||
VALUE Object::Set(VALUE self, VALUE key, VALUE value) {
|
||||
if (rb_obj_is_kind_of(key, rb_cNumeric)) {
|
||||
return Bool(Object(self)->Set(UInt32(key), Value(value)));
|
||||
} else {
|
||||
return Bool(Object(self)->Set(*Value(key), Value(value)));
|
||||
}
|
||||
}
|
||||
|
||||
VALUE Object::Get(VALUE self, VALUE key) {
|
||||
if (rb_obj_is_kind_of(key, rb_cNumeric)) {
|
||||
return Value(Object(self)->Get(UInt32(key)));
|
||||
} else {
|
||||
return Value(Object(self)->Get(*Value(key)));
|
||||
}
|
||||
}
|
||||
|
||||
Object::operator VALUE() {
|
||||
if (handle.IsEmpty()) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
Backref* backref;
|
||||
|
||||
v8::Local<v8::String> key(v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), "rr::Backref"));
|
||||
v8::Local<v8::Value> external = handle->GetHiddenValue(key);
|
||||
|
||||
VALUE value;
|
||||
|
||||
if (external.IsEmpty()) {
|
||||
value = downcast();
|
||||
backref = new Backref(value);
|
||||
|
||||
handle->SetHiddenValue(key, backref->toExternal());
|
||||
} else {
|
||||
v8::External* wrapper = v8::External::Cast(*external);
|
||||
backref = (Backref*)wrapper->Value();
|
||||
value = backref->get();
|
||||
|
||||
if (!RTEST(value)) {
|
||||
value = downcast();
|
||||
backref->set(value);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
VALUE Object::downcast() {
|
||||
// TODO: Enable this when the methods are implemented
|
||||
// if (handle->IsFunction()) {
|
||||
// return Function((v8::Handle<v8::Function>) v8::Function::Cast(*handle));
|
||||
// }
|
||||
//
|
||||
// if (handle->IsArray()) {
|
||||
// return Array((v8::Handle<v8::Array>)v8::Array::Cast(*handle));
|
||||
// }
|
||||
//
|
||||
// if (handle->IsDate()) {
|
||||
// // return Date(handle);
|
||||
// }
|
||||
//
|
||||
// if (handle->IsBooleanObject()) {
|
||||
// // return BooleanObject(handle);
|
||||
// }
|
||||
//
|
||||
// if (handle->IsNumberObject()) {
|
||||
// // return NumberObject(handle);
|
||||
// }
|
||||
//
|
||||
// if (handle->IsStringObject()) {
|
||||
// // return StringObject(handle);
|
||||
// }
|
||||
//
|
||||
// if (handle->IsRegExp()) {
|
||||
// // return RegExp(handle);
|
||||
// }
|
||||
|
||||
return Ref<v8::Object>::operator VALUE();
|
||||
}
|
||||
}
|
68
ext/v8/object.h
Normal file
68
ext/v8/object.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
#ifndef RR_OBJECT
|
||||
#define RR_OBJECT
|
||||
|
||||
namespace rr {
|
||||
|
||||
class Object : public Ref<v8::Object> {
|
||||
public:
|
||||
static void Init();
|
||||
static VALUE New(VALUE self);
|
||||
static VALUE Set(VALUE self, VALUE key, VALUE value);
|
||||
// static VALUE ForceSet(VALUE self, VALUE key, VALUE value);
|
||||
static VALUE Get(VALUE self, VALUE key);
|
||||
// static VALUE GetPropertyAttributes(VALUE self, VALUE key);
|
||||
// static VALUE Has(VALUE self, VALUE key);
|
||||
// static VALUE Delete(VALUE self, VALUE key);
|
||||
// static VALUE ForceDelete(VALUE self, VALUE key);
|
||||
// static VALUE SetAccessor(int argc, VALUE* argv, VALUE self);
|
||||
// static VALUE GetPropertyNames(VALUE self);
|
||||
// static VALUE GetOwnPropertyNames(VALUE self);
|
||||
// static VALUE GetPrototype(VALUE self);
|
||||
// static VALUE SetPrototype(VALUE self, VALUE prototype);
|
||||
// static VALUE FindInstanceInPrototypeChain(VALUE self, VALUE impl);
|
||||
// static VALUE ObjectProtoToString(VALUE self);
|
||||
// static VALUE GetConstructorName(VALUE self);
|
||||
// static VALUE InternalFieldCount(VALUE self);
|
||||
// static VALUE GetInternalField(VALUE self, VALUE idx);
|
||||
// static VALUE SetInternalField(VALUE self, VALUE idx, VALUE value);
|
||||
// static VALUE HasOwnProperty(VALUE self, VALUE key);
|
||||
// static VALUE HasRealNamedProperty(VALUE self, VALUE key);
|
||||
// static VALUE HasRealIndexedProperty(VALUE self, VALUE idx);
|
||||
// static VALUE HasRealNamedCallbackProperty(VALUE self, VALUE key);
|
||||
// static VALUE GetRealNamedPropertyInPrototypeChain(VALUE self, VALUE key);
|
||||
// static VALUE GetRealNamedProperty(VALUE self, VALUE key);
|
||||
// static VALUE HasNamedLookupInterceptor(VALUE self);
|
||||
// static VALUE HasIndexedLookupInterceptor(VALUE self);
|
||||
// static VALUE TurnOnAccessCheck(VALUE self);
|
||||
// static VALUE GetIdentityHash(VALUE self);
|
||||
// static VALUE SetHiddenValue(VALUE self, VALUE key, VALUE value);
|
||||
// static VALUE GetHiddenValue(VALUE self, VALUE key);
|
||||
// static VALUE DeleteHiddenValue(VALUE self, VALUE key);
|
||||
// static VALUE IsDirty(VALUE self);
|
||||
// static VALUE Clone(VALUE self);
|
||||
// static VALUE CreationContext(VALUE self);
|
||||
// static VALUE SetIndexedPropertiesToPixelData(VALUE self, VALUE data, VALUE length);
|
||||
// static VALUE GetIndexedPropertiesPixelData(VALUE self);
|
||||
// static VALUE HasIndexedPropertiesInPixelData(VALUE self);
|
||||
// static VALUE GetIndexedPropertiesPixelDataLength(VALUE self);
|
||||
// static VALUE SetIndexedPropertiesToExternalArrayData(VALUE self);
|
||||
// static VALUE HasIndexedPropertiesInExternalArrayData(VALUE self);
|
||||
// static VALUE GetIndexedPropertiesExternalArrayData(VALUE self);
|
||||
// static VALUE GetIndexedPropertiesExternalArrayDataType(VALUE self);
|
||||
// static VALUE GetIndexedPropertiesExternalArrayDataLength(VALUE self);
|
||||
// static VALUE IsCallable(VALUE self);
|
||||
// static VALUE CallAsFunction(VALUE self, VALUE recv, VALUE argv);
|
||||
// static VALUE CallAsConstructor(VALUE self, VALUE argv);
|
||||
|
||||
inline Object(VALUE value) : Ref<v8::Object>(value) {}
|
||||
inline Object(v8::Handle<v8::Object> object) : Ref<v8::Object>(object) {}
|
||||
|
||||
virtual operator VALUE();
|
||||
|
||||
protected:
|
||||
VALUE downcast();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
124
ext/v8/ref.h
Normal file
124
ext/v8/ref.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
#ifndef RR_REF
|
||||
#define RR_REF
|
||||
|
||||
namespace rr {
|
||||
/**
|
||||
* A Reference to a V8 managed object
|
||||
*
|
||||
* Uses type coercion to quickly convert from a v8 handle
|
||||
* to a ruby object and back again. Suppose we have a v8 handle
|
||||
* that we want to return to Ruby. We can put it into a Ref:
|
||||
*
|
||||
* v8::Handle<v8::Object> object = v8::Object::New();
|
||||
* VALUE val = Ref<v8::Object>(object);
|
||||
*
|
||||
* this will create a `v8::Persistent` handle for the object
|
||||
* so that it will not be garbage collected by v8. It then
|
||||
* stuffs this new persistent handle into a Data_Wrap_Struct
|
||||
* which can then be passed to Ruby code. When this struct
|
||||
* is garbage collected by Ruby, it enqueues the corresponding
|
||||
* v8 handle to be released during v8 gc.
|
||||
*
|
||||
* By the same token, you can use Refs to unwrap a Data_Wrap_Struct
|
||||
* which has been generated in this fashion and call through to
|
||||
* the underlying v8 methods. Suppose we are passed a VALUE `val`
|
||||
* wrapping a v8::Object:
|
||||
*
|
||||
* Ref<v8::Object> object(val);
|
||||
* object->Get(v8::String::New("foo"));
|
||||
*
|
||||
*/
|
||||
template <class T>
|
||||
class Ref {
|
||||
public:
|
||||
Ref(VALUE value) {
|
||||
this->value = value;
|
||||
}
|
||||
|
||||
Ref(v8::Local<T> handle) {
|
||||
this->handle = handle;
|
||||
}
|
||||
|
||||
virtual ~Ref() {}
|
||||
|
||||
/*
|
||||
* Coerce a Ref into a Ruby VALUE
|
||||
*/
|
||||
virtual operator VALUE() const {
|
||||
if (handle.IsEmpty()) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
return Data_Wrap_Struct(Class, 0, &Holder::enqueue, new Holder(handle));
|
||||
}
|
||||
|
||||
/*
|
||||
* Coerce a Ref into a v8::Local.
|
||||
*/
|
||||
virtual operator v8::Handle<T>() const {
|
||||
if (RTEST(this->value)) {
|
||||
Holder* holder = NULL;
|
||||
Data_Get_Struct(this->value, class Holder, holder);
|
||||
|
||||
return v8::Local<T>::New(v8::Isolate::GetCurrent(), *holder->handle);
|
||||
} else {
|
||||
return v8::Local<T>();
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
Holder* holder = NULL;
|
||||
Data_Get_Struct(this->value, class Holder, holder);
|
||||
holder->dispose();
|
||||
}
|
||||
|
||||
/*
|
||||
* Pointer de-reference operators, this lets you use a ref to
|
||||
* call through to underlying v8 methods. e.g
|
||||
*
|
||||
* Ref<v8::Object>(value)->ToString();
|
||||
*/
|
||||
inline v8::Handle<T> operator->() const { return *this; }
|
||||
inline v8::Handle<T> operator*() const { return *this; }
|
||||
|
||||
class Holder {
|
||||
friend class Ref;
|
||||
public:
|
||||
Holder(v8::Handle<T> handle) {
|
||||
this->disposed_p = false;
|
||||
this->handle = new v8::Persistent<T>(v8::Isolate::GetCurrent(), handle);
|
||||
}
|
||||
|
||||
virtual ~Holder() {
|
||||
this->dispose();
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
if (!this->disposed_p) {
|
||||
handle->Reset();
|
||||
delete handle;
|
||||
this->disposed_p = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
v8::Persistent<T>* handle;
|
||||
bool disposed_p;
|
||||
|
||||
static void enqueue(Holder* holder) {
|
||||
// TODO
|
||||
// GC::Finalize(holder);
|
||||
}
|
||||
};
|
||||
|
||||
VALUE value;
|
||||
v8::Handle<T> handle;
|
||||
static VALUE Class;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
VALUE Ref<T>::Class;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
11
ext/v8/rr.h
11
ext/v8/rr.h
|
@ -12,10 +12,19 @@
|
|||
|
||||
#include "class_builder.h"
|
||||
#include "pointer.h"
|
||||
#include "ref.h"
|
||||
|
||||
#include "v8.h"
|
||||
#include "isolate.h"
|
||||
#include "handles.h"
|
||||
#include "context.h"
|
||||
|
||||
#include "equiv.h"
|
||||
#include "bool.h"
|
||||
#include "uint32.h"
|
||||
#include "value.h"
|
||||
#include "backref.h"
|
||||
|
||||
#include "object.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
|
18
ext/v8/uint32.h
Normal file
18
ext/v8/uint32.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef RR_UINT32
|
||||
#define RR_UINT32
|
||||
|
||||
namespace rr {
|
||||
|
||||
class UInt32 : public Equiv {
|
||||
public:
|
||||
UInt32(VALUE val) : Equiv(val) {}
|
||||
UInt32(uint32_t ui) : Equiv(UINT2NUM(ui)) {}
|
||||
|
||||
inline operator uint32_t() {
|
||||
return RTEST(value) ? NUM2UINT(value) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
172
ext/v8/value.cc
Normal file
172
ext/v8/value.cc
Normal file
|
@ -0,0 +1,172 @@
|
|||
#include "rr.h"
|
||||
|
||||
namespace rr {
|
||||
|
||||
VALUE Value::Empty;
|
||||
|
||||
void Value::Init() {
|
||||
Empty = rb_eval_string("Object.new");
|
||||
|
||||
ClassBuilder("Value").
|
||||
defineConst("Empty", Empty).
|
||||
|
||||
defineMethod("IsUndefined", &IsUndefined).
|
||||
defineMethod("IsNull", &IsNull).
|
||||
defineMethod("IsTrue", &IsTrue).
|
||||
defineMethod("IsFalse", &IsFalse).
|
||||
// defineMethod("IsString", &IsString).
|
||||
// defineMethod("IsFunction", &IsFunction).
|
||||
// defineMethod("IsArray", &IsArray).
|
||||
defineMethod("IsObject", &IsObject).
|
||||
// defineMethod("IsBoolean", &IsBoolean).
|
||||
// defineMethod("IsNumber", &IsNumber).
|
||||
// defineMethod("IsExternal", &IsExternal).
|
||||
// defineMethod("IsInt32", &IsInt32).
|
||||
// defineMethod("IsUint32", &IsUint32).
|
||||
// defineMethod("IsDate", &IsDate).
|
||||
// defineMethod("IsBooleanObject", &IsBooleanObject).
|
||||
// defineMethod("IsNumberObject", &IsNumberObject).
|
||||
// defineMethod("IsStringObject", &IsStringObject).
|
||||
// defineMethod("IsNativeError", &IsNativeError).
|
||||
// defineMethod("IsRegExp", &IsRegExp).
|
||||
// defineMethod("ToString", &ToString).
|
||||
// defineMethod("ToDetailString", &ToDetailString).
|
||||
// defineMethod("ToObject", &ToObject).
|
||||
// defineMethod("BooleanValue", &BooleanValue).
|
||||
// defineMethod("NumberValue", &NumberValue).
|
||||
// defineMethod("IntegerValue", &IntegerValue).
|
||||
// defineMethod("Uint32Value", &Uint32Value).
|
||||
// defineMethod("IntegerValue", &IntegerValue).
|
||||
// defineMethod("Equals", &Equals).
|
||||
// defineMethod("StrictEquals", &StrictEquals).
|
||||
|
||||
store(&Class);
|
||||
|
||||
rb_gc_register_address(&Empty);
|
||||
}
|
||||
|
||||
VALUE Value::IsUndefined(VALUE self) {
|
||||
return Bool(Value(self)->IsUndefined());
|
||||
}
|
||||
|
||||
VALUE Value::IsNull(VALUE self) {
|
||||
return Bool(Value(self)->IsNull());
|
||||
}
|
||||
|
||||
VALUE Value::IsTrue(VALUE self) {
|
||||
return Bool(Value(self)->IsTrue());
|
||||
}
|
||||
|
||||
VALUE Value::IsFalse(VALUE self) {
|
||||
return Bool(Value(self)->IsFalse());
|
||||
}
|
||||
|
||||
VALUE Value::IsObject(VALUE self) {
|
||||
return Bool(Value(self)->IsObject());
|
||||
}
|
||||
|
||||
VALUE Value::Equals(VALUE self, VALUE other) {
|
||||
return Bool(Value(self)->Equals(Value(other)));
|
||||
}
|
||||
|
||||
VALUE Value::StrictEquals(VALUE self, VALUE other) {
|
||||
return Bool(Value(self)->StrictEquals(Value(other)));
|
||||
}
|
||||
|
||||
Value::operator VALUE() {
|
||||
if (handle.IsEmpty() || handle->IsUndefined() || handle->IsNull()) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
if (handle->IsTrue()) {
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
if (handle->IsFalse()) {
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// if (handle->IsExternal()) {
|
||||
// return External((v8::Handle<v8::External>)v8::External::Cast(*handle));
|
||||
// }
|
||||
|
||||
// TODO
|
||||
// if (handle->IsUint32()) {
|
||||
// return UInt32(handle->Uint32Value());
|
||||
// }
|
||||
//
|
||||
// if (handle->IsInt32()) {
|
||||
// return INT2FIX(handle->Int32Value());
|
||||
// }
|
||||
|
||||
if (handle->IsBoolean()) {
|
||||
return handle->BooleanValue() ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// if (handle->IsNumber()) {
|
||||
// return rb_float_new(handle->NumberValue());
|
||||
// }
|
||||
|
||||
// TODO
|
||||
// if (handle->IsString()) {
|
||||
// return String(handle->ToString());
|
||||
// }
|
||||
//
|
||||
// if (handle->IsDate()) {
|
||||
// return Date((v8::Handle<v8::Date>)v8::Date::Cast(*handle));
|
||||
// }
|
||||
|
||||
if (handle->IsObject()) {
|
||||
return Object(handle->ToObject());
|
||||
}
|
||||
|
||||
return Ref<v8::Value>::operator VALUE();
|
||||
}
|
||||
|
||||
Value::operator v8::Handle<v8::Value>() const {
|
||||
if (rb_equal(value, Empty)) {
|
||||
return v8::Handle<v8::Value>();
|
||||
}
|
||||
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
|
||||
switch (TYPE(value)) {
|
||||
case T_FIXNUM:
|
||||
return v8::Integer::New(isolate, NUM2INT(value));
|
||||
case T_FLOAT:
|
||||
return v8::Number::New(isolate, NUM2DBL(value));
|
||||
case T_STRING:
|
||||
return v8::String::NewFromUtf8(isolate, RSTRING_PTR(value), v8::String::kNormalString, (int)RSTRING_LEN(value));
|
||||
case T_NIL:
|
||||
return v8::Null(isolate);
|
||||
case T_TRUE:
|
||||
return v8::True(isolate);
|
||||
case T_FALSE:
|
||||
return v8::False(isolate);
|
||||
case T_DATA:
|
||||
return Ref<v8::Value>::operator v8::Handle<v8::Value>();
|
||||
case T_OBJECT:
|
||||
case T_CLASS:
|
||||
case T_ICLASS:
|
||||
case T_MODULE:
|
||||
case T_REGEXP:
|
||||
case T_MATCH:
|
||||
case T_ARRAY:
|
||||
case T_HASH:
|
||||
case T_STRUCT:
|
||||
case T_BIGNUM:
|
||||
case T_FILE:
|
||||
case T_SYMBOL:
|
||||
case T_UNDEF:
|
||||
case T_NODE:
|
||||
default:
|
||||
rb_warn("unknown conversion to V8 for: %s", RSTRING_PTR(rb_inspect(value)));
|
||||
return v8::String::NewFromUtf8(isolate, "Undefined Conversion");
|
||||
}
|
||||
|
||||
return v8::Undefined(isolate);
|
||||
}
|
||||
|
||||
}
|
51
ext/v8/value.h
Normal file
51
ext/v8/value.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
#ifndef RR_VALUE
|
||||
#define RR_VALUE
|
||||
|
||||
namespace rr {
|
||||
|
||||
class Value : public Ref<v8::Value> {
|
||||
public:
|
||||
static void Init();
|
||||
static VALUE IsUndefined(VALUE self);
|
||||
static VALUE IsNull(VALUE self);
|
||||
static VALUE IsTrue(VALUE self);
|
||||
static VALUE IsFalse(VALUE self);
|
||||
// static VALUE IsString(VALUE self);
|
||||
// static VALUE IsFunction(VALUE self);
|
||||
// static VALUE IsArray(VALUE self);
|
||||
static VALUE IsObject(VALUE self);
|
||||
static VALUE IsBoolean(VALUE self);
|
||||
// static VALUE IsNumber(VALUE self);
|
||||
// static VALUE IsExternal(VALUE self);
|
||||
// static VALUE IsInt32(VALUE self);
|
||||
// static VALUE IsUint32(VALUE self);
|
||||
// static VALUE IsDate(VALUE self);
|
||||
// static VALUE IsBooleanObject(VALUE self);
|
||||
// static VALUE IsNumberObject(VALUE self);
|
||||
// static VALUE IsStringObject(VALUE self);
|
||||
// static VALUE IsNativeError(VALUE self);
|
||||
// static VALUE IsRegExp(VALUE self);
|
||||
// static VALUE ToString(VALUE self);
|
||||
// static VALUE ToDetailString(VALUE self);
|
||||
// static VALUE ToObject(VALUE self);
|
||||
// static VALUE BooleanValue(VALUE self);
|
||||
// static VALUE NumberValue(VALUE self);
|
||||
// static VALUE IntegerValue(VALUE self);
|
||||
// static VALUE Uint32Value(VALUE self);
|
||||
// static VALUE Int32Value(VALUE self);
|
||||
|
||||
static VALUE Equals(VALUE self, VALUE other);
|
||||
static VALUE StrictEquals(VALUE self, VALUE other);
|
||||
|
||||
inline Value(VALUE value) : Ref<v8::Value>(value) {}
|
||||
inline Value(v8::Handle<v8::Value> value) : Ref<v8::Value>(value) {}
|
||||
|
||||
virtual operator VALUE();
|
||||
virtual operator v8::Handle<v8::Value>() const;
|
||||
|
||||
static VALUE Empty;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
require 'v8/init'
|
||||
require 'c_spec_helper'
|
||||
|
||||
describe 'handles' do
|
||||
describe '#HandleScope' do
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'v8/init'
|
||||
require 'c_spec_helper'
|
||||
|
||||
describe V8::C::Isolate do
|
||||
it 'can create a new isolate' do
|
||||
|
|
9
spec/c/object_spec.rb
Normal file
9
spec/c/object_spec.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
require 'c_spec_helper'
|
||||
|
||||
describe V8::C::Object do
|
||||
requires_v8_context
|
||||
|
||||
it 'can create a new object' do
|
||||
expect(V8::C::Object.New).to be
|
||||
end
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
require 'v8/init'
|
||||
require 'c_spec_helper'
|
||||
|
||||
describe V8::C::V8 do
|
||||
it 'can say its version' do
|
||||
|
|
39
spec/c_spec_helper.rb
Normal file
39
spec/c_spec_helper.rb
Normal file
|
@ -0,0 +1,39 @@
|
|||
require 'v8/weak'
|
||||
require 'v8/init'
|
||||
|
||||
module V8ContextHelpers
|
||||
module GroupMethods
|
||||
def requires_v8_context
|
||||
around(:each) do |example|
|
||||
bootstrap_v8_context(&example)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def bootstrap_v8_context
|
||||
isolate = V8::C::Isolate.New
|
||||
|
||||
begin
|
||||
isolate.Enter
|
||||
|
||||
# V8::C::Locker() do
|
||||
V8::C::HandleScope(isolate) do
|
||||
@cxt = V8::C::Context::New(isolate)
|
||||
begin
|
||||
@cxt.Enter
|
||||
yield
|
||||
ensure
|
||||
@cxt.Exit
|
||||
end
|
||||
end
|
||||
# end
|
||||
ensure
|
||||
isolate.Exit
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.configure do |c|
|
||||
c.include V8ContextHelpers
|
||||
c.extend V8ContextHelpers::GroupMethods
|
||||
end
|
Loading…
Add table
Reference in a new issue