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 */ 36bool 37ecma_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 */ 114ecma_native_pointer_t * 115ecma_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 */ 162bool 163ecma_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