From 9261a722c999e9f8b07cb9f7ac70c7d9c62dac07 Mon Sep 17 00:00:00 2001 From: Michael Anthony Leon Date: Thu, 11 Nov 2021 18:48:30 -0800 Subject: [PATCH] Implement Object.hasOwn Summary: Implement `hasOwn` according to the language specs [here](https://tc39.es/proposal-accessible-object-hasownproperty/). Reviewed By: avp Differential Revision: D32287266 fbshipit-source-id: 22a8520adfa09a193696a68459c475005a29b752 --- include/hermes/VM/NativeFunctions.def | 1 + include/hermes/VM/PredefinedStrings.def | 1 + lib/VM/JSLib/Object.cpp | 64 ++++++++++++++++++------- test/hermes/object-functions.js | 33 +++++++++++++ 4 files changed, 81 insertions(+), 18 deletions(-) diff --git a/include/hermes/VM/NativeFunctions.def b/include/hermes/VM/NativeFunctions.def index 2716f7feaa9..68cc54e5b0e 100644 --- a/include/hermes/VM/NativeFunctions.def +++ b/include/hermes/VM/NativeFunctions.def @@ -203,6 +203,7 @@ NATIVE_FUNCTION(objectGetOwnPropertyDescriptors) NATIVE_FUNCTION(objectGetOwnPropertyNames) NATIVE_FUNCTION(objectGetOwnPropertySymbols) NATIVE_FUNCTION(objectGetPrototypeOf) +NATIVE_FUNCTION(objectHasOwn) NATIVE_FUNCTION(objectIs) NATIVE_FUNCTION(objectIsExtensible) NATIVE_FUNCTION(objectIsFrozen) diff --git a/include/hermes/VM/PredefinedStrings.def b/include/hermes/VM/PredefinedStrings.def index ee7b3683889..23cb244ce1f 100644 --- a/include/hermes/VM/PredefinedStrings.def +++ b/include/hermes/VM/PredefinedStrings.def @@ -31,6 +31,7 @@ STR(toString, "toString") STR(description, "description") STR(toLocaleString, "toLocaleString") STR(hasOwnProperty, "hasOwnProperty") +STR(hasOwn, "hasOwn") STR(isPrototypeOf, "isPrototypeOf") STR(propertyIsEnumerable, "propertyIsEnumerable") STR(valueOf, "valueOf") diff --git a/lib/VM/JSLib/Object.cpp b/lib/VM/JSLib/Object.cpp index 263e04b3a31..4c3862142f6 100644 --- a/lib/VM/JSLib/Object.cpp +++ b/lib/VM/JSLib/Object.cpp @@ -160,6 +160,13 @@ Handle createObjectConstructor(Runtime *runtime) { ctx, objectGetOwnPropertySymbols, 1); + defineMethod( + runtime, + cons, + Predefined::getSymbolID(Predefined::hasOwn), + ctx, + objectHasOwn, + 1); defineMethod( runtime, cons, @@ -1262,24 +1269,8 @@ objectPrototypeValueOf(void *, Runtime *runtime, NativeArgs args) { return res; } -/// ES11.0 19.1.3.2 -CallResult -objectPrototypeHasOwnProperty(void *, Runtime *runtime, NativeArgs args) { - /// 1. Let P be ? ToPropertyKey(V). - auto PRes = toPropertyKey(runtime, args.getArgHandle(0)); - if (LLVM_UNLIKELY(PRes == ExecutionStatus::EXCEPTION)) { - return ExecutionStatus::EXCEPTION; - } - Handle<> P = *PRes; - - /// 2. Let O be ? ToObject(this value). - auto ORes = toObject(runtime, args.getThisHandle()); - if (LLVM_UNLIKELY(ORes == ExecutionStatus::EXCEPTION)) { - return ExecutionStatus::EXCEPTION; - } - Handle O = runtime->makeHandle(ORes.getValue()); - - /// 3. Return ? HasOwnProperty(O, P). +static CallResult +objectHasOwnHelper(Runtime *runtime, Handle O, Handle<> P) { ComputedPropertyDescriptor desc; MutableHandle tmpPropNameStorage{runtime}; CallResult hasProp = JSObject::getOwnComputedDescriptor( @@ -1306,6 +1297,43 @@ objectPrototypeHasOwnProperty(void *, Runtime *runtime, NativeArgs args) { return HermesValue::encodeBoolValue(false); } +/// ES11.0 19.1.3.2 +CallResult +objectPrototypeHasOwnProperty(void *, Runtime *runtime, NativeArgs args) { + /// 1. Let P be ? ToPropertyKey(V). + auto PRes = toPropertyKey(runtime, args.getArgHandle(0)); + if (LLVM_UNLIKELY(PRes == ExecutionStatus::EXCEPTION)) { + return ExecutionStatus::EXCEPTION; + } + + /// 2. Let O be ? ToObject(this value). + auto ORes = toObject(runtime, args.getThisHandle()); + if (LLVM_UNLIKELY(ORes == ExecutionStatus::EXCEPTION)) { + return ExecutionStatus::EXCEPTION; + } + /// 3. Return ? HasOwnProperty(O, P). + Handle O = runtime->makeHandle(ORes.getValue()); + return objectHasOwnHelper(runtime, O, *PRes); +} + +CallResult +objectHasOwn(void *, Runtime *runtime, NativeArgs args) { + /// 1. Let O be ? ToObject(O). + auto ORes = toObject(runtime, args.getArgHandle(0)); + if (LLVM_UNLIKELY(ORes == ExecutionStatus::EXCEPTION)) { + return ExecutionStatus::EXCEPTION; + } + Handle O = runtime->makeHandle(ORes.getValue()); + + /// 2. Let P be ? ToPropertyKey(P). + auto PRes = toPropertyKey(runtime, args.getArgHandle(1)); + if (LLVM_UNLIKELY(PRes == ExecutionStatus::EXCEPTION)) { + return ExecutionStatus::EXCEPTION; + } + /// 3. Return ? HasOwnProperty(O, P). + return objectHasOwnHelper(runtime, O, *PRes); +} + CallResult objectPrototypeIsPrototypeOf(void *, Runtime *runtime, NativeArgs args) { if (LLVM_UNLIKELY(!args.getArg(0).isObject())) { diff --git a/test/hermes/object-functions.js b/test/hermes/object-functions.js index 55a82ab7562..a3615c74aa6 100644 --- a/test/hermes/object-functions.js +++ b/test/hermes/object-functions.js @@ -175,6 +175,39 @@ try { } //CHECK: to_prim +print('hasOwn'); +// CHECK-LABEL: hasOwn +var obj = new Object(); +obj.prop = 'exists'; + +function changeO() { + obj.newprop = obj.prop; + delete obj.prop; +} + +print(Object.hasOwn(obj, 'prop')); +//CHECK: true +changeO(); +print(Object.hasOwn(obj, 'prop')); +//CHECK: false +print(Object.hasOwn(obj, 'newprop')); +//CHECK: true +print(Object.hasOwn(obj, 'new' + 'prop')); +//CHECK: true +obj[5] = 'exists'; +print(Object.hasOwn(obj, 5)); +//CHECK: true +print(Object.hasOwn([1, 2], 0)); +//CHECK: true +print(Object.hasOwn([1, 2], 2)); +//CHECK: false + +var child = Object.create(obj); +print(Object.hasOwn(child, 'newprop')); +//CHECK: false +print(Object.hasOwn(child, 5)); +//CHECK: false + print('defineProperties'); // CHECK-LABEL: defineProperties var a = [];