Correctly enumerate function property members.

Functions has several built-in non-enumerable properties, and
they are correctly ignored during enumeration after this patch.

External function prototype is also lazy enumerated.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg 2017-09-01 04:26:35 -07:00 committed by yichoi
parent 7905422b19
commit 522c7d3f87
4 changed files with 347 additions and 162 deletions

View File

@ -142,125 +142,6 @@ ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */
return func_p;
} /* ecma_op_create_function_object */
/**
* List names of a Function object's lazy instantiated properties,
* adding them to corresponding string collections
*
* See also:
* ecma_op_function_try_to_lazy_instantiate_property
*/
void
ecma_op_function_list_lazy_property_names (bool separate_enumerable, /**< true - list enumerable properties into
* main collection and non-enumerable
* to collection of 'skipped
* non-enumerable' properties,
* false - list all properties into main
* collection.
*/
ecma_collection_header_t *main_collection_p, /**< 'main' collection */
ecma_collection_header_t *non_enum_collection_p) /**< skipped
* 'non-enumerable'
* collection */
{
ecma_collection_header_t *for_enumerable_p = main_collection_p;
JERRY_UNUSED (for_enumerable_p);
ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p;
ecma_string_t *name_p;
/* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */
name_p = ecma_new_ecma_length_string ();
ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true);
ecma_deref_ecma_string (name_p);
/* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */
name_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE);
ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true);
ecma_deref_ecma_string (name_p);
} /* ecma_op_function_list_lazy_property_names */
/**
* Lazy instantation of non-builtin ecma function object's properties
*
* Warning:
* Only non-configurable properties could be instantiated lazily in this function,
* as configurable properties could be deleted and it would be incorrect
* to reinstantiate them in the function in second time.
*
* @return pointer to newly instantiated property, if a property was instantiated,
* NULL - otherwise
*/
ecma_property_t *
ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< the function object */
ecma_string_t *property_name_p) /**< property name */
{
JERRY_ASSERT (!ecma_get_object_is_builtin (object_p));
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_PROTOTYPE))
{
/* ECMA-262 v5, 13.2, 16-18 */
/* 16. */
ecma_object_t *proto_object_p = ecma_op_create_object_object_noarg ();
/* 17. */
ecma_string_t magic_string_constructor;
ecma_init_ecma_magic_string (&magic_string_constructor, LIT_MAGIC_STRING_CONSTRUCTOR);
ecma_property_value_t *constructor_prop_value_p;
constructor_prop_value_p = ecma_create_named_data_property (proto_object_p,
&magic_string_constructor,
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
NULL);
constructor_prop_value_p->value = ecma_make_object_value (object_p);
/* 18. */
ecma_property_t *prototype_prop_p;
ecma_property_value_t *prototype_prop_value_p;
prototype_prop_value_p = ecma_create_named_data_property (object_p,
property_name_p,
ECMA_PROPERTY_FLAG_WRITABLE,
&prototype_prop_p);
prototype_prop_value_p->value = ecma_make_object_value (proto_object_p);
ecma_deref_object (proto_object_p);
return prototype_prop_p;
}
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_CALLER)
|| ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_ARGUMENTS))
{
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
const ecma_compiled_code_t *bytecode_data_p;
bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t,
ext_func_p->u.function.bytecode_cp);
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE)
{
ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);
ecma_property_t *caller_prop_p;
/* The property_name_p argument contans the name. */
ecma_create_named_accessor_property (object_p,
property_name_p,
thrower_p,
thrower_p,
ECMA_PROPERTY_FIXED,
&caller_prop_p);
ecma_deref_object (thrower_p);
return caller_prop_p;
}
}
return NULL;
} /* ecma_op_function_try_to_lazy_instantiate_property */
/**
* External function object creation operation.
*
@ -291,17 +172,6 @@ ecma_op_create_external_function_object (ecma_external_handler_t handler_cb) /**
ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) function_obj_p;
ext_func_obj_p->u.external_handler_cb = handler_cb;
ecma_string_t *magic_string_prototype_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE);
ecma_builtin_helper_def_prop (function_obj_p,
magic_string_prototype_p,
ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED),
true, /* Writable */
false, /* Enumerable */
false, /* Configurable */
false); /* Failure handling */
ecma_deref_ecma_string (magic_string_prototype_p);
return function_obj_p;
} /* ecma_op_create_external_function_object */
@ -757,6 +627,118 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
return ret_value;
} /* ecma_op_function_construct */
/**
* Lazy instantation of non-builtin ecma function object's properties
*
* Warning:
* Only non-configurable properties could be instantiated lazily in this function,
* as configurable properties could be deleted and it would be incorrect
* to reinstantiate them in the function in second time.
*
* @return pointer to newly instantiated property, if a property was instantiated,
* NULL - otherwise
*/
ecma_property_t *
ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< the function object */
ecma_string_t *property_name_p) /**< property name */
{
JERRY_ASSERT (!ecma_get_object_is_builtin (object_p));
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_PROTOTYPE))
{
/* ECMA-262 v5, 13.2, 16-18 */
/* 16. */
ecma_object_t *proto_object_p = ecma_op_create_object_object_noarg ();
/* 17. */
ecma_string_t magic_string_constructor;
ecma_init_ecma_magic_string (&magic_string_constructor, LIT_MAGIC_STRING_CONSTRUCTOR);
ecma_property_value_t *constructor_prop_value_p;
constructor_prop_value_p = ecma_create_named_data_property (proto_object_p,
&magic_string_constructor,
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
NULL);
constructor_prop_value_p->value = ecma_make_object_value (object_p);
/* 18. */
ecma_property_t *prototype_prop_p;
ecma_property_value_t *prototype_prop_value_p;
prototype_prop_value_p = ecma_create_named_data_property (object_p,
property_name_p,
ECMA_PROPERTY_FLAG_WRITABLE,
&prototype_prop_p);
prototype_prop_value_p->value = ecma_make_object_value (proto_object_p);
ecma_deref_object (proto_object_p);
return prototype_prop_p;
}
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_CALLER)
|| ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_ARGUMENTS))
{
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
const ecma_compiled_code_t *bytecode_data_p;
bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t,
ext_func_p->u.function.bytecode_cp);
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE)
{
ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);
ecma_property_t *caller_prop_p;
/* The property_name_p argument contans the name. */
ecma_create_named_accessor_property (object_p,
property_name_p,
thrower_p,
thrower_p,
ECMA_PROPERTY_FIXED,
&caller_prop_p);
ecma_deref_object (thrower_p);
return caller_prop_p;
}
}
return NULL;
} /* ecma_op_function_try_to_lazy_instantiate_property */
/**
* Create specification defined non-configurable properties for external functions.
*
* See also:
* ECMA-262 v5, 15.3.4.5
*
* @return pointer property, if one was instantiated,
* NULL - otherwise.
*/
ecma_property_t *
ecma_op_external_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< object */
ecma_string_t *property_name_p) /**< property's name */
{
JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_PROTOTYPE))
{
ecma_property_t *prototype_prop_p;
ecma_property_value_t *prototype_prop_value_p;
prototype_prop_value_p = ecma_create_named_data_property (object_p,
property_name_p,
ECMA_PROPERTY_FLAG_WRITABLE,
&prototype_prop_p);
prototype_prop_value_p->value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
return prototype_prop_p;
}
return NULL;
} /* ecma_op_external_function_try_to_lazy_instantiate_property */
/**
* Create specification defined non-configurable properties for bound functions.
*
@ -836,6 +818,134 @@ ecma_op_bound_function_try_to_lazy_instantiate_property (ecma_object_t *object_p
return NULL;
} /* ecma_op_bound_function_try_to_lazy_instantiate_property */
/**
* List names of a Function object's lazy instantiated properties,
* adding them to corresponding string collections
*
* See also:
* ecma_op_function_try_to_lazy_instantiate_property
*/
void
ecma_op_function_list_lazy_property_names (ecma_object_t *object_p, /**< functionobject */
bool separate_enumerable, /**< true - list enumerable properties into
* main collection and non-enumerable
* to collection of 'skipped
* non-enumerable' properties,
* false - list all properties into main
* collection.
*/
ecma_collection_header_t *main_collection_p, /**< 'main' collection */
ecma_collection_header_t *non_enum_collection_p) /**< skipped
* 'non-enumerable'
* collection */
{
JERRY_UNUSED (main_collection_p);
ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p;
/* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */
ecma_string_t *name_p = ecma_new_ecma_length_string ();
ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true);
ecma_deref_ecma_string (name_p);
/* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */
name_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE);
ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true);
ecma_deref_ecma_string (name_p);
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
const ecma_compiled_code_t *bytecode_data_p;
bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t,
ext_func_p->u.function.bytecode_cp);
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE)
{
/* 'caller' property is non-enumerable (ECMA-262 v5, 13.2.5) */
name_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER);
ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true);
ecma_deref_ecma_string (name_p);
/* 'arguments' property is non-enumerable (ECMA-262 v5, 13.2.5) */
name_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true);
ecma_deref_ecma_string (name_p);
}
} /* ecma_op_function_list_lazy_property_names */
/**
* List names of an External Function object's lazy instantiated properties,
* adding them to corresponding string collections
*
* See also:
* ecma_op_external_function_try_to_lazy_instantiate_property
*/
void
ecma_op_external_function_list_lazy_property_names (bool separate_enumerable, /**< true - list enumerable properties
* into main collection and
* non-enumerable to collection
* of 'skipped non-enumerable'
* properties,
* false - list all properties into
* main collection.
*/
ecma_collection_header_t *main_collection_p, /**< 'main'
* collection */
ecma_collection_header_t *non_enum_collection_p) /**< skipped
* collection */
{
JERRY_UNUSED (main_collection_p);
ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p;
/* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */
ecma_string_t *name_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE);
ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true);
ecma_deref_ecma_string (name_p);
} /* ecma_op_external_function_list_lazy_property_names */
/**
* List names of a Bound Function object's lazy instantiated properties,
* adding them to corresponding string collections
*
* See also:
* ecma_op_bound_function_try_to_lazy_instantiate_property
*/
void
ecma_op_bound_function_list_lazy_property_names (bool separate_enumerable, /**< true - list enumerable properties
* into main collection and
* non-enumerable to collection
* of 'skipped non-enumerable'
* properties,
* false - list all properties into
* main collection.
*/
ecma_collection_header_t *main_collection_p, /**< 'main'
* collection */
ecma_collection_header_t *non_enum_collection_p) /**< skipped
* 'non-enumerable'
* collection */
{
JERRY_UNUSED (main_collection_p);
ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p;
/* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */
ecma_string_t *name_p = ecma_new_ecma_length_string ();
ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true);
ecma_deref_ecma_string (name_p);
/* 'caller' property is non-enumerable (ECMA-262 v5, 13.2.5) */
name_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER);
ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true);
ecma_deref_ecma_string (name_p);
/* 'arguments' property is non-enumerable (ECMA-262 v5, 13.2.5) */
name_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true);
ecma_deref_ecma_string (name_p);
} /* ecma_op_bound_function_list_lazy_property_names */
/**
* @}
* @}

View File

@ -32,14 +32,6 @@ bool ecma_is_constructor (ecma_value_t value);
ecma_object_t *
ecma_op_create_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p);
void
ecma_op_function_list_lazy_property_names (bool separate_enumerable,
ecma_collection_header_t *main_collection_p,
ecma_collection_header_t *non_enum_collection_p);
ecma_property_t *
ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p);
ecma_object_t *
ecma_op_create_external_function_object (ecma_external_handler_t handler_cb);
@ -54,9 +46,31 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, const ecma_value_t *argum
ecma_value_t
ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value);
ecma_property_t *
ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p);
ecma_property_t *
ecma_op_external_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p);
ecma_property_t *
ecma_op_bound_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p);
void
ecma_op_function_list_lazy_property_names (ecma_object_t *object_p,
bool separate_enumerable,
ecma_collection_header_t *main_collection_p,
ecma_collection_header_t *non_enum_collection_p);
void
ecma_op_external_function_list_lazy_property_names (bool separate_enumerable,
ecma_collection_header_t *main_collection_p,
ecma_collection_header_t *non_enum_collection_p);
void
ecma_op_bound_function_list_lazy_property_names (bool separate_enumerable,
ecma_collection_header_t *main_collection_p,
ecma_collection_header_t *non_enum_collection_p);
/**
* @}
* @}

View File

@ -233,6 +233,10 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */
/* Get prototype physical property. */
property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p);
}
else if (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)
{
property_p = ecma_op_external_function_try_to_lazy_instantiate_property (object_p, property_name_p);
}
else if (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
{
property_p = ecma_op_bound_function_try_to_lazy_instantiate_property (object_p, property_name_p);
@ -535,6 +539,10 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */
/* Get prototype physical property. */
property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p);
}
else if (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)
{
property_p = ecma_op_external_function_try_to_lazy_instantiate_property (object_p, property_name_p);
}
else if (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
{
property_p = ecma_op_bound_function_try_to_lazy_instantiate_property (object_p, property_name_p);
@ -826,6 +834,10 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */
/* Get prototype physical property. */
property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p);
}
else if (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)
{
property_p = ecma_op_external_function_try_to_lazy_instantiate_property (object_p, property_name_p);
}
else if (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
{
property_p = ecma_op_bound_function_try_to_lazy_instantiate_property (object_p, property_name_p);
@ -1361,8 +1373,6 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */
switch (type)
{
case ECMA_OBJECT_TYPE_GENERAL:
case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION:
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{
break;
}
@ -1378,11 +1388,26 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */
}
case ECMA_OBJECT_TYPE_FUNCTION:
{
ecma_op_function_list_lazy_property_names (is_enumerable_only,
ecma_op_function_list_lazy_property_names (obj_p,
is_enumerable_only,
prop_names_p,
skipped_non_enumerable_p);
break;
}
case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION:
{
ecma_op_external_function_list_lazy_property_names (is_enumerable_only,
prop_names_p,
skipped_non_enumerable_p);
break;
}
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{
ecma_op_bound_function_list_lazy_property_names (is_enumerable_only,
prop_names_p,
skipped_non_enumerable_p);
break;
}
case ECMA_OBJECT_TYPE_CLASS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
@ -1504,15 +1529,6 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */
ecma_append_to_values_collection (skipped_non_enumerable_p,
ecma_make_string_value (name_p),
true);
uint8_t hash = (uint8_t) name_p->hash;
uint32_t bitmap_row = (uint32_t) (hash / bitmap_row_size);
uint32_t bitmap_column = (uint32_t) (hash % bitmap_row_size);
if ((names_hashes_bitmap[bitmap_row] & (1u << bitmap_column)) == 0)
{
names_hashes_bitmap[bitmap_row] |= (1u << bitmap_column);
}
}
ecma_deref_ecma_string (name_p);
@ -1541,7 +1557,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */
}
}
/* Second pass: collecting properties names into arrays */
/* Second pass: collecting property names into arrays. */
JMEM_DEFINE_LOCAL_ARRAY (names_p,
array_index_named_properties_count + string_named_properties_count,
ecma_string_t *);
@ -1622,7 +1638,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */
i < array_index_named_properties_count + string_named_properties_count;
i++)
{
bool is_append;
bool is_append = true;
ecma_string_t *name_p = names_p[i];
@ -1632,16 +1648,12 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */
if ((names_hashes_bitmap[bitmap_row] & (1u << bitmap_column)) == 0)
{
/* no name with the hash is in constructed collection */
is_append = true;
/* This hash has not been used before (for non-skipped). */
names_hashes_bitmap[bitmap_row] |= (1u << bitmap_column);
}
else
{
/* name with same hash already occured */
bool is_equal_found = false;
/* Name with same hash has already occured. */
ecma_collection_iterator_init (&iter, ret_p);
while (ecma_collection_iterator_next (&iter))
@ -1650,10 +1662,14 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */
if (ecma_compare_ecma_strings (name_p, iter_name_p))
{
is_equal_found = true;
is_append = false;
break;
}
}
}
if (is_append)
{
ecma_collection_iterator_init (&iter, skipped_non_enumerable_p);
while (ecma_collection_iterator_next (&iter))
{
@ -1661,11 +1677,10 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */
if (ecma_compare_ecma_strings (name_p, iter_name_p))
{
is_equal_found = true;
is_append = false;
break;
}
}
is_append = !is_equal_found;
}
if (is_append)

View File

@ -0,0 +1,46 @@
// 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 getProperties(obj)
{
var str = "";
for (name in obj)
{
if (str)
{
str += " " + name;
}
else
{
str = name;
}
}
return str;
}
var prototype_obj = { dummy:1, length:1, caller:null,
arguments:null, prototype:null };
var func = function() {};
Object.setPrototypeOf(func, prototype_obj);
assert(getProperties(func) == "dummy caller arguments");
var bound_func = (function() {}).bind(null);
Object.setPrototypeOf(bound_func, prototype_obj);
assert(getProperties(bound_func) == "dummy prototype");
// 'print' is an external function
Object.setPrototypeOf(print, prototype_obj);
assert(getProperties(print) == "dummy length caller arguments");