diff --git a/atom/common/api/atom_api_v8_util.cc b/atom/common/api/atom_api_v8_util.cc index bba3399a8dbd..c86335adb15e 100644 --- a/atom/common/api/atom_api_v8_util.cc +++ b/atom/common/api/atom_api_v8_util.cc @@ -2,22 +2,51 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. +#include +#include + #include "atom/common/api/object_life_monitor.h" #include "atom/common/node_includes.h" +#include "base/stl_util.h" #include "native_mate/dictionary.h" #include "v8/include/v8-profiler.h" namespace { +// A Persistent that can be copied and will not free itself. +template +struct LeakedPersistentTraits { + typedef v8::Persistent > LeakedPersistent; + static const bool kResetInDestructor = false; + template + static V8_INLINE void Copy(const v8::Persistent& source, + LeakedPersistent* dest) { + // do nothing, just allow copy + } +}; + +// The handles are leaked on purpose. +using FunctionTemplateHandle = + LeakedPersistentTraits::LeakedPersistent; +std::map function_templates_; + v8::Local CreateObjectWithName(v8::Isolate* isolate, - v8::Local name) { + const std::string& name) { + if (name == "Object") + return v8::Object::New(isolate); + + if (ContainsKey(function_templates_, name)) + return v8::Local::New( + isolate, function_templates_[name])->GetFunction()->NewInstance(); + v8::Local t = v8::FunctionTemplate::New(isolate); - t->SetClassName(name); + t->SetClassName(mate::StringToV8(isolate, name)); + function_templates_[name] = FunctionTemplateHandle(isolate, t); return t->GetFunction()->NewInstance(); } v8::Local GetHiddenValue(v8::Local object, - v8::Local key) { + v8::Local key) { return object->GetHiddenValue(key); } diff --git a/atom/renderer/api/lib/remote.coffee b/atom/renderer/api/lib/remote.coffee index 2828586849f2..3ed44278bd71 100644 --- a/atom/renderer/api/lib/remote.coffee +++ b/atom/renderer/api/lib/remote.coffee @@ -65,39 +65,17 @@ metaToValue = (meta) -> return metaToValue obj else # Function call. - ret = ipcRenderer.sendSync 'ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments) - return metaToValue ret + obj = ipcRenderer.sendSync 'ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments) + return metaToValue obj else ret = v8Util.createObjectWithName meta.name # Polulate delegate members. for member in meta.members - do (member) -> - if member.type is 'function' - ret[member.name] = - class RemoteMemberFunction - constructor: -> - if @constructor is RemoteMemberFunction - # Constructor call. - obj = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', meta.id, member.name, wrapArgs(arguments) - return metaToValue obj - else - # Call member function. - ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CALL', meta.id, member.name, wrapArgs(arguments) - return metaToValue ret - else - Object.defineProperty ret, member.name, - enumerable: true, - configurable: false, - set: (value) -> - # Set member data. - ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_SET', meta.id, member.name, value - value - - get: -> - # Get member data. - ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_GET', meta.id, member.name - metaToValue ret + if member.type is 'function' + ret[member.name] = createRemoteMemberFunction meta.id, member.name + else + Object.defineProperty ret, member.name, createRemoteMemberProperty(meta.id, member.name) # Track delegate object's life time, and tell the browser to clean up # when the object is GCed. @@ -117,6 +95,35 @@ metaToPlainObject = (meta) -> obj[name] = value for {name, value} in meta.members obj +# Create a RemoteMemberFunction instance. +# This function's content should not be inlined into metaToValue, otherwise V8 +# may consider it circular reference. +createRemoteMemberFunction = (metaId, name) -> + class RemoteMemberFunction + constructor: -> + if @constructor is RemoteMemberFunction + # Constructor call. + ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', metaId, name, wrapArgs(arguments) + return metaToValue ret + else + # Call member function. + ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CALL', metaId, name, wrapArgs(arguments) + return metaToValue ret + +# Create configuration for defineProperty. +# This function's content should not be inlined into metaToValue, otherwise V8 +# may consider it circular reference. +createRemoteMemberProperty = (metaId, name) -> + enumerable: true, + configurable: false, + set: (value) -> + # Set member data. + ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_SET', metaId, name, value + value + get: -> + # Get member data. + metaToValue ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, name) + # Browser calls a callback in renderer. ipcRenderer.on 'ATOM_RENDERER_CALLBACK', (event, id, args) -> callbacksRegistry.apply id, metaToValue(args)