Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessors should be kept alive during their invocation #4943

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions jerry-core/ecma/operations/ecma-function-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,55 @@ ecma_op_function_call_bound (ecma_object_t *func_obj_p, /**< Function object */
return ret_value;
} /* ecma_op_function_call_bound */

/**
* Invoke accessor getter function
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_op_invoke_getter (ecma_getter_setter_pointers_t *get_set_pair_p, /**< accessor pair */
ecma_value_t this_value) /**< 'this' argument's value */
{
if (get_set_pair_p->getter_cp == JMEM_CP_NULL)
{
return ECMA_VALUE_UNDEFINED;
}

ecma_object_t *getter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp);
ecma_ref_object (getter_p);

ecma_value_t result = ecma_op_function_call (getter_p, this_value, NULL, 0);
ecma_deref_object (getter_p);

return result;
} /* ecma_op_invoke_getter */

/**
* Invoke accessor setter function
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_op_invoke_setter (ecma_getter_setter_pointers_t *get_set_pair_p, /**< accessor pair */
ecma_value_t this_value, /**< 'this' argument's value */
ecma_value_t value) /**< value to set */
{
if (get_set_pair_p->setter_cp == JMEM_CP_NULL)
{
return ECMA_VALUE_UNDEFINED;
}

ecma_object_t *setter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->setter_cp);
ecma_ref_object (setter_p);

ecma_value_t result = ecma_op_function_call (setter_p, this_value, &value, 1);
ecma_deref_object (setter_p);

return result;
} /* ecma_op_invoke_setter */

/**
* General [[Call]] implementation
*
Expand Down
5 changes: 5 additions & 0 deletions jerry-core/ecma/operations/ecma-function-object.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ ecma_object_t *ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p

ecma_value_t ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value);

ecma_value_t ecma_op_invoke_getter (ecma_getter_setter_pointers_t *get_set_pair_p, ecma_value_t this_value);

ecma_value_t
ecma_op_invoke_setter (ecma_getter_setter_pointers_t *get_set_pair_p, ecma_value_t this_value, ecma_value_t value);

ecma_value_t ecma_op_function_validated_call (ecma_value_t callee,
ecma_value_t this_arg_value,
const ecma_value_t *arguments_list_p,
Expand Down
19 changes: 5 additions & 14 deletions jerry-core/ecma/operations/ecma-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -748,16 +748,7 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */
return ecma_fast_copy_value (prop_value_p->value);
}

ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (prop_value_p);

if (get_set_pair_p->getter_cp == JMEM_CP_NULL)
{
return ECMA_VALUE_UNDEFINED;
}

ecma_object_t *getter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp);

return ecma_op_function_call (getter_p, base_value, NULL, 0);
return ecma_op_invoke_getter (ecma_get_named_accessor_property (prop_value_p), base_value);
} /* ecma_op_object_find_own */

/**
Expand Down Expand Up @@ -1532,6 +1523,7 @@ ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */
}
}

ecma_getter_setter_pointers_t *get_set_pair_p = NULL;
jmem_cpointer_t setter_cp = JMEM_CP_NULL;

if (property_p != NULL)
Expand All @@ -1557,7 +1549,6 @@ ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */
}
else
{
ecma_getter_setter_pointers_t *get_set_pair_p;
get_set_pair_p = ecma_get_named_accessor_property (ECMA_PROPERTY_VALUE_PTR (property_p));
setter_cp = get_set_pair_p->setter_cp;
}
Expand Down Expand Up @@ -1598,7 +1589,8 @@ ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */

if (!(inherited_property & ECMA_PROPERTY_FLAG_DATA))
{
setter_cp = ecma_get_named_accessor_property (property_ref.value_p)->setter_cp;
get_set_pair_p = ecma_get_named_accessor_property (property_ref.value_p);
setter_cp = get_set_pair_p->setter_cp;
create_new_property = false;
break;
}
Expand Down Expand Up @@ -1673,8 +1665,7 @@ ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */
return ecma_raise_readonly_assignment (property_name_p, is_throw);
}

ecma_value_t ret_value =
ecma_op_function_call (ECMA_GET_NON_NULL_POINTER (ecma_object_t, setter_cp), receiver, &value, 1);
ecma_value_t ret_value = ecma_op_invoke_setter (get_set_pair_p, receiver, value);

if (!ECMA_IS_VALUE_ERROR (ret_value))
{
Expand Down
13 changes: 2 additions & 11 deletions jerry-core/ecma/operations/ecma-reference.c
Original file line number Diff line number Diff line change
Expand Up @@ -371,17 +371,8 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical
return ecma_fast_copy_value (prop_value_p->value);
}

ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (prop_value_p);

if (get_set_pair_p->getter_cp == JMEM_CP_NULL)
{
return ECMA_VALUE_UNDEFINED;
}

ecma_object_t *getter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp);

ecma_value_t base_value = ecma_make_object_value (binding_obj_p);
return ecma_op_function_call (getter_p, base_value, NULL, 0);
return ecma_op_invoke_getter (ecma_get_named_accessor_property (prop_value_p),
ecma_make_object_value (binding_obj_p));
}
#endif /* JERRY_LCACHE */
}
Expand Down
7 changes: 2 additions & 5 deletions jerry-core/vm/opcodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1429,9 +1429,7 @@ opfunc_private_set (ecma_value_t base, /**< this object */
return ecma_raise_type_error (ECMA_ERR_PRIVATE_FIELD_WAS_DEFINED_WITHOUT_A_SETTER);
}

ecma_object_t *setter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->setter_cp);

return ecma_op_function_call (setter_p, base, &value, 1);
return ecma_op_invoke_setter (get_set_pair_p, base, value);
} /* opfunc_private_set */

/**
Expand Down Expand Up @@ -1479,8 +1477,7 @@ opfunc_private_get (ecma_value_t base, /**< this object */
}
else
{
ecma_object_t *getter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp);
result = ecma_op_function_call (getter_p, base, NULL, 0);
result = ecma_op_invoke_getter (get_set_pair_p, base);
}
}

Expand Down
41 changes: 41 additions & 0 deletions tests/jerry/es.next/regression-test-issue-4900.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// 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.

function assertArrayEqual(actual, expected) {
assert(actual.length === expected.length);

for (var i = 0; i < actual.length; i++) {
assert(actual[i] === expected[i]);
}
}

var i = 0;
var a = [];
var JSEtest = [];

JSEtest.__defineGetter__(0, function NaN() {
if (i++ > 2) {
return;
}

JSEtest.shift();
gc();
a.push(0);
a.concat(JSEtest);
});

JSEtest[0];

assertArrayEqual(a, [0, 0, 0]);
assertArrayEqual(JSEtest, []);