• 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 #include "ecma-exceptions.h"
17 #include "ecma-function-object.h"
18 #include "ecma-gc.h"
19 #include "ecma-globals.h"
20 #include "ecma-helpers.h"
21 #include "ecma-lcache.h"
22 #include "ecma-lex-env.h"
23 #include "ecma-objects.h"
24 #include "ecma-proxy-object.h"
25 #include "ecma-reference.h"
26 #include "jrt.h"
27 
28 /** \addtogroup ecma ECMA
29  * @{
30  *
31  * \addtogroup references ECMA-Reference
32  * @{
33  */
34 
35 /**
36  * Resolve syntactic reference.
37  *
38  * @return ECMA_OBJECT_POINTER_ERROR - if the operation fails
39  *         pointer to lexical environment - if the reference's base is resolved sucessfully,
40  *         NULL - otherwise.
41  */
42 ecma_object_t *
ecma_op_resolve_reference_base(ecma_object_t * lex_env_p,ecma_string_t * name_p)43 ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical environment */
44                                 ecma_string_t *name_p) /**< identifier's name */
45 {
46   JERRY_ASSERT (lex_env_p != NULL);
47 
48   while (true)
49   {
50 #if ENABLED (JERRY_ES2015)
51     if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND)
52     {
53       JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
54       lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
55     }
56 #endif /* ENABLED (JERRY_ES2015) */
57 
58     ecma_value_t has_binding = ecma_op_has_binding (lex_env_p, name_p);
59 
60 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
61     if (ECMA_IS_VALUE_ERROR (has_binding))
62     {
63       return ECMA_OBJECT_POINTER_ERROR;
64     }
65 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
66 
67     if (ecma_is_value_true (has_binding))
68     {
69       return lex_env_p;
70     }
71 
72     if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)
73     {
74       return NULL;
75     }
76 
77     lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
78   }
79 } /* ecma_op_resolve_reference_base */
80 
81 #if ENABLED (JERRY_ES2015)
82 /**
83  * Perform GetThisEnvironment and GetSuperBase operations
84  *
85  * See also: ECMAScript v6, 8.1.1.3.5
86  *
87  * @return ECMA_VALUE_ERROR - if the operation fails
88  *         ECMA_VALUE_UNDEFINED - if the home object is null
89  *         value of the [[HomeObject]].[[Prototype]] internal slot - otherwise
90  */
91 ecma_value_t
ecma_op_resolve_super_base(ecma_object_t * lex_env_p)92 ecma_op_resolve_super_base (ecma_object_t *lex_env_p) /**< starting lexical environment */
93 {
94   JERRY_ASSERT (lex_env_p != NULL);
95 
96   while (true)
97   {
98     if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND)
99     {
100       ecma_object_t *home_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u1.home_object_cp);
101 
102 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
103       if (ECMA_OBJECT_IS_PROXY (home_p))
104       {
105         return ecma_proxy_object_get_prototype_of (home_p);
106       }
107 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
108 
109       jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (home_p);
110 
111       if (proto_cp == JMEM_CP_NULL)
112       {
113         return ECMA_VALUE_NULL;
114       }
115 
116       ecma_object_t *proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp);
117       ecma_ref_object (proto_p);
118 
119       return ecma_make_object_value (proto_p);
120     }
121 
122     if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)
123     {
124       break;
125     }
126 
127     lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
128   }
129 
130   return ECMA_VALUE_UNDEFINED;
131 } /* ecma_op_resolve_super_base */
132 
133 /**
134  * Helper method for HasBindig operation
135  *
136  * See also:
137  *         ECMA-262 v6, 8.1.1.2.1 steps 7-9;
138  *
139  * @return ECMA_VALUE_TRUE - if the property is unscopable
140  *         ECMA_VALUE_FALSE - if a the property is not unscopable
141  *         ECMA_VALUE_ERROR - otherwise
142  */
143 static ecma_value_t
ecma_op_is_prop_unscopable(ecma_object_t * binding_obj_p,ecma_string_t * prop_name_p)144 ecma_op_is_prop_unscopable (ecma_object_t *binding_obj_p, /**< binding object */
145                             ecma_string_t *prop_name_p) /**< property's name */
146 {
147   ecma_value_t unscopables = ecma_op_object_get_by_symbol_id (binding_obj_p, LIT_GLOBAL_SYMBOL_UNSCOPABLES);
148 
149   if (ECMA_IS_VALUE_ERROR (unscopables))
150   {
151     return unscopables;
152   }
153 
154   if (ecma_is_value_object (unscopables))
155   {
156     ecma_object_t *unscopables_obj_p = ecma_get_object_from_value (unscopables);
157     ecma_value_t get_unscopables_value = ecma_op_object_get (unscopables_obj_p, prop_name_p);
158     ecma_deref_object (unscopables_obj_p);
159 
160     if (ECMA_IS_VALUE_ERROR (get_unscopables_value))
161     {
162       return get_unscopables_value;
163     }
164 
165     bool is_blocked = ecma_op_to_boolean (get_unscopables_value);
166 
167     ecma_free_value (get_unscopables_value);
168 
169     return ecma_make_boolean_value (is_blocked);
170   }
171 
172   ecma_free_value (unscopables);
173 
174   return ECMA_VALUE_FALSE;
175 } /* ecma_op_is_prop_unscopable */
176 #endif /* ENABLED (JERRY_ES2015) */
177 
178 /**
179  * Helper method for HasBindig operation
180  *
181  * See also:
182  *         ECMA-262 v6, 8.1.1.2.1 steps 7-9;
183  *
184  * @return ECMA_VALUE_TRUE - if the property is unscopable
185  *         ECMA_VALUE_FALSE - if a the property is not unscopable
186  *         ECMA_VALUE_ERROR - otherwise
187  */
188 
189 /**
190  * Resolve value corresponding to the given object environment reference.
191  *
192  * Note: the steps are already include the HasBindig operation steps
193  *
194  *  See also:
195  *         ECMA-262 v6, 8.1.1.2.1
196  *
197  * @return ECMA_VALUE_ERROR - if the operation fails
198  *         ECMA_VALUE_NOT_FOUND - if the binding not exists or blocked via @@unscopables
199  *         result of the binding - otherwise
200  */
201 ecma_value_t
ecma_op_object_bound_environment_resolve_reference_value(ecma_object_t * lex_env_p,ecma_string_t * name_p)202 ecma_op_object_bound_environment_resolve_reference_value (ecma_object_t *lex_env_p, /**< lexical environment */
203                                                           ecma_string_t *name_p) /**< variable name */
204 {
205   ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
206   ecma_value_t found_binding;
207 
208 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
209   if (ECMA_OBJECT_IS_PROXY (binding_obj_p))
210   {
211     found_binding = ecma_proxy_object_has (binding_obj_p, name_p);
212 
213     if (!ecma_is_value_true (found_binding))
214     {
215       return ECMA_IS_VALUE_ERROR (found_binding) ? found_binding : ECMA_VALUE_NOT_FOUND;
216     }
217   }
218   else
219   {
220 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
221     found_binding = ecma_op_object_find (binding_obj_p, name_p);
222 
223     if (ECMA_IS_VALUE_ERROR (found_binding) || !ecma_is_value_found (found_binding))
224     {
225       return found_binding;
226     }
227 
228 #if ENABLED (JERRY_ES2015)
229     if (JERRY_LIKELY (lex_env_p == ecma_get_global_scope ()))
230 #endif /* ENABLED (JERRY_ES2015) */
231     {
232       return found_binding;
233     }
234 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
235   }
236 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
237 
238 #if ENABLED (JERRY_ES2015)
239   ecma_value_t blocked = ecma_op_is_prop_unscopable (binding_obj_p, name_p);
240 
241   if (ecma_is_value_false (blocked))
242   {
243 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
244     if (ECMA_OBJECT_IS_PROXY (binding_obj_p))
245     {
246       return ecma_proxy_object_get (binding_obj_p, name_p, ecma_make_object_value (binding_obj_p));
247     }
248 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
249     return found_binding;
250   }
251 
252 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
253   if (!ECMA_OBJECT_IS_PROXY (binding_obj_p))
254   {
255     ecma_free_value (found_binding);
256   }
257 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
258 
259   return ECMA_IS_VALUE_ERROR (blocked) ? blocked : ECMA_VALUE_NOT_FOUND;
260 #endif /* ENABLED (JERRY_ES2015) */
261 } /* ecma_op_object_bound_environment_resolve_reference_value */
262 
263 /**
264  * Resolve value corresponding to reference.
265  *
266  * @return value of the reference
267  */
268 ecma_value_t
ecma_op_resolve_reference_value(ecma_object_t * lex_env_p,ecma_string_t * name_p)269 ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical environment */
270                                  ecma_string_t *name_p) /**< identifier's name */
271 {
272   JERRY_ASSERT (lex_env_p != NULL);
273 
274   while (true)
275   {
276     ecma_lexical_environment_type_t lex_env_type = ecma_get_lex_env_type (lex_env_p);
277 
278     if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
279     {
280       ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
281 
282       if (property_p != NULL)
283       {
284         ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
285 
286 #if ENABLED (JERRY_ES2015)
287         if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED))
288         {
289           return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be"
290                                                            " initialized before reading their value."));
291         }
292 #endif /* ENABLED (JERRY_ES2015) */
293 
294         return ecma_fast_copy_value (property_value_p->value);
295       }
296     }
297     else if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND)
298     {
299 #if ENABLED (JERRY_ES2015)
300       bool lcache_lookup_allowed = (lex_env_p == ecma_get_global_environment ());
301 #else /* !ENABLED (JERRY_ES2015)*/
302       bool lcache_lookup_allowed = true;
303 #endif /* ENABLED (JERRY_ES2015) */
304 
305       if (lcache_lookup_allowed)
306       {
307 #if ENABLED (JERRY_LCACHE)
308         ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
309         ecma_property_t *property_p = ecma_lcache_lookup (binding_obj_p, name_p);
310 
311         if (property_p != NULL)
312         {
313           ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
314 
315           if (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA)
316           {
317             return ecma_fast_copy_value (prop_value_p->value);
318           }
319 
320           JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);
321 
322           ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (prop_value_p);
323 
324           if (get_set_pair_p->getter_cp == JMEM_CP_NULL)
325           {
326             return ECMA_VALUE_UNDEFINED;
327           }
328 
329           ecma_object_t *getter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp);
330 
331           ecma_value_t base_value = ecma_make_object_value (binding_obj_p);
332           return ecma_op_function_call (getter_p, base_value, NULL, 0);
333         }
334 #endif /* ENABLED (JERRY_LCACHE) */
335       }
336 
337       ecma_value_t result = ecma_op_object_bound_environment_resolve_reference_value (lex_env_p, name_p);
338 
339       if (ecma_is_value_found (result))
340       {
341         /* Note: the result may contains ECMA_VALUE_ERROR */
342         return result;
343       }
344     }
345     else
346     {
347 #if ENABLED (JERRY_ES2015)
348       JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND);
349 #else /* !ENABLED (JERRY_ES2015) */
350       JERRY_UNREACHABLE ();
351 #endif /* ENABLED (JERRY_ES2015) */
352     }
353 
354     if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)
355     {
356       break;
357     }
358 
359     lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
360   }
361 
362 #if ENABLED (JERRY_ERROR_MESSAGES)
363   ecma_value_t name_val = ecma_make_string_value (name_p);
364   ecma_value_t error_value = ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE,
365                                                                     "% is not defined",
366                                                                     name_val);
367 #else /* ENABLED (JERRY_ERROR_MESSAGES) */
368   ecma_value_t error_value = ecma_raise_reference_error (NULL);
369 #endif /* !ENABLED (JERRY_ERROR_MESSAGES) */
370   return error_value;
371 } /* ecma_op_resolve_reference_value */
372 
373 /**
374  * @}
375  * @}
376  */
377