Revision: 9407
Author: [email protected]
Date: Thu Sep 22 10:12:41 2011
Log: Handle function proxies as getters/setters.
[email protected]
BUG=v8:1543
TEST=
Review URL: http://codereview.chromium.org/7849021
http://code.google.com/p/v8/source/detail?r=9407
Modified:
/branches/bleeding_edge/src/builtins.cc
/branches/bleeding_edge/src/debug.cc
/branches/bleeding_edge/src/execution.cc
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/test/mjsunit/harmony/proxies.js
=======================================
--- /branches/bleeding_edge/src/builtins.cc Thu Sep 22 04:30:04 2011
+++ /branches/bleeding_edge/src/builtins.cc Thu Sep 22 10:12:41 2011
@@ -441,7 +441,7 @@
for (int i = 0; i < n_args; i++) {
argv[i] = args.at<Object>(i + 1).location();
}
- bool pending_exception = false;
+ bool pending_exception;
Handle<Object> result = Execution::Call(function,
args.receiver(),
n_args,
=======================================
--- /branches/bleeding_edge/src/debug.cc Wed Sep 21 04:20:05 2011
+++ /branches/bleeding_edge/src/debug.cc Thu Sep 22 10:12:41 2011
@@ -773,7 +773,7 @@
// Execute the shared function in the debugger context.
Handle<Context> context = isolate->global_context();
- bool caught_exception = false;
+ bool caught_exception;
Handle<JSFunction> function =
factory->NewFunctionFromSharedFunctionInfo(function_info, context);
@@ -1104,7 +1104,7 @@
Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
// Call HandleBreakPointx.
- bool caught_exception = false;
+ bool caught_exception;
const int argc = 2;
Object** argv[argc] = {
break_id.location(),
@@ -2353,7 +2353,7 @@
Handle<JSValue> wrapper = GetScriptWrapper(script);
// Call UpdateScriptBreakPoints expect no exceptions.
- bool caught_exception = false;
+ bool caught_exception;
const int argc = 1;
Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points),
@@ -2494,7 +2494,7 @@
exec_state.location(),
Handle<Object>::cast(event_data).location(),
event_listener_data_.location() };
- bool caught_exception = false;
+ bool caught_exception;
Execution::TryCall(fun, isolate_->global(), argc, argv,
&caught_exception);
// Silently ignore exceptions from debug event listeners.
}
=======================================
--- /branches/bleeding_edge/src/execution.cc Mon Sep 19 11:36:47 2011
+++ /branches/bleeding_edge/src/execution.cc Thu Sep 22 10:12:41 2011
@@ -151,6 +151,8 @@
Object*** args,
bool* pending_exception,
bool convert_receiver) {
+ *pending_exception = false;
+
if (!callable->IsJSFunction()) {
callable = TryGetFunctionDelegate(callable, pending_exception);
if (*pending_exception) return callable;
@@ -195,6 +197,7 @@
v8::TryCatch catcher;
catcher.SetVerbose(false);
catcher.SetCaptureMessage(false);
+ *caught_exception = false;
Handle<Object> result = Invoke(false, func, receiver, argc, args,
caught_exception);
@@ -756,7 +759,7 @@
Handle<Object>::cast(fun).location(),
pos.location(),
is_global.location() };
- bool caught_exception = false;
+ bool caught_exception;
Handle<Object> result =
TryCall(isolate->get_stack_trace_line_fun(),
isolate->js_builtins_object(), argc, args,
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Thu Sep 22 06:54:53 2011
+++ /branches/bleeding_edge/src/objects-inl.h Thu Sep 22 10:12:41 2011
@@ -172,6 +172,13 @@
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() >=
FIRST_SPEC_OBJECT_TYPE;
}
+
+
+bool Object::IsSpecFunction() {
+ if (!Object::IsHeapObject()) return false;
+ InstanceType type = HeapObject::cast(this)->map()->instance_type();
+ return type == JS_FUNCTION_TYPE || type == JS_FUNCTION_PROXY_TYPE;
+}
bool Object::IsSymbol() {
=======================================
--- /branches/bleeding_edge/src/objects.cc Thu Sep 22 06:54:53 2011
+++ /branches/bleeding_edge/src/objects.cc Thu Sep 22 10:12:41 2011
@@ -205,8 +205,9 @@
// __defineGetter__ callback
if (structure->IsFixedArray()) {
Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
- if (getter->IsJSFunction()) {
- return GetPropertyWithDefinedGetter(receiver,
JSFunction::cast(getter));
+ if (getter->IsSpecFunction()) {
+ // TODO(rossberg): nicer would be to cast to some JSCallable here...
+ return GetPropertyWithDefinedGetter(receiver,
JSReceiver::cast(getter));
}
// Getter is not a function.
return isolate->heap()->undefined_value();
@@ -261,17 +262,20 @@
MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
- JSFunction* getter) {
+ JSReceiver* getter) {
HandleScope scope;
- Handle<JSFunction> fun(JSFunction::cast(getter));
+ Handle<JSReceiver> fun(getter);
Handle<Object> self(receiver);
#ifdef ENABLE_DEBUGGER_SUPPORT
Debug* debug = fun->GetHeap()->isolate()->debug();
// Handle stepping into a getter if step into is active.
- if (debug->StepInActive()) {
- debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
+ // TODO(rossberg): should this apply to getters that are function
proxies?
+ if (debug->StepInActive() && fun->IsJSFunction()) {
+ debug->HandleStepIn(
+ Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
}
#endif
+
bool has_pending_exception;
Handle<Object> result =
Execution::Call(fun, self, 0, NULL, &has_pending_exception);
@@ -1882,8 +1886,9 @@
if (structure->IsFixedArray()) {
Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
- if (setter->IsJSFunction()) {
- return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
+ if (setter->IsSpecFunction()) {
+ // TODO(rossberg): nicer would be to cast to some JSCallable here...
+ return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
} else {
if (strict_mode == kNonStrictMode) {
return value;
@@ -1902,17 +1907,19 @@
}
-MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSFunction* setter,
+MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
Object* value) {
Isolate* isolate = GetIsolate();
Handle<Object> value_handle(value, isolate);
- Handle<JSFunction> fun(JSFunction::cast(setter), isolate);
+ Handle<JSReceiver> fun(setter, isolate);
Handle<JSReceiver> self(this, isolate);
#ifdef ENABLE_DEBUGGER_SUPPORT
Debug* debug = isolate->debug();
// Handle stepping into a setter if step into is active.
- if (debug->StepInActive()) {
- debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
+ // TODO(rossberg): should this apply to getters that are function
proxies?
+ if (debug->StepInActive() && fun->IsJSFunction()) {
+ debug->HandleStepIn(
+ Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
}
#endif
bool has_pending_exception;
@@ -2323,8 +2330,9 @@
ASSERT(!isolate->has_pending_exception());
if (!setter->IsUndefined()) {
// We have a setter -- invoke it.
+ // TODO(rossberg): nicer would be to cast to some JSCallable here...
return proxy->SetPropertyWithDefinedSetter(
- JSFunction::cast(*setter), *value);
+ JSReceiver::cast(*setter), *value);
} else {
Handle<String> get_name =
isolate->factory()->LookupAsciiSymbol("get_");
Handle<Object> getter(v8::internal::GetProperty(desc, get_name));
@@ -2482,7 +2490,7 @@
}
Object*** argv = reinterpret_cast<Object***>(args);
- bool threw = false;
+ bool threw;
return Execution::Call(trap, handler, argc, argv, &threw);
}
@@ -3977,7 +3985,7 @@
bool is_getter,
Object* fun,
PropertyAttributes attributes) {
- ASSERT(fun->IsJSFunction() || fun->IsUndefined());
+ ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
Isolate* isolate = GetIsolate();
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
@@ -8418,8 +8426,9 @@
// __defineGetter__ callback
if (structure->IsFixedArray()) {
Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
- if (getter->IsJSFunction()) {
- return GetPropertyWithDefinedGetter(receiver,
JSFunction::cast(getter));
+ if (getter->IsSpecFunction()) {
+ // TODO(rossberg): nicer would be to cast to some JSCallable here...
+ return GetPropertyWithDefinedGetter(receiver,
JSReceiver::cast(getter));
}
// Getter is not a function.
return isolate->heap()->undefined_value();
@@ -8474,8 +8483,9 @@
if (structure->IsFixedArray()) {
Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
- if (setter->IsJSFunction()) {
- return SetPropertyWithDefinedSetter(JSFunction::cast(*setter), value);
+ if (setter->IsSpecFunction()) {
+ // TODO(rossberg): nicer would be to cast to some JSCallable here...
+ return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter),
value);
} else {
if (strict_mode == kNonStrictMode) {
return value;
=======================================
--- /branches/bleeding_edge/src/objects.h Thu Sep 22 06:54:53 2011
+++ /branches/bleeding_edge/src/objects.h Thu Sep 22 10:12:41 2011
@@ -863,6 +863,9 @@
V(AccessCheckNeeded) \
V(JSGlobalPropertyCell) \
+
+class JSReceiver;
+
// Object is the abstract superclass for all classes in the
// object hierarchy.
// Object does not use any virtual functions to avoid the
@@ -887,6 +890,7 @@
#undef DECLARE_STRUCT_PREDICATE
INLINE(bool IsSpecObject());
+ INLINE(bool IsSpecFunction());
// Oddball testing.
INLINE(bool IsUndefined());
@@ -936,7 +940,7 @@
String* key,
PropertyAttributes* attributes);
MUST_USE_RESULT MaybeObject* GetPropertyWithDefinedGetter(Object*
receiver,
- JSFunction*
getter);
+ JSReceiver*
getter);
inline MaybeObject* GetElement(uint32_t index);
// For use when we know that no exception can be thrown.
@@ -1356,7 +1360,7 @@
Object* value,
PropertyAttributes attributes,
StrictModeFlag strict_mode);
- MUST_USE_RESULT MaybeObject* SetPropertyWithDefinedSetter(JSFunction*
setter,
+ MUST_USE_RESULT MaybeObject* SetPropertyWithDefinedSetter(JSReceiver*
setter,
Object* value);
MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode
mode);
=======================================
--- /branches/bleeding_edge/src/runtime.cc Thu Sep 22 06:54:53 2011
+++ /branches/bleeding_edge/src/runtime.cc Thu Sep 22 10:12:41 2011
@@ -4206,7 +4206,7 @@
CONVERT_CHECKED(String, name, args[1]);
CONVERT_CHECKED(Smi, flag_setter, args[2]);
Object* fun = args[3];
- RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
+ RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
CONVERT_CHECKED(Smi, flag_attr, args[4]);
int unchecked = flag_attr->value();
RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) ==
0);
@@ -8422,7 +8422,7 @@
argv[i] = Handle<Object>(object);
}
- bool threw = false;
+ bool threw;
Handle<JSReceiver> hfun(fun);
Handle<Object> hreceiver(receiver);
Handle<Object> result = Execution::Call(
@@ -12957,7 +12957,7 @@
Handle<Object> receiver(isolate->global_context()->global());
// This handle is nor shared, nor used later, so it's safe.
Object** argv[] = { key_handle.location() };
- bool pending_exception = false;
+ bool pending_exception;
value = Execution::Call(factory,
receiver,
1,
=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/proxies.js Thu Sep 22
06:54:53 2011
+++ /branches/bleeding_edge/test/mjsunit/harmony/proxies.js Thu Sep 22
10:12:41 2011
@@ -2019,7 +2019,7 @@
function TestCall(isStrict, callTrap) {
assertEquals(42, callTrap(5, 37))
- // TODO(rossberg): unrelated bug: this does not succeed for optimized
code.
+ // TODO(rossberg): unrelated bug: this does not succeed for optimized
code:
// assertEquals(isStrict ? undefined : global_object, receiver)
var f = Proxy.createFunction({}, callTrap)
@@ -2236,3 +2236,120 @@
TestConstructThrow(function() { throw "myexn" })
TestConstructThrow(Proxy.createFunction({}, function() { throw "myexn" }))
TestConstructThrow(CreateFrozen({}, function() { throw "myexn" }))
+
+
+
+// Getters and setters.
+
+var value
+var receiver
+
+function TestAccessorCall(getterCallTrap, setterCallTrap) {
+ var handler = {fix: function() { return {} }}
+ var pgetter = Proxy.createFunction(handler, getterCallTrap)
+ var psetter = Proxy.createFunction(handler, setterCallTrap)
+
+ var o = {}
+ var oo = Object.create(o)
+ Object.defineProperty(o, "a", {get: pgetter, set: psetter})
+ Object.defineProperty(o, "b", {get: pgetter})
+ Object.defineProperty(o, "c", {set: psetter})
+ Object.defineProperty(o, "3", {get: pgetter, set: psetter})
+ Object.defineProperty(oo, "a", {value: 43})
+
+ receiver = ""
+ assertEquals(42, o.a)
+ assertSame(o, receiver)
+ receiver = ""
+ assertEquals(42, o.b)
+ assertSame(o, receiver)
+ receiver = ""
+ assertEquals(undefined, o.c)
+ assertEquals("", receiver)
+ receiver = ""
+ assertEquals(42, o["a"])
+ assertSame(o, receiver)
+ receiver = ""
+ assertEquals(42, o[3])
+ assertSame(o, receiver)
+
+ receiver = ""
+ assertEquals(43, oo.a)
+ assertEquals("", receiver)
+ receiver = ""
+ assertEquals(42, oo.b)
+ assertSame(o, receiver)
+ receiver = ""
+ assertEquals(undefined, oo.c)
+ assertEquals("", receiver)
+ receiver = ""
+ assertEquals(43, oo["a"])
+ assertEquals("", receiver)
+ receiver = ""
+ assertEquals(42, oo[3])
+ assertSame(o, receiver)
+
+ receiver = ""
+ assertEquals(50, o.a = 50)
+ assertSame(o, receiver)
+ assertEquals(50, value)
+ receiver = ""
+ assertEquals(51, o.b = 51)
+ assertEquals("", receiver)
+ assertEquals(50, value) // no setter
+ assertThrows(function() { "use strict"; o.b = 51 }, TypeError)
+ receiver = ""
+ assertEquals(52, o.c = 52)
+ assertSame(o, receiver)
+ assertEquals(52, value)
+ receiver = ""
+ assertEquals(53, o["a"] = 53)
+ assertSame(o, receiver)
+ assertEquals(53, value)
+ receiver = ""
+ assertEquals(54, o[3] = 54)
+ assertSame(o, receiver)
+ assertEquals(54, value)
+
+ value = 0
+ receiver = ""
+ assertEquals(60, oo.a = 60)
+ assertEquals("", receiver)
+ assertEquals(0, value) // oo has own 'a'
+ assertEquals(61, oo.b = 61)
+ assertSame("", receiver)
+ assertEquals(0, value) // no setter
+ assertThrows(function() { "use strict"; oo.b = 61 }, TypeError)
+ receiver = ""
+ assertEquals(62, oo.c = 62)
+ assertSame(oo, receiver)
+ assertEquals(62, value)
+ receiver = ""
+ assertEquals(63, oo["c"] = 63)
+ assertSame(oo, receiver)
+ assertEquals(63, value)
+ receiver = ""
+ assertEquals(64, oo[3] = 64)
+ assertSame(oo, receiver)
+ assertEquals(64, value)
+}
+
+TestAccessorCall(
+ function() { receiver = this; return 42 },
+ function(x) { receiver = this; value = x }
+)
+
+TestAccessorCall(
+ function() { "use strict"; receiver = this; return 42 },
+ function(x) { "use strict"; receiver = this; value = x }
+)
+
+TestAccessorCall(
+ Proxy.createFunction({}, function() { receiver = this; return 42 }),
+ Proxy.createFunction({}, function(x) { receiver = this; value = x })
+)
+
+TestAccessorCall(
+ CreateFrozen({}, function() { receiver = this; return 42 }),
+ CreateFrozen({}, function(x) { receiver = this; value = x })
+)
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev