Reviewers: rossberg,
Description:
Make Object.observe on the global object functional
The approach in this change is to handle the unwrapping/wrapping of the
global
object transparently with respect to the JS implementation of
Object.observe. An
alternate approach would be to add a runtime method like %IsJSGlobalProxy
and
%UnwrapJSGlobalProxy, but it seems ugly to give JS (even implementation JS)
access to the unwrapped global.
BUG=v8:2409
Please review this at https://codereview.chromium.org/11414094/
SVN Base: http://v8.googlecode.com/svn/branches/bleeding_edge
Affected files:
M src/objects.cc
M src/runtime.cc
M test/mjsunit/harmony/object-observe.js
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index
efc4868ad94d068ff263151ed165fdb526967ffb..aa3ab585123c721e58ddcbbc116991dc3cae602d
100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -1748,6 +1748,9 @@ void JSObject::EnqueueChangeRecord(Handle<JSObject>
object,
Isolate* isolate = object->GetIsolate();
HandleScope scope;
Handle<String> type = isolate->factory()->LookupAsciiSymbol(type_str);
+ if (object->IsJSGlobalObject()) {
+ object = handle(JSGlobalObject::cast(*object)->global_receiver(),
isolate);
+ }
Handle<Object> args[] = { type, object, name, old_value };
bool threw;
Execution::Call(Handle<JSFunction>(isolate->observers_notify_change()),
Index: src/runtime.cc
diff --git a/src/runtime.cc b/src/runtime.cc
index
252b624024cd431bed30f75165798abfa7108b62..fb626948fbb23ac3539e07bd817b9f3f6e151ad6
100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -13158,6 +13158,12 @@ RUNTIME_FUNCTION(MaybeObject*,
Runtime_HaveSameMap) {
RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) {
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSReceiver, obj, 0);
+ if (obj->IsJSGlobalProxy()) {
+ Object* proto = obj->GetPrototype();
+ if (obj->IsNull()) return isolate->heap()->undefined_value();
+ ASSERT(proto->IsJSGlobalObject());
+ obj = JSReceiver::cast(proto);
+ }
return isolate->heap()->ToBoolean(obj->map()->is_observed());
}
@@ -13166,6 +13172,14 @@ RUNTIME_FUNCTION(MaybeObject*,
Runtime_SetIsObserved) {
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSReceiver, obj, 0);
CONVERT_BOOLEAN_ARG_CHECKED(is_observed, 1);
+ JSGlobalProxy* global_proxy = NULL;
+ if (obj->IsJSGlobalProxy()) {
+ Object* proto = obj->GetPrototype();
+ if (obj->IsNull()) return isolate->heap()->undefined_value();
+ ASSERT(proto->IsJSGlobalObject());
+ global_proxy = JSGlobalProxy::cast(obj);
+ obj = JSReceiver::cast(proto);
+ }
if (obj->map()->is_observed() != is_observed) {
MaybeObject* maybe = obj->map()->Copy();
Map* map;
@@ -13201,6 +13215,10 @@ RUNTIME_FUNCTION(MaybeObject*,
Runtime_ObjectHashTableGet) {
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(ObjectHashTable, table, 0);
Object* key = args[1];
+ if (key->IsJSGlobalProxy()) {
+ key = key->GetPrototype();
+ if (key->IsNull()) return isolate->heap()->undefined_value();
+ }
Object* lookup = table->Lookup(key);
return lookup->IsTheHole() ? isolate->heap()->undefined_value() : lookup;
}
@@ -13211,6 +13229,10 @@ RUNTIME_FUNCTION(MaybeObject*,
Runtime_ObjectHashTableSet) {
ASSERT(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(ObjectHashTable, table, 0);
Handle<Object> key = args.at<Object>(1);
+ if (key->IsJSGlobalProxy()) {
+ key = handle(key->GetPrototype(), isolate);
+ if (key->IsNull()) return isolate->heap()->undefined_value();
+ }
Handle<Object> value = args.at<Object>(2);
return *PutIntoObjectHashTable(table, key, value);
}
@@ -13221,6 +13243,10 @@ RUNTIME_FUNCTION(MaybeObject*,
Runtime_ObjectHashTableHas) {
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(ObjectHashTable, table, 0);
Object* key = args[1];
+ if (key->IsJSGlobalProxy()) {
+ key = key->GetPrototype();
+ if (key->IsNull()) return isolate->heap()->undefined_value();
+ }
Object* lookup = table->Lookup(key);
return isolate->heap()->ToBoolean(!lookup->IsTheHole());
}
Index: test/mjsunit/harmony/object-observe.js
diff --git a/test/mjsunit/harmony/object-observe.js
b/test/mjsunit/harmony/object-observe.js
index
26d097ecee7f50106cd64f2e8ebe4aa8f73a7b4c..b9f4b43cf0d7f19b20caffea620765552f080d5f
100644
--- a/test/mjsunit/harmony/object-observe.js
+++ b/test/mjsunit/harmony/object-observe.js
@@ -56,7 +56,9 @@ function createObserver() {
assertCallbackRecords: function(recs) {
this.assertRecordCount(recs.length);
for (var i = 0; i < recs.length; i++) {
- print(i, JSON.stringify(this.records[i]), JSON.stringify(recs[i]));
+ try {
+ print(i, JSON.stringify(this.records[i]),
JSON.stringify(recs[i]));
+ } catch (e) { }
assertSame(this.records[i].object, recs[i].object);
assertEquals('string', typeof recs[i].type);
assertPropertiesEqual(this.records[i], recs[i]);
@@ -462,7 +464,9 @@ function createProxy(create, x) {
},
target: {isProxy: true},
callback: function(changeRecords) {
- print("callback", JSON.stringify(handler.proxy),
JSON.stringify(got));
+ try {
+ print("callback", JSON.stringify(handler.proxy),
JSON.stringify(got));
+ } catch (e) { }
for (var i in changeRecords) {
var got = changeRecords[i];
var change = {object: handler.proxy, name: got.name, type:
got.type};
@@ -503,9 +507,7 @@ function blacklisted(obj, prop) {
// TODO(observe): oldValue when reconfiguring array length
(obj instanceof Array && prop === "length") ||
// TODO(observe): prototype property on functions
- (obj instanceof Function && prop === "prototype") ||
- // TODO(observe): global object
- obj === this;
+ (obj instanceof Function && prop === "prototype")
}
for (var i in objects) for (var j in properties) {
@@ -513,7 +515,7 @@ for (var i in objects) for (var j in properties) {
var prop = properties[j];
if (blacklisted(obj, prop)) continue;
var desc = Object.getOwnPropertyDescriptor(obj, prop);
- print("***", typeof obj, JSON.stringify(obj), prop);
+ try { print("***", typeof obj, JSON.stringify(obj), prop) } catch (e) {
};
if (!desc || desc.configurable)
TestObserveConfigurable(obj, prop);
else if (desc.writable)
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev