From dc3f52930795d2cb7d2d4389cfcb80d6aef9b4d6 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Tue, 26 Aug 2014 12:43:13 +0400 Subject: [PATCH] Implementing 'typeof' opcode handler. --- src/libcoreint/opcodes-ecma-support.h | 1 + src/libcoreint/opcodes-helpers-variables.c | 19 ++- src/libcoreint/opcodes.c | 148 ++++++++++++++++++++- src/libecmaoperations/ecma-magic-strings.c | 4 + src/libecmaoperations/ecma-magic-strings.h | 12 +- tests/jerry/typeof.js | 29 ++++ 6 files changed, 204 insertions(+), 9 deletions(-) create mode 100644 tests/jerry/typeof.js diff --git a/src/libcoreint/opcodes-ecma-support.h b/src/libcoreint/opcodes-ecma-support.h index 61c211323..6b87437d6 100644 --- a/src/libcoreint/opcodes-ecma-support.h +++ b/src/libcoreint/opcodes-ecma-support.h @@ -29,6 +29,7 @@ #include "ecma-try-catch-macro.h" #include "ecma-objects.h" +bool is_reg_variable (int_data_t *int_data, idx_t var_idx); ecma_completion_value_t get_variable_value (int_data_t *, idx_t, bool); ecma_completion_value_t set_variable_value (int_data_t *, idx_t, ecma_value_t); diff --git a/src/libcoreint/opcodes-helpers-variables.c b/src/libcoreint/opcodes-helpers-variables.c index 173187de8..0ed457271 100644 --- a/src/libcoreint/opcodes-helpers-variables.c +++ b/src/libcoreint/opcodes-helpers-variables.c @@ -54,6 +54,19 @@ do_strict_eval_arguments_check (ecma_reference_t ref) /**< ECMA-reference */ return ret; } /* do_strict_eval_arguments_check */ +/** + * Check if the variable is register variable. + * + * @return true - if var_idx is register variable in current interpreter context, + * false - otherwise. + */ +bool +is_reg_variable (int_data_t *int_data, /**< interpreter context */ + idx_t var_idx) /**< variable identifier */ +{ + return (var_idx >= int_data->min_reg_num && var_idx <= int_data->max_reg_num); +} /* is_reg_variable */ + /** * Get variable's value. * @@ -68,8 +81,7 @@ get_variable_value (int_data_t *int_data, /**< interpreter context */ { ecma_completion_value_t ret_value; - if (var_idx >= int_data->min_reg_num - && var_idx <= int_data->max_reg_num) + if (is_reg_variable (int_data, var_idx)) { ecma_value_t reg_value = int_data->regs_p[ var_idx - int_data->min_reg_num ]; @@ -119,8 +131,7 @@ set_variable_value (int_data_t *int_data, /**< interpreter context */ { ecma_completion_value_t ret_value; - if (var_idx >= int_data->min_reg_num - && var_idx <= int_data->max_reg_num) + if (is_reg_variable (int_data, var_idx)) { ecma_value_t reg_value = int_data->regs_p[ var_idx - int_data->min_reg_num ]; diff --git a/src/libcoreint/opcodes.c b/src/libcoreint/opcodes.c index 27632bf30..a69c28e98 100644 --- a/src/libcoreint/opcodes.c +++ b/src/libcoreint/opcodes.c @@ -128,7 +128,6 @@ free_string_literal_copy (string_literal_copy *str_lit_descr_p) /**< string lite op (prop_set_decl) \ op (obj_decl) \ op (delete) \ - op (typeof) \ op (with) \ op (end_with) \ op (meta) \ @@ -1092,6 +1091,153 @@ opfunc_this (opcode_t opdata, /**< operation data */ return ret_value; } /* opfunc_this */ +/** + * Evaluate argument of typeof. + * + * See also: ECMA-262 v5, 11.4.3 + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value + */ +static ecma_completion_value_t +evaluate_arg_for_typeof (int_data_t *int_data, /**< interpreter context */ + idx_t var_idx) /**< arg variable identifier */ +{ + ecma_completion_value_t ret_value; + + if (is_reg_variable (int_data, var_idx)) + { + // 2.b + ret_value = get_variable_value (int_data, + var_idx, + false); + JERRY_ASSERT (ecma_is_completion_value_normal (ret_value)); + } + else + { + ecma_string_t *var_name_string_p = ecma_new_ecma_string_from_lit_index (var_idx); + + ecma_reference_t ref = ecma_op_get_identifier_reference (int_data->lex_env_p, + var_name_string_p, + int_data->is_strict); + + ecma_deref_ecma_string (var_name_string_p); + + const bool is_unresolvable_reference = ecma_is_value_undefined (ref.base); + + if (is_unresolvable_reference) + { + ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); + } + else + { + ret_value = ecma_op_get_value (ref); + } + + ecma_free_reference (ref); + } + + return ret_value; +} /* evaluate_arg_for_typeof */ + +/** + * 'typeof' opcode handler. + * + * See also: ECMA-262 v5, 11.4.3 + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value + */ +ecma_completion_value_t +opfunc_typeof (opcode_t opdata, /**< operation data */ + int_data_t *int_data) /**< interpreter context */ +{ + const idx_t dst_var_idx = opdata.data.typeof.lhs; + const idx_t obj_var_idx = opdata.data.typeof.obj; + + int_data->pos++; + + ecma_completion_value_t ret_value; + + ECMA_TRY_CATCH (typeof_evaluate_arg_completion, + evaluate_arg_for_typeof (int_data, + obj_var_idx), + ret_value); + + ecma_value_t typeof_arg = typeof_evaluate_arg_completion.value; + + ecma_string_t *type_str_p = NULL; + + switch ((ecma_type_t)typeof_arg.value_type) + { + case ECMA_TYPE_SIMPLE: + { + switch ((ecma_simple_value_t)typeof_arg.value) + { + case ECMA_SIMPLE_VALUE_UNDEFINED: + { + type_str_p = ecma_get_magic_string (ECMA_MAGIC_STRING_UNDEFINED); + break; + } + case ECMA_SIMPLE_VALUE_NULL: + { + type_str_p = ecma_get_magic_string (ECMA_MAGIC_STRING_NULL); + break; + } + case ECMA_SIMPLE_VALUE_FALSE: + { + type_str_p = ecma_get_magic_string (ECMA_MAGIC_STRING_FALSE); + break; + } + case ECMA_SIMPLE_VALUE_TRUE: + { + type_str_p = ecma_get_magic_string (ECMA_MAGIC_STRING_TRUE); + break; + } + case ECMA_SIMPLE_VALUE_EMPTY: + case ECMA_SIMPLE_VALUE_ARRAY_REDIRECT: + case ECMA_SIMPLE_VALUE__COUNT: + { + JERRY_UNREACHABLE (); + } + } + break; + } + case ECMA_TYPE_NUMBER: + { + type_str_p = ecma_get_magic_string (ECMA_MAGIC_STRING_NUMBER); + break; + } + case ECMA_TYPE_STRING: + { + type_str_p = ecma_get_magic_string (ECMA_MAGIC_STRING_STRING); + break; + } + case ECMA_TYPE_OBJECT: + { + if (ecma_op_is_callable (typeof_arg)) + { + type_str_p = ecma_get_magic_string (ECMA_MAGIC_STRING_FUNCTION); + } + else + { + type_str_p = ecma_get_magic_string (ECMA_MAGIC_STRING_OBJECT); + } + break; + } + } + + ret_value = set_variable_value (int_data, + dst_var_idx, + ecma_make_string_value (type_str_p)); + + ecma_deref_ecma_string (type_str_p); + + ECMA_FINALIZE (typeof_evaluate_arg_completion); + + return ret_value; +} /* opfunc_typeof */ + #define GETOP_DEF_1(a, name, field1) \ inline opcode_t getop_##name (idx_t arg1) \ { \ diff --git a/src/libecmaoperations/ecma-magic-strings.c b/src/libecmaoperations/ecma-magic-strings.c index b3074a9f9..dda6ccde7 100644 --- a/src/libecmaoperations/ecma-magic-strings.c +++ b/src/libecmaoperations/ecma-magic-strings.c @@ -46,6 +46,10 @@ ecma_get_magic_string_zt (ecma_magic_string_id_t id) /**< magic string id */ case ECMA_MAGIC_STRING_NULL: return (ecma_char_t*) "null"; case ECMA_MAGIC_STRING_FALSE: return (ecma_char_t*) "false"; case ECMA_MAGIC_STRING_TRUE: return (ecma_char_t*) "true"; + case ECMA_MAGIC_STRING_NUMBER: return (ecma_char_t*) "number"; + case ECMA_MAGIC_STRING_STRING: return (ecma_char_t*) "string"; + case ECMA_MAGIC_STRING_OBJECT: return (ecma_char_t*) "object"; + case ECMA_MAGIC_STRING_FUNCTION: return (ecma_char_t*) "function"; case ECMA_MAGIC_STRING_LENGTH: return (ecma_char_t*) "length"; case ECMA_MAGIC_STRING_NAN: return (ecma_char_t*) "NaN"; case ECMA_MAGIC_STRING_INFINITY: return (ecma_char_t*) "Infinity"; diff --git a/src/libecmaoperations/ecma-magic-strings.h b/src/libecmaoperations/ecma-magic-strings.h index 2481e5d42..22d18f04a 100644 --- a/src/libecmaoperations/ecma-magic-strings.h +++ b/src/libecmaoperations/ecma-magic-strings.h @@ -36,10 +36,14 @@ typedef enum ECMA_MAGIC_STRING_CONSTRUCTOR, /**< "constructor" */ ECMA_MAGIC_STRING_CALLER, /**< "caller" */ ECMA_MAGIC_STRING_CALLEE, /**< "callee" */ - ECMA_MAGIC_STRING_UNDEFINED,/**< "undefined" */ - ECMA_MAGIC_STRING_NULL,/**< "null" */ - ECMA_MAGIC_STRING_FALSE,/**< "false" */ - ECMA_MAGIC_STRING_TRUE,/**< "true" */ + ECMA_MAGIC_STRING_UNDEFINED, /**< "undefined" */ + ECMA_MAGIC_STRING_NULL, /**< "null" */ + ECMA_MAGIC_STRING_FALSE, /**< "false" */ + ECMA_MAGIC_STRING_TRUE, /**< "true" */ + ECMA_MAGIC_STRING_NUMBER, /**< "number" */ + ECMA_MAGIC_STRING_STRING, /**< "string" */ + ECMA_MAGIC_STRING_OBJECT, /**< "object" */ + ECMA_MAGIC_STRING_FUNCTION, /**< "function" */ ECMA_MAGIC_STRING_LENGTH, /**< "length" */ ECMA_MAGIC_STRING_NAN, /**< "NaN" */ ECMA_MAGIC_STRING_INFINITY /**< "Infinity" */ diff --git a/tests/jerry/typeof.js b/tests/jerry/typeof.js new file mode 100644 index 000000000..53f82a288 --- /dev/null +++ b/tests/jerry/typeof.js @@ -0,0 +1,29 @@ +// Copyright 2014 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. + +function f() +{ + return 1; +} + +assert(typeof(a) === "undefined"); +assert(typeof(null) === "null"); +assert(typeof(false) === "false"); +assert(typeof(true) === "true"); +assert(typeof(1) === "number"); +assert(typeof(1.1) === "number"); +assert(typeof('abcd') === "string"); +assert(typeof("1.1") === "string"); +assert(typeof(this) === "object"); +assert(typeof(f) === "function");