• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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