Revision: 17481
Author: [email protected]
Date: Tue Nov 5 12:25:32 2013 UTC
Log: Make Object.freeze/seal/preventExtensions observable
Note: spec has been updated here:
http://wiki.ecmascript.org/doku.php?id=harmony:observe_spec_changes.
[email protected], rossberg
BUG=v8:2975,v8:2941
Review URL: https://codereview.chromium.org/47703003
http://code.google.com/p/v8/source/detail?r=17481
Modified:
/branches/bleeding_edge/src/object-observe.js
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/v8natives.js
/branches/bleeding_edge/test/mjsunit/harmony/object-observe.js
=======================================
--- /branches/bleeding_edge/src/object-observe.js Tue Nov 5 11:23:08 2013
UTC
+++ /branches/bleeding_edge/src/object-observe.js Tue Nov 5 12:25:32 2013
UTC
@@ -132,7 +132,8 @@
'updated',
'deleted',
'prototype',
- 'reconfigured'
+ 'reconfigured',
+ 'preventExtensions'
]);
// An Observer is a registration to observe an object by a callback with
@@ -463,9 +464,20 @@
if (!ObjectInfoHasActiveObservers(objectInfo))
return;
- var changeRecord = (arguments.length < 4) ?
- { type: type, object: object, name: name } :
- { type: type, object: object, name: name, oldValue: oldValue };
+ var changeRecord;
+ if (arguments.length == 2) {
+ changeRecord = { type: type, object: object };
+ } else if (arguments.length == 3) {
+ changeRecord = { type: type, object: object, name: name };
+ } else {
+ changeRecord = {
+ type: type,
+ object: object,
+ name: name,
+ oldValue: oldValue
+ };
+ }
+
ObjectFreeze(changeRecord);
ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord);
}
=======================================
--- /branches/bleeding_edge/src/objects.cc Tue Nov 5 12:11:27 2013 UTC
+++ /branches/bleeding_edge/src/objects.cc Tue Nov 5 12:25:32 2013 UTC
@@ -2175,11 +2175,13 @@
object = handle(JSGlobalObject::cast(*object)->global_receiver(),
isolate);
}
Handle<Object> args[] = { type, object, name, old_value };
+ int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
bool threw;
+
Execution::Call(isolate,
Handle<JSFunction>(isolate->observers_notify_change()),
isolate->factory()->undefined_value(),
- old_value->IsTheHole() ? 3 : 4, args,
+ argc, args,
&threw);
ASSERT(!threw);
}
@@ -5442,6 +5444,9 @@
Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
Isolate* isolate = object->GetIsolate();
+
+ if (!object->map()->is_extensible()) return object;
+
if (object->IsAccessCheckNeeded() &&
!isolate->MayNamedAccess(*object,
isolate->heap()->undefined_value(),
@@ -5484,6 +5489,11 @@
new_map->set_is_extensible(false);
object->set_map(*new_map);
ASSERT(!object->map()->is_extensible());
+
+ if (FLAG_harmony_observation && object->map()->is_observed()) {
+ EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
+ isolate->factory()->the_hole_value());
+ }
return object;
}
@@ -5512,6 +5522,7 @@
Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
// Freezing non-strict arguments should be handled elsewhere.
ASSERT(!object->HasNonStrictArgumentsElements());
+ ASSERT(!object->map()->is_observed());
if (object->map()->is_frozen()) return object;
=======================================
--- /branches/bleeding_edge/src/v8natives.js Thu Oct 17 10:02:45 2013 UTC
+++ /branches/bleeding_edge/src/v8natives.js Tue Nov 5 12:25:32 2013 UTC
@@ -1249,7 +1249,7 @@
throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
}
var isProxy = %IsJSProxy(obj);
- if (isProxy || %HasNonStrictArgumentsElements(obj)) {
+ if (isProxy || %HasNonStrictArgumentsElements(obj) || %IsObserved(obj)) {
if (isProxy) {
ProxyFix(obj);
}
=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/object-observe.js Tue Nov
5 11:23:08 2013 UTC
+++ /branches/bleeding_edge/test/mjsunit/harmony/object-observe.js Tue Nov
5 12:25:32 2013 UTC
@@ -300,8 +300,103 @@
{ object: obj, type: 'deleted', name: '', oldValue: ' ' },
]);
+// Object.preventExtensions
+reset();
+var obj = { foo: 'bar'};
+Object.observe(obj, observer.callback);
+obj.baz = 'bat';
+Object.preventExtensions(obj);
+
+Object.deliverChangeRecords(observer.callback);
+observer.assertCallbackRecords([
+ { object: obj, type: 'new', name: 'baz' },
+ { object: obj, type: 'preventExtensions' },
+]);
+
+reset();
+var obj = { foo: 'bar'};
+Object.preventExtensions(obj);
+Object.observe(obj, observer.callback);
+Object.preventExtensions(obj);
+Object.deliverChangeRecords(observer.callback);
+observer.assertNotCalled();
+
+// Object.freeze
+reset();
+var obj = { a: 'a' };
+Object.defineProperty(obj, 'b', {
+ writable: false,
+ configurable: true,
+ value: 'b'
+});
+Object.defineProperty(obj, 'c', {
+ writable: true,
+ configurable: false,
+ value: 'c'
+});
+Object.defineProperty(obj, 'd', {
+ writable: false,
+ configurable: false,
+ value: 'd'
+});
+Object.observe(obj, observer.callback);
+Object.freeze(obj);
+
+Object.deliverChangeRecords(observer.callback);
+observer.assertCallbackRecords([
+ { object: obj, type: 'reconfigured', name: 'a' },
+ { object: obj, type: 'reconfigured', name: 'b' },
+ { object: obj, type: 'reconfigured', name: 'c' },
+ { object: obj, type: 'preventExtensions' },
+]);
+
+reset();
+var obj = { foo: 'bar'};
+Object.freeze(obj);
+Object.observe(obj, observer.callback);
+Object.freeze(obj);
+Object.deliverChangeRecords(observer.callback);
+observer.assertNotCalled();
+
+// Object.seal
+reset();
+var obj = { a: 'a' };
+Object.defineProperty(obj, 'b', {
+ writable: false,
+ configurable: true,
+ value: 'b'
+});
+Object.defineProperty(obj, 'c', {
+ writable: true,
+ configurable: false,
+ value: 'c'
+});
+Object.defineProperty(obj, 'd', {
+ writable: false,
+ configurable: false,
+ value: 'd'
+});
+Object.observe(obj, observer.callback);
+Object.seal(obj);
+
+Object.deliverChangeRecords(observer.callback);
+observer.assertCallbackRecords([
+ { object: obj, type: 'reconfigured', name: 'a' },
+ { object: obj, type: 'reconfigured', name: 'b' },
+ { object: obj, type: 'preventExtensions' },
+]);
+
+reset();
+var obj = { foo: 'bar'};
+Object.seal(obj);
+Object.observe(obj, observer.callback);
+Object.seal(obj);
+Object.deliverChangeRecords(observer.callback);
+observer.assertNotCalled();
+
// Observing a continuous stream of changes, while itermittantly
unobserving.
reset();
+var obj = {};
Object.observe(obj, observer.callback);
Object.getNotifier(obj).notify({
type: 'updated',
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.