From 1937f820e19ee3bc42ab051c95e06f6bed0af1f9 Mon Sep 17 00:00:00 2001 From: kisbg Date: Thu, 17 Dec 2020 09:44:59 +0100 Subject: [PATCH] Added new target support to Boolean, String, Number Object (#4368) JerryScript-DCO-1.0-Signed-off-by: bence gabor kis kisbg@inf.u-szeged.hu --- .../ecma/operations/ecma-boolean-object.c | 28 +++++++++++- jerry-core/ecma/operations/ecma-conversion.c | 44 ++++++++++++++++--- jerry-core/ecma/operations/ecma-conversion.h | 4 ++ .../ecma/operations/ecma-number-object.c | 27 ++++++++++-- .../ecma/operations/ecma-string-object.c | 26 +++++++++-- tests/jerry/es.next/new-target-for-boolean.js | 31 +++++++++++++ tests/jerry/es.next/new-target-for-number.js | 32 ++++++++++++++ tests/jerry/es.next/new-target-for-string.js | 33 ++++++++++++++ tests/test262-esnext-excludelist.xml | 3 -- 9 files changed, 211 insertions(+), 17 deletions(-) create mode 100644 tests/jerry/es.next/new-target-for-boolean.js create mode 100644 tests/jerry/es.next/new-target-for-number.js create mode 100644 tests/jerry/es.next/new-target-for-string.js diff --git a/jerry-core/ecma/operations/ecma-boolean-object.c b/jerry-core/ecma/operations/ecma-boolean-object.c index 469d26f91..bdbea39e2 100644 --- a/jerry-core/ecma/operations/ecma-boolean-object.c +++ b/jerry-core/ecma/operations/ecma-boolean-object.c @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "jcontext.h" #include "ecma-alloc.h" #include "ecma-boolean-object.h" #include "ecma-builtins.h" @@ -22,6 +23,7 @@ #include "ecma-helpers.h" #include "ecma-objects.h" #include "ecma-objects-general.h" +#include "ecma-function-object.h" /** \addtogroup ecma ECMA * @{ @@ -42,13 +44,28 @@ ecma_value_t ecma_op_create_boolean_object (ecma_value_t arg) /**< argument passed to the Boolean constructor */ { bool boolean_value = ecma_op_to_boolean (arg); + ecma_builtin_id_t proto_id; #if ENABLED (JERRY_BUILTIN_BOOLEAN) - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE); + proto_id = ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE; #else /* ENABLED (JERRY_BUILTIN_BOOLEAN) */ - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); + proto_id = ECMA_BUILTIN_ID_OBJECT_PROTOTYPE; #endif /* !(ENABLED (JERRY_BUILTIN_BOOLEAN) */ + ecma_object_t *prototype_obj_p = ecma_builtin_get (proto_id); + +#if ENABLED (JERRY_ESNEXT) + ecma_object_t *new_target = JERRY_CONTEXT (current_new_target); + if (new_target) + { + prototype_obj_p = ecma_op_get_prototype_from_constructor (new_target, proto_id); + + if (JERRY_UNLIKELY (prototype_obj_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + } +#endif /* ENABLED (JERRY_ESNEXT) */ ecma_object_t *object_p = ecma_create_object (prototype_obj_p, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS); @@ -57,6 +74,13 @@ ecma_op_create_boolean_object (ecma_value_t arg) /**< argument passed to the Boo ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_BOOLEAN_UL; ext_object_p->u.class_prop.u.value = ecma_make_boolean_value (boolean_value); +#if ENABLED (JERRY_ESNEXT) + if (new_target) + { + ecma_deref_object (prototype_obj_p); + } +#endif /* ENABLED (JERRY_ESNEXT) */ + return ecma_make_object_value (object_p); } /* ecma_op_create_boolean_object */ diff --git a/jerry-core/ecma/operations/ecma-conversion.c b/jerry-core/ecma/operations/ecma-conversion.c index 5e945e408..ed7135fec 100644 --- a/jerry-core/ecma/operations/ecma-conversion.c +++ b/jerry-core/ecma/operations/ecma-conversion.c @@ -531,14 +531,22 @@ ecma_value_t ecma_op_to_object (ecma_value_t value) /**< ecma value */ { ecma_check_value_type_is_spec_defined (value); + ecma_builtin_id_t proto_id = ECMA_BUILTIN_ID_OBJECT_PROTOTYPE; + uint16_t lit_id; if (ecma_is_value_number (value)) { - return ecma_op_create_number_object (value); +#if ENABLED (JERRY_BUILTIN_NUMBER) + proto_id = ECMA_BUILTIN_ID_NUMBER_PROTOTYPE; +#endif /* ENABLED (JERRY_BUILTIN_NUMBER) */ + lit_id = LIT_MAGIC_STRING_NUMBER_UL; } else if (ecma_is_value_string (value)) { - return ecma_op_create_string_object (&value, 1); +#if ENABLED (JERRY_BUILTIN_STRING) + proto_id = ECMA_BUILTIN_ID_STRING_PROTOTYPE; +#endif /* ENABLED (JERRY_BUILTIN_STRING) */ + lit_id = LIT_MAGIC_STRING_STRING_UL; } else if (ecma_is_value_object (value)) { @@ -547,7 +555,8 @@ ecma_op_to_object (ecma_value_t value) /**< ecma value */ #if ENABLED (JERRY_ESNEXT) else if (ecma_is_value_symbol (value)) { - return ecma_op_create_symbol_object (value); + proto_id = ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE; + lit_id = LIT_MAGIC_STRING_SYMBOL_UL; } #endif /* ENABLED (JERRY_ESNEXT) */ #if ENABLED (JERRY_BUILTIN_BIGINT) @@ -566,12 +575,37 @@ ecma_op_to_object (ecma_value_t value) /**< ecma value */ else { JERRY_ASSERT (ecma_is_value_boolean (value)); - - return ecma_op_create_boolean_object (value); +#if ENABLED (JERRY_BUILTIN_BOOLEAN) + proto_id = ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE; +#endif /* ENABLED (JERRY_BUILTIN_BOOLEAN) */ + lit_id = LIT_MAGIC_STRING_BOOLEAN_UL; } } + + return ecma_op_create_class_object (proto_id, value, lit_id); } /* ecma_op_to_object */ +/** + * Create a ECMA_OBJECT_TYPE_CLASS object from the given arguments. + * + * @return ecma_value - constructed object + */ +ecma_value_t +ecma_op_create_class_object (ecma_builtin_id_t proto_id, /**< prototype id */ + ecma_value_t value, /**< ecma value */ + uint16_t class_id) /**< magic string id */ +{ + ecma_object_t *object_p = ecma_create_object (ecma_builtin_get (proto_id), + sizeof (ecma_extended_object_t), + ECMA_OBJECT_TYPE_CLASS); + + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + ext_object_p->u.class_prop.class_id = class_id; + ext_object_p->u.class_prop.u.value = ecma_copy_value_if_not_object (value); + + return ecma_make_object_value (object_p); +} /* ecma_op_create_class_object */ + /** * FromPropertyDescriptor operation. * diff --git a/jerry-core/ecma/operations/ecma-conversion.h b/jerry-core/ecma/operations/ecma-conversion.h index 1a53da34c..32de03757 100644 --- a/jerry-core/ecma/operations/ecma-conversion.h +++ b/jerry-core/ecma/operations/ecma-conversion.h @@ -18,6 +18,7 @@ #include "ecma-globals.h" #include "ecma-helpers.h" +#include "ecma-builtins.h" /** \addtogroup ecma ECMA * @{ @@ -59,6 +60,9 @@ ecma_string_t *ecma_op_to_string (ecma_value_t value); ecma_string_t *ecma_op_to_property_key (ecma_value_t value); ecma_value_t ecma_op_to_object (ecma_value_t value); bool ecma_op_is_integer (ecma_number_t value); +ecma_value_t ecma_op_create_class_object (ecma_builtin_id_t proto_id, + ecma_value_t value, + uint16_t lit_id); ecma_value_t ecma_op_to_integer (ecma_value_t value, ecma_number_t *number_p); ecma_value_t ecma_op_to_length (ecma_value_t value, ecma_length_t *length); #if ENABLED (JERRY_ESNEXT) diff --git a/jerry-core/ecma/operations/ecma-number-object.c b/jerry-core/ecma/operations/ecma-number-object.c index 6bd76981b..4bd79068c 100644 --- a/jerry-core/ecma/operations/ecma-number-object.c +++ b/jerry-core/ecma/operations/ecma-number-object.c @@ -22,6 +22,8 @@ #include "ecma-number-object.h" #include "ecma-objects.h" #include "ecma-objects-general.h" +#include "ecma-function-object.h" +#include "jcontext.h" /** \addtogroup ecma ECMA * @{ @@ -50,12 +52,24 @@ ecma_op_create_number_object (ecma_value_t arg) /**< argument passed to the Numb } conv_to_num_completion = ecma_make_number_value (num); + ecma_builtin_id_t proto_id; #if ENABLED (JERRY_BUILTIN_NUMBER) - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_NUMBER_PROTOTYPE); + proto_id = ECMA_BUILTIN_ID_NUMBER_PROTOTYPE; #else /* ENABLED (JERRY_BUILTIN_NUMBER) */ - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); + proto_id = ECMA_BUILTIN_ID_OBJECT_PROTOTYPE; #endif /* ENABLED (JERRY_BUILTIN_NUMBER) */ - + ecma_object_t *prototype_obj_p = ecma_builtin_get (proto_id); +#if ENABLED (JERRY_ESNEXT) + ecma_object_t *new_target = JERRY_CONTEXT (current_new_target); + if (new_target) + { + prototype_obj_p = ecma_op_get_prototype_from_constructor (new_target, proto_id); + if (JERRY_UNLIKELY (prototype_obj_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + } +#endif /* ENABLED (JERRY_ESNEXT) */ ecma_object_t *object_p = ecma_create_object (prototype_obj_p, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS); @@ -65,7 +79,12 @@ ecma_op_create_number_object (ecma_value_t arg) /**< argument passed to the Numb /* Pass reference (no need to free conv_to_num_completion). */ ext_object_p->u.class_prop.u.value = conv_to_num_completion; - +#if ENABLED (JERRY_ESNEXT) + if (new_target) + { + ecma_deref_object (prototype_obj_p); + } +#endif /* ENABLED (JERRY_ESNEXT) */ return ecma_make_object_value (object_p); } /* ecma_op_create_number_object */ diff --git a/jerry-core/ecma/operations/ecma-string-object.c b/jerry-core/ecma/operations/ecma-string-object.c index 141435a22..a6b263d0a 100644 --- a/jerry-core/ecma/operations/ecma-string-object.c +++ b/jerry-core/ecma/operations/ecma-string-object.c @@ -22,6 +22,8 @@ #include "ecma-objects.h" #include "ecma-objects-general.h" #include "ecma-string-object.h" +#include "ecma-function-object.h" +#include "jcontext.h" /** \addtogroup ecma ECMA * @{ @@ -60,12 +62,24 @@ ecma_op_create_string_object (const ecma_value_t *arguments_list_p, /**< list of prim_value = ecma_make_string_value (str_p); } + ecma_builtin_id_t proto_id; #if ENABLED (JERRY_BUILTIN_STRING) - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_STRING_PROTOTYPE); + proto_id = ECMA_BUILTIN_ID_STRING_PROTOTYPE; #else /* !ENABLED (JERRY_BUILTIN_STRING) */ - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); + proto_id = ECMA_BUILTIN_ID_OBJECT_PROTOTYPE; #endif /* ENABLED (JERRY_BUILTIN_STRING) */ - + ecma_object_t *prototype_obj_p = ecma_builtin_get (proto_id); +#if ENABLED (JERRY_ESNEXT) + ecma_object_t *new_target = JERRY_CONTEXT (current_new_target); + if (new_target) + { + prototype_obj_p = ecma_op_get_prototype_from_constructor (new_target, proto_id); + if (JERRY_UNLIKELY (prototype_obj_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + } +#endif /* ENABLED (JERRY_ESNEXT) */ ecma_object_t *object_p = ecma_create_object (prototype_obj_p, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS); @@ -74,6 +88,12 @@ ecma_op_create_string_object (const ecma_value_t *arguments_list_p, /**< list of ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_STRING_UL; ext_object_p->u.class_prop.u.value = prim_value; +#if ENABLED (JERRY_ESNEXT) + if (new_target) + { + ecma_deref_object (prototype_obj_p); + } +#endif /* ENABLED (JERRY_ESNEXT) */ return ecma_make_object_value (object_p); } /* ecma_op_create_string_object */ diff --git a/tests/jerry/es.next/new-target-for-boolean.js b/tests/jerry/es.next/new-target-for-boolean.js new file mode 100644 index 000000000..89fc94502 --- /dev/null +++ b/tests/jerry/es.next/new-target-for-boolean.js @@ -0,0 +1,31 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + Reflect.construct (Boolean, true); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.construct (Boolean, false); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +class MyBoolean extends Boolean {}; +var b1= new MyBoolean(); +assert(Object.getPrototypeOf(b1) == MyBoolean.prototype) diff --git a/tests/jerry/es.next/new-target-for-number.js b/tests/jerry/es.next/new-target-for-number.js new file mode 100644 index 000000000..23fe5f035 --- /dev/null +++ b/tests/jerry/es.next/new-target-for-number.js @@ -0,0 +1,32 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + Reflect.construct (Number); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.construct (Number, 1); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +class MyNumber extends Number {}; +var n1= new MyNumber(); + +assert(Object.getPrototypeOf(n1) == MyNumber.prototype) diff --git a/tests/jerry/es.next/new-target-for-string.js b/tests/jerry/es.next/new-target-for-string.js new file mode 100644 index 000000000..c75b2de20 --- /dev/null +++ b/tests/jerry/es.next/new-target-for-string.js @@ -0,0 +1,33 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + try { + Reflect.construct (String, ""); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + Reflect.construct (String, "randomText"); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +class MyString extends String {}; +var s1= new MyString(); + +assert(Object.getPrototypeOf(s1) == MyString.prototype) diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index 298306eb1..79e486dc0 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -9641,7 +9641,6 @@ - @@ -9656,7 +9655,6 @@ - @@ -9668,7 +9666,6 @@ -