• 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-alloc.h"
17 #include "ecma-array-object.h"
18 #include "ecma-globals.h"
19 #include "ecma-objects.h"
20 #include "ecma-objects-general.h"
21 #include "ecma-helpers.h"
22 
23 /** \addtogroup ecma ECMA
24  * @{
25  *
26  * \addtogroup ecmahelpers Helpers for operations with ECMA data types
27  * @{
28  */
29 
30 /**
31  * Create a native pointer property to store the native pointer and its type info.
32  *
33  * @return true - if property was just created with specified value,
34  *         false - otherwise, if property existed before the call, it's value was updated
35  */
36 bool
ecma_create_native_pointer_property(ecma_object_t * obj_p,void * native_p,void * info_p)37 ecma_create_native_pointer_property (ecma_object_t *obj_p, /**< object to create property in */
38                                      void *native_p, /**< native pointer */
39                                      void *info_p) /**< native pointer's type info */
40 {
41   ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
42 
43   if (ecma_op_object_is_fast_array (obj_p))
44   {
45     ecma_fast_array_convert_to_normal (obj_p);
46   }
47 
48   ecma_property_t *property_p = ecma_find_named_property (obj_p, name_p);
49 
50   bool is_new = (property_p == NULL);
51 
52   ecma_native_pointer_t *native_pointer_p;
53 
54   if (property_p == NULL)
55   {
56     ecma_property_value_t *value_p;
57     value_p = ecma_create_named_data_property (obj_p, name_p, ECMA_PROPERTY_CONFIGURABLE_WRITABLE, &property_p);
58 
59     ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p);
60 
61     native_pointer_p = jmem_heap_alloc_block (sizeof (ecma_native_pointer_t));
62 
63     ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, native_pointer_p);
64   }
65   else
66   {
67     ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
68 
69     ecma_native_pointer_t *iter_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t, value_p->value);
70 
71     /* There should be at least 1 native pointer in the chain */
72     JERRY_ASSERT (iter_p != NULL);
73 
74     while (true)
75     {
76       if (iter_p->info_p == info_p)
77       {
78         /* The native info already exists -> update the corresponding data */
79         iter_p->data_p = native_p;
80         return false;
81       }
82 
83       if (iter_p->next_p == NULL)
84       {
85         /* The native info does not exist -> append a new element to the chain */
86         break;
87       }
88 
89       iter_p = iter_p->next_p;
90     }
91 
92     native_pointer_p = jmem_heap_alloc_block (sizeof (ecma_native_pointer_t));
93 
94     iter_p->next_p = native_pointer_p;
95   }
96 
97   native_pointer_p->data_p = native_p;
98   native_pointer_p->info_p = info_p;
99   native_pointer_p->next_p = NULL;
100 
101   return is_new;
102 } /* ecma_create_native_pointer_property */
103 
104 /**
105  * Get value of native package stored in the object's property with specified identifier
106  *
107  * Note:
108  *      property identifier should be one of the following:
109  *        - LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER
110  *
111  * @return native pointer data if property exists
112  *         NULL otherwise
113  */
114 ecma_native_pointer_t *
ecma_get_native_pointer_value(ecma_object_t * obj_p,void * info_p)115 ecma_get_native_pointer_value (ecma_object_t *obj_p, /**< object to get property value from */
116                                void *info_p) /**< native pointer's type info */
117 {
118   if (ecma_op_object_is_fast_array (obj_p))
119   {
120     /* Fast access mode array can not have native pointer properties */
121     return NULL;
122   }
123 
124   ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
125   ecma_property_t *property_p = ecma_find_named_property (obj_p, name_p);
126 
127   if (property_p == NULL)
128   {
129     return NULL;
130   }
131 
132   ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
133 
134   ecma_native_pointer_t *native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t,
135                                                                              value_p->value);
136 
137   JERRY_ASSERT (native_pointer_p != NULL);
138 
139   while (native_pointer_p != NULL)
140   {
141     if (native_pointer_p->info_p == info_p)
142     {
143       return native_pointer_p;
144     }
145 
146     native_pointer_p = native_pointer_p->next_p;
147   }
148 
149   return NULL;
150 } /* ecma_get_native_pointer_value */
151 
152 /**
153  * Delete the previously set native pointer by the native type info from the specified object.
154  *
155  * Note:
156  *      If the specified object has no matching native pointer for the given native type info
157  *      the function has no effect.
158  *
159  * @return true - if the native pointer has been deleted succesfully
160  *         false - otherwise
161  */
162 bool
ecma_delete_native_pointer_property(ecma_object_t * obj_p,void * info_p)163 ecma_delete_native_pointer_property (ecma_object_t *obj_p, /**< object to delete property from */
164                                      void *info_p) /**< native pointer's type info */
165 {
166   if (ecma_op_object_is_fast_array (obj_p))
167   {
168     /* Fast access mode array can not have native pointer properties */
169     return false;
170   }
171 
172   ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
173   ecma_property_t *property_p = ecma_find_named_property (obj_p, name_p);
174 
175   if (property_p == NULL)
176   {
177     return false;
178   }
179 
180   ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
181 
182   ecma_native_pointer_t *native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t,
183                                                                              value_p->value);
184   ecma_native_pointer_t *prev_p = NULL;
185 
186   JERRY_ASSERT (native_pointer_p != NULL);
187 
188   while (native_pointer_p != NULL)
189   {
190     if (native_pointer_p->info_p == info_p)
191     {
192       if (prev_p == NULL)
193       {
194         if (native_pointer_p->next_p == NULL)
195         {
196           /* Only one native pointer property exists, so the property can be deleted as well. */
197           ecma_op_general_object_delete (obj_p, name_p, false);
198 
199           jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t));
200           return true;
201         }
202         else
203         {
204           /* There are at least two native pointers and the first one should be deleted.
205              In this case the second element's data is copied to the head of the chain, and freed as well. */
206           ecma_native_pointer_t *next_p = native_pointer_p->next_p;
207           memcpy (native_pointer_p, next_p, sizeof (ecma_native_pointer_t));
208           jmem_heap_free_block (next_p, sizeof (ecma_native_pointer_t));
209           return true;
210         }
211       }
212       else
213       {
214         /* There are at least two native pointers and not the first element should be deleted.
215            In this case the current element's next element reference is copied to the previous element. */
216         prev_p->next_p = native_pointer_p->next_p;
217         jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t));
218         return true;
219       }
220     }
221 
222     prev_p = native_pointer_p;
223     native_pointer_p = native_pointer_p->next_p;
224   }
225 
226   return false;
227 } /* ecma_delete_native_pointer_property */
228 
229 /**
230  * @}
231  * @}
232  */
233