diff options
Diffstat (limited to 'src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp')
-rw-r--r-- | src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp | 797 |
1 files changed, 395 insertions, 402 deletions
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index 85ae0cd..8b2bb04 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -23,74 +23,50 @@ */ #include "uscxml/Common.h" -#include "uscxml/config.h" -#include "V8DataModel.h" -#include "V8DOM.h" -#include "dom/V8Document.h" -#include "dom/V8Node.h" -#include "dom/V8Element.h" -#include "dom/V8Text.h" -#include "dom/V8CDATASection.h" -#include "dom/V8SCXMLEvent.h" - -#include "dom/V8ArrayBuffer.h" -#include "dom/V8Int8Array.h" -#include "dom/V8Uint8Array.h" -#include "dom/V8Uint8ClampedArray.h" -#include "dom/V8Int16Array.h" -#include "dom/V8Uint16Array.h" -#include "dom/V8Int32Array.h" -#include "dom/V8Uint32Array.h" -#include "dom/V8Float32Array.h" -#include "dom/V8Float64Array.h" -#include "dom/V8DataView.h" - -#include "uscxml/Message.h" -#include "uscxml/dom/DOMUtils.h" -#include <glog/logging.h> - -#ifdef BUILD_AS_PLUGINS -#include <Pluma/Connector.hpp> -#endif +#include "uscxml/util/URL.h" +#include "uscxml/util/String.h" -#define TO_V8_DOMVALUE(type) \ -v8::Handle<v8::Function> retCtor = V8##type::getTmpl()->GetFunction();\ -v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance());\ -struct V8##type::V8##type##Private* retPrivData = new V8##type::V8##type##Private();\ -retPrivData->dom = _dom;\ -retPrivData->nativeObj = new type<std::string>(node);\ -retObj->SetInternalField(0, V8DOM::toExternal(retPrivData));\ -retObj.MakeWeak(0, V8##type::jsDestructor);\ -return retObj; +#include "V8DataModel.h" +//#include "V8SCXMLEvent.h" +#include "uscxml/messages/Event.h" +#include "uscxml/util/DOM.h" +#include <easylogging++.h> -namespace uscxml { +using namespace xercesc; -using namespace Arabica::XPath; -using namespace Arabica::DOM; +static v8::Local<v8::Value> XMLString2JS(const XMLCh* input) { + char* res = xercesc::XMLString::transcode(input); + v8::Local<v8::Value> handle = v8::String::New(res); + return handle; +} -#ifdef BUILD_AS_PLUGINS -PLUMA_CONNECTOR -bool pluginConnect(pluma::Host& host) { - host.add( new V8DataModelProvider() ); - return true; +static XMLCh* JS2XMLString(const v8::Local<v8::Value>& value) { + v8::String::AsciiValue s(value); + XMLCh* ret = xercesc::XMLString::transcode(*s); + return(ret); } -#endif -V8DataModel::V8DataModel() : _ioProcessorsAreSet(false), _invokersAreSet(false) { +// javascript magic here + +#define SWIG_V8_VERSION 0x034000 +#include "V8DOM.cpp.inc" + +namespace uscxml { + +V8DataModel::V8DataModel() { // _contexts.push_back(v8::Context::New()); } V8DataModel::~V8DataModel() { - while(_contexts.size() > 0) { - _contexts.back().Dispose(); - _contexts.pop_back(); - } - if (_dom) - delete _dom; + _context.Dispose(); +// if (_isolate != NULL) { +// _isolate->Dispose(); +// } } void V8DataModel::addExtension(DataModelExtension* ext) { +#if 0 if (_extensions.find(ext) != _extensions.end()) return; @@ -100,7 +76,7 @@ void V8DataModel::addExtension(DataModelExtension* ext) { v8::Locker locker; v8::HandleScope scope; v8::Context::Scope contextScope(_contexts.front()); - v8::Handle<v8::Object> currScope = _contexts.front()->Global(); + v8::Local<v8::Object> currScope = _contexts.front()->Global(); std::list<std::string> locPath = tokenize(ext->provides(), '.'); std::list<std::string>::iterator locIter = locPath.begin(); @@ -126,9 +102,11 @@ void V8DataModel::addExtension(DataModelExtension* ext) { break; } } +#endif } -v8::Handle<v8::Value> V8DataModel::jsExtension(const v8::Arguments& args) { +void V8DataModel::jsExtension(const v8::FunctionCallbackInfo<v8::Value>& info) { +#if 0 DataModelExtension* extension = static_cast<DataModelExtension*>(v8::External::Unwrap(args.Data())); v8::Local<v8::String> memberJS; @@ -151,33 +129,101 @@ v8::Handle<v8::Value> V8DataModel::jsExtension(const v8::Arguments& args) { return ((V8DataModel*)(extension->dm))->getDataAsValue(extension->getValueOf(memberName)); } return v8::Undefined(); +#endif } -boost::shared_ptr<DataModelImpl> V8DataModel::create(InterpreterInfo* interpreter) { - boost::shared_ptr<V8DataModel> dm = boost::shared_ptr<V8DataModel>(new V8DataModel()); - dm->_interpreter = interpreter; - v8::Locker locker; - v8::HandleScope scope; +std::mutex V8DataModel::_initMutex; + +v8::Isolate* V8DataModel::_isolate = NULL; + +void V8NodeListIndexedPropertyHandler(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) { + xercesc::DOMNodeList* list; + SWIG_V8_GetInstancePtr(info.Holder(), (void**)&list); + + if (list->getLength() >= index) { + xercesc::DOMNode* node = list->item(index); + + v8::Handle<v8::Value> val = SWIG_NewPointerObj(SWIG_as_voidptr(node), SWIG_TypeDynamicCast(SWIGTYPE_p_XERCES_CPP_NAMESPACE__DOMNode, SWIG_as_voidptrptr(&node)), 0 | 0 ); + info.GetReturnValue().Set(val); + return; + } + info.GetReturnValue().Set(v8::Undefined()); - dm->_dom = new V8DOM(); -// dom->interpreter = interpreter; - dm->_dom->xpath = new XPath<std::string>(); - dm->_dom->xpath->setNamespaceContext(*interpreter->getNameSpaceInfo().getNSContext()); - dm->_dom->storage = new Storage(URL::getResourceDir() + PATH_SEPERATOR + interpreter->getName() + ".storage"); - dm->_dom->nsInfo = new NameSpaceInfo(interpreter->getNameSpaceInfo()); - // see http://stackoverflow.com/questions/3171418/v8-functiontemplate-class-instance +} + +std::shared_ptr<DataModelImpl> V8DataModel::create(DataModelCallbacks* callbacks) { + std::shared_ptr<V8DataModel> dm(new V8DataModel()); + dm->_callbacks = callbacks; + + // TODO: we cannot use one isolate per thread as swig's type will be unknown :( + // We could register them by hand and avoid the _export_ globals in swig? + if (dm->_isolate == NULL) { + dm->_isolate = v8::Isolate::New(); + } + + v8::Locker locker(dm->_isolate); + v8::Isolate::Scope isoScope(dm->_isolate); + + // Create a handle scope to hold the temporary references. + v8::HandleScope scope(dm->_isolate); + + // Create a template for the global object where we set the built-in global functions. + v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); // some free functions - v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); - global->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast<void*>(dm.get()))), v8::ReadOnly); - global->Set(v8::String::New("print"), v8::FunctionTemplate::New(jsPrint, v8::External::New(reinterpret_cast<void*>(dm.get()))), v8::ReadOnly); + global->Set(v8::String::NewSymbol("print"), + v8::FunctionTemplate::New(dm->_isolate, jsPrint,v8::External::New(reinterpret_cast<void*>(dm.get())))); + global->Set(v8::String::NewSymbol("In"), + v8::FunctionTemplate::New(dm->_isolate, jsIn, v8::External::New(reinterpret_cast<void*>(dm.get())))); + + v8::Local<v8::Context> context = v8::Context::New(dm->_isolate, NULL, global); + + dm->_context.Reset(dm->_isolate, context); - v8::Persistent<v8::Context> context = v8::Context::New(0, global); + // Enter the new context so all the following operations take place within it. v8::Context::Scope contextScope(context); + assert(dm->_isolate->GetCurrentContext() == context); + + // not thread safe! + { + std::lock_guard<std::mutex> lock(_initMutex); + SWIGV8_INIT(context->Global()); + + // register subscript operator with nodelist + v8::Handle<v8::FunctionTemplate> _exports_DOMNodeList_class = SWIGV8_CreateClassTemplate("_exports_DOMNodeList"); + + _exports_DOMNodeList_class->InstanceTemplate()->SetIndexedPropertyHandler(V8NodeListIndexedPropertyHandler); + SWIGV8_AddMemberFunction(_exports_DOMNodeList_class, "item", _wrap_DOMNodeList_item); + SWIGV8_AddMemberFunction(_exports_DOMNodeList_class, "getLength", _wrap_DOMNodeList_getLength); + + SWIGV8_SET_CLASS_TEMPL(_exports_DOMNodeList_clientData.class_templ, _exports_DOMNodeList_class); + + } + + context->Global()->SetAccessor(v8::String::NewSymbol("_sessionid"), + V8DataModel::getAttribute, + V8DataModel::setWithException, + v8::String::New(callbacks->getSessionId().c_str())); + context->Global()->SetAccessor(v8::String::NewSymbol("_name"), + V8DataModel::getAttribute, + V8DataModel::setWithException, + v8::String::New(callbacks->getName().c_str())); + context->Global()->SetAccessor(v8::String::NewSymbol("_ioprocessors"), + V8DataModel::getIOProcessors, + V8DataModel::setWithException, + v8::External::New(reinterpret_cast<void*>(dm.get()))); + context->Global()->SetAccessor(v8::String::NewSymbol("_invokers"), + V8DataModel::getInvokers, + V8DataModel::setWithException, + v8::External::New(reinterpret_cast<void*>(dm.get()))); + +// v8::Persistent<v8::Value, v8::CopyablePersistentTraits<v8::Value> > persistent(_isolate, context); + +#if 0 // instantiate the document function - v8::Handle<v8::Function> docCtor = V8Document::getTmpl()->GetFunction(); - v8::Handle<v8::Object> docObj = docCtor->NewInstance(); + v8::Local<v8::Function> docCtor = V8Document::getTmpl()->GetFunction(); + v8::Local<v8::Object> docObj = docCtor->NewInstance(); V8Document::V8DocumentPrivate* privData = new V8Document::V8DocumentPrivate(); privData->nativeObj = new Document<std::string>(interpreter->getDocument()); @@ -200,169 +246,209 @@ boost::shared_ptr<DataModelImpl> V8DataModel::create(InterpreterInfo* interprete context->Global()->Set(v8::String::New("DataView"), V8DataView::getConstructor()->GetFunction()); - context->Global()->SetAccessor(v8::String::New("_sessionid"), - V8DataModel::getAttribute, - V8DataModel::setWithException, - v8::String::New(interpreter->getSessionId().c_str())); - context->Global()->SetAccessor(v8::String::New("_name"), - V8DataModel::getAttribute, - V8DataModel::setWithException, - v8::String::New(interpreter->getName().c_str())); - context->Global()->SetAccessor(v8::String::New("_ioprocessors"), - V8DataModel::getIOProcessors, - V8DataModel::setWithException, - v8::External::New(reinterpret_cast<void*>(dm.get()))); - context->Global()->SetAccessor(v8::String::New("_invokers"), - V8DataModel::getInvokers, - V8DataModel::setWithException, - v8::External::New(reinterpret_cast<void*>(dm.get()))); - - dm->_contexts.push_back(context); // instantiate objects - we have to have a context for that! dm->eval(Element<std::string>(), "_x = {};"); +#endif return dm; } -v8::Handle<v8::Value> V8DataModel::getAttribute(v8::Local<v8::String> property, const v8::AccessorInfo& info) { - return info.Data(); +void V8DataModel::getAttribute(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) { + info.GetReturnValue().Set(info.Data()); } -void V8DataModel::setWithException(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info) { +void V8DataModel::setWithException(v8::Local<v8::String> property, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { v8::String::AsciiValue data(property); std::string msg = "Cannot set " + std::string(*data); v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(msg.c_str()))); } -v8::Handle<v8::Value> V8DataModel::getIOProcessors(v8::Local<v8::String> property, const v8::AccessorInfo& info) { - V8DataModel* dataModel = V8DOM::toClassPtr<V8DataModel>(info.Data()); +void V8DataModel::getIOProcessors(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Local<v8::External> field = v8::Local<v8::External>::Cast(info.Data()); + V8DataModel* dataModel = (V8DataModel*)field->Value(); + + if (dataModel->_ioProcessors.IsEmpty()) { - if (!dataModel->_ioProcessorsAreSet) { - dataModel->_ioProcessors = v8::Persistent<v8::Object>::New(v8::Object::New()); - //v8::Handle<v8::Object> ioProcessorObj = v8::Object::New(); - std::map<std::string, IOProcessor> ioProcessors = dataModel->_interpreter->getIOProcessors(); + v8::Local<v8::Object> ioProcs = v8::Local<v8::Object>::New(v8::Isolate::GetCurrent(), v8::Object::New()); + //v8::Local<v8::Object> ioProcessorObj = v8::Object::New(); + std::map<std::string, IOProcessor> ioProcessors = dataModel->_callbacks->getIOProcessors(); std::map<std::string, IOProcessor>::const_iterator ioProcIter = ioProcessors.begin(); while(ioProcIter != ioProcessors.end()) { // std::cout << ioProcIter->first << std::endl; - dataModel->_ioProcessors->Set(v8::String::New(ioProcIter->first.c_str()), - dataModel->getDataAsValue(ioProcIter->second.getDataModelVariables())); + ioProcs->Set(v8::String::New(ioProcIter->first.c_str()), + dataModel->getDataAsValue(ioProcIter->second.getDataModelVariables())); ioProcIter++; } - dataModel->_ioProcessorsAreSet = true; + dataModel->_ioProcessors.Reset(v8::Isolate::GetCurrent(), ioProcs); } - return dataModel->_ioProcessors; + info.GetReturnValue().Set(dataModel->_ioProcessors); } -v8::Handle<v8::Value> V8DataModel::getInvokers(v8::Local<v8::String> property, const v8::AccessorInfo& info) { - V8DataModel* dataModel = V8DOM::toClassPtr<V8DataModel>(info.Data()); +void V8DataModel::getInvokers(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Local<v8::External> field = v8::Local<v8::External>::Cast(info.Data()); + V8DataModel* dataModel = (V8DataModel*)field->Value(); - if (!dataModel->_invokersAreSet) { - dataModel->_invokers = v8::Persistent<v8::Object>::New(v8::Object::New()); - //v8::Handle<v8::Object> ioProcessorObj = v8::Object::New(); - std::map<std::string, Invoker> invokers = dataModel->_interpreter->getInvokers(); + if (dataModel->_invokers.IsEmpty()) { + v8::Local<v8::Object> invoks = v8::Local<v8::Object>::New(v8::Isolate::GetCurrent(), v8::Object::New()); + //v8::Local<v8::Object> ioProcessorObj = v8::Object::New(); + std::map<std::string, Invoker> invokers = dataModel->_callbacks->getInvokers(); std::map<std::string, Invoker>::const_iterator invokerIter = invokers.begin(); while(invokerIter != invokers.end()) { // std::cout << ioProcIter->first << std::endl; - dataModel->_invokers->Set(v8::String::New(invokerIter->first.c_str()), - dataModel->getDataAsValue(invokerIter->second.getDataModelVariables())); + invoks->Set(v8::String::New(invokerIter->first.c_str()), + dataModel->getDataAsValue(invokerIter->second.getDataModelVariables())); invokerIter++; } - dataModel->_invokersAreSet = true; + dataModel->_invokers.Reset(v8::Isolate::GetCurrent(), invoks); } - return dataModel->_invokers; + info.GetReturnValue().Set(dataModel->_invokers); } -void V8DataModel::pushContext() { - _contexts.push_back(_contexts.back().New(_contexts.back())); -} +void V8DataModel::setEvent(const Event& event) { + + v8::Locker locker(_isolate); + v8::Isolate::Scope isoScope(_isolate); -void V8DataModel::popContext() { - if (_contexts.size() > 1) { - _contexts.back().Dispose(); - _contexts.pop_back(); + v8::HandleScope scope(_isolate); + v8::Local<v8::Context> ctx = v8::Local<v8::Context>::New(_isolate, _context); + + v8::Local<v8::Object> global = ctx->Global(); + v8::Context::Scope contextScope(ctx); // segfaults at newinstance without! + assert(_isolate->GetCurrentContext() == ctx); // only valid in context::scope + + +#if 0 + // this would work as swig_exports_ will get redefined per isolate + { + std::lock_guard<std::mutex> lock(_initMutex); + SWIGV8_INIT(context->Global()); } -} +#endif -void V8DataModel::initialize() { -} + Event* evPtr = new Event(event); -void V8DataModel::setEvent(const Event& event) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - v8::Handle<v8::Object> global = _contexts.front()->Global(); +// v8::Handle<v8::FunctionTemplate> classTmpl = v8::Local<v8::FunctionTemplate>::New(_isolate, V8SCXMLEvent::getTmpl()); +// v8::Local<v8::Object> eventObj = classTmpl->InstanceTemplate()->NewInstance(); +// eventObj->SetAlignedPointerInInternalField(0, (void*)evPtr); +// assert(eventObj->GetAlignedPointerFromInternalField(0) == evPtr); - v8::Handle<v8::Function> eventCtor = V8SCXMLEvent::getTmpl()->GetFunction(); - v8::Persistent<v8::Object> eventObj = v8::Persistent<v8::Object>::New(eventCtor->NewInstance()); + v8::Local<v8::Value> eventVal = SWIG_V8_NewPointerObj(evPtr, SWIGTYPE_p_uscxml__Event, SWIG_POINTER_OWN); + v8::Local<v8::Object> eventObj = v8::Local<v8::Object>::Cast(eventVal); - V8SCXMLEvent::V8SCXMLEventPrivate* privData = new V8SCXMLEvent::V8SCXMLEventPrivate(); - privData->nativeObj = new Event(event); - privData->dom = _dom; - eventObj->SetInternalField(0, V8DOM::toExternal(privData)); - eventObj.MakeWeak(0, V8SCXMLEvent::jsDestructor); + /* + v8::Local<v8::Array> properties = eventObj->GetPropertyNames(); + for (int i = 0; i < properties->Length(); i++) { + assert(properties->Get(i)->IsString()); + v8::String::AsciiValue key(v8::Local<v8::String>::Cast(properties->Get(i))); + std::cout << *key << std::endl; + } + */ + + // test333 + if (event.origintype.size() > 0) { + eventObj->Set(v8::String::NewSymbol("origintype"),v8::String::NewFromUtf8(_isolate, event.origintype.c_str())); + } else { + eventObj->Set(v8::String::NewSymbol("origintype"),v8::Undefined(_isolate)); + } + // test335 + if (event.origin.size() > 0) { + eventObj->Set(v8::String::NewSymbol("origin"),v8::String::NewFromUtf8(_isolate, event.origin.c_str())); + } else { + eventObj->Set(v8::String::NewSymbol("origin"),v8::Undefined(_isolate)); + } + // test337 + if (!event.hideSendId) { + eventObj->Set(v8::String::NewSymbol("sendid"),v8::String::NewFromUtf8(_isolate, event.sendid.c_str())); + } else { + eventObj->Set(v8::String::NewSymbol("sendid"),v8::Undefined(_isolate)); + } + // test339 + if (event.invokeid.size() > 0) { + eventObj->Set(v8::String::NewSymbol("invokeid"),v8::String::NewFromUtf8(_isolate, event.invokeid.c_str())); + } else { + eventObj->Set(v8::String::NewSymbol("invokeid"),v8::Undefined(_isolate)); + } - if (event.raw.size() == 0) { - std::stringstream ssRaw; - ssRaw << event; - privData->nativeObj->raw = ssRaw.str(); + // test 331 + switch (event.eventType) { + case Event::EXTERNAL: + eventObj->Set(v8::String::NewSymbol("type"), v8::String::NewFromUtf8(_isolate, "external")); + break; + case Event::INTERNAL: + eventObj->Set(v8::String::NewSymbol("type"), v8::String::NewFromUtf8(_isolate, "internal")); + break; + case Event::PLATFORM: + eventObj->Set(v8::String::NewSymbol("type"), v8::String::NewFromUtf8(_isolate, "platform")); + break; } - if (event.dom) { - eventObj->Set(v8::String::New("data"), getNodeAsValue(event.dom)); - } else if (event.content.length() > 0) { - // _event.data is a string or JSON - Data json = Data::fromJSON(event.content); - if (!json.empty()) { - eventObj->Set(v8::String::New("data"), getDataAsValue(json)); - } else { - eventObj->Set(v8::String::New("data"), v8::String::New(spaceNormalize(event.content).c_str())); - } + if (event.data.node) { + eventObj->Set(v8::String::NewSymbol("data"), getNodeAsValue(event.data.node)); } else { // _event.data is KVP - Event eventCopy(event); - if (!eventCopy.params.empty()) { - Event::params_t::iterator paramIter = eventCopy.params.begin(); - while(paramIter != eventCopy.params.end()) { - eventCopy.data.compound[paramIter->first] = paramIter->second; + Data data = event.data; + if (!event.params.empty()) { + Event::params_t::const_iterator paramIter = event.params.begin(); + while(paramIter != event.params.end()) { + data.compound[paramIter->first] = paramIter->second; paramIter++; } } - if (!eventCopy.namelist.empty()) { - Event::namelist_t::iterator nameListIter = eventCopy.namelist.begin(); - while(nameListIter != eventCopy.namelist.end()) { - eventCopy.data.compound[nameListIter->first] = nameListIter->second; + if (!event.namelist.empty()) { + Event::namelist_t::const_iterator nameListIter = event.namelist.begin(); + while(nameListIter != event.namelist.end()) { + data.compound[nameListIter->first] = nameListIter->second; nameListIter++; } } - if (!eventCopy.data.empty()) { + if (!data.empty()) { // std::cout << Data::toJSON(eventCopy.data); - eventObj->Set(v8::String::New("data"), getDataAsValue(eventCopy.data)); // set data part of _event + eventObj->Set(v8::String::NewSymbol("data"), getDataAsValue(data)); // set data part of _event } else { // test 343 / test 488 - eventObj->Set(v8::String::New("data"), v8::Undefined()); // set data part of _event + eventObj->Set(v8::String::NewSymbol("data"), v8::Undefined()); // set data part of _event } } // we cannot make _event v8::ReadOnly as it will ignore subsequent setEvents - global->Set(v8::String::New("_event"), eventObj); + global->Set(v8::String::NewSymbol("_event"), eventObj); + _event.Reset(_isolate, eventObj); } -Data V8DataModel::getStringAsData(const std::string& content) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - v8::Handle<v8::Value> result = evalAsValue(content); +Data V8DataModel::getAsData(const std::string& content) { + return Data::fromJSON(content); +} + +Data V8DataModel::evalAsData(const std::string& content) { + v8::Locker locker(_isolate); + v8::Isolate::Scope isoScope(_isolate); + + v8::HandleScope scope(_isolate); + v8::Local<v8::Context> ctx = v8::Local<v8::Context>::New(_isolate, _context); + v8::Context::Scope contextScope(ctx); // segfaults at newinstance without! + + v8::Local<v8::Value> result = evalAsValue(content); Data data = getValueAsData(result); return data; } -Data V8DataModel::getValueAsData(const v8::Handle<v8::Value>& value) { +Data V8DataModel::getValueAsData(const v8::Local<v8::Value>& value) { + v8::Locker locker(_isolate); + v8::Isolate::Scope isoScope(_isolate); + v8::HandleScope scope(_isolate); + std::set<v8::Value*> foo = std::set<v8::Value*>(); return getValueAsData(value, foo); } -Data V8DataModel::getValueAsData(const v8::Handle<v8::Value>& value, std::set<v8::Value*>& alreadySeen) { +Data V8DataModel::getValueAsData(const v8::Local<v8::Value>& value, std::set<v8::Value*>& alreadySeen) { + + v8::Local<v8::Context> ctx = v8::Local<v8::Context>::New(_isolate, _context); + v8::Context::Scope contextScope(ctx); // segfaults at newinstance without! + Data data; /// TODO: Breaking cycles does not work yet @@ -372,7 +458,7 @@ Data V8DataModel::getValueAsData(const v8::Handle<v8::Value>& value, std::set<v8 if (false) { } else if (value->IsArray()) { - v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value); + v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(value); for (int i = 0; i < array->Length(); i++) { data.array.push_back(getValueAsData(array->Get(i), alreadySeen)); } @@ -396,33 +482,36 @@ Data V8DataModel::getValueAsData(const v8::Handle<v8::Value>& value, std::set<v8 } else if (value->IsNull()) { LOG(ERROR) << "IsNull is unimplemented" << std::endl; } else if (value->IsNumber()) { - v8::String::AsciiValue prop(v8::Handle<v8::String>::Cast(v8::Handle<v8::Number>::Cast(value))); + v8::String::AsciiValue prop(v8::Local<v8::String>::Cast(v8::Local<v8::Number>::Cast(value))); data.atom = *prop; } else if (value->IsNumberObject()) { LOG(ERROR) << "IsNumberObject is unimplemented" << std::endl; } else if (value->IsObject()) { - if (V8ArrayBuffer::hasInstance(value)) { - uscxml::V8ArrayBuffer::V8ArrayBufferPrivate* privObj = V8DOM::toClassPtr<V8ArrayBuffer::V8ArrayBufferPrivate >(value->ToObject()->GetInternalField(0)); - data.binary = privObj->nativeObj->_blob; - return data; - } - if (V8Node::hasInstance(value)) { - uscxml::V8Node::V8NodePrivate* privObj = V8DOM::toClassPtr<V8Node::V8NodePrivate >(value->ToObject()->GetInternalField(0)); - data.node = *privObj->nativeObj; + +// if (V8ArrayBuffer::hasInstance(value)) { +// uscxml::V8ArrayBuffer::V8ArrayBufferPrivate* privObj = V8DOM::toClassPtr<V8ArrayBuffer::V8ArrayBufferPrivate >(value->ToObject()->GetInternalField(0)); +// data.binary = privObj->nativeObj->_blob; +// return data; +// } + + v8::Local<v8::FunctionTemplate> tmpl = v8::Local<v8::FunctionTemplate>::New(_isolate, _exports_DOMNode_clientData.class_templ); + if (tmpl->HasInstance(value)) { + SWIG_V8_GetInstancePtr(value, (void**)&(data.node)); return data; } - v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); + + v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(value); v8::Local<v8::Array> properties = object->GetPropertyNames(); for (int i = 0; i < properties->Length(); i++) { assert(properties->Get(i)->IsString()); - v8::String::AsciiValue key(v8::Handle<v8::String>::Cast(properties->Get(i))); + v8::String::AsciiValue key(v8::Local<v8::String>::Cast(properties->Get(i))); v8::Local<v8::Value> property = object->Get(properties->Get(i)); data.compound[*key] = getValueAsData(property, alreadySeen); } } else if (value->IsRegExp()) { LOG(ERROR) << "IsRegExp is unimplemented" << std::endl; } else if(value->IsString()) { - v8::String::AsciiValue property(v8::Handle<v8::String>::Cast(value)); + v8::String::AsciiValue property(v8::Local<v8::String>::Cast(value)); data.atom = *property; data.type = Data::VERBATIM; } else if(value->IsStringObject()) { @@ -433,45 +522,32 @@ Data V8DataModel::getValueAsData(const v8::Handle<v8::Value>& value, std::set<v8 LOG(ERROR) << "IsUint32 is unimplemented" << std::endl; } else if(value->IsUndefined()) { data.atom = "undefined"; + } else { + LOG(ERROR) << "Value's type is unknown!" << std::endl; } return data; } -v8::Handle<v8::Value> V8DataModel::getNodeAsValue(const Node<std::string>& node) { - - switch (node.getNodeType()) { - case Node_base::ELEMENT_NODE: { - TO_V8_DOMVALUE(Element); - } - case Node_base::TEXT_NODE: { - TO_V8_DOMVALUE(Text); - } - case Node_base::CDATA_SECTION_NODE: { - TO_V8_DOMVALUE(CDATASection); - } - case Node_base::DOCUMENT_NODE: { - TO_V8_DOMVALUE(Document); - } - default: { - TO_V8_DOMVALUE(Node); - } - } - +v8::Local<v8::Value> V8DataModel::getNodeAsValue(const xercesc::DOMNode* node) { + return SWIG_NewPointerObj(SWIG_as_voidptr(node), + SWIG_TypeDynamicCast(SWIGTYPE_p_XERCES_CPP_NAMESPACE__DOMNode, + SWIG_as_voidptrptr(&node)), + 0); } -v8::Handle<v8::Value> V8DataModel::getDataAsValue(const Data& data) { +v8::Local<v8::Value> V8DataModel::getDataAsValue(const Data& data) { + if (data.compound.size() > 0) { - v8::Handle<v8::Object> value = v8::Object::New(); + v8::Local<v8::Object> value = v8::Object::New(); std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin(); while(compoundIter != data.compound.end()) { -// std::cout << compoundIter->first.c_str() << std::endl; - value->Set(v8::String::New(compoundIter->first.c_str()), getDataAsValue(compoundIter->second)); + value->Set(v8::String::NewSymbol(compoundIter->first.c_str()), getDataAsValue(compoundIter->second)); compoundIter++; } return value; } if (data.array.size() > 0) { - v8::Handle<v8::Object> value = v8::Array::New(); + v8::Local<v8::Object> value = v8::Array::New(_isolate, data.array.size()); std::list<Data>::const_iterator arrayIter = data.array.begin(); uint32_t index = 0; while(arrayIter != data.array.end()) { @@ -490,61 +566,55 @@ v8::Handle<v8::Value> V8DataModel::getDataAsValue(const Data& data) { break; } } - if (data.binary) { - uscxml::ArrayBuffer* arrBuffer = new uscxml::ArrayBuffer(data.binary); - v8::Handle<v8::Function> retCtor = V8ArrayBuffer::getTmpl()->GetFunction(); - v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance()); - - struct V8ArrayBuffer::V8ArrayBufferPrivate* retPrivData = new V8ArrayBuffer::V8ArrayBufferPrivate(); - retPrivData->nativeObj = arrBuffer; - retObj->SetInternalField(0, V8DOM::toExternal(retPrivData)); - - retObj.MakeWeak(0, V8ArrayBuffer::jsDestructor); - return retObj; - } + if (data.node) { + return getNodeAsValue(data.node); + } + +// if (data.binary) { +// uscxml::ArrayBuffer* arrBuffer = new uscxml::ArrayBuffer(data.binary); +// v8::Local<v8::Function> retCtor = V8ArrayBuffer::getTmpl()->GetFunction(); +// v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance()); +// +// struct V8ArrayBuffer::V8ArrayBufferPrivate* retPrivData = new V8ArrayBuffer::V8ArrayBufferPrivate(); +// retPrivData->nativeObj = arrBuffer; +// retObj->SetInternalField(0, V8DOM::toExternal(retPrivData)); +// +// retObj.MakeWeak(0, V8ArrayBuffer::jsDestructor); +// return retObj; +// } // this will never be reached return v8::Undefined(); } -v8::Handle<v8::Value> V8DataModel::jsPrint(const v8::Arguments& args) { - if (args.Length() > 0) { - v8::String::AsciiValue printMsg(args[0]->ToString()); +void V8DataModel::jsPrint(const v8::FunctionCallbackInfo<v8::Value>& info) { + if (info.Length() > 0) { + v8::String::AsciiValue printMsg(info[0]->ToString()); std::cout << *printMsg; } - return v8::Undefined(); } -v8::Handle<v8::Value> V8DataModel::jsIn(const v8::Arguments& args) { - V8DataModel* INSTANCE = static_cast<V8DataModel*>(v8::External::Unwrap(args.Data())); - for (unsigned int i = 0; i < args.Length(); i++) { - if (args[i]->IsString()) { - std::string stateName(*v8::String::AsciiValue(args[i]->ToString())); - if (INSTANCE->_interpreter->isInState(stateName)) { +void V8DataModel::jsIn(const v8::FunctionCallbackInfo<v8::Value>& info) { + v8::Local<v8::External> field = v8::Local<v8::External>::Cast(info.Data()); + V8DataModel* dataModel = (V8DataModel*)field->Value(); + + for (unsigned int i = 0; i < info.Length(); i++) { + if (info[i]->IsString()) { + std::string stateName(*v8::String::AsciiValue(info[i]->ToString())); + if (dataModel->_callbacks->isInState(stateName)) { continue; } } - return v8::Boolean::New(false); + info.GetReturnValue().Set(false); + return; } - return v8::Boolean::New(true); -} - -bool V8DataModel::validate(const std::string& location, const std::string& schema) { - return true; -} - -bool V8DataModel::isLocation(const std::string& expr) { - // location needs to be RHS and ++ is only valid for RHS - return isValidSyntax(expr + "++"); + info.GetReturnValue().Set(true); } bool V8DataModel::isValidSyntax(const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; v8::TryCatch tryCatch; - v8::Context::Scope contextScope(_contexts.back()); - v8::Handle<v8::String> source = v8::String::New(expr.c_str()); - v8::Handle<v8::Script> script = v8::Script::Compile(source); + v8::Local<v8::String> source = v8::String::New(expr.c_str()); + v8::Local<v8::Script> script = v8::Script::Compile(source); if (script.IsEmpty() || tryCatch.HasCaught()) { return false; @@ -554,19 +624,18 @@ bool V8DataModel::isValidSyntax(const std::string& expr) { } uint32_t V8DataModel::getLength(const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::TryCatch tryCatch; - v8::Context::Scope contextScope(_contexts.back()); - v8::Handle<v8::Value> result = evalAsValue(expr); + v8::Locker locker(_isolate); + v8::Isolate::Scope isoScope(_isolate); + v8::HandleScope scope(_isolate); + + v8::Local<v8::Context> ctx = v8::Local<v8::Context>::New(_isolate, _context); + v8::Context::Scope contextScope(ctx); // segfaults at newinstance without! + + v8::Local<v8::Value> result = evalAsValue(expr); if (!result.IsEmpty() && result->IsArray()) return result.As<v8::Array>()->Length(); - Event exceptionEvent; - exceptionEvent.name = "error.execution"; - exceptionEvent.data.compound["cause"] = Data("'" + expr + "' does not evaluate to an array.", Data::VERBATIM); - - throw(exceptionEvent); + ERROR_EXECUTION_THROW("'" + expr + "' does not evaluate to an array.") } void V8DataModel::setForeach(const std::string& item, @@ -576,10 +645,20 @@ void V8DataModel::setForeach(const std::string& item, if (!isDeclared(item)) { assign(item, Data()); } + + v8::Locker locker(_isolate); + v8::Isolate::Scope isoScope(_isolate); + v8::HandleScope scope(_isolate); + + v8::Local<v8::Context> ctx = v8::Local<v8::Context>::New(_isolate, _context); + v8::Context::Scope contextScope(ctx); // segfaults at newinstance without! + // assign array element to item std::stringstream ss; - ss << array << "[" << iteration << "]"; - assign(item, Data(ss.str(), Data::INTERPRETED)); + ss << item << " = " << array << "[" << iteration << "]"; +// assign(item, Data(ss.str(), Data::INTERPRETED)); + // test152: we need "'continue' = array[index]" to throw + evalAsValue(ss.str()); if (index.length() > 0) { // assign iteration element to index std::stringstream ss; @@ -588,29 +667,23 @@ void V8DataModel::setForeach(const std::string& item, } } -void V8DataModel::eval(const Element<std::string>& scriptElem, - const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - evalAsValue(expr); -} - bool V8DataModel::isDeclared(const std::string& expr) { /** * Undeclared variables can be checked by trying to access them and catching * a reference error. */ - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); + v8::Locker locker(_isolate); + v8::Isolate::Scope isoScope(_isolate); - v8::TryCatch tryCatch; - v8::Handle<v8::String> source = v8::String::New(expr.c_str()); - v8::Handle<v8::Script> script = v8::Script::Compile(source); + v8::HandleScope scope(_isolate); + v8::Local<v8::Context> ctx = v8::Local<v8::Context>::New(_isolate, _context); + v8::Context::Scope contextScope(ctx); // segfaults at newinstance without! + + v8::Local<v8::String> source = v8::String::New(expr.c_str()); + v8::Local<v8::Script> script = v8::Script::Compile(source); - v8::Handle<v8::Value> result; + v8::Local<v8::Value> result; if (!script.IsEmpty()) result = script->Run(); @@ -621,152 +694,62 @@ bool V8DataModel::isDeclared(const std::string& expr) { } bool V8DataModel::evalAsBool(const std::string& expr) { - return evalAsBool(Arabica::DOM::Element<std::string>(), expr); -} + v8::Locker locker(_isolate); + v8::Isolate::Scope isoScope(_isolate); -bool V8DataModel::evalAsBool(const Arabica::DOM::Element<std::string>& node, const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - v8::Handle<v8::Value> result = evalAsValue(expr); + v8::HandleScope scope(_isolate); + v8::Local<v8::Context> ctx = v8::Local<v8::Context>::New(_isolate, _context); + v8::Context::Scope contextScope(ctx); // segfaults at newinstance without! + + v8::Local<v8::Value> result = evalAsValue(expr); return(result->ToBoolean()->BooleanValue()); } -std::string V8DataModel::evalAsString(const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - v8::Handle<v8::Value> result = evalAsValue(expr); - if (result->IsObject()) { - v8::Local<v8::Object> obj = result->ToObject(); - v8::Local<v8::Object> proto; - - proto = obj->FindInstanceInPrototypeChain(V8Document::getTmpl()); - if (!proto.IsEmpty()) { - struct V8Document::V8DocumentPrivate* privData = - V8DOM::toClassPtr<V8Document::V8DocumentPrivate >(obj->GetInternalField(0)); - std::stringstream ss; - ss << privData->nativeObj->getDocumentElement(); - return ss.str(); - } - - proto = obj->FindInstanceInPrototypeChain(V8Node::getTmpl()); - if (!proto.IsEmpty()) { - struct V8Node::V8NodePrivate* privData = - V8DOM::toClassPtr<V8Node::V8NodePrivate >(obj->GetInternalField(0)); - std::stringstream ss; - ss << privData->nativeObj; - return ss.str(); - } - Data data = getValueAsData(result); - return toStr(data); - } - if (result->IsNumber()) { - return toStr(result->ToNumber()->NumberValue()); - } - v8::String::AsciiValue data(result->ToString()); - return std::string(*data); -} +void V8DataModel::assign(const std::string& location, const Data& data) { -double V8DataModel::evalAsNumber(const std::string& expr) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - v8::Handle<v8::Value> result = evalAsValue(expr); - if (result->IsNumber()) { - return result->ToNumber()->NumberValue(); - } - return 0; -} + v8::Locker locker(_isolate); + v8::Isolate::Scope isoScope(_isolate); + v8::HandleScope scope(_isolate); -void V8DataModel::assign(const Element<std::string>& assignElem, - const Node<std::string>& node, - const std::string& content) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - v8::Handle<v8::Object> global = _contexts.front()->Global(); + v8::Local<v8::Context> ctx = v8::Local<v8::Context>::New(_isolate, _context); + v8::Local<v8::Object> global = ctx->Global(); + v8::Context::Scope contextScope(ctx); // segfaults at newinstance without! - std::string key; - if (HAS_ATTR(assignElem, "id")) { - key = ATTR(assignElem, "id"); - } else if (HAS_ATTR(assignElem, "location")) { - key = ATTR(assignElem, "location"); - } - if (key.length() == 0) - throw Event("error.execution", Event::PLATFORM); - - if (key.compare("_sessionid") == 0) // test 322 + if (location.compare("_sessionid") == 0) // test 322 ERROR_EXECUTION_THROW("Cannot assign to _sessionId"); - if (key.compare("_name") == 0) + if (location.compare("_name") == 0) ERROR_EXECUTION_THROW("Cannot assign to _name"); - if (key.compare("_ioprocessors") == 0) // test 326 + if (location.compare("_ioprocessors") == 0) // test 326 ERROR_EXECUTION_THROW("Cannot assign to _ioprocessors"); - if (key.compare("_invokers") == 0) + if (location.compare("_invokers") == 0) ERROR_EXECUTION_THROW("Cannot assign to _invokers"); - if (key.compare("_event") == 0) + if (location.compare("_event") == 0) ERROR_EXECUTION_THROW("Cannot assign to _event"); - if (HAS_ATTR(assignElem, "expr")) { - evalAsValue(key + " = " + ATTR(assignElem, "expr")); - } else if (node) { - global->Set(v8::String::New(key.c_str()), getNodeAsValue(node)); - } else if (content.size() > 0) { - try { - evalAsValue(key + " = " + content); - } catch (...) { - evalAsValue(key + " = " + "\"" + spaceNormalize(content) + "\""); - } + if (data.node) { + global->Set(v8::String::NewSymbol(location.c_str()), getNodeAsValue(data.node)); } else { - global->Set(v8::String::New(key.c_str()), v8::Undefined()); + evalAsValue(location + " = " + Data::toJSON(data)); } } -void V8DataModel::assign(const std::string& location, - const Data& data) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - - std::stringstream ssJSON; - ssJSON << data; - evalAsValue(location + " = " + ssJSON.str()); -} - -void V8DataModel::init(const Element<std::string>& dataElem, - const Node<std::string>& doc, - const std::string& content) { - try { - assign(dataElem, doc, content); - } catch (Event e) { - // test 277 - std::string key; - if (HAS_ATTR(dataElem, "id")) { - key = ATTR(dataElem, "id"); - } else if (HAS_ATTR(dataElem, "location")) { - key = ATTR(dataElem, "location"); - } - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - - evalAsValue(key + " = undefined", true); - throw e; - } -}; - void V8DataModel::init(const std::string& location, const Data& data) { + v8::Locker locker(_isolate); + v8::Isolate::Scope isoScope(_isolate); + v8::HandleScope scope(_isolate); + + v8::Local<v8::Context> ctx = v8::Local<v8::Context>::New(_isolate, _context); + v8::Context::Scope contextScope(ctx); // segfaults at newinstance without! + try { assign(location, data); - } catch (Event e) { + } catch (ErrorEvent e) { // test 277 - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.front()); - evalAsValue(location + " = undefined", true); + + // we need to get error.execution into the queue throw e; } } @@ -791,12 +774,22 @@ std::string V8DataModel::andExpressions(std::list<std::string> expressions) { return exprSS.str(); } -v8::Handle<v8::Value> V8DataModel::evalAsValue(const std::string& expr, bool dontThrow) { +v8::Local<v8::Value> V8DataModel::evalAsValue(const std::string& expr, bool dontThrow) { + +// v8::Locker locker(_isolate); +// v8::Isolate::Scope isoScope(_isolate); +// +// v8::HandleScope scope(_isolate); +// v8::EscapableHandleScope escape(_isolate); +// v8::Local<v8::Context> ctx = v8::Local<v8::Context>::New(_isolate, _context); +// v8::Context::Scope contextScope(ctx); // segfaults at newinstance without! + v8::TryCatch tryCatch; - v8::Handle<v8::String> source = v8::String::New(expr.c_str()); - v8::Handle<v8::Script> script = v8::Script::Compile(source); - v8::Handle<v8::Value> result; + v8::Local<v8::String> source = v8::String::New(expr.c_str()); + v8::Local<v8::Script> script = v8::Script::Compile(source); + + v8::Local<v8::Value> result; if (!script.IsEmpty()) result = script->Run(); @@ -811,14 +804,14 @@ v8::Handle<v8::Value> V8DataModel::evalAsValue(const std::string& expr, bool don void V8DataModel::throwExceptionEvent(const v8::TryCatch& tryCatch) { assert(tryCatch.HasCaught()); - Event exceptionEvent; + ErrorEvent exceptionEvent; exceptionEvent.name = "error.execution"; exceptionEvent.eventType = Event::PLATFORM; std::string exceptionString(*v8::String::AsciiValue(tryCatch.Exception())); exceptionEvent.data.compound["cause"] = Data(exceptionString, Data::VERBATIM);; - v8::Handle<v8::Message> message = tryCatch.Message(); + v8::Local<v8::Message> message = tryCatch.Message(); if (!message.IsEmpty()) { std::string filename(*v8::String::AsciiValue(message->GetScriptResourceName())); exceptionEvent.data.compound["filename"] = Data(filename, Data::VERBATIM); |