void Genesis::InstallExperimentalNativeFunctions() {
if (FLAG_harmony_proxies) {
+ INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap);
INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap);
INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap);
}
V(MAP_CACHE_INDEX, Object, map_cache) \
V(CONTEXT_DATA_INDEX, Object, data) \
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
+ V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \
V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap)
OUT_OF_MEMORY_INDEX,
CONTEXT_DATA_INDEX,
ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
+ DERIVED_HAS_TRAP_INDEX,
DERIVED_GET_TRAP_INDEX,
DERIVED_SET_TRAP_INDEX,
}
+bool JSReceiver::HasProperty(String* name) {
+ if (IsJSProxy()) {
+ return JSProxy::cast(this)->HasPropertyWithHandler(name);
+ }
+ return GetPropertyAttribute(name) != ABSENT;
+}
+
+
+bool JSReceiver::HasLocalProperty(String* name) {
+ if (IsJSProxy()) {
+ return JSProxy::cast(this)->HasPropertyWithHandler(name);
+ }
+ return GetLocalPropertyAttribute(name) != ABSENT;
+}
+
+
PropertyAttributes JSReceiver::GetPropertyAttribute(String* key) {
return GetPropertyAttributeWithReceiver(this, key);
}
}
+bool JSProxy::HasPropertyWithHandler(String* name_raw) {
+ Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
+ Handle<Object> receiver(this);
+ Handle<Object> name(name_raw);
+ Handle<Object> handler(this->handler());
+
+ // Extract trap function.
+ Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
+ Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (trap->IsUndefined()) {
+ trap = isolate->derived_has_trap();
+ }
+
+ // Call trap function.
+ Object** args[] = { name.location() };
+ bool has_exception;
+ Handle<Object> result =
+ Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
+ if (has_exception) return Failure::Exception();
+
+ return result->ToBoolean()->IsTrue();
+}
+
+
MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
String* name_raw,
Object* value_raw,
PropertyAttributes GetLocalPropertyAttribute(String* name);
// Can cause a GC.
- bool HasProperty(String* name) {
- return GetPropertyAttribute(name) != ABSENT;
- }
-
- // Can cause a GC.
- bool HasLocalProperty(String* name) {
- return GetLocalPropertyAttribute(name) != ABSENT;
- }
+ inline bool HasProperty(String* name);
+ inline bool HasLocalProperty(String* name);
// Return the object's prototype (might be Heap::null_value()).
inline Object* GetPrototype();
// Casting.
static inline JSProxy* cast(Object* obj);
+ bool HasPropertyWithHandler(String* name);
+
MUST_USE_RESULT MaybeObject* SetPropertyWithHandler(
String* name,
Object* value,
NoHandleAllocation na;
ASSERT(args.length() == 2);
- // Only JS objects can have properties.
- if (args[0]->IsJSObject()) {
- JSObject* object = JSObject::cast(args[0]);
+ // Only JS receivers can have properties.
+ if (args[0]->IsJSReceiver()) {
+ JSReceiver* receiver = JSReceiver::cast(args[0]);
CONVERT_CHECKED(String, key, args[1]);
- if (object->HasProperty(key)) return isolate->heap()->true_value();
+ if (receiver->HasProperty(key)) return isolate->heap()->true_value();
}
return isolate->heap()->false_value();
}
if (!IS_SPEC_OBJECT(x)) {
throw %MakeTypeError('invalid_in_operator_use', [this, x]);
}
- return %_IsNonNegativeSmi(this) ? %HasElement(x, this) : %HasProperty(x, %ToString(this));
+ return %_IsNonNegativeSmi(this) && !%IsJSProxy(x) ?
+ %HasElement(x, this) : %HasProperty(x, %ToString(this));
}
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// TODO(rossberg): test exception cases.
+
// Getters.
+// Element (in).
+
+var key
+function TestIn(handler) {
+ var o = Proxy.create(handler)
+ assertTrue("a" in o)
+ assertEquals("a", key)
+ assertTrue(99 in o)
+ assertEquals("99", key)
+ assertFalse("z" in o)
+ assertEquals("z", key)
+
+ if ("b" in o) {
+ } else {
+ assertTrue(false)
+ }
+ assertEquals("b", key)
+
+ if ("zz" in o) {
+ assertTrue(false)
+ }
+ assertEquals("zz", key)
+
+ if (!("c" in o)) {
+ assertTrue(false)
+ }
+ assertEquals("c", key)
+
+ if (!("zzz" in o)) {
+ } else {
+ assertTrue(false)
+ }
+ assertEquals("zzz", key)
+}
+
+TestIn({
+ has: function(k) { key = k; return k < "z" }
+})
+TestIn({
+ has: function(k) { return this.has2(k) },
+ has2: function(k) { key = k; return k < "z" }
+})
+TestIn({
+ getPropertyDescriptor: function(k) {
+ key = k; return k < "z" ? {value: 42} : void 0
+ }
+})
+TestIn({
+ getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
+ getPropertyDescriptor2: function(k) {
+ key = k; return k < "z" ? {value: 42} : void 0
+ }
+})
+TestIn({
+ getPropertyDescriptor: function(k) {
+ key = k; return k < "z" ? {get value() { return 42 }} : void 0
+ }
+})
+TestIn({
+ get: undefined,
+ getPropertyDescriptor: function(k) {
+ key = k; return k < "z" ? {value: 42} : void 0
+ }
+})
+
+TestIn(Proxy.create({
+ get: function(pr, pk) {
+ return function(k) { key = k; return k < "z" }
+ }
+}))
+
+
+
// Instanceof (instanceof).
function TestInstanceof() {