Hi,
due to fundamental problems in the design of the Persistent handle API, we feel the need to considerably change the V8 API to ensure that the Persistent class is safe to use. Currently, it is extremely difficult to use safely and can easily lead to heap corruption. To get an understanding of the problem, see https://code.google.com/p/v8/issues/detail?id=1889.
At the moment we’re considering the following major changes:
Making Persistent an independent class (no longer deriving from Handle).
Deprecating Local and eventually removing it in favor of just having Handle.
Changing all callbacks that return Handle<Value> to return void and instead pass the return value in as a parameter.
The last change is not inherently required by the changes to Persistent but rather to maintain performant callbacks which return Persistent. The old style of callbacks we want to be deprecate and eventually remove. In the meantime, old style callbacks can support the return value parameter when an empty handle is returned, providing a transition path.
I have created two patches that attempt this transformation (most of it anyway). They are https://codereview.chromium.org/12729023/ and https://codereview.chromium.org/12494012/.
Not everything is yet set in stone, and I expect a certain amount of change to the overall implementation path as we work through implementation issues and receive feedback.
Dan
At the moment we’re considering the following major changes:
Making Persistent an independent class (no longer deriving from Handle).
Deprecating Local and eventually removing it in favor of just having Handle.
Changing all callbacks that return Handle<Value> to return void and instead pass the return value in as a parameter.
Glad to see Persistent getting so much love. I'd just like to drop my 2 cents worth of pain recently.
A quick update:I've committed the changes to deprecate all old style callbacks in favour of the new style which return void. As of version 3.20, using old style callbacks will issue deprecation warnings but they will continue to be in the api and work for some number of versions to come to allow for a transition path for embedders.
The transition from Local to Handle won't happen for a while. It's more of a cleanup step after everything else is done, and there's no urgency since there shouldn't be any performance impact.
The callback signature changes alone break almost every single line of v8-using code i've written (tens of thousands of them), and i am still undecided as to whether to spend several weeks of my time patching for or whether to simply drop by v8-related projects (i'm leaning strongly towards the latter). i'm getting too old to spend weeks patching every time a 3rd-party library pulls the rug out from under me (and this isn't the first time v8 has done it, though this is certainly the most invasive change so far).
I feel your pain. Converting chrome was a large amount of tedious work.
Ultimately, though, the v8 team does not want to support two APIs for any sustained amount of time. I've put up a header only library on github that embedders can use if they do not want to rewrite all their callbacks: https://github.com/drcarney66/v8-backport. You will, however, have to install wrap<your_old_function_name> at callback registration time
instead of your_old_function_name. This far from a perfect solution, but should help in a lot of cases, and it's certainly less work that manually converting a zillion functions. Note that performance sensitive functions should be converted.
Additionally, as things like Arguments, InvocationCallback, and AccessorInfo are removed from v8.h, I'll just create a compatible version in the header which should keep things compiling for anyone choosing to use that library.
One further note: instead of removing Local, Handle is going to be removed instead, which should cause embedders a lot less pain.
> One further note: instead of removing Local, Handle is going to be removed instead, which should cause embedders a lot less pain.
Interesting. Thanks for the heads up. Does this mean Undefined/True/False etc. will return Local<Value>?
Interesting. Thanks for the heads up. Does this mean Undefined/True/False etc. will return Local<Value>?
Not at all. AFAIK you don't have to use scope.Close() when returning those values so the nomenclature just might seem a little strange. That's all.
i will certainly be taking a look at that. Maybe i can use it as a pattern for porting even if i can't use it directly. My code is primarily library-level templates which convert arbitrary client-side functions to InvocationCallbacks (http://code.google.com/p/v8-juice/wiki/V8Convert_XTo), so these changes really hit me where it hurts.
Would it be possible to rename GetReturnValue() to ReturnValue()?
Embedders will be typing that a lot so briefer is better IMO.
Is that comment in error? Put another way: if or when those functions
are removed, how are you supposed to get at the handle that the
Persistent points to?
Another thing is Persistent<T>::ClearAndLeak(). Here is its definition:
V8_INLINE(T* ClearAndLeak());
What purpose does it serve? You can't construct a Handle<T> from a
raw T*, all constructors and New() class methods that take a T* are
private.
--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/6kSAbnUb-rQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
Ben just landed the 3.20.x upgrade to Node, and I'm noticing a non-trivial performance regression using Persistent<>. Before it was fast to cache objects that would be passed to Function::Call as Persistent<Object>, but now it seems to require a Local<Object>::New(Isolate*, Persistent<Object>) before being sent. For quick calls out of cc to js it's adding ~10% to call time. Is there a way around this regression that I'm not seeing?
I'm not quite sure what you mean. Do you mean you want to return a value stored in a Persistent? If so, that's done via GetReturnValue().Set(Persistent&). That should take care of the regression if that's the case. If not, could you provide me with an example?
Local<Function>::New(isolate, p_fn)->Call(Local<Object>::New(isolate, p_obj), argc, argv[]);
I'm afraid that, if you use 3.20, for the cases you've mentioned, you're stuck with that performance regression if you use the API correctly. While cutting Chrome over to this API, we had to use a lot of reinterpret_casts<Local*> to work around some of these problems.
The weak callback problem we've already discovered and are in the process of fixing, but I'm not sure when the new weak callback API will arrive.For certain API functions, we can create a version that's callable from a Persistent directly, but Function::Call unfortunately isn't one of them.
We have a few functions slated to have a Persistent version, like GetAlignedPointerFromInternalField,
and if there are certain functions causing you pain, we can look at adding them if you send me a list. If there's any path by which a function might allocate heap memory, however, we cannot add it.
Right now the largest pain is needing to Local<T>::New() the Persistent<T>* passed to the MakeWeak callback so we can access external memory attached via Object::SetIndexedPropertiesToExternalArrayData().
As for using reinterpret_cast<Local*>, will that be a long-er term solution for problems like the following:
void CallMe(const FunctionCallbackInfo<Value>& args) {HandleScope scope(args.GetCurrentIsolate());// storing and passing a cached empty object is the fastest way I've found// to call a js fn from ccToLocal<Function>(&p_call_this_often)->Call(ToLocal<Object>(&p_empty_obj), argc, argv);}
Right now they'd be:- Object::HasIndexedPropertiesInExternalArrayData()- Object::GetIndexedPropertiesExternalArrayData()- Object::GetIndexedPropertiesExternalArrayDataLength()
Constantly needing to create a Local<T>::New() every time I need to use a Persistent<T> in cases like the above isn't playing nicely. I've noticed since the change that GC time from --prof has grown around 5% in high I/O scenarios.
The issue Trevor's reporting is that each Local that's created with
Local<T>::New() gets added to the active HandleScope's internal list.
Before the Persistent changes, dereferencing a Persistent was cheap,
now it's not (if it's weak.)
--
Why can't the Persistent use a RIAA pattern that's reference counted? Ideally, I'd like to create a persistent, copy it to another persistent (which would increment the reference), then the last one to go out of scope should be disposed automatically in the destructor. In other words, I'd like to use it like a boost::shared_ptr.
But if you centralize the storage and information associated with an indirection, then all copies, weak or otherwise should point to the same object. If during a weak callback disposes the handle, and others are referring to it such that it isn't the last reference, the memory associated with the handle shouldn't be disposed, but the handle data should be. Then, the other handles when calling IsEmpty should return true. The centralized data used for the Persistent is reference counted and only when the reference count becomes zero should the actual centralized storage memory be disposed. Make sense?
Honestly right now persistent is so hard to use his suggestion would be welcome. Making the end user build his own ref counting scheme around Persistent is not better IMO.
So with the resent changes to Persistent how can we store a series of Persistent<Function> handles to an STL container like map ?
--
So with the resent changes to Persistent how can we store a series of Persistent<Function> handles to an STL container like map ?