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