diff --git a/src/libecmaobjects/ecma-alloc.c b/src/libecmaobjects/ecma-alloc.c index 283b8acfb..bc188aa98 100644 --- a/src/libecmaobjects/ecma-alloc.c +++ b/src/libecmaobjects/ecma-alloc.c @@ -48,6 +48,8 @@ JERRY_STATIC_ASSERT( sizeof (ecma_CompletionValue_t) == sizeof(uint32_t) ); /** * Template of an allocation routine. + * + * FIXME: Run GC only if allocation failed. */ #define ALLOC( ecmaType) ecma_ ## ecmaType ## _t * \ ecma_Alloc ## ecmaType (void) \ @@ -62,13 +64,13 @@ ecma_Alloc ## ecmaType (void) \ } /** - * Free routine template + * Deallocation routine template */ -#define FREE( ecmaType) void \ -ecma_Free ## ecmaType( ecma_ ## ecmaType ## _t *p ## ecmaType) \ +#define DEALLOC( ecmaType) void \ +ecma_Dealloc ## ecmaType( ecma_ ## ecmaType ## _t *p ## ecmaType) \ { \ mem_PoolsFree( mem_SizeToPoolChunkType( sizeof(ecma_ ## ecmaType ## _t)), \ - (uint8_t*) p ## ecmaType); \ + (uint8_t*) p ## ecmaType); \ } /** @@ -76,7 +78,7 @@ ecma_Free ## ecmaType( ecma_ ## ecmaType ## _t *p ## ecmaType) \ */ #define DECLARE_ROUTINES_FOR( ecmaType) \ ALLOC( ecmaType) \ - FREE( ecmaType) + DEALLOC( ecmaType) DECLARE_ROUTINES_FOR (Object) DECLARE_ROUTINES_FOR (Property) diff --git a/src/libecmaobjects/ecma-alloc.h b/src/libecmaobjects/ecma-alloc.h index 78e660a98..f617be20b 100644 --- a/src/libecmaobjects/ecma-alloc.h +++ b/src/libecmaobjects/ecma-alloc.h @@ -33,9 +33,9 @@ extern ecma_Object_t *ecma_AllocObject(void); /** - * Free memory from an ecma-object + * Dealloc memory from an ecma-object */ -extern void ecma_FreeObject( ecma_Object_t *pObject); +extern void ecma_DeallocObject( ecma_Object_t *pObject); /** * Allocate memory for ecma-property @@ -45,9 +45,9 @@ extern void ecma_FreeObject( ecma_Object_t *pObject); extern ecma_Property_t *ecma_AllocProperty(void); /** - * Free memory from an ecma-property + * Dealloc memory from an ecma-property */ -extern void ecma_FreeProperty( ecma_Property_t *pProperty); +extern void ecma_DeallocProperty( ecma_Property_t *pProperty); /** * Allocate memory for ecma-number @@ -57,9 +57,9 @@ extern void ecma_FreeProperty( ecma_Property_t *pProperty); extern ecma_Number_t *ecma_AllocNumber(void); /** - * Free memory from an ecma-number + * Dealloc memory from an ecma-number */ -extern void ecma_FreeNumber( ecma_Number_t *pNumber); +extern void ecma_DeallocNumber( ecma_Number_t *pNumber); /** * Allocate memory for first chunk of an ecma-array @@ -69,9 +69,9 @@ extern void ecma_FreeNumber( ecma_Number_t *pNumber); extern ecma_ArrayFirstChunk_t *ecma_AllocArrayFirstChunk(void); /** - * Free memory from first chunk of an ecma-array + * Dealloc memory from first chunk of an ecma-array */ -extern void ecma_FreeArrayFirstChunk( ecma_ArrayFirstChunk_t *pFirstChunk); +extern void ecma_DeallocArrayFirstChunk( ecma_ArrayFirstChunk_t *pFirstChunk); /** * Allocate memory for non-first chunk of an ecma-array @@ -81,13 +81,13 @@ extern void ecma_FreeArrayFirstChunk( ecma_ArrayFirstChunk_t *pFirstChunk); extern ecma_ArrayNonFirstChunk_t *ecma_AllocArrayNonFirstChunk(void); /** - * Free memory from non-first chunk of an ecma-array + * Dealloc memory from non-first chunk of an ecma-array */ -extern void ecma_FreeArrayNonFirstChunk( ecma_ArrayNonFirstChunk_t *pNumber); +extern void ecma_DeallocArrayNonFirstChunk( ecma_ArrayNonFirstChunk_t *pNumber); #endif /* JERRY_ECMA_ALLOC_H */ /** * @} * @} - */ \ No newline at end of file + */ diff --git a/src/libecmaobjects/ecma-gc.c b/src/libecmaobjects/ecma-gc.c index 4ced0032a..859f39efa 100644 --- a/src/libecmaobjects/ecma-gc.c +++ b/src/libecmaobjects/ecma-gc.c @@ -97,120 +97,6 @@ ecma_GCInit( void) ecma_GC_Queue = NULL; } /* ecma_GCInit */ -/** - * Garbage collect described value - */ -static void -ecma_GCValue( ecma_Value_t valueDescription) /**< value description */ -{ - switch ( (ecma_Type_t) valueDescription.m_ValueType ) - { - case ECMA_TYPE_SIMPLE: - { - /* doesn't hold additional memory */ - break; - } - - case ECMA_TYPE_NUMBER: - { - ecma_Number_t *pNumber = ecma_GetPointer( valueDescription.m_Value); - ecma_FreeNumber( pNumber); - break; - } - - case ECMA_TYPE_STRING: - { - ecma_ArrayFirstChunk_t *pString = ecma_GetPointer( valueDescription.m_Value); - ecma_FreeArray( pString); - break; - } - - case ECMA_TYPE_OBJECT: - { - ecma_DerefObject( ecma_GetPointer( valueDescription.m_Value)); - break; - } - - case ECMA_TYPE__COUNT: - { - JERRY_UNREACHABLE(); - } - } -} /* ecma_GCValue */ - -/** - * Garbage collect a named data property - */ -static void -ecma_GCNamedDataProperty( ecma_Property_t *pProperty) /**< the property */ -{ - JERRY_ASSERT( pProperty->m_Type == ECMA_PROPERTY_NAMEDDATA ); - - ecma_FreeArray( ecma_GetPointer( pProperty->u.m_NamedDataProperty.m_pName)); - ecma_GCValue( pProperty->u.m_NamedDataProperty.m_Value); -} /* ecma_GCNamedDataProperty */ - -/** - * Garbage collect a named accessor property - */ -static void -ecma_GCNamedAccessorProperty( ecma_Property_t *pProperty) /**< the property */ -{ - JERRY_ASSERT( pProperty->m_Type == ECMA_PROPERTY_NAMEDACCESSOR ); - - ecma_FreeArray( ecma_GetPointer( pProperty->u.m_NamedAccessorProperty.m_pName)); - - ecma_Object_t *pGet = ecma_GetPointer(pProperty->u.m_NamedAccessorProperty.m_pGet); - ecma_Object_t *pSet = ecma_GetPointer(pProperty->u.m_NamedAccessorProperty.m_pSet); - - if ( pGet != NULL ) - { - ecma_DerefObject( pGet); - } - - if ( pSet != NULL ) - { - ecma_DerefObject( pSet); - } -} /* ecma_GCNamedAccessorProperty */ - -/** - * Garbage collect an internal property - */ -static void -ecma_GCInternalProperty( ecma_Property_t *pProperty) /**< the property */ -{ - JERRY_ASSERT( pProperty->m_Type == ECMA_PROPERTY_INTERNAL ); - - ecma_InternalPropertyId_t propertyId = pProperty->u.m_InternalProperty.m_InternalPropertyType; - uint32_t propertyValue = pProperty->u.m_InternalProperty.m_Value; - - switch ( propertyId ) - { - case ECMA_INTERNAL_PROPERTY_CLASS: /* a string */ - case ECMA_INTERNAL_PROPERTY_NUMBER_INDEXED_ARRAY_VALUES: /* an array */ - case ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES: /* an array */ - { - ecma_FreeArray( ecma_GetPointer( propertyValue)); - break; - } - - case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */ - case ECMA_INTERNAL_PROPERTY_BINDING_OBJECT: /* an object */ - { - ecma_DerefObject( ecma_GetPointer( propertyValue)); - break; - } - - case ECMA_INTERNAL_PROPERTY_PROTOTYPE: /* the property's value is located in ecma_Object_t */ - case ECMA_INTERNAL_PROPERTY_EXTENSIBLE: /* the property's value is located in ecma_Object_t */ - case ECMA_INTERNAL_PROPERTY_PROVIDE_THIS: /* a boolean flag */ - { - break; - } - } -} /* ecma_GCInternalProperty */ - /** * Run garbage collecting */ @@ -228,31 +114,8 @@ ecma_GCRun( void) property != NULL; property = pNextProperty ) { - switch ( (ecma_PropertyType_t) property->m_Type ) - { - case ECMA_PROPERTY_NAMEDDATA: - { - ecma_GCNamedDataProperty( property); - - break; - } - - case ECMA_PROPERTY_NAMEDACCESSOR: - { - ecma_GCNamedAccessorProperty( property); - - break; - } - - case ECMA_PROPERTY_INTERNAL: - { - ecma_GCInternalProperty( property); - - break; - } - } - pNextProperty = ecma_GetPointer( property->m_pNextProperty); + ecma_FreeProperty( property); } @@ -274,7 +137,7 @@ ecma_GCRun( void) } } - ecma_FreeObject( pObject); + ecma_DeallocObject( pObject); } } /* ecma_RunGC */ diff --git a/src/libecmaobjects/ecma-globals.h b/src/libecmaobjects/ecma-globals.h index b8a302fb8..3760b299f 100644 --- a/src/libecmaobjects/ecma-globals.h +++ b/src/libecmaobjects/ecma-globals.h @@ -153,6 +153,33 @@ typedef enum { ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES } ecma_InternalPropertyId_t; +/** + * Property's 'Writable' attribute's values description. + */ +typedef enum +{ + ECMA_PROPERTY_WRITABLE, /**< property's 'Writable' attribute is true */ + ECMA_PROPERTY_NOT_WRITABLE /**< property's 'Writable' attribute is false */ +} ecma_PropertyWritableValue_t; + +/** + * Property's 'Enumerable' attribute's values description. + */ +typedef enum +{ + ECMA_PROPERTY_ENUMERABLE, /**< property's 'Enumerable' attribute is true */ + ECMA_PROPERTY_NOT_ENUMERABLE /**< property's 'Enumerable' attribute is false */ +} ecma_PropertyEnumerableValue_t; + +/** + * Property's 'Configurable' attribute's values description. + */ +typedef enum +{ + ECMA_PROPERTY_CONFIGURABLE, /**< property's 'Configurable' attribute is true */ + ECMA_PROPERTY_NOT_CONFIGURABLE /**< property's 'Configurable' attribute is false */ +} ecma_PropertyConfigurableValue_t; + /** * Description of ecma-property. */ @@ -171,13 +198,13 @@ typedef struct ecma_Property_t { /** Compressed pointer to property's name (pointer to String) */ unsigned int m_pName : ECMA_POINTER_FIELD_WIDTH; - /** Attribute 'Writable' */ + /** Attribute 'Writable' (ecma_PropertyWritableValue_t) */ unsigned int m_Writable : 1; - /** Attribute 'Enumerable' */ + /** Attribute 'Enumerable' (ecma_PropertyEnumerableValue_t) */ unsigned int m_Enumerable : 1; - /** Attribute 'Configurable' */ + /** Attribute 'Configurable' (ecma_PropertyConfigurableValue_t) */ unsigned int m_Configurable : 1; /** Value */ @@ -189,10 +216,10 @@ typedef struct ecma_Property_t { /** Compressed pointer to property's name (pointer to String) */ unsigned int m_pName : ECMA_POINTER_FIELD_WIDTH; - /** Attribute 'Enumerable' */ + /** Attribute 'Enumerable' (ecma_PropertyEnumerableValue_t) */ unsigned int m_Enumerable : 1; - /** Attribute 'Configurable' */ + /** Attribute 'Configurable' (ecma_PropertyConfigurableValue_t) */ unsigned int m_Configurable : 1; /** Compressed pointer to property's getter */ diff --git a/src/libecmaobjects/ecma-helpers-value.c b/src/libecmaobjects/ecma-helpers-value.c index 1c562e40f..170aa40d1 100644 --- a/src/libecmaobjects/ecma-helpers-value.c +++ b/src/libecmaobjects/ecma-helpers-value.c @@ -20,6 +20,8 @@ * @{ */ +#include "ecma-alloc.h" +#include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" #include "globals.h" @@ -31,10 +33,10 @@ * false - otherwise. */ bool -ecma_IsUndefinedValue( ecma_Value_t value) /**< ecma-value */ +ecma_IsValueUndefined( ecma_Value_t value) /**< ecma-value */ { return ( value.m_ValueType == ECMA_TYPE_SIMPLE && value.m_Value == ECMA_SIMPLE_VALUE_UNDEFINED ); -} /* ecma_IsUndefinedValue */ +} /* ecma_IsValueUndefined */ /** * Check if the value is null. @@ -43,10 +45,10 @@ ecma_IsUndefinedValue( ecma_Value_t value) /**< ecma-value */ * false - otherwise. */ bool -ecma_IsNullValue( ecma_Value_t value) /**< ecma-value */ +ecma_IsValueNull( ecma_Value_t value) /**< ecma-value */ { return ( value.m_ValueType == ECMA_TYPE_SIMPLE && value.m_Value == ECMA_SIMPLE_VALUE_NULL ); -} /* ecma_IsNullValue */ +} /* ecma_IsValueNull */ /** * Check if the value is boolean. @@ -55,11 +57,11 @@ ecma_IsNullValue( ecma_Value_t value) /**< ecma-value */ * false - otherwise. */ bool -ecma_IsBooleanValue( ecma_Value_t value) /**< ecma-value */ +ecma_IsValueBoolean( ecma_Value_t value) /**< ecma-value */ { return ( ( value.m_ValueType == ECMA_TYPE_SIMPLE && value.m_Value == ECMA_SIMPLE_VALUE_FALSE ) || ( value.m_ValueType == ECMA_TYPE_SIMPLE && value.m_Value == ECMA_SIMPLE_VALUE_TRUE ) ); -} /* ecma_IsBooleanValue */ +} /* ecma_IsValueBoolean */ /** * Check if the value is true. @@ -73,7 +75,7 @@ ecma_IsBooleanValue( ecma_Value_t value) /**< ecma-value */ bool ecma_IsValueTrue( ecma_Value_t value) /**< ecma-value */ { - JERRY_ASSERT( ecma_IsBooleanValue( value) ); + JERRY_ASSERT( ecma_IsValueBoolean( value) ); return ( value.m_ValueType == ECMA_TYPE_SIMPLE && value.m_Value == ECMA_SIMPLE_VALUE_TRUE ); } /* ecma_IsValueTrue */ @@ -103,6 +105,115 @@ ecma_MakeObjectValue( ecma_Object_t* object_p) /**< object to reference in value return object_value; } /* ecma_MakeObjectValue */ +/** + * Copy ecma-value. + * + * Note: + * Operation algorithm. + * switch (valuetype) + * case simple: + * simply return the value as it was passed; + * case number/string: + * copy the number/string + * and return new ecma-value + * pointing to copy of the number/string; + * case object; + * increase reference counter of the object + * and return the value as it was passed. + * + * @return See note. + */ +ecma_Value_t +ecma_CopyValue( const ecma_Value_t value) /**< ecma-value */ +{ + ecma_Value_t value_copy; + + switch ( (ecma_Type_t)value.m_ValueType ) + { + case ECMA_TYPE_SIMPLE: + { + value_copy = value; + } + case ECMA_TYPE_NUMBER: + { + ecma_Number_t *num_p = ecma_GetPointer( value.m_Value); + JERRY_ASSERT( num_p != NULL ); + + ecma_Number_t *number_copy_p = ecma_AllocNumber(); + *number_copy_p = *num_p; + + value_copy = (ecma_Value_t) { .m_ValueType = ECMA_TYPE_NUMBER }; + ecma_SetPointer( value_copy.m_Value, number_copy_p); + } + case ECMA_TYPE_STRING: + { + ecma_ArrayFirstChunk_t *string_p = ecma_GetPointer( value.m_Value); + JERRY_ASSERT( string_p != NULL ); + + ecma_ArrayFirstChunk_t *string_copy_p = ecma_DuplicateEcmaString( string_p); + + value_copy = (ecma_Value_t) { .m_ValueType = ECMA_TYPE_STRING }; + ecma_SetPointer( value_copy.m_Value, string_copy_p); + } + case ECMA_TYPE_OBJECT: + { + ecma_Object_t *obj_p = ecma_GetPointer( value.m_Value); + JERRY_ASSERT( obj_p != NULL ); + + ecma_RefObject( obj_p); + + value_copy = value; + } + case ECMA_TYPE__COUNT: + { + JERRY_UNREACHABLE(); + } + } + + return value_copy; +} /* ecma_CopyValue */ + +/** + * Free memory used for the value + */ +void +ecma_FreeValue( ecma_Value_t value) /**< value description */ +{ + switch ( (ecma_Type_t) value.m_ValueType ) + { + case ECMA_TYPE_SIMPLE: + { + /* doesn't hold additional memory */ + break; + } + + case ECMA_TYPE_NUMBER: + { + ecma_Number_t *pNumber = ecma_GetPointer( value.m_Value); + ecma_DeallocNumber( pNumber); + break; + } + + case ECMA_TYPE_STRING: + { + ecma_ArrayFirstChunk_t *pString = ecma_GetPointer( value.m_Value); + ecma_FreeArray( pString); + break; + } + + case ECMA_TYPE_OBJECT: + { + ecma_DerefObject( ecma_GetPointer( value.m_Value)); + break; + } + + case ECMA_TYPE__COUNT: + { + JERRY_UNREACHABLE(); + } + } +} /* ecma_FreeValue */ + /** * Completion value constructor */ @@ -131,6 +242,36 @@ ecma_MakeThrowValue( ecma_Object_t *exception_p) /**< an object */ ECMA_TARGET_ID_RESERVED); } /* ecma_MakeThrowValue */ +/** + * Check if the completion value is normal true. + * + * @return true - if the completion type is normal and + * value contains ecma-true simple value, + * false - otherwise. + */ +bool +ecma_IsCompletionValueNormalTrue( ecma_CompletionValue_t value) /**< completion value */ +{ + return ( value.type == ECMA_COMPLETION_TYPE_NORMAL + && value.value.m_ValueType == ECMA_TYPE_SIMPLE + && value.value.m_Value == ECMA_SIMPLE_VALUE_TRUE ); +} /* ecma_IsCompletionValueNormalTrue */ + +/** + * Check if the completion value is normal false. + * + * @return true - if the completion type is normal and + * value contains ecma-false simple value, + * false - otherwise. + */ +bool +ecma_IsCompletionValueNormalFalse( ecma_CompletionValue_t value) /**< completion value */ +{ + return ( value.type == ECMA_COMPLETION_TYPE_NORMAL + && value.value.m_ValueType == ECMA_TYPE_SIMPLE + && value.value.m_Value == ECMA_SIMPLE_VALUE_FALSE ); +} /* ecma_IsCompletionValueNormalFalse */ + /** * @} * @} diff --git a/src/libecmaobjects/ecma-helpers.c b/src/libecmaobjects/ecma-helpers.c index 4ae5be949..a49c180db 100644 --- a/src/libecmaobjects/ecma-helpers.c +++ b/src/libecmaobjects/ecma-helpers.c @@ -21,6 +21,7 @@ */ #include "ecma-alloc.h" +#include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" #include "jerry-libc.h" @@ -200,6 +201,39 @@ ecma_GetInternalProperty(ecma_Object_t *pObject, /**< object descriptor */ return pProperty; } /* ecma_GetInternalProperty */ +/** + * Create named data property with given name, attributes and undefined value + * in the specified object. + * + * @return pointer to newly created property + */ +ecma_Property_t* +ecma_CreateNamedProperty(ecma_Object_t *obj_p, /**< object */ + ecma_Char_t *name_p, /**< property name */ + ecma_PropertyWritableValue_t writable, /**< 'writable' attribute */ + ecma_PropertyEnumerableValue_t enumerable, /**< 'enumerable' attribute */ + ecma_PropertyConfigurableValue_t configurable) /**< 'configurable' attribute */ +{ + JERRY_ASSERT( obj_p != NULL && name_p != NULL ); + + ecma_Property_t *prop = ecma_AllocProperty(); + + prop->m_Type = ECMA_PROPERTY_NAMEDDATA; + + ecma_SetPointer( prop->u.m_NamedDataProperty.m_pName, ecma_NewEcmaString( name_p)); + + prop->u.m_NamedDataProperty.m_Writable = writable; + prop->u.m_NamedDataProperty.m_Enumerable = enumerable; + prop->u.m_NamedDataProperty.m_Configurable = configurable; + + prop->u.m_NamedDataProperty.m_Value = ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_UNDEFINED); + + ecma_SetPointer( prop->m_pNextProperty, ecma_GetPointer( obj_p->m_pProperties)); + ecma_SetPointer( obj_p->m_pProperties, prop); + + return prop; +} /* ecma_CreateNamedProperty */ + /** * Find named data property or named access property in specified object. * @@ -207,11 +241,11 @@ ecma_GetInternalProperty(ecma_Object_t *pObject, /**< object descriptor */ * NULL - otherwise. */ ecma_Property_t* -ecma_FindNamedProperty(ecma_Object_t *obj_p, /**< object to find property in */ - ecma_Char_t *string_p) /**< property's name */ +ecma_FindNamedProperty(ecma_Object_t *obj_p, /**< object to find property in */ + ecma_Char_t *name_p) /**< property's name */ { JERRY_ASSERT( obj_p != NULL ); - JERRY_ASSERT( string_p != NULL ); + JERRY_ASSERT( name_p != NULL ); for ( ecma_Property_t *property_p = ecma_GetPointer( obj_p->m_pProperties); property_p != NULL; @@ -232,7 +266,7 @@ ecma_FindNamedProperty(ecma_Object_t *obj_p, /**< object to find property in */ JERRY_ASSERT( property_name_p != NULL ); - if ( ecma_CompareCharBufferToEcmaString( string_p, property_name_p) ) + if ( ecma_CompareCharBufferToEcmaString( name_p, property_name_p) ) { return property_p; } @@ -241,17 +275,218 @@ ecma_FindNamedProperty(ecma_Object_t *obj_p, /**< object to find property in */ return NULL; } /* ecma_FindNamedProperty */ +/** + * Get named data property or named access property in specified object. + * + * Warning: + * the property must exist + * + * @return pointer to the property, if it is found, + * NULL - otherwise. + */ +ecma_Property_t* +ecma_GetNamedProperty(ecma_Object_t *obj_p, /**< object to find property in */ + ecma_Char_t *name_p) /**< property's name */ +{ + JERRY_ASSERT( obj_p != NULL ); + JERRY_ASSERT( name_p != NULL ); + + ecma_Property_t *property_p = ecma_FindNamedProperty( obj_p, name_p); + + JERRY_ASSERT( property_p != NULL ); + + return property_p; +} /* ecma_GetNamedProperty */ + +/** + * Get named data property in specified object. + * + * Warning: + * the property must exist and be named data property + * + * @return pointer to the property, if it is found, + * NULL - otherwise. + */ +ecma_Property_t* +ecma_GetNamedDataProperty(ecma_Object_t *obj_p, /**< object to find property in */ + ecma_Char_t *name_p) /**< property's name */ +{ + JERRY_ASSERT( obj_p != NULL ); + JERRY_ASSERT( name_p != NULL ); + + ecma_Property_t *property_p = ecma_FindNamedProperty( obj_p, name_p); + + JERRY_ASSERT( property_p != NULL && property_p->m_Type == ECMA_PROPERTY_NAMEDDATA ); + + return property_p; +} /* ecma_GetNamedDataProperty */ + +/** + * Free the named data property and values it references. + */ +void +ecma_FreeNamedDataProperty( ecma_Property_t *pProperty) /**< the property */ +{ + JERRY_ASSERT( pProperty->m_Type == ECMA_PROPERTY_NAMEDDATA ); + + ecma_FreeArray( ecma_GetPointer( pProperty->u.m_NamedDataProperty.m_pName)); + ecma_FreeValue( pProperty->u.m_NamedDataProperty.m_Value); + + ecma_DeallocProperty( pProperty); +} /* ecma_FreeNamedDataProperty */ + +/** + * Free the named accessor property and values it references. + */ +void +ecma_FreeNamedAccessorProperty( ecma_Property_t *pProperty) /**< the property */ +{ + JERRY_ASSERT( pProperty->m_Type == ECMA_PROPERTY_NAMEDACCESSOR ); + + ecma_FreeArray( ecma_GetPointer( pProperty->u.m_NamedAccessorProperty.m_pName)); + + ecma_Object_t *pGet = ecma_GetPointer(pProperty->u.m_NamedAccessorProperty.m_pGet); + ecma_Object_t *pSet = ecma_GetPointer(pProperty->u.m_NamedAccessorProperty.m_pSet); + + if ( pGet != NULL ) + { + ecma_DerefObject( pGet); + } + + if ( pSet != NULL ) + { + ecma_DerefObject( pSet); + } + + ecma_DeallocProperty( pProperty); +} /* ecma_FreeNamedAccessorProperty */ + +/** + * Free the internal property and values it references. + */ +void +ecma_FreeInternalProperty( ecma_Property_t *pProperty) /**< the property */ +{ + JERRY_ASSERT( pProperty->m_Type == ECMA_PROPERTY_INTERNAL ); + + ecma_InternalPropertyId_t propertyId = pProperty->u.m_InternalProperty.m_InternalPropertyType; + uint32_t propertyValue = pProperty->u.m_InternalProperty.m_Value; + + switch ( propertyId ) + { + case ECMA_INTERNAL_PROPERTY_CLASS: /* a string */ + case ECMA_INTERNAL_PROPERTY_NUMBER_INDEXED_ARRAY_VALUES: /* an array */ + case ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES: /* an array */ + { + ecma_FreeArray( ecma_GetPointer( propertyValue)); + break; + } + + case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */ + case ECMA_INTERNAL_PROPERTY_BINDING_OBJECT: /* an object */ + { + ecma_DerefObject( ecma_GetPointer( propertyValue)); + break; + } + + case ECMA_INTERNAL_PROPERTY_PROTOTYPE: /* the property's value is located in ecma_Object_t */ + case ECMA_INTERNAL_PROPERTY_EXTENSIBLE: /* the property's value is located in ecma_Object_t */ + case ECMA_INTERNAL_PROPERTY_PROVIDE_THIS: /* a boolean flag */ + { + break; + } + } + + ecma_DeallocProperty( pProperty); +} /* ecma_FreeInternalProperty */ + +/** + * Free the property and values it references. + */ +void +ecma_FreeProperty(ecma_Property_t *prop_p) /**< property */ +{ + switch ( (ecma_PropertyType_t) prop_p->m_Type ) + { + case ECMA_PROPERTY_NAMEDDATA: + { + ecma_FreeNamedDataProperty( prop_p); + + break; + } + + case ECMA_PROPERTY_NAMEDACCESSOR: + { + ecma_FreeNamedAccessorProperty( prop_p); + + break; + } + + case ECMA_PROPERTY_INTERNAL: + { + ecma_FreeInternalProperty( prop_p); + + break; + } + } +} /* ecma_FreeProperty */ + +/** + * Delete the object's property. + * + * Warning: specified property must be owned by specified object. + */ +void +ecma_DeleteProperty(ecma_Object_t *obj_p, /**< object */ + ecma_Property_t *prop_p) /**< property */ +{ + for ( ecma_Property_t *cur_prop_p = ecma_GetPointer( obj_p->m_pProperties), *prev_prop_p = NULL, *next_prop_p; + cur_prop_p != NULL; + prev_prop_p = cur_prop_p, cur_prop_p = next_prop_p ) + { + next_prop_p = ecma_GetPointer( cur_prop_p->m_pNextProperty); + + if ( cur_prop_p == prop_p ) + { + ecma_FreeProperty( prop_p); + + if ( prev_prop_p == NULL ) + { + ecma_SetPointer( obj_p->m_pProperties, next_prop_p); + } else + { + ecma_SetPointer( prev_prop_p->m_pNextProperty, next_prop_p); + } + + return; + } + } + + JERRY_UNREACHABLE(); +} /* ecma_DeleteProperty */ + /** * Allocate new ecma-string and fill it with characters from specified buffer * * @return Pointer to first chunk of an array, containing allocated string */ ecma_ArrayFirstChunk_t* -ecma_NewEcmaString(const ecma_Char_t *pString, /**< buffer of characters */ - ecma_Length_t length) /**< length of string, in characters */ +ecma_NewEcmaString(const ecma_Char_t *pString) /**< zero-terminated string of ecma-characters */ { - JERRY_ASSERT( length == 0 || pString != NULL ); + ecma_Length_t length = 0; + /* + * TODO: Do not precalculate length. + */ + if ( pString != NULL ) + { + const ecma_Char_t *iter_p = pString; + while ( *iter_p++ ) + { + length++; + } + } + ecma_ArrayFirstChunk_t *pStringFirstChunk = ecma_AllocArrayFirstChunk(); pStringFirstChunk->m_Header.m_UnitNumber = length; @@ -395,13 +630,13 @@ ecma_FreeArray( ecma_ArrayFirstChunk_t *pFirstChunk) /**< first chunk of the arr ecma_ArrayNonFirstChunk_t *pNonFirstChunk = ecma_GetPointer( pFirstChunk->m_Header.m_pNextChunk); - ecma_FreeArrayFirstChunk( pFirstChunk); + ecma_DeallocArrayFirstChunk( pFirstChunk); while ( pNonFirstChunk != NULL ) { ecma_ArrayNonFirstChunk_t *pNextChunk = ecma_GetPointer( pNonFirstChunk->m_pNextChunk); - ecma_FreeArrayNonFirstChunk( pNonFirstChunk); + ecma_DeallocArrayNonFirstChunk( pNonFirstChunk); pNonFirstChunk = pNextChunk; } diff --git a/src/libecmaobjects/ecma-helpers.h b/src/libecmaobjects/ecma-helpers.h index e0dd15d56..8f87ddaf2 100644 --- a/src/libecmaobjects/ecma-helpers.h +++ b/src/libecmaobjects/ecma-helpers.h @@ -42,16 +42,22 @@ extern void* ecma_DecompressPointer(uintptr_t compressedPointer); (field) = ecma_CompressPointer( nonCompressedPointer) & ( ( 1u << ECMA_POINTER_FIELD_WIDTH ) - 1) /* ecma-helpers-value.c */ -extern bool ecma_IsUndefinedValue( ecma_Value_t value); -extern bool ecma_IsNullValue( ecma_Value_t value); -extern bool ecma_IsBooleanValue( ecma_Value_t value); +extern bool ecma_IsValueUndefined( ecma_Value_t value); +extern bool ecma_IsValueNull( ecma_Value_t value); +extern bool ecma_IsValueBoolean( ecma_Value_t value); extern bool ecma_IsValueTrue( ecma_Value_t value); extern ecma_Value_t ecma_MakeSimpleValue( ecma_SimpleValue_t value); extern ecma_Value_t ecma_MakeObjectValue( ecma_Object_t* object_p); +extern ecma_Value_t ecma_CopyValue( const ecma_Value_t value); +extern void ecma_FreeValue( const ecma_Value_t value); + extern ecma_CompletionValue_t ecma_MakeCompletionValue( ecma_CompletionType_t type, ecma_Value_t value, uint8_t target); extern ecma_CompletionValue_t ecma_MakeThrowValue( ecma_Object_t *exception_p); +extern bool ecma_IsCompletionValueNormalFalse( ecma_CompletionValue_t value); +extern bool ecma_IsCompletionValueNormalTrue( ecma_CompletionValue_t value); + extern ecma_Object_t* ecma_CreateObject( ecma_Object_t *pPrototypeObject, bool isExtensible); extern ecma_Object_t* ecma_CreateLexicalEnvironment( ecma_Object_t *pOuterLexicalEnvironment, ecma_LexicalEnvironmentType_t type); @@ -59,11 +65,20 @@ extern ecma_Object_t* ecma_CreateLexicalEnvironment( ecma_Object_t *pOuterLexica extern ecma_Property_t* ecma_CreateInternalProperty(ecma_Object_t *pObject, ecma_InternalPropertyId_t propertyId); extern ecma_Property_t* ecma_FindInternalProperty(ecma_Object_t *pObject, ecma_InternalPropertyId_t propertyId); extern ecma_Property_t* ecma_GetInternalProperty(ecma_Object_t *pObject, ecma_InternalPropertyId_t propertyId); -extern ecma_Property_t* ecma_SetInternalProperty(ecma_Object_t *pObject, ecma_InternalPropertyId_t propertyId); -extern ecma_Property_t *ecma_FindNamedProperty(ecma_Object_t *obj_p, ecma_Char_t *string_p); +extern ecma_Property_t *ecma_CreateNamedProperty(ecma_Object_t *obj_p, ecma_Char_t *name_p, ecma_PropertyWritableValue_t writable, ecma_PropertyEnumerableValue_t enumerable, ecma_PropertyConfigurableValue_t configurable); +extern ecma_Property_t *ecma_FindNamedProperty(ecma_Object_t *obj_p, ecma_Char_t *name_p); +extern ecma_Property_t *ecma_GetNamedProperty(ecma_Object_t *obj_p, ecma_Char_t *name_p); +extern ecma_Property_t *ecma_GetNamedDataProperty(ecma_Object_t *obj_p, ecma_Char_t *name_p); -extern ecma_ArrayFirstChunk_t* ecma_NewEcmaString( const ecma_Char_t *pString, ecma_Length_t length); +extern void ecma_FreeInternalProperty(ecma_Property_t *prop_p); +extern void ecma_FreeNamedDataProperty(ecma_Property_t *prop_p); +extern void ecma_FreeNamedAccessorProperty(ecma_Property_t *prop_p); +extern void ecma_FreeProperty(ecma_Property_t *prop_p); + +extern void ecma_DeleteProperty( ecma_Object_t *obj_p, ecma_Property_t *prop_p); + +extern ecma_ArrayFirstChunk_t* ecma_NewEcmaString( const ecma_Char_t *pString); extern ssize_t ecma_CopyEcmaStringCharsToBuffer( ecma_ArrayFirstChunk_t *pFirstChunk, uint8_t *pBuffer, size_t bufferSize); extern ecma_ArrayFirstChunk_t* ecma_DuplicateEcmaString( ecma_ArrayFirstChunk_t *pFirstChunk); extern bool ecma_CompareCharBufferToEcmaString( ecma_Char_t *pString, ecma_ArrayFirstChunk_t *pEcmaString); diff --git a/src/libecmaoperations/ecma-get-put-value.c b/src/libecmaoperations/ecma-get-put-value.c index a00413965..8a632b7a2 100644 --- a/src/libecmaoperations/ecma-get-put-value.c +++ b/src/libecmaoperations/ecma-get-put-value.c @@ -18,7 +18,6 @@ */ #include "ecma-exceptions.h" -#include "ecma-gc.h" #include "ecma-helpers.h" #include "ecma-lex-env.h" #include "ecma-operations.h" @@ -30,49 +29,6 @@ * @{ */ -/** - * Resolve syntactic reference to ECMA-reference. - * - * Warning: string pointed by name_p - * must not be freed or reused - * until the reference is freed. - * - * @return ECMA-reference (if base value is an object, upon return - * it's reference counter is increased by one). - */ -ecma_Reference_t -ecma_OpGetIdentifierReference(ecma_Object_t *lex_env_p, /**< lexical environment */ - ecma_Char_t *name_p, /**< identifier's name */ - bool is_strict) /**< strict reference flag */ -{ - JERRY_ASSERT( lex_env_p != NULL ); - - ecma_Object_t *lex_env_iter_p = lex_env_p; - - while ( lex_env_iter_p != NULL ) - { - ecma_CompletionValue_t completion_value; - completion_value = ecma_OpHasBinding( lex_env_iter_p, name_p); - - JERRY_ASSERT( completion_value.type == ECMA_COMPLETION_TYPE_NORMAL ); - - if ( ecma_IsValueTrue( completion_value.value) ) - { - ecma_RefObject( lex_env_iter_p); - - return (ecma_Reference_t) { .base = ecma_MakeObjectValue( lex_env_iter_p), - .referenced_name_p = name_p, - .is_strict = is_strict }; - } - - lex_env_iter_p = ecma_GetPointer( lex_env_iter_p->u.m_LexicalEnvironment.m_pOuterReference); - } - - return (ecma_Reference_t) { .base = ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_UNDEFINED), - .referenced_name_p = NULL, - .is_strict = is_strict }; -} /* ecma_OpGetIdentifierReference */ - /** * GetValue operation. * @@ -82,28 +38,31 @@ ecma_CompletionValue_t ecma_OpGetValue( ecma_Reference_t *ref_p) /**< ECMA-reference */ { const ecma_Value_t base = ref_p->base; - const bool is_unresolvable_reference = ecma_IsUndefinedValue( base); - const bool has_primitive_base = ( ecma_IsBooleanValue( base) + const bool is_unresolvable_reference = ecma_IsValueUndefined( base); + const bool has_primitive_base = ( ecma_IsValueBoolean( base) || base.m_ValueType == ECMA_TYPE_NUMBER || base.m_ValueType == ECMA_TYPE_STRING ); const bool is_property_reference = has_primitive_base || ( base.m_ValueType == ECMA_TYPE_OBJECT ); + // GetValue_3 if ( is_unresolvable_reference ) { return ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_REFERENCE)); } + // GetValue_4 if ( is_property_reference ) { - if ( !has_primitive_base ) + if ( !has_primitive_base ) // GetValue_4.a { ecma_Object_t *obj_p = ecma_GetPointer( base.m_Value); JERRY_ASSERT( obj_p != NULL && !obj_p->m_IsLexicalEnvironment ); - /* return [[Get]]( obj_p as this, ref_p->referenced_name_p) */ + // GetValue_4.b case 1 + /* return [[Get]]( base as this, ref_p->referenced_name_p) */ JERRY_UNIMPLEMENTED(); } else - { + { // GetValue_4.b case 2 /* ecma_Object_t *obj_p = ecma_ToObject( base); JERRY_ASSERT( obj_p != NULL && !obj_p->m_IsLexicalEnvironment ); @@ -126,7 +85,7 @@ ecma_OpGetValue( ecma_Reference_t *ref_p) /**< ECMA-reference */ ECMA_TARGET_ID_RESERVED); } else { - [[Call]]( getter, base as this); + return [[Call]]( getter, base as this); } } */ @@ -134,6 +93,7 @@ ecma_OpGetValue( ecma_Reference_t *ref_p) /**< ECMA-reference */ } } else { + // GetValue_5 ecma_Object_t *lex_env_p = ecma_GetPointer( base.m_Value); JERRY_ASSERT( lex_env_p != NULL && lex_env_p->m_IsLexicalEnvironment ); @@ -151,7 +111,116 @@ ecma_CompletionValue_t ecma_OpSetValue(ecma_Reference_t *ref_p, /**< ECMA-reference */ ecma_Value_t value) /**< ECMA-value */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( ref_p, value); + const ecma_Value_t base = ref_p->base; + const bool is_unresolvable_reference = ecma_IsValueUndefined( base); + const bool has_primitive_base = ( ecma_IsValueBoolean( base) + || base.m_ValueType == ECMA_TYPE_NUMBER + || base.m_ValueType == ECMA_TYPE_STRING ); + const bool is_property_reference = has_primitive_base || ( base.m_ValueType == ECMA_TYPE_OBJECT ); + + if ( is_unresolvable_reference ) // PutValue_3 + { + if ( ref_p->is_strict ) // PutValue_3.a + { + return ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_REFERENCE)); + } else // PutValue_3.b + { + /* + ecma_Object_t *global_object_p = ecma_GetGlobalObject(); + + return global_object_p->[[Put]]( ref_p->referenced_name_p, value, false); + */ + + JERRY_UNIMPLEMENTED(); + } + } else if ( is_property_reference ) // PutValue_4 + { + if ( !has_primitive_base ) // PutValue_4.a + { + // PutValue_4.b case 1 + + /* return [[Put]]( base as this, ref_p->referenced_name_p, value, ref_p->is_strict); */ + JERRY_UNIMPLEMENTED(); + } else + { + // PutValue_4.b case 2 + + /* + // PutValue_sub_1 + ecma_Object_t *obj_p = ecma_ToObject( base); + JERRY_ASSERT( obj_p != NULL && !obj_p->m_IsLexicalEnvironment ); + + // PutValue_sub_2 + if ( !obj_p->[[CanPut]]( ref_p->referenced_name_p) ) + { + // PutValue_sub_2.a + if ( ref_p->is_strict ) + { + return ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_TYPE)); + } else + { // PutValue_sub_2.b + return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL, + ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_EMPTY), + ECMA_TARGET_ID_RESERVED); + } + } + + // PutValue_sub_3 + ecma_Property_t *own_prop = obj_p->[[GetOwnProperty]]( ref_p->referenced_name_p); + + // PutValue_sub_4 + if ( ecma_OpIsDataDescriptor( own_prop) ) + { + // PutValue_sub_4.a + if ( ref_p->is_strict ) + { + return ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_TYPE)); + } else + { // PutValue_sub_4.b + return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL, + ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_EMPTY), + ECMA_TARGET_ID_RESERVED); + } + } + + // PutValue_sub_5 + ecma_Property_t *prop = obj_p->[[GetProperty]]( ref_p->referenced_name_p); + + // PutValue_sub_6 + if ( ecma_OpIsAccessorDescriptor( prop) ) + { + // PutValue_sub_6.a + ecma_Object_t *setter = ecma_GetPointer( property->u.m_NamedAccessorProperty.m_pSet); + JERRY_ASSERT( setter != NULL ); + + // PutValue_sub_6.b + return [[Call]]( setter, base as this, value); + } else // PutValue_sub_7 + { + // PutValue_sub_7.a + if ( ref_p->is_strict ) + { + return ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_TYPE)); + } + } + + // PutValue_sub_8 + return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL, + ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_EMPTY), + ECMA_TARGET_ID_RESERVED); + */ + + JERRY_UNIMPLEMENTED(); + } + } else + { + // PutValue_7 + ecma_Object_t *lex_env_p = ecma_GetPointer( base.m_Value); + + JERRY_ASSERT( lex_env_p != NULL && lex_env_p->m_IsLexicalEnvironment ); + + return ecma_OpSetMutableBinding( lex_env_p, ref_p->referenced_name_p, value, ref_p->is_strict); + } } /* ecma_OpSetValue */ /** diff --git a/src/libecmaoperations/ecma-lex-env.c b/src/libecmaoperations/ecma-lex-env.c index be79fcbe5..f98599016 100644 --- a/src/libecmaoperations/ecma-lex-env.c +++ b/src/libecmaoperations/ecma-lex-env.c @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "ecma-exceptions.h" #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-lex-env.h" @@ -46,7 +47,8 @@ ecma_OpHasBinding(ecma_Object_t *lex_env_p, /**< lexical environment */ { ecma_Property_t *property_p = ecma_FindNamedProperty( lex_env_p, name_p); - has_binding = ( property_p != NULL ) ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE; + has_binding = ( property_p != NULL ) ? ECMA_SIMPLE_VALUE_TRUE + : ECMA_SIMPLE_VALUE_FALSE; } case ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND: { @@ -69,7 +71,32 @@ ecma_OpCreateMutableBinding(ecma_Object_t *lex_env_p, /**< lexical environment * ecma_Char_t *name_p, /**< argument N */ bool is_deletable) /**< argument D */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( lex_env_p, name_p, is_deletable); + JERRY_ASSERT( lex_env_p != NULL && lex_env_p->m_IsLexicalEnvironment ); + JERRY_ASSERT( name_p != NULL ); + + switch ( (ecma_LexicalEnvironmentType_t) lex_env_p->u.m_LexicalEnvironment.m_Type ) + { + case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE: + { + JERRY_ASSERT( ecma_IsCompletionValueNormalFalse( ecma_OpHasBinding( lex_env_p, name_p)) ); + + ecma_CreateNamedProperty( lex_env_p, + name_p, + ECMA_PROPERTY_WRITABLE, + ECMA_PROPERTY_NOT_ENUMERABLE, + is_deletable ? ECMA_PROPERTY_CONFIGURABLE + : ECMA_PROPERTY_NOT_CONFIGURABLE); + + } + case ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND: + { + JERRY_UNIMPLEMENTED(); + } + } + + return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL, + ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_EMPTY), + ECMA_TARGET_ID_RESERVED); } /* ecma_OpCreateMutableBinding */ /** @@ -83,7 +110,34 @@ ecma_OpSetMutableBinding(ecma_Object_t *lex_env_p, /**< lexical environment */ ecma_Value_t value, /**< argument V */ bool is_strict) /**< argument S */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( lex_env_p, name_p, value, is_strict); + JERRY_ASSERT( lex_env_p != NULL && lex_env_p->m_IsLexicalEnvironment ); + JERRY_ASSERT( name_p != NULL ); + + JERRY_ASSERT( ecma_IsCompletionValueNormalTrue( ecma_OpHasBinding( lex_env_p, name_p)) ); + + switch ( (ecma_LexicalEnvironmentType_t) lex_env_p->u.m_LexicalEnvironment.m_Type ) + { + case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE: + { + ecma_Property_t *property_p = ecma_GetNamedDataProperty( lex_env_p, name_p); + + if ( property_p->u.m_NamedDataProperty.m_Writable == ECMA_PROPERTY_WRITABLE ) + { + property_p->u.m_NamedDataProperty.m_Value = value; + } else if ( is_strict ) + { + return ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_TYPE)); + } + } + case ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND: + { + JERRY_UNIMPLEMENTED(); + } + } + + return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL, + ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_EMPTY), + ECMA_TARGET_ID_RESERVED); } /* ecma_OpSetMutableBinding */ /** @@ -96,7 +150,47 @@ ecma_OpGetBindingValue(ecma_Object_t *lex_env_p, /**< lexical environment */ ecma_Char_t *name_p, /**< argument N */ bool is_strict) /**< argument S */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( lex_env_p, name_p, is_strict); + JERRY_ASSERT( lex_env_p != NULL && lex_env_p->m_IsLexicalEnvironment ); + JERRY_ASSERT( name_p != NULL ); + + JERRY_ASSERT( ecma_IsCompletionValueNormalTrue( ecma_OpHasBinding( lex_env_p, name_p)) ); + + switch ( (ecma_LexicalEnvironmentType_t) lex_env_p->u.m_LexicalEnvironment.m_Type ) + { + case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE: + { + ecma_Property_t *property_p = ecma_GetNamedDataProperty( lex_env_p, name_p); + + ecma_Value_t prop_value = property_p->u.m_NamedDataProperty.m_Value; + + /* is the binding mutable? */ + if ( property_p->u.m_NamedDataProperty.m_Writable == ECMA_PROPERTY_WRITABLE ) + { + return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL, + prop_value, + ECMA_TARGET_ID_RESERVED); + } else if ( prop_value.m_ValueType == ECMA_TYPE_SIMPLE + && prop_value.m_Value == ECMA_SIMPLE_VALUE_EMPTY ) + { + /* unitialized immutable binding */ + if ( is_strict ) + { + return ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_REFERENCE)); + } else + { + return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL, + ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_UNDEFINED), + ECMA_TARGET_ID_RESERVED); + } + } + } + case ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND: + { + JERRY_UNIMPLEMENTED(); + } + } + + JERRY_UNREACHABLE(); } /* ecma_OpGetBindingValue */ /** @@ -108,7 +202,45 @@ ecma_CompletionValue_t ecma_OpDeleteBinding(ecma_Object_t *lex_env_p, /**< lexical environment */ ecma_Char_t *name_p) /**< argument N */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( lex_env_p, name_p); + JERRY_ASSERT( lex_env_p != NULL && lex_env_p->m_IsLexicalEnvironment ); + JERRY_ASSERT( name_p != NULL ); + + switch ( (ecma_LexicalEnvironmentType_t) lex_env_p->u.m_LexicalEnvironment.m_Type ) + { + case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE: + { + ecma_Property_t *prop_p = ecma_FindNamedProperty( lex_env_p, name_p); + ecma_SimpleValue_t ret_val; + + if ( prop_p == NULL ) + { + ret_val = ECMA_SIMPLE_VALUE_TRUE; + } else + { + JERRY_ASSERT( prop_p->m_Type == ECMA_PROPERTY_NAMEDDATA ); + + if ( prop_p->u.m_NamedDataProperty.m_Configurable == ECMA_PROPERTY_NOT_CONFIGURABLE ) + { + ret_val = ECMA_SIMPLE_VALUE_FALSE; + } else + { + ecma_DeleteProperty( lex_env_p, prop_p); + + ret_val = ECMA_SIMPLE_VALUE_TRUE; + } + } + + return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL, + ecma_MakeSimpleValue( ret_val), + ECMA_TARGET_ID_RESERVED); + } + case ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND: + { + JERRY_UNIMPLEMENTED(); + } + } + + JERRY_UNREACHABLE(); } /* ecma_OpDeleteBinding */ /** @@ -119,7 +251,23 @@ ecma_OpDeleteBinding(ecma_Object_t *lex_env_p, /**< lexical environment */ ecma_CompletionValue_t ecma_OpImplicitThisValue( ecma_Object_t *lex_env_p) /**< lexical environment */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( lex_env_p); + JERRY_ASSERT( lex_env_p != NULL && lex_env_p->m_IsLexicalEnvironment ); + + switch ( (ecma_LexicalEnvironmentType_t) lex_env_p->u.m_LexicalEnvironment.m_Type ) + { + case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE: + { + return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL, + ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_UNDEFINED), + ECMA_TARGET_ID_RESERVED); + } + case ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND: + { + JERRY_UNIMPLEMENTED(); + } + } + + JERRY_UNREACHABLE(); } /* ecma_OpImplicitThisValue */ /** @@ -131,7 +279,35 @@ ecma_CompletionValue_t ecma_OpCreateImmutableBinding(ecma_Object_t *lex_env_p, /**< lexical environment */ ecma_Char_t *name_p) /**< argument N */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( lex_env_p, name_p); + JERRY_ASSERT( lex_env_p != NULL && lex_env_p->m_IsLexicalEnvironment ); + + switch ( (ecma_LexicalEnvironmentType_t) lex_env_p->u.m_LexicalEnvironment.m_Type ) + { + case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE: + { + JERRY_ASSERT( ecma_IsCompletionValueNormalFalse( ecma_OpHasBinding( lex_env_p, name_p)) ); + + /* + * Warning: + * Whether immutable bindings are deletable seems not to be defined by ECMA v5. + */ + ecma_Property_t *prop_p = ecma_CreateNamedProperty( lex_env_p, + name_p, + ECMA_PROPERTY_NOT_WRITABLE, + ECMA_PROPERTY_NOT_ENUMERABLE, + ECMA_PROPERTY_NOT_CONFIGURABLE); + + JERRY_ASSERT( prop_p->u.m_NamedDataProperty.m_Value.m_ValueType == ECMA_TYPE_SIMPLE ); + + prop_p->u.m_NamedDataProperty.m_Value.m_Value = ECMA_SIMPLE_VALUE_EMPTY; + } + case ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND: + { + JERRY_UNREACHABLE(); + } + } + + JERRY_UNREACHABLE(); } /* ecma_OpCreateImmutableBinding */ /** @@ -144,7 +320,30 @@ ecma_OpInitializeImmutableBinding(ecma_Object_t *lex_env_p, /**< lexical environ ecma_Char_t *name_p, /**< argument N */ ecma_Value_t value) /**< argument V */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( lex_env_p, name_p, value); + JERRY_ASSERT( lex_env_p != NULL && lex_env_p->m_IsLexicalEnvironment ); + + switch ( (ecma_LexicalEnvironmentType_t) lex_env_p->u.m_LexicalEnvironment.m_Type ) + { + case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE: + { + JERRY_ASSERT( ecma_IsCompletionValueNormalTrue( ecma_OpHasBinding( lex_env_p, name_p)) ); + + ecma_Property_t *prop_p = ecma_GetNamedDataProperty( lex_env_p, name_p); + + /* The binding must be unitialized immutable binding */ + JERRY_ASSERT( prop_p->u.m_NamedDataProperty.m_Writable == ECMA_PROPERTY_NOT_WRITABLE + && prop_p->u.m_NamedDataProperty.m_Value.m_ValueType == ECMA_TYPE_SIMPLE + && prop_p->u.m_NamedDataProperty.m_Value.m_Value == ECMA_SIMPLE_VALUE_EMPTY ); + + prop_p->u.m_NamedDataProperty.m_Value = value; + } + case ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND: + { + JERRY_UNREACHABLE(); + } + } + + JERRY_UNREACHABLE(); } /* ecma_OpInitializeImmutableBinding */ /** diff --git a/src/libecmaoperations/ecma-reference.c b/src/libecmaoperations/ecma-reference.c new file mode 100644 index 000000000..5e957b5e7 --- /dev/null +++ b/src/libecmaoperations/ecma-reference.c @@ -0,0 +1,109 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-gc.h" +#include "ecma-globals.h" +#include "ecma-helpers.h" +#include "ecma-lex-env.h" +#include "ecma-reference.h" +#include "globals.h" + +/** \addtogroup ecma ---TODO--- + * @{ + */ + +/** + * \addtogroup references ECMA-Reference + * @{ + */ + +/** + * Resolve syntactic reference to ECMA-reference. + * + * Warning: string pointed by name_p + * must not be freed or reused + * until the reference is freed. + * + * @return ECMA-reference (if base value is an object, upon return + * it's reference counter is increased by one). + */ +ecma_Reference_t +ecma_OpGetIdentifierReference(ecma_Object_t *lex_env_p, /**< lexical environment */ + ecma_Char_t *name_p, /**< identifier's name */ + bool is_strict) /**< strict reference flag */ +{ + JERRY_ASSERT( lex_env_p != NULL ); + + ecma_Object_t *lex_env_iter_p = lex_env_p; + + while ( lex_env_iter_p != NULL ) + { + ecma_CompletionValue_t completion_value; + completion_value = ecma_OpHasBinding( lex_env_iter_p, name_p); + + if ( ecma_IsCompletionValueNormalTrue( completion_value) ) + { + return ecma_MakeReference( ecma_MakeObjectValue( lex_env_iter_p), + name_p, + is_strict); + } else + { + JERRY_ASSERT( ecma_IsCompletionValueNormalFalse( completion_value) ); + } + + lex_env_iter_p = ecma_GetPointer( lex_env_iter_p->u.m_LexicalEnvironment.m_pOuterReference); + } + + return ecma_MakeReference( ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_UNDEFINED), + name_p, + is_strict); +} /* ecma_OpGetIdentifierReference */ + +/** + * ECMA-reference constructor. + * + * Warning: string pointed by name_p + * must not be freed or reused + * until the reference is freed. + * + * @return ECMA-reference (if base_p it not NULL, then upon return + * corresponding object's reference counter is increased by one). + */ +ecma_Reference_t +ecma_MakeReference(ecma_Value_t base, /**< base value */ + ecma_Char_t *name_p, /**< referenced name */ + bool is_strict) /**< strict reference flag */ +{ + return (ecma_Reference_t) { .base = ecma_CopyValue( base), + .referenced_name_p = name_p, + .is_strict = is_strict }; +} /* ecma_MakeReference */ + +/** + * Free specified ECMA-reference. + * + * Warning: + * after freeing all copy of the reference become invalid. + */ +void +ecma_FreeReference( const ecma_Reference_t ref) /**< reference */ +{ + ecma_FreeValue( ref.base); +} /* ecma_FreeReference */ + +/** + * @} + * @} + */ diff --git a/src/libecmaoperations/ecma-reference.h b/src/libecmaoperations/ecma-reference.h new file mode 100644 index 000000000..78e3b4172 --- /dev/null +++ b/src/libecmaoperations/ecma-reference.h @@ -0,0 +1,40 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMA_REFERENCE_H +#define ECMA_REFERENCE_H + +#include "ecma-globals.h" +#include "globals.h" + +/** \addtogroup ecma ---TODO--- + * @{ + */ + +/** + * \addtogroup references ECMA-Reference + * @{ + */ + +extern ecma_Reference_t ecma_OpGetIdentifierReference(ecma_Object_t *lex_env_p, ecma_Char_t *name_p, bool is_strict); +extern ecma_Reference_t ecma_MakeReference( ecma_Value_t base, ecma_Char_t *name_p, bool is_strict); +extern void ecma_FreeReference( const ecma_Reference_t ref); + +/** + * @} + * @} + */ + +#endif /* !ECMA_REFERENCE_H */