1 /* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /**
17 * Implementation of ECMA GetValue and PutValue
18 */
19
20 #include "ecma-builtins.h"
21 #include "ecma-exceptions.h"
22 #include "ecma-gc.h"
23 #include "ecma-helpers.h"
24 #include "ecma-lex-env.h"
25 #include "ecma-objects.h"
26 #include "ecma-function-object.h"
27 #include "ecma-objects-general.h"
28 #include "ecma-try-catch-macro.h"
29 #include "ecma-reference.h"
30
31 /** \addtogroup ecma ECMA
32 * @{
33 *
34 * \addtogroup lexicalenvironment Lexical environment
35 * @{
36 */
37
38 /**
39 * GetValue operation part
40 *
41 * See also: ECMA-262 v5, 8.7.1, sections 3 and 5
42 *
43 * @return ecma value
44 * Returned value must be freed with ecma_free_value.
45 */
46 ecma_value_t
ecma_op_get_value_lex_env_base(ecma_object_t * lex_env_p,ecma_object_t ** ref_base_lex_env_p,ecma_string_t * name_p)47 ecma_op_get_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environment */
48 ecma_object_t **ref_base_lex_env_p, /**< [out] reference's base (lexical environment) */
49 ecma_string_t *name_p) /**< variable name */
50 {
51 JERRY_ASSERT (lex_env_p != NULL
52 && ecma_is_lexical_environment (lex_env_p));
53
54 while (true)
55 {
56 switch (ecma_get_lex_env_type (lex_env_p))
57 {
58 case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE:
59 {
60 ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
61
62 if (property_p != NULL)
63 {
64 *ref_base_lex_env_p = lex_env_p;
65 ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
66
67 #if ENABLED (JERRY_ES2015)
68 if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED))
69 {
70 return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be"
71 " initialized before reading their value."));
72 }
73 #endif /* ENABLED (JERRY_ES2015) */
74
75 return ecma_fast_copy_value (property_value_p->value);
76 }
77 break;
78 }
79 #if ENABLED (JERRY_ES2015)
80 case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND:
81 {
82 break;
83 }
84 #endif /* ENABLED (JERRY_ES2015) */
85 default:
86 {
87 JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
88
89 ecma_value_t result = ecma_op_object_bound_environment_resolve_reference_value (lex_env_p, name_p);
90
91 if (ecma_is_value_found (result))
92 {
93 /* Note: the result may contains ECMA_VALUE_ERROR */
94 *ref_base_lex_env_p = lex_env_p;
95 return result;
96 }
97
98 break;
99 }
100 }
101
102 if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)
103 {
104 break;
105 }
106
107 lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
108 }
109
110 *ref_base_lex_env_p = NULL;
111 #if ENABLED (JERRY_ERROR_MESSAGES)
112 return ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE,
113 "% is not defined",
114 ecma_make_string_value (name_p));
115 #else /* ENABLED (JERRY_ERROR_MESSAGES) */
116 return ecma_raise_reference_error (NULL);
117 #endif /* ENABLED (JERRY_ERROR_MESSAGES) */
118
119 } /* ecma_op_get_value_lex_env_base */
120
121 /**
122 * GetValue operation part (object base).
123 *
124 * See also: ECMA-262 v5, 8.7.1, section 4
125 *
126 * @return ecma value
127 * Returned value must be freed with ecma_free_value.
128 */
129 ecma_value_t
ecma_op_get_value_object_base(ecma_value_t base_value,ecma_string_t * property_name_p)130 ecma_op_get_value_object_base (ecma_value_t base_value, /**< base value */
131 ecma_string_t *property_name_p) /**< property name */
132 {
133 ecma_object_t *obj_p;
134
135 if (JERRY_UNLIKELY (ecma_is_value_object (base_value)))
136 {
137 obj_p = ecma_get_object_from_value (base_value);
138 }
139 else
140 {
141 ecma_builtin_id_t id = ECMA_BUILTIN_ID_OBJECT_PROTOTYPE;
142
143 if (JERRY_LIKELY (ecma_is_value_string (base_value)))
144 {
145 ecma_string_t *string_p = ecma_get_string_from_value (base_value);
146
147 if (ecma_string_is_length (property_name_p))
148 {
149 return ecma_make_uint32_value (ecma_string_get_length (string_p));
150 }
151
152 uint32_t index = ecma_string_get_array_index (property_name_p);
153
154 if (index != ECMA_STRING_NOT_ARRAY_INDEX
155 && index < ecma_string_get_length (string_p))
156 {
157 ecma_char_t char_at_idx = ecma_string_get_char_at_pos (string_p, index);
158 return ecma_make_string_value (ecma_new_ecma_string_from_code_unit (char_at_idx));
159 }
160
161 #if ENABLED (JERRY_BUILTIN_STRING)
162 id = ECMA_BUILTIN_ID_STRING_PROTOTYPE;
163 #endif /* ENABLED (JERRY_BUILTIN_STRING) */
164 }
165 else if (ecma_is_value_number (base_value))
166 {
167 #if ENABLED (JERRY_BUILTIN_NUMBER)
168 id = ECMA_BUILTIN_ID_NUMBER_PROTOTYPE;
169 #endif /* ENABLED (JERRY_BUILTIN_NUMBER) */
170 }
171 #if ENABLED (JERRY_ES2015)
172 else if (ecma_is_value_symbol (base_value))
173 {
174 id = ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE;
175 }
176 #endif /* ENABLED (JERRY_ES2015) */
177 else
178 {
179 JERRY_ASSERT (ecma_is_value_boolean (base_value));
180 #if ENABLED (JERRY_BUILTIN_BOOLEAN)
181 id = ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE;
182 #endif /* ENABLED (JERRY_BUILTIN_BOOLEAN) */
183 }
184
185 obj_p = ecma_builtin_get (id);
186 }
187
188 return ecma_op_object_get_with_receiver (obj_p, property_name_p, base_value);
189 } /* ecma_op_get_value_object_base */
190
191 /**
192 * PutValue operation part
193 *
194 * See also: ECMA-262 v5, 8.7.2, sections 3 and 5
195 *
196 * @return ecma value
197 * Returned value must be freed with ecma_free_value.
198 */
199 ecma_value_t
ecma_op_put_value_lex_env_base(ecma_object_t * lex_env_p,ecma_string_t * name_p,bool is_strict,ecma_value_t value)200 ecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environment */
201 ecma_string_t *name_p, /**< variable name */
202 bool is_strict, /**< flag indicating strict mode */
203 ecma_value_t value) /**< ECMA-value */
204 {
205 JERRY_ASSERT (lex_env_p != NULL
206 && ecma_is_lexical_environment (lex_env_p));
207
208 while (true)
209 {
210 switch (ecma_get_lex_env_type (lex_env_p))
211 {
212 case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE:
213 {
214 ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
215
216 if (property_p != NULL)
217 {
218 if (ecma_is_property_writable (*property_p))
219 {
220 ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
221
222 #if ENABLED (JERRY_ES2015)
223 if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED))
224 {
225 return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be"
226 " initialized before writing their value."));
227 }
228 #endif /* ENABLED (JERRY_ES2015) */
229
230 ecma_named_data_property_assign_value (lex_env_p, property_value_p, value);
231 }
232 #if ENABLED (JERRY_ES2015)
233 else if (ecma_is_property_enumerable (*property_p))
234 {
235 return ecma_raise_type_error (ECMA_ERR_MSG ("Constant bindings cannot be reassigned."));
236 }
237 #endif /* ENABLED (JERRY_ES2015) */
238 else if (is_strict)
239 {
240 return ecma_raise_type_error (ECMA_ERR_MSG ("Binding cannot be set."));
241 }
242 return ECMA_VALUE_EMPTY;
243 }
244 break;
245 }
246 #if ENABLED (JERRY_ES2015)
247 case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND:
248 {
249 break;
250 }
251 #endif /* ENABLED (JERRY_ES2015) */
252 default:
253 {
254 JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
255
256 ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
257
258 ecma_value_t has_property = ecma_op_object_has_property (binding_obj_p, name_p);
259
260 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
261 if (ECMA_IS_VALUE_ERROR (has_property))
262 {
263 return has_property;
264 }
265 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
266
267 if (ecma_is_value_true (has_property))
268 {
269 ecma_value_t completion = ecma_op_object_put (binding_obj_p,
270 name_p,
271 value,
272 is_strict);
273
274 if (ECMA_IS_VALUE_ERROR (completion))
275 {
276 return completion;
277 }
278
279 JERRY_ASSERT (ecma_is_value_boolean (completion));
280 return ECMA_VALUE_EMPTY;
281 }
282
283 break;
284 }
285 }
286
287 if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)
288 {
289 break;
290 }
291
292 lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
293 }
294
295 if (is_strict)
296 {
297 #if ENABLED (JERRY_ERROR_MESSAGES)
298 return ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE,
299 "% is not defined",
300 ecma_make_string_value (name_p));
301 #else /* !ENABLED (JERRY_ERROR_MESSAGES) */
302 return ecma_raise_reference_error (NULL);
303 #endif /* ENABLED (JERRY_ERROR_MESSAGES) */
304 }
305
306 ecma_value_t completion = ecma_op_object_put (ecma_builtin_get_global (),
307 name_p,
308 value,
309 false);
310
311 JERRY_ASSERT (ecma_is_value_boolean (completion));
312
313 return ECMA_VALUE_EMPTY;
314 } /* ecma_op_put_value_lex_env_base */
315
316 /**
317 * @}
318 * @}
319 */
320