diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-function.cpp index 65308d23e..04fddbe5e 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-function.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function.cpp @@ -14,16 +14,13 @@ */ #include "ecma-alloc.h" -#include "ecma-builtins.h" #include "ecma-conversion.h" -#include "ecma-exceptions.h" #include "ecma-gc.h" -#include "ecma-globals.h" -#include "ecma-helpers.h" -#include "ecma-objects.h" #include "ecma-function-object.h" +#include "ecma-lex-env.h" #include "ecma-try-catch-macro.h" -#include "jrt.h" +#include "serializer.h" +#include "parser.h" #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" @@ -59,6 +56,9 @@ ecma_builtin_function_dispatch_call (const ecma_value_t *arguments_list_p, /**< /** * Handle calling [[Construct]] of built-in Function object * + * See also: + * ECMA-262 v5, 15.3. + * * @return completion-value */ ecma_completion_value_t @@ -67,7 +67,127 @@ ecma_builtin_function_dispatch_construct (const ecma_value_t *arguments_list_p, { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); - ECMA_BUILTIN_CP_UNIMPLEMENTED (arguments_list_p, arguments_list_len); + ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); + + /* Last string, if any, is the function's body, and the rest, if any - are the function's parameter names */ + MEM_DEFINE_LOCAL_ARRAY (string_params_p, + arguments_list_len == 0 ? 1 : arguments_list_len, + ecma_string_t*); + uint32_t params_count; + + size_t zt_strings_buffer_size; + + if (arguments_list_len == 0) + { + /* 3. */ + string_params_p[0] = ecma_new_ecma_string_from_magic_string_id (ECMA_MAGIC_STRING__EMPTY); + zt_strings_buffer_size = sizeof (ecma_char_t); + params_count = 1; + } + else + { + /* 4., 5., 6. */ + zt_strings_buffer_size = 0; + + params_count = 0; + while (params_count < arguments_list_len + && ecma_is_completion_value_empty (ret_value)) + { + ECMA_TRY_CATCH (str_arg_value, + ecma_op_to_string (arguments_list_p[params_count]), + ret_value); + + string_params_p[params_count] = ecma_copy_or_ref_ecma_string (ecma_get_string_from_value (str_arg_value)); + zt_strings_buffer_size += ((size_t) ecma_string_get_length (string_params_p[params_count]) + + sizeof (ecma_char_t)); + params_count++; + + ECMA_FINALIZE (str_arg_value); + } + } + + if (ecma_is_completion_value_empty (ret_value)) + { + JERRY_ASSERT (params_count >= 1); + + MEM_DEFINE_LOCAL_ARRAY (zt_string_params_p, + params_count, + ecma_char_t*); + MEM_DEFINE_LOCAL_ARRAY (zt_string_buffer_p, + zt_strings_buffer_size, + ecma_char_t); + + ssize_t zt_string_buffer_pos = 0; + for (uint32_t i = 0; i < params_count; i++) + { + ssize_t sz = ecma_string_to_zt_string (string_params_p[i], + &zt_string_buffer_p[zt_string_buffer_pos], + (ssize_t) zt_strings_buffer_size - zt_string_buffer_pos); + JERRY_ASSERT (sz > 0); + + zt_string_params_p[i] = zt_string_buffer_p + zt_string_buffer_pos; + + zt_string_buffer_pos += sz; + } + + parser_init (); + + /* + * FIXME: + * Handle syntax errors + */ + parser_parse_new_function ((const char **) zt_string_params_p, params_count); + const opcode_t* opcodes_p = (const opcode_t*) serializer_get_bytecode (); + serializer_print_opcodes (); + parser_free (); + + bool is_strict = false; + bool do_instantiate_arguments_object = true; + + opcode_scope_code_flags_t scope_flags = vm_get_scope_flags (opcodes_p, + 0); + + if (scope_flags & OPCODE_SCOPE_CODE_FLAGS_STRICT) + { + is_strict = true; + } + + if ((scope_flags & OPCODE_SCOPE_CODE_FLAGS_NOT_REF_ARGUMENTS_IDENTIFIER) + && (scope_flags & OPCODE_SCOPE_CODE_FLAGS_NOT_REF_EVAL_IDENTIFIER)) + { + /* the code doesn't use 'arguments' identifier + * and doesn't perform direct call to eval, + * so Arguments object can't be referenced */ + do_instantiate_arguments_object = false; + } + + /* 11. */ + ecma_object_t *glob_lex_env_p = ecma_get_global_environment (); + + ecma_object_t *func_obj_p = ecma_op_create_function_object (params_count > 1u ? string_params_p : NULL, + (ecma_length_t) (params_count - 1u), + glob_lex_env_p, + is_strict, + do_instantiate_arguments_object, + opcodes_p, + 1); + + ecma_deref_object (glob_lex_env_p); + + ret_value = ecma_make_normal_completion_value (ecma_make_object_value (func_obj_p)); + + MEM_FINALIZE_LOCAL_ARRAY (zt_string_buffer_p); + MEM_FINALIZE_LOCAL_ARRAY (zt_string_params_p); + } + + for (uint32_t i = 0; i < params_count; i++) + { + ecma_deref_ecma_string (string_params_p[i]); + } + + MEM_FINALIZE_LOCAL_ARRAY (string_params_p); + + return ret_value; } /* ecma_builtin_function_dispatch_construct */ /** diff --git a/tests/jerry/function_construct.js b/tests/jerry/function_construct.js new file mode 100644 index 000000000..0a2d70364 --- /dev/null +++ b/tests/jerry/function_construct.js @@ -0,0 +1,81 @@ +// Copyright 2015 Samsung Electronics Co., Ltd. +// +// 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. + +var f = new Function (''); +assert (f () === undefined); + +var f = new Function ('"use strict"; f = undefined;'); +assert (f () === undefined && f === undefined); + +var f = new Function ('"use strict"; q = undefined;'); +try +{ + f (); + assert (false); +} +catch (e) +{ + assert (e instanceof ReferenceError); +} + +for (i = 1; i < 10; i ++) +{ + var f = new Function ('a', 'b', 'var q = a; b++; function f (k) {return q + k + b++;}; return f;'); + + var fns = new Array (); + + for (var n = 0; n < 10; n++) + { + var r = f (1, 7); + fns[n] = r; + + var check_value = 10; + + for (var m = 0; m < 100; m++) + { + var value = r (1); + assert (check_value++ === value); + } + } + + var check_value = 109; + for (var n = 0; n < 11; n++) + { + for (var m = 0; m < 10; m++) + { + var value = fns [m] (m * n); + assert (value == check_value + m * n); + } + + check_value++; + } +} + +try +{ + new Function ({ + toString : function () { + throw new TypeError(); + }, + valueOf : function () { + throw new TypeError(); + } + }); + + assert (false); +} +catch (e) +{ + assert (e instanceof TypeError); +}