diff --git a/atom/browser/api/event_emitter.h b/atom/browser/api/event_emitter.h index 4fb953b63992..42816d42a45b 100644 --- a/atom/browser/api/event_emitter.h +++ b/atom/browser/api/event_emitter.h @@ -45,6 +45,8 @@ class EventEmitter : public Wrappable { content::WebContents* sender, IPC::Message* message, const Args&... args) { + v8::Locker locker(isolate()); + v8::HandleScope handle_scope(isolate()); v8::Local event = CreateJSEvent(isolate(), sender, message); return EmitWithEvent(name, event, args...); } diff --git a/atom/browser/lib/objects-registry.coffee b/atom/browser/lib/objects-registry.coffee index f102cbef894e..ccfe2dbe0ad2 100644 --- a/atom/browser/lib/objects-registry.coffee +++ b/atom/browser/lib/objects-registry.coffee @@ -1,82 +1,65 @@ EventEmitter = require('events').EventEmitter -IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap v8Util = process.atomBinding 'v8_util' -# Class to reference all objects. -class ObjectsStore - @stores = {} - - constructor: -> - @nextId = 0 - @objects = [] - - getNextId: -> - ++@nextId - - add: (obj) -> - id = @getNextId() - @objects[id] = obj - id - - has: (id) -> - @objects[id]? - - remove: (id) -> - throw new Error("Invalid key #{id} for ObjectsStore") unless @has id - delete @objects[id] - - get: (id) -> - throw new Error("Invalid key #{id} for ObjectsStore") unless @has id - @objects[id] - - @forRenderView: (key) -> - @stores[key] = new ObjectsStore unless @stores[key]? - @stores[key] - - @releaseForRenderView: (key) -> - delete @stores[key] - class ObjectsRegistry extends EventEmitter constructor: -> @setMaxListeners Number.MAX_VALUE + @nextId = 0 - # Objects in weak map will be not referenced (so we won't leak memory), and - # every object created in browser will have a unique id in weak map. - @objectsWeakMap = new IDWeakMap - @objectsWeakMap.add = (obj) -> - id = IDWeakMap::add.call this, obj - v8Util.setHiddenValue obj, 'atomId', id - id + # Stores all objects by ref-counting. + # (id) => {object, count} + @storage = {} + + # Stores the IDs of objects referenced by WebContents. + # (webContentsId) => {(id) => (count)} + @owners = {} # Register a new object, the object would be kept referenced until you release # it explicitly. - add: (key, obj) -> - # Some native objects may already been added to objectsWeakMap, be care not - # to add it twice. - @objectsWeakMap.add obj unless v8Util.getHiddenValue obj, 'atomId' - id = v8Util.getHiddenValue obj, 'atomId' + add: (webContentsId, obj) -> + id = @saveToStorage obj + # Remember the owner. + @owners[webContentsId] ?= {} + @owners[webContentsId][id] ?= 0 + @owners[webContentsId][id]++ + # Returns object's id + id - # Store and reference the object, then return the storeId which points to - # where the object is stored. The caller can later dereference the object - # with the storeId. - # We use a difference key because the same object can be referenced for - # multiple times by the same renderer view. - store = ObjectsStore.forRenderView key - storeId = store.add obj - - [id, storeId] - - # Get an object according to its id. + # Get an object according to its ID. get: (id) -> - @objectsWeakMap.get id + @storage[id]?.object - # Remove an object according to its storeId. - remove: (key, storeId) -> - ObjectsStore.forRenderView(key).remove storeId + # Dereference an object according to its ID. + remove: (webContentsId, id) -> + @dereference id, 1 + # Also reduce the count in owner. + pointer = @owners[webContentsId] + --pointer[id] + delete pointer[id] if pointer[id] is 0 - # Clear all references to objects from renderer view. - clear: (key) -> - @emit "clear-#{key}" - ObjectsStore.releaseForRenderView key + # Clear all references to objects refrenced by the WebContents. + clear: (webContentsId) -> + @emit "clear-#{webContentsId}" + return unless @owners[webContentsId]? + @dereference id, count for id, count of @owners[webContentsId] + delete @owners[webContentsId] + + # Private: Saves the object into storage and assigns an ID for it. + saveToStorage: (object) -> + id = v8Util.getHiddenValue object, 'atomId' + unless id + id = ++@nextId + @storage[id] = {count: 0, object} + v8Util.setHiddenValue object, 'atomId', id + ++@storage[id].count + id + + # Private: Dereference the object from store. + dereference: (id, count) -> + pointer = @storage[id] + pointer.count -= count + if pointer.count is 0 + v8Util.deleteHiddenValue pointer.object, 'atomId' + delete @storage[id] module.exports = new ObjectsRegistry diff --git a/atom/browser/lib/rpc-server.coffee b/atom/browser/lib/rpc-server.coffee index 3eba472570a7..0a28d350e8a9 100644 --- a/atom/browser/lib/rpc-server.coffee +++ b/atom/browser/lib/rpc-server.coffee @@ -4,7 +4,7 @@ objectsRegistry = require './objects-registry.js' v8Util = process.atomBinding 'v8_util' # Convert a real value into meta data. -valueToMeta = (sender, value) -> +valueToMeta = (sender, value, optimizeSimpleObject=false) -> meta = type: typeof value meta.type = 'buffer' if Buffer.isBuffer value @@ -12,6 +12,10 @@ valueToMeta = (sender, value) -> meta.type = 'array' if Array.isArray value meta.type = 'promise' if value? and value.constructor.name is 'Promise' + # Treat simple objects as value. + if optimizeSimpleObject and meta.type is 'object' and v8Util.getHiddenValue value, 'simple' + meta.type = 'value' + # Treat the arguments object as array. meta.type = 'array' if meta.type is 'object' and value.callee? and value.length? @@ -24,7 +28,7 @@ valueToMeta = (sender, value) -> # Reference the original value if it's an object, because when it's # passed to renderer we would assume the renderer keeps a reference of # it. - [meta.id, meta.storeId] = objectsRegistry.add sender.getId(), value + meta.id = objectsRegistry.add sender.getId(), value meta.members = [] meta.members.push {name: prop, type: typeof field} for prop, field of value @@ -80,11 +84,11 @@ unwrapArgs = (sender, args) -> callFunction = (event, func, caller, args) -> if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function' args.push (ret) -> - event.returnValue = valueToMeta event.sender, ret + event.returnValue = valueToMeta event.sender, ret, true func.apply caller, args else ret = func.apply caller, args - event.returnValue = valueToMeta event.sender, ret + event.returnValue = valueToMeta event.sender, ret, true # Send by BrowserWindow when its render view is deleted. process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (id) -> @@ -170,8 +174,8 @@ ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, id, name) -> catch e event.returnValue = errorToMeta e -ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, storeId) -> - objectsRegistry.remove event.sender.getId(), storeId +ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, id) -> + objectsRegistry.remove event.sender.getId(), id ipc.on 'ATOM_BROWSER_GUEST_WEB_CONTENTS', (event, guestInstanceId) -> try diff --git a/atom/common/api/atom_api_id_weak_map.cc b/atom/common/api/atom_api_id_weak_map.cc deleted file mode 100644 index c5fbf09370f2..000000000000 --- a/atom/common/api/atom_api_id_weak_map.cc +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/api/atom_api_id_weak_map.h" - -#include "native_mate/constructor.h" -#include "native_mate/object_template_builder.h" - -#include "atom/common/node_includes.h" - -namespace atom { - -namespace api { - -IDWeakMap::IDWeakMap() { -} - -IDWeakMap::~IDWeakMap() { -} - -int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Local object) { - return map_.Add(isolate, object); -} - -v8::Local IDWeakMap::Get(v8::Isolate* isolate, int32_t key) { - v8::MaybeLocal result = map_.Get(isolate, key); - if (result.IsEmpty()) { - isolate->ThrowException(v8::Exception::Error( - mate::StringToV8(isolate, "Invalid key"))); - return v8::Undefined(isolate); - } else { - return result.ToLocalChecked(); - } -} - -bool IDWeakMap::Has(int32_t key) const { - return map_.Has(key); -} - -std::vector IDWeakMap::Keys() const { - return map_.Keys(); -} - -void IDWeakMap::Remove(int32_t key) { - map_.Remove(key); -} - -// static -void IDWeakMap::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - mate::ObjectTemplateBuilder(isolate, prototype) - .SetMethod("add", &IDWeakMap::Add) - .SetMethod("get", &IDWeakMap::Get) - .SetMethod("has", &IDWeakMap::Has) - .SetMethod("keys", &IDWeakMap::Keys) - .SetMethod("remove", &IDWeakMap::Remove); -} - -} // namespace api - -} // namespace atom - - -namespace { - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - using atom::api::IDWeakMap; - v8::Isolate* isolate = context->GetIsolate(); - v8::Local constructor = mate::CreateConstructor( - isolate, - "IDWeakMap", - base::Bind(&mate::NewOperatorFactory)); - exports->Set(mate::StringToSymbol(isolate, "IDWeakMap"), constructor); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_id_weak_map, Initialize) diff --git a/atom/common/api/atom_api_id_weak_map.h b/atom/common/api/atom_api_id_weak_map.h deleted file mode 100644 index 955bd83088ac..000000000000 --- a/atom/common/api/atom_api_id_weak_map.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Copyright (c) 2012 Intel Corp. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_API_ATOM_API_ID_WEAK_MAP_H_ -#define ATOM_COMMON_API_ATOM_API_ID_WEAK_MAP_H_ - -#include - -#include "atom/common/id_weak_map.h" -#include "native_mate/wrappable.h" - -namespace atom { - -namespace api { - -// Like ES6's WeakMap, but the key is Integer and the value is Weak Pointer. -class IDWeakMap : public mate::Wrappable { - public: - IDWeakMap(); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - private: - virtual ~IDWeakMap(); - - int32_t Add(v8::Isolate* isolate, v8::Local object); - v8::Local Get(v8::Isolate* isolate, int32_t key); - bool Has(int32_t key) const; - std::vector Keys() const; - void Remove(int32_t key); - - atom::IDWeakMap map_; - - DISALLOW_COPY_AND_ASSIGN(IDWeakMap); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_COMMON_API_ATOM_API_ID_WEAK_MAP_H_ diff --git a/atom/common/api/atom_api_v8_util.cc b/atom/common/api/atom_api_v8_util.cc index ae90fe1f37fc..21f23a97b456 100644 --- a/atom/common/api/atom_api_v8_util.cc +++ b/atom/common/api/atom_api_v8_util.cc @@ -28,6 +28,11 @@ void SetHiddenValue(v8::Local object, object->SetHiddenValue(key, value); } +void DeleteHiddenValue(v8::Local object, + v8::Local key) { + object->DeleteHiddenValue(key); +} + int32_t GetObjectHash(v8::Local object) { return object->GetIdentityHash(); } @@ -48,6 +53,7 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("createObjectWithName", &CreateObjectWithName); dict.SetMethod("getHiddenValue", &GetHiddenValue); dict.SetMethod("setHiddenValue", &SetHiddenValue); + dict.SetMethod("deleteHiddenValue", &DeleteHiddenValue); dict.SetMethod("getObjectHash", &GetObjectHash); dict.SetMethod("setDestructor", &SetDestructor); dict.SetMethod("takeHeapSnapshot", &TakeHeapSnapshot); diff --git a/atom/common/api/object_life_monitor.cc b/atom/common/api/object_life_monitor.cc index 18d2a3a4d53f..9b7c7fe6d05f 100644 --- a/atom/common/api/object_life_monitor.cc +++ b/atom/common/api/object_life_monitor.cc @@ -5,32 +5,52 @@ #include "atom/common/api/object_life_monitor.h" -#include "native_mate/compat.h" +#include "base/bind.h" +#include "base/message_loop/message_loop.h" namespace atom { // static void ObjectLifeMonitor::BindTo(v8::Isolate* isolate, v8::Local target, - v8::Local destructor) { - target->SetHiddenValue(MATE_STRING_NEW(isolate, "destructor"), destructor); - - ObjectLifeMonitor* olm = new ObjectLifeMonitor(); - olm->handle_.reset(isolate, target); - olm->handle_.SetWeak(olm, WeakCallback); + v8::Local destructor) { + new ObjectLifeMonitor(isolate, target, destructor); } -ObjectLifeMonitor::ObjectLifeMonitor() { +ObjectLifeMonitor::ObjectLifeMonitor(v8::Isolate* isolate, + v8::Local target, + v8::Local destructor) + : isolate_(isolate), + context_(isolate, isolate->GetCurrentContext()), + target_(isolate, target), + destructor_(isolate, destructor), + weak_ptr_factory_(this) { + target_.SetWeak(this, OnObjectGC, v8::WeakCallbackType::kParameter); } // static -void ObjectLifeMonitor::WeakCallback( - const v8::WeakCallbackData& data) { - // destructor.call(object, object); - v8::Local obj = data.GetValue(); - v8::Local::Cast(obj->GetHiddenValue( - MATE_STRING_NEW(data.GetIsolate(), "destructor")))->Call(obj, 0, NULL); - delete data.GetParameter(); +void ObjectLifeMonitor::OnObjectGC( + const v8::WeakCallbackInfo& data) { + // Usually FirstWeakCallback should do nothing other than reset |object_| + // and then set a second weak callback to run later. We can sidestep that, + // because posting a task to the current message loop is all but free - but + // DO NOT add any more work to this method. The only acceptable place to add + // code is RunCallback. + ObjectLifeMonitor* self = data.GetParameter(); + self->target_.Reset(); + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(&ObjectLifeMonitor::RunCallback, + self->weak_ptr_factory_.GetWeakPtr())); +} + +void ObjectLifeMonitor::RunCallback() { + v8::HandleScope handle_scope(isolate_); + v8::Local context = v8::Local::New( + isolate_, context_); + v8::Context::Scope context_scope(context); + v8::Local::New(isolate_, destructor_)->Call( + context->Global(), 0, nullptr); + delete this; } } // namespace atom diff --git a/atom/common/api/object_life_monitor.h b/atom/common/api/object_life_monitor.h index e8dbbcf65f15..90216d8227a5 100644 --- a/atom/common/api/object_life_monitor.h +++ b/atom/common/api/object_life_monitor.h @@ -6,7 +6,8 @@ #define ATOM_COMMON_API_OBJECT_LIFE_MONITOR_H_ #include "base/basictypes.h" -#include "native_mate/scoped_persistent.h" +#include "base/memory/weak_ptr.h" +#include "v8/include/v8.h" namespace atom { @@ -14,15 +15,23 @@ class ObjectLifeMonitor { public: static void BindTo(v8::Isolate* isolate, v8::Local target, - v8::Local destructor); + v8::Local destructor); private: - ObjectLifeMonitor(); + ObjectLifeMonitor(v8::Isolate* isolate, + v8::Local target, + v8::Local destructor); - static void WeakCallback( - const v8::WeakCallbackData& data); + static void OnObjectGC(const v8::WeakCallbackInfo& data); - mate::ScopedPersistent handle_; + void RunCallback(); + + v8::Isolate* isolate_; + v8::Global context_; + v8::Global target_; + v8::Global destructor_; + + base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ObjectLifeMonitor); }; diff --git a/atom/common/id_weak_map.cc b/atom/common/id_weak_map.cc index 4e86d7309a82..c5c4b60cac5c 100644 --- a/atom/common/id_weak_map.cc +++ b/atom/common/id_weak_map.cc @@ -10,6 +10,22 @@ namespace atom { +namespace { + +struct ObjectKey { + ObjectKey(int id, IDWeakMap* map) : id(id), map(map) {} + int id; + IDWeakMap* map; +}; + +void OnObjectGC(const v8::WeakCallbackInfo& data) { + ObjectKey* key = data.GetParameter(); + key->map->Remove(key->id); + delete key; +} + +} // namespace + IDWeakMap::IDWeakMap() : next_id_(0) { } @@ -18,11 +34,9 @@ IDWeakMap::~IDWeakMap() { int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Local object) { int32_t id = GetNextID(); - object->SetHiddenValue(mate::StringToSymbol(isolate, "IDWeakMapKey"), - mate::Converter::ToV8(isolate, id)); - auto global = make_linked_ptr(new v8::Global(isolate, object)); - global->SetWeak(this, &WeakCallback); + ObjectKey* key = new ObjectKey(id, this); + global->SetWeak(key, OnObjectGC, v8::WeakCallbackType::kParameter); map_[id] = global; return id; } @@ -71,12 +85,4 @@ int32_t IDWeakMap::GetNextID() { return ++next_id_; } -// static -void IDWeakMap::WeakCallback( - const v8::WeakCallbackData& data) { - int32_t id = data.GetValue()->GetHiddenValue( - mate::StringToV8(data.GetIsolate(), "IDWeakMapKey"))->Int32Value(); - data.GetParameter()->Remove(id); -} - } // namespace atom diff --git a/atom/common/id_weak_map.h b/atom/common/id_weak_map.h index b16334d6cea1..9fe71ebb616f 100644 --- a/atom/common/id_weak_map.h +++ b/atom/common/id_weak_map.h @@ -44,9 +44,6 @@ class IDWeakMap { // Returns next available ID. int32_t GetNextID(); - static void WeakCallback( - const v8::WeakCallbackData& data); - // ID of next stored object. int32_t next_id_; diff --git a/atom/common/native_mate_converters/gfx_converter.cc b/atom/common/native_mate_converters/gfx_converter.cc index 6620276b584e..37e7aeb3a48b 100644 --- a/atom/common/native_mate_converters/gfx_converter.cc +++ b/atom/common/native_mate_converters/gfx_converter.cc @@ -14,7 +14,8 @@ namespace mate { v8::Local Converter::ToV8(v8::Isolate* isolate, const gfx::Point& val) { - mate::Dictionary dict(isolate, v8::Object::New(isolate)); + mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); + dict.SetHidden("simple", true); dict.Set("x", val.x()); dict.Set("y", val.y()); return dict.GetHandle(); @@ -35,7 +36,8 @@ bool Converter::FromV8(v8::Isolate* isolate, v8::Local Converter::ToV8(v8::Isolate* isolate, const gfx::Size& val) { - mate::Dictionary dict(isolate, v8::Object::New(isolate)); + mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); + dict.SetHidden("simple", true); dict.Set("width", val.width()); dict.Set("height", val.height()); return dict.GetHandle(); @@ -56,7 +58,8 @@ bool Converter::FromV8(v8::Isolate* isolate, v8::Local Converter::ToV8(v8::Isolate* isolate, const gfx::Rect& val) { - mate::Dictionary dict(isolate, v8::Object::New(isolate)); + mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); + dict.SetHidden("simple", true); dict.Set("x", val.x()); dict.Set("y", val.y()); dict.Set("width", val.width()); @@ -95,7 +98,8 @@ struct Converter { v8::Local Converter::ToV8(v8::Isolate* isolate, const gfx::Display& val) { - mate::Dictionary dict(isolate, v8::Object::New(isolate)); + mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); + dict.SetHidden("simple", true); dict.Set("id", val.id()); dict.Set("bounds", val.bounds()); dict.Set("workArea", val.work_area()); diff --git a/atom/common/native_mate_converters/v8_value_converter.cc b/atom/common/native_mate_converters/v8_value_converter.cc index a6358b363eea..a91e614fc6dd 100644 --- a/atom/common/native_mate_converters/v8_value_converter.cc +++ b/atom/common/native_mate_converters/v8_value_converter.cc @@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/values.h" +#include "native_mate/dictionary.h" #include "vendor/node/src/node_buffer.h" namespace atom { @@ -179,7 +180,8 @@ v8::Local V8ValueConverter::ToV8Array( v8::Local V8ValueConverter::ToV8Object( v8::Isolate* isolate, const base::DictionaryValue* val) const { - v8::Local result(v8::Object::New(isolate)); + mate::Dictionary result = mate::Dictionary::CreateEmpty(isolate); + result.SetHidden("simple", true); for (base::DictionaryValue::Iterator iter(*val); !iter.IsAtEnd(); iter.Advance()) { @@ -188,17 +190,14 @@ v8::Local V8ValueConverter::ToV8Object( CHECK(!child_v8.IsEmpty()); v8::TryCatch try_catch; - result->Set( - v8::String::NewFromUtf8(isolate, key.c_str(), v8::String::kNormalString, - key.length()), - child_v8); + result.Set(key, child_v8); if (try_catch.HasCaught()) { LOG(ERROR) << "Setter for property " << key.c_str() << " threw an " << "exception."; } } - return result; + return result.GetHandle(); } base::Value* V8ValueConverter::FromV8ValueImpl( diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 8c03f1459967..5aed5619f9cf 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -47,7 +47,6 @@ REFERENCE_MODULE(atom_browser_window); REFERENCE_MODULE(atom_common_asar); REFERENCE_MODULE(atom_common_clipboard); REFERENCE_MODULE(atom_common_crash_reporter); -REFERENCE_MODULE(atom_common_id_weak_map); REFERENCE_MODULE(atom_common_native_image); REFERENCE_MODULE(atom_common_screen); REFERENCE_MODULE(atom_common_shell); diff --git a/atom/renderer/api/lib/remote.coffee b/atom/renderer/api/lib/remote.coffee index 29a24b1789ef..abd86e7eee0c 100644 --- a/atom/renderer/api/lib/remote.coffee +++ b/atom/renderer/api/lib/remote.coffee @@ -102,7 +102,7 @@ metaToValue = (meta) -> # Track delegate object's life time, and tell the browser to clean up # when the object is GCed. v8Util.setDestructor ret, -> - ipc.send 'ATOM_BROWSER_DEREFERENCE', meta.storeId + ipc.send 'ATOM_BROWSER_DEREFERENCE', meta.id # Remember object's id. v8Util.setHiddenValue ret, 'atomId', meta.id diff --git a/filenames.gypi b/filenames.gypi index feb35789afe1..af0c56e1ea69 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -235,8 +235,6 @@ 'atom/common/api/atom_api_asar.cc', 'atom/common/api/atom_api_clipboard.cc', 'atom/common/api/atom_api_crash_reporter.cc', - 'atom/common/api/atom_api_id_weak_map.cc', - 'atom/common/api/atom_api_id_weak_map.h', 'atom/common/api/atom_api_native_image.cc', 'atom/common/api/atom_api_native_image.h', 'atom/common/api/atom_api_native_image_mac.mm', diff --git a/spec/chromium-spec.coffee b/spec/chromium-spec.coffee index 704e5bbcac74..f98c8a75c742 100644 --- a/spec/chromium-spec.coffee +++ b/spec/chromium-spec.coffee @@ -8,7 +8,7 @@ remote = require 'remote' describe 'chromium feature', -> fixtures = path.resolve __dirname, 'fixtures' - describe 'heap snapshot', -> + xdescribe 'heap snapshot', -> it 'does not crash', -> process.atomBinding('v8_util').takeHeapSnapshot() diff --git a/vendor/native_mate b/vendor/native_mate index b41635e80921..8ca005eb4159 160000 --- a/vendor/native_mate +++ b/vendor/native_mate @@ -1 +1 @@ -Subproject commit b41635e80921bddbf1a36f030490e063cd593477 +Subproject commit 8ca005eb41591f583ebab804945311903f866ad6