diff --git a/Makefile b/Makefile index aa5b4b0dc..20657979a 100644 --- a/Makefile +++ b/Makefile @@ -25,18 +25,18 @@ INCLUDES = -I src OBJS = $(sort \ $(patsubst %.c,./$(OBJ_DIR)/%.o,$(notdir $(SOURCES)))) -CC = $(CROSS_COMPILE)gcc +CC = $(CROSS_COMPILE)gcc-4.8 LD = $(CROSS_COMPILE)ld OBJDUMP = $(CROSS_COMPILE)objdump OBJCOPY = $(CROSS_COMPILE)objcopy SIZE = $(CROSS_COMPILE)size # General flags -CFLAGS ?= $(INCLUDES) -Wall -std=c99 -fdiagnostics-color=always -CFLAGS += -Wextra -Wpedantic -Wformat-security -Wlogical-op -CFLAGS += -Wformat-nonliteral -Winit-self -Wstack-protector -CFLAGS += -Wconversion -Wsign-conversion -Winline -CFLAGS += -Wstrict-prototypes -Wmissing-prototypes +CFLAGS ?= $(INCLUDES) -Wall -std=c99 -m32# -fdiagnostics-color=always +#CFLAGS += -Wextra -Wpedantic -Wformat-security -Wlogical-op +#CFLAGS += -Wformat-nonliteral -Winit-self -Wstack-protector +#CFLAGS += -Wconversion -Wsign-conversion -Winline +#CFLAGS += -Wstrict-prototypes -Wmissing-prototypes # Flags for MCU #CFLAGS += -mlittle-endian -mcpu=cortex-m4 -march=armv7e-m -mthumb @@ -46,20 +46,22 @@ CFLAGS += -Wstrict-prototypes -Wmissing-prototypes DEBUG_OPTIONS = -g3 -O0 -DDEBUG #-fsanitize=address RELEASE_OPTIONS = -Os -Werror +DEFINES = -DMEM_HEAP_CHUNK_SIZE=256 -DMEM_HEAP_AREA_SIZE=32768 + .PHONY: all debug release clean install test all: debug debug: - $(CC) $(INCLUDES) $(CFLAGS) $(DEBUG_OPTIONS) $(SOURCES) \ + $(CC) $(INCLUDES) $(CFLAGS) $(DEBUG_OPTIONS) $(DEFINES) $(SOURCES) \ -o $(TARGET) release: - $(CC) $(INCLUDES) $(CFLAGS) $(RELEASE_OPTIONS) $(SOURCES) \ + $(CC) $(INCLUDES) $(CFLAGS) $(RELEASE_OPTIONS) $(DEFINES) $(SOURCES) \ -o $(TARGET) clean: - rm -f $(OBJ_DIR)/*.o *.o + rm -f $(OBJ_DIR)/*.o *.o *~ lexer.log parser.log rm -f $(TARGET) rm -f $(TARGET).elf rm -f $(TARGET).bin diff --git a/src/ctx-reference.c b/src/ctx-reference.c new file mode 100644 index 000000000..43f839bb2 --- /dev/null +++ b/src/ctx-reference.c @@ -0,0 +1,224 @@ +/* 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. + */ + +/** \addtogroup ctxman Context manager + * @{ + * + * \addtogroup resolvedreference Resolved reference type + * @{ + */ + +/** + * Implementation of Reference's operations + */ + +#include "defs.h" +#include "ecma_defs.h" +#include "ecma_helpers.h" +#include "ctx-reference.h" + +/** + * GetBase operation of Reference. + * + * @return base value component of reference + */ +ecma_Object_t* +ctx_reference_get_base( ctx_Reference_t *reference_p) /**< reference */ +{ + return reference_p->m_Base; +} /* ctx_reference_get_base */ + +/** + * GetReferencedName operation of Reference. + * + * @return pointer to first chunk of ecma-array containing the referenced name + */ +const ecma_ArrayFirstChunk_t* +ctx_reference_get_referenced_name( ctx_Reference_t *reference_p) /**< reference */ +{ + const ecma_Property_t *property_p = reference_p->m_ReferencedProperty; + + switch ( (ecma_PropertyType_t) property_p->m_Type ) + { + case ECMA_PROPERTY_NAMEDDATA: + return ecma_GetPointer( property_p->u.m_NamedDataProperty.m_pName); + + case ECMA_PROPERTY_NAMEDACCESSOR: + return ecma_GetPointer( property_p->u.m_NamedAccessorProperty.m_pName); + + case ECMA_PROPERTY_INTERNAL: + /* will trap below */ + break; + } + + JERRY_UNREACHABLE(); +} /* ctx_reference_get_referenced_name */ + +/** + * IsStrictReference operation of Reference. + * + * @return strict component of reference: + * true - if reference is strict, + * false - otherwise. + */ +bool +ctx_reference_is_strict_reference( ctx_Reference_t *reference_p) /**< reference */ +{ + return reference_p->m_Strict; +} /* ctx_reference_is_strict_reference */ + +/** + * IsPropertyReference operation of Reference. + * + * @return true - if either the base value is an object or HasPrimitiveBase returns true; + * false - otherwise. + */ +bool +ctx_reference_is_property_reference( ctx_Reference_t * reference_p) /**< reference */ +{ + + return (reference_p->m_Base != NULL + && !reference_p->m_Base->m_IsLexicalEnvironment ); +} /* ctx_reference_is_property_reference */ + +/** + * IsUnresolvableReference operation of Reference. + * + * @return true - if the base value is undefined; + * false - otherwise. + */ +bool +ctx_reference_is_unresolvable_reference( ctx_Reference_t * reference_p) /**< reference */ +{ + return ( reference_p->m_Base == NULL ); +} /* ctx_reference_is_unresolvable_reference */ + +/** + * Get referenced property. + * + * @return pointer to ecma-property + * (which describes object's property or a lexical environment's binding). + */ +ecma_Property_t* +ctx_reference_get_referenced_component( ctx_Reference_t *reference_p) /**< reference */ +{ + return reference_p->m_ReferencedProperty; +} /* ctx_reference_get_referenced_component */ + +/** + * Resolve syntactic reference + * + * Note: + * Returned value must be freed using ctx_free_resolved_reference + * + * @return pointer to resolved reference description + */ +ctx_Reference_t* +ctx_resolve_syntactic_reference(ecma_Object_t *lex_env_p, /**< lexical environment of current context */ + ctx_SyntacticReference_t *syntactic_reference_p) /** syntactic reference + * to resolve */ +{ + JERRY_ASSERT(lex_env_p != NULL + && lex_env_p->m_GCInfo.m_IsObjectValid + && lex_env_p->m_IsLexicalEnvironment ); + JERRY_ASSERT(syntactic_reference_p != NULL + && syntactic_reference_p->m_Name != NULL + && ( !syntactic_reference_p->m_IsPropertyReference + || syntactic_reference_p->m_PropertyName != NULL ) ); + + ctx_Reference_t *reference_p = (ctx_Reference_t*) mem_HeapAllocBlock(sizeof (ctx_Reference_t), MEM_HEAP_ALLOC_LONG_TERM); + + bool is_variable_resolved = false; + ecma_Property_t *resolved_variable_p = NULL; + + /* resolving variable name */ + while ( !is_variable_resolved && lex_env_p != NULL ) + { + for ( ecma_Property_t *property_p = ecma_GetPointer( lex_env_p->m_pProperties); + property_p != NULL; + property_p = ecma_GetPointer( property_p->m_pNextProperty) ) + { + ecma_ArrayFirstChunk_t *property_name_p = NULL; + + /* + * TODO: make corresponding helper + */ + switch ( (ecma_PropertyType_t) property_p->m_Type ) + { + case ECMA_PROPERTY_NAMEDDATA: + property_name_p = ecma_GetPointer( property_p->u.m_NamedDataProperty.m_pName); + break; + + case ECMA_PROPERTY_NAMEDACCESSOR: + property_name_p = ecma_GetPointer( property_p->u.m_NamedAccessorProperty.m_pName); + break; + + case ECMA_PROPERTY_INTERNAL: + continue; + } + + if ( ecma_CompareCharBufferToEcmaString(syntactic_reference_p->m_Name, + property_name_p) ) + { + resolved_variable_p = property_p; + is_variable_resolved = true; + + break; + } + } + + lex_env_p = ecma_GetPointer( lex_env_p->u_Attributes.m_LexicalEnvironment.m_pOuterReference); + } + + if ( !is_variable_resolved ) + { + *reference_p = (ctx_Reference_t){ + .m_IsValid = true, + .m_Base = NULL, + .m_ReferencedProperty = NULL, + .m_Strict = syntactic_reference_p->m_StrictReference + }; + } else + { + if ( !syntactic_reference_p->m_IsPropertyReference ) + { + *reference_p = (ctx_Reference_t){ + .m_IsValid = true, + .m_Base = lex_env_p, + .m_ReferencedProperty = resolved_variable_p, + .m_Strict = syntactic_reference_p->m_StrictReference + }; + + } else + { + JERRY_UNIMPLEMENTED(); + } + } + + return reference_p; +} /* ctx_resolve_syntactic_reference */ + +void +ctx_free_resolved_reference( ctx_Reference_t *reference_p) +{ + (void)reference_p; + + JERRY_UNIMPLEMENTED(); +} /* ctx_free_resolved_reference */ + +/** + * @} + * @} + */ diff --git a/src/ctx-reference.h b/src/ctx-reference.h new file mode 100644 index 000000000..8380075ef --- /dev/null +++ b/src/ctx-reference.h @@ -0,0 +1,133 @@ +/* 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 CTX_REFERENCE_H +#define CTX_REFERENCE_H + +#include "ctx-reference.h" +#include "defs.h" +#include "ecma_defs.h" + +/** \addtogroup ctxman Context manager + * @{ + */ + +/** + * \addtogroup syntacticreference Textual reference to variable/property + * @{ + */ + +/** + * Syntactic (textual/unresolved) reference to a variable/object's property. + */ +typedef struct { + /** + * Flag indicating that this is reference to a property. + * + * Note: + * m_PropertyName is valid only if m_IsPropertyReference is true. + */ + uint32_t m_IsPropertyReference : 1; + + /** + * Flag indicating that this reference is strict (see also: ECMA-262 v5, 8.7). + */ + uint32_t m_StrictReference : 1; + + /** + * Name of variable (Null-terminated string). + */ + ecma_Char_t* m_Name; + + /** + * Name of object's property (Null-terminated string). + */ + ecma_Char_t* m_PropertyName; +} ctx_SyntacticReference_t; + +/** + * @} + */ + +/** + * \addtogroup resolvedreference Resolved reference type + * @{ + */ + +/** + * Description of resolved reference. + * + * Implementation details: + * 1. In contrast to Reference specification type the referenced name + * is not stored as string, but is resolved and stored as pointer + * to ecma-property. + * + * If the referenced element is deleted, the m_IsValid must be set to false. + * + * 2. Is base is Boolean, String, Number, then it is converted to Object via + * ecma_ToObject and then is stored in the reference. + * + * See also: ECMA-262 v5, 8.7. + */ +typedef struct +{ + /** + * Flag indicating whether the reference is valid. + * + * The flag is initially set to true. + * + */ + bool m_IsValid; + + /** + * Base value + * + * May be undefined (NULL), Object or Lexical Environment + */ + ecma_Object_t* m_Base; + + /** + * Referenced property. + * + * Note: + * in case base is lexical environment this is reference to variable. + */ + ecma_Property_t* m_ReferencedProperty; + + /** + * Strict reference flag. + */ + bool m_Strict; +} ctx_Reference_t; + +/* + * ctx-reference.c + */ +extern ecma_Object_t* ctx_reference_get_base( ctx_Reference_t *reference_p); +extern const ecma_ArrayFirstChunk_t* ctx_reference_get_referenced_name( ctx_Reference_t *reference_p); +extern bool ctx_reference_is_strict_reference( ctx_Reference_t *reference_p); +extern bool ctx_reference_is_property_reference( ctx_Reference_t *reference_p); +extern bool ctx_reference_is_unresolvable_reference( ctx_Reference_t *reference_p); +extern ecma_Property_t *ctx_reference_get_referenced_component( ctx_Reference_t *reference_p); + +extern ctx_Reference_t* ctx_resolve_syntactic_reference( ecma_Object_t *lex_env_p, ctx_SyntacticReference_t *syntactic_reference_p); +extern void ctx_free_resolved_reference( ctx_Reference_t *reference_p); + +/** + * @} + * @} + */ + +#endif /* !CTX_REFERENCE_H */ \ No newline at end of file diff --git a/src/ctx_manager.c b/src/ctx_manager.c new file mode 100644 index 000000000..80a4277d9 --- /dev/null +++ b/src/ctx_manager.c @@ -0,0 +1,560 @@ +/* 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 "ctx_manager.h" +#include "ctx-reference.h" +#include "defs.h" +#include "ecma_alloc.h" +#include "ecma_defs.h" +#include "ecma_conversion.h" +#include "ecma_gc.h" +#include "ecma_helpers.h" +#include "jerry_libc.h" +#include "mem_poolman.h" + +/** \addtogroup ctxman Context manager + * @{ + */ + +/** + * Maximum depth of varibles' context nestings stack. + * + * TODO: Move to configuration header. + */ +#define CTX_MAX_NUMBER_OF_VARIABLES_CONTEXTS 32 + +/** + * JerryScript needs at least one variables' context nesting. + */ +JERRY_STATIC_ASSERT( CTX_MAX_NUMBER_OF_VARIABLES_CONTEXTS >= 1 ); + +/** + * Description of a variables' context + */ +typedef struct +{ + /** + * Pointer to object, associated with 'this' keyword. + */ + ecma_Object_t *pThisBinding; + + /** + * Chain of lexical environments + */ + ecma_Object_t *pLexicalEnvironment; +} ctx_VariablesContext_t; + +/** + * Stack of variables' contexts. + */ +static ctx_VariablesContext_t ctx_Stack[ CTX_MAX_NUMBER_OF_VARIABLES_CONTEXTS ]; + +/** + * Current nestings' stack depth. + */ +static size_t ctx_ContextsNumber = 0; + +/** + * Current variables' context (context on the top of stack) + */ +#define ctx_CurrentContext ( ctx_Stack[ ctx_ContextsNumber - 1 ]) + +/** + * The global object + */ +ecma_Object_t* ctx_pGlobalObject; + +/** + * Get ecma-value from variable + * + * @return value descriptor + */ +static ecma_Value_t +ctx_GetValueDescriptorFromVariable( ctx_SyntacticReference_t *pVar) /**< variable */ +{ + /* + * TODO: + */ + (void)pVar; + JERRY_UNIMPLEMENTED(); +} /* ctx_GetValueDescriptorFromVariable */ + +/** + * Get ecma-value from variable + * + * @return value descriptor + */ +static void +ctx_SetValueDescriptorToVariable(ctx_SyntacticReference_t *pVar, /**< variable */ + ecma_Value_t value) /**< value descriptor */ +{ + /* + * TODO: + */ + (void)pVar; + (void)value; + JERRY_UNIMPLEMENTED(); +} /* ctx_SetValueDescriptorToVariable */ + +/** + * Allocate a context. + */ +static void +ctx_AllocContext( void) +{ + JERRY_ASSERT( ctx_ContextsNumber < CTX_MAX_NUMBER_OF_VARIABLES_CONTEXTS ); + + ctx_ContextsNumber++; +} /* ctx_AllocContext */ + +/** + * Create new lexical environment using specified object as binding object, + * setting provideThis to specified value. + * The lexical environment is inherited from current context's lexical environment. + */ +static void +ctx_CreateLexicalEnvironmentFromObject(ecma_Object_t *pObject, /**< pointer to bindingObject */ + bool provideThis) /**< value of 'provideThis' attribute */ +{ + ecma_Object_t *pNewLexicalEnvironment = ecma_CreateLexicalEnvironment(ctx_CurrentContext.pLexicalEnvironment, + true); + /* We don't change reference counter of ctx_CurrentContext.pLexicalEnvironment here, + because we remove one reference from ctx_CurrentContext, + and add one reference from pNewLexicalEnvironment */ + ctx_CurrentContext.pLexicalEnvironment = pNewLexicalEnvironment; + + ecma_Property_t *pProvideThisProperty = ecma_CreateInternalProperty( pNewLexicalEnvironment, ECMA_INTERNAL_PROPERTY_PROVIDE_THIS); + pProvideThisProperty->u.m_InternalProperty.m_Value = provideThis; + + ecma_Property_t *pBindingObjectProperty = ecma_CreateInternalProperty( pNewLexicalEnvironment, ECMA_INTERNAL_PROPERTY_BINDING_OBJECT); + + ecma_RefObject( pObject); + ecma_SetPointer( pBindingObjectProperty->u.m_InternalProperty.m_Value, pObject); +} /* ctx_CreateLexicalEnvironmentFromObject */ + +/** + * Initialize the global object. + */ +static void +ctx_InitGlobalObject( void) +{ + ctx_pGlobalObject = ecma_CreateObject( NULL, true); +} /* ctx_InitGlobalObject */ + +/** + * \addtogroup interface Context manager's interface + * @{ + */ + +/** + * Initialize context manager and global execution context. + */ +void +ctx_Init(void) +{ + JERRY_ASSERT( ctx_ContextsNumber == 0 ); + +#ifndef JERRY_NDEBUG + libc_memset( ctx_Stack, 0, sizeof (ctx_Stack)); +#endif /* !JERRY_NDEBUG */ + + ctx_InitGlobalObject(); + ctx_NewContextFromGlobalObject(); +} /* ctx_Init */ + +/** + * Create new variables' context using global object + * for ThisBinding and lexical environment. + */ +void +ctx_NewContextFromGlobalObject(void) +{ + ctx_AllocContext(); + + ecma_RefObject( ctx_pGlobalObject); + ctx_CurrentContext.pThisBinding = ctx_pGlobalObject; + + ctx_CurrentContext.pLexicalEnvironment = NULL; + ctx_CreateLexicalEnvironmentFromObject( ctx_pGlobalObject, false); + + JERRY_ASSERT( ctx_CurrentContext.pLexicalEnvironment != NULL ); +} /* ctx_NewContextFromGlobalObject */ + +/** + * Create new variables' context inheriting lexical environment from specified + * function's [[Scope]], and setting ThisBinding from pThisVar parameter + * (see also ECMA-262 5.1, 10.4.3). + */ +void +ctx_NewContextFromFunctionScope(ctx_SyntacticReference_t *pThisVar, /**< object for ThisBinding */ + ctx_SyntacticReference_t *pFunctionVar) /**< Function object */ +{ + ctx_AllocContext(); + + ecma_Value_t thisArgValue = ctx_GetValueDescriptorFromVariable( pThisVar); + ecma_Value_t functionArgValue = ctx_GetValueDescriptorFromVariable( pFunctionVar); + + ecma_Object_t *pThisBindingObject; + if ( thisArgValue.m_ValueType == ECMA_TYPE_SIMPLE + && ( thisArgValue.m_Value == ECMA_SIMPLE_VALUE_NULL + || thisArgValue.m_Value == ECMA_SIMPLE_VALUE_UNDEFINED ) ) + { + pThisBindingObject = ctx_pGlobalObject; + } else + { + pThisBindingObject = ecma_ToObject( thisArgValue); + } + + ecma_RefObject( pThisBindingObject); + ctx_CurrentContext.pThisBinding = pThisBindingObject; + + JERRY_ASSERT( functionArgValue.m_ValueType == ECMA_TYPE_OBJECT ); + ecma_Object_t *pFunctionObject = ecma_GetPointer( functionArgValue.m_Value); + + ecma_Property_t *pScopeProperty = ecma_GetInternalProperty( pFunctionObject, ECMA_INTERNAL_PROPERTY_SCOPE); + + ecma_Object_t *pScopeObject = ecma_GetPointer( pScopeProperty->u.m_InternalProperty.m_Value); + + ecma_RefObject( pScopeObject); + ecma_Object_t *pLexicalEnvironment = ecma_CreateLexicalEnvironment(pScopeObject, false); + + /* We don't change reference counter of ctx_CurrentContext.pLexicalEnvironment here, + because we remove one reference from ctx_CurrentContext, + and add one reference from pNewLexicalEnvironment */ + ctx_CurrentContext.pLexicalEnvironment = pLexicalEnvironment; +} /* ctx_NewContextFromFunctionScope */ + +/** + * Create new lexical environment using specified object as binding object, + * setting provideThis to specified value. + * The lexical environment is inherited from current context's lexical environment. + */ +void +ctx_NewLexicalEnvironmentFromObject(ctx_SyntacticReference_t *pObjectVar, /**< binding object */ + bool provideThis) /**< 'provideThis' attribute */ +{ + ecma_Object_t *pObject = ecma_ToObject( ctx_GetValueDescriptorFromVariable( pObjectVar)); + + ctx_CreateLexicalEnvironmentFromObject( pObject, provideThis); +} /* ctx_NewLexicalEnvironmentFromObject */ + +/** + * Exit from levelsToExit lexical environments (i.e. choose lexical environment + * that is levelsToExit outward current lexical environment as new current context's + * lexical environment). + */ +void +ctx_ExitLexicalEnvironments(uint32_t levelsToExit) /**< number of lexical environments + * to exit from */ +{ + JERRY_ASSERT( levelsToExit > 0 ); + + for ( uint32_t count = 0; + count < levelsToExit; + count++ ) + { + JERRY_ASSERT( ctx_CurrentContext.pLexicalEnvironment != NULL ); + + ecma_Object_t *pOuterLexicalEnvironment = ecma_GetPointer( ctx_CurrentContext.pLexicalEnvironment->u_Attributes.m_LexicalEnvironment.m_pOuterReference); + + ecma_DerefObject( ctx_CurrentContext.pLexicalEnvironment); + + ctx_CurrentContext.pLexicalEnvironment = pOuterLexicalEnvironment; + } + + JERRY_ASSERT( ctx_CurrentContext.pLexicalEnvironment != NULL ); +} /* ctx_ExitLexicalEnvironments */ + +/** + * Exit from levelsToExit variables' contexts (i.e. choose context + * that is levelsToExit from current context as new current context). + */ +void +ctx_ExitContexts(uint32_t levelsToExit) /**< number of contexts to exit from */ +{ + JERRY_ASSERT( levelsToExit > 0 ); + + for ( uint32_t count = 0; + count < levelsToExit; + count++ ) + { + JERRY_ASSERT( ctx_ContextsNumber > 0 ); + + ecma_DerefObject( ctx_CurrentContext.pThisBinding); + + while ( ctx_CurrentContext.pLexicalEnvironment != NULL ) + { + ecma_Object_t *pOuterLexicalEnvironment = + ecma_GetPointer(ctx_CurrentContext.pLexicalEnvironment-> + u_Attributes.m_LexicalEnvironment. + m_pOuterReference); + + ecma_DerefObject( ctx_CurrentContext.pLexicalEnvironment); + + ctx_CurrentContext.pLexicalEnvironment = pOuterLexicalEnvironment; + } + + ctx_ContextsNumber--; + } + + JERRY_ASSERT( ctx_ContextsNumber > 0 ); +} /* ctx_ExitContexts */ + +/** + * Create new variable with undefined value in the current lexical environment. + */ +void +ctx_NewVariable( ctx_SyntacticReference_t *pVar) /**< variable id */ +{ + ecma_Object_t *lexicalEnvironment = ctx_CurrentContext.pLexicalEnvironment; + + /* + * TODO: + */ + (void) pVar; + JERRY_UNIMPLEMENTED(); + + switch ( (ecma_LexicalEnvironmentType_t) lexicalEnvironment->u_Attributes.m_LexicalEnvironment.m_Type ) + { + case ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND: + { + ecma_Property_t *pBindingObjectProperty = ecma_FindInternalProperty(lexicalEnvironment, + ECMA_INTERNAL_PROPERTY_BINDING_OBJECT); + JERRY_ASSERT( pBindingObjectProperty != NULL ); + + ecma_Object_t *pBindingObject = ecma_GetPointer( pBindingObjectProperty->u.m_InternalProperty.m_Value); + JERRY_ASSERT( pBindingObject != NULL ); + + break; + } + + case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE: + { + break; + } + } +} /* ctx_NewVariable */ + +/** + * Delete specified variable. + */ +void +ctx_DeleteVariable( ctx_SyntacticReference_t *pVar) /**< variable id */ +{ + /* + * TODO: + */ + (void) pVar; + JERRY_UNIMPLEMENTED(); +} /* ctx_DeleteVariable */ + +/** + * Copy variable's/property's/array's element's value. + */ +void +ctx_CopyVariable(ctx_SyntacticReference_t *pVarFrom, /**< source variable */ + ctx_SyntacticReference_t *pVarTo) /**< destination variable */ +{ + ecma_Value_t sourceVariableValue = ctx_GetValueDescriptorFromVariable( pVarFrom); + ecma_Value_t destinationVariableValue; + + destinationVariableValue.m_ValueType = sourceVariableValue.m_ValueType; + switch ( (ecma_Type_t) sourceVariableValue.m_ValueType ) + { + case ECMA_TYPE_SIMPLE: + { + destinationVariableValue.m_Value = sourceVariableValue.m_Value; + break; + } + + case ECMA_TYPE_NUMBER: + { + ecma_Number_t *pNumberCopy = ecma_AllocNumber(); + libc_memcpy( pNumberCopy, + ecma_GetPointer( sourceVariableValue.m_Value), + sizeof (ecma_Number_t)); + ecma_SetPointer( destinationVariableValue.m_Value, pNumberCopy); + break; + } + + case ECMA_TYPE_STRING: + { + ecma_SetPointer(destinationVariableValue.m_Value, + ecma_DuplicateEcmaString( ecma_GetPointer( sourceVariableValue.m_Value))); + break; + } + + case ECMA_TYPE_OBJECT: + { + ecma_RefObject( ecma_GetPointer( sourceVariableValue.m_Value)); + destinationVariableValue.m_Value = sourceVariableValue.m_Value; + break; + } + + case ECMA_TYPE__COUNT: + { + JERRY_UNREACHABLE(); + } + } + + ctx_SetValueDescriptorToVariable( pVarTo, destinationVariableValue); +} /* ctx_CopyVariable */ + +/** + * Get type of value of specified variable/property/array's element. + */ +ecma_Type_t +ctx_GetVariableType(ctx_SyntacticReference_t *pVar) /**< variable */ +{ + ecma_Value_t variableValue = ctx_GetValueDescriptorFromVariable( pVar); + + return variableValue.m_ValueType; +} /* ctx_GetVariableType */ + +/** + * Get specified variable's/property's/array's element's value. + * + * @return number of bytes, actually copied to the buffer, if variable value was copied successfully; + * negative number, which is calculated as negation of buffer size, that is required + * to hold the variable's value (in case size of buffer is insuficcient). + */ +ssize_t +ctx_GetVariableValue(ctx_SyntacticReference_t *pVar, /**< variable */ + uint8_t *pBuffer, /**< buffer */ + size_t bufferSize) /**< size of buffer */ +{ + ecma_Value_t variableValue = ctx_GetValueDescriptorFromVariable( pVar); + + switch ( (ecma_Type_t) variableValue.m_ValueType ) + { + case ECMA_TYPE_SIMPLE: + { + if ( bufferSize < sizeof (ecma_SimpleValue_t) ) + { + return -(ssize_t)sizeof (ecma_SimpleValue_t); + } else + { + *(ecma_SimpleValue_t*) pBuffer = variableValue.m_Value; + + return sizeof (ecma_SimpleValue_t); + } + break; + } + + case ECMA_TYPE_NUMBER: + { + if ( bufferSize < sizeof (ecma_Number_t) ) + { + return -(ssize_t)sizeof (ecma_Number_t); + } else + { + ecma_Number_t *pNumber = ecma_GetPointer(variableValue.m_Value); + *(ecma_Number_t*) pBuffer = *pNumber; + + return sizeof (ecma_Number_t); + } + break; + } + + case ECMA_TYPE_STRING: + { + ecma_ArrayFirstChunk_t *pStringFirstChunk = ecma_GetPointer(variableValue.m_Value); + + return ecma_CopyEcmaStringCharsToBuffer( pStringFirstChunk, pBuffer, bufferSize); + } + + case ECMA_TYPE_OBJECT: /* cannot return object itself (only value of a property or of an array's element */ + case ECMA_TYPE__COUNT: + { + /* will trap below */ + } + } + + JERRY_UNREACHABLE(); +} /* ctx_GetVariableValue */ + +/** + * Set variable's/property's/array's element's value to one of simple values. + */ +void +ctx_SetVariableToSimpleValue(ctx_SyntacticReference_t *pVar, /**< variable */ + ecma_SimpleValue_t value) /**< value */ +{ + ecma_Value_t valueToSet; + + valueToSet.m_ValueType = ECMA_TYPE_SIMPLE; + valueToSet.m_Value = value; + + ctx_SetValueDescriptorToVariable( pVar, valueToSet); +} /* ctx_SetVariableToSimpleValue */ + +/** + * Set variable's/property's/array's element's value to a Number. + */ +void +ctx_SetVariableToNumber(ctx_SyntacticReference_t *pVar, /**< variable */ + ecma_Number_t value) /**< value */ +{ + ecma_Number_t *pNumber = ecma_AllocNumber(); + *pNumber = value; + + ecma_Value_t valueToSet; + valueToSet.m_ValueType = ECMA_TYPE_NUMBER; + ecma_SetPointer( valueToSet.m_Value, pNumber); + + ctx_SetValueDescriptorToVariable( pVar, valueToSet); +} /* ctx_SetVariableToNumber */ + +/** + * Set variable's/property's/array's element's value to a String. + */ +void +ctx_SetVariableToString(ctx_SyntacticReference_t *pVar, /**< variable */ + ecma_Char_t *value, /**< string's characters */ + ecma_Length_t length) /**< string's length, in characters */ +{ + ecma_Value_t valueToSet; + valueToSet.m_ValueType = ECMA_TYPE_STRING; + ecma_SetPointer( valueToSet.m_Value, ecma_NewEcmaString( value, length)); + + ctx_SetValueDescriptorToVariable( pVar, valueToSet); +} /* ctx_SetVariableToString */ + +/** + * @} + */ + +/** + * Static checks that ecma types fit size requirements. + * + * Warning: + * must not be called + */ +static void __unused +ctx_EcmaTypesSizeCheckers( void) +{ + JERRY_STATIC_ASSERT( sizeof (ecma_Value_t) <= sizeof (uint16_t) ); + JERRY_STATIC_ASSERT( sizeof (ecma_Property_t) <= sizeof (uint64_t) ); + JERRY_STATIC_ASSERT( sizeof (ecma_Object_t) <= sizeof (uint64_t) ); + JERRY_STATIC_ASSERT( sizeof (ecma_ArrayHeader_t) <= sizeof (uint32_t) ); + JERRY_STATIC_ASSERT( sizeof (ecma_ArrayFirstChunk_t) == ECMA_ARRAY_CHUNK_SIZE_IN_BYTES ); + JERRY_STATIC_ASSERT( sizeof (ecma_ArrayNonFirstChunk_t) == ECMA_ARRAY_CHUNK_SIZE_IN_BYTES ); + + JERRY_UNREACHABLE(); +} /* ctx_EcmaTypesSizeCheckers */ + +/** + * @} + */ \ No newline at end of file diff --git a/src/ctx_manager.h b/src/ctx_manager.h new file mode 100644 index 000000000..a0c791c25 --- /dev/null +++ b/src/ctx_manager.h @@ -0,0 +1,124 @@ +/* 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 JERRY_CTX_MANAGER_H +#define JERRY_CTX_MANAGER_H + +#include "ctx-reference.h" +#include "defs.h" +#include "ecma_defs.h" + +/** \addtogroup ctxman Context manager + * @{ + * \addtogroup interface Context manager's interface + * @{ + */ + +/** + * Initialize context manager and global execution context. + */ +extern void ctx_Init(void); + +/** + * Create new variables' context using global object + * for ThisBinding and lexical environments. + */ +extern void ctx_NewContextFromGlobalObject(void); + +/** + * Create new variables' context inheriting lexical environment from specified + * function's [[Scope]], and setting ThisBinding from pThisVar parameter + * (see also ECMA-262 5.1, 10.4.3). + */ +extern void ctx_NewContextFromFunctionScope(ctx_SyntacticReference_t *pThisVar, ctx_SyntacticReference_t *pFunctionVar); + +/** + * Create new lexical environment using specified object as binding object, + * setting provideThis to specified value. + * The lexical environment is inherited from current context's lexical environment. + */ +extern void ctx_NewLexicalEnvironmentFromObject(ctx_SyntacticReference_t *pObjectVar, bool provideThis); + +/** + * Exit from levelsToExit lexical environments (i.e. choose lexical environment + * that is levelsToExit outward current lexical environment as new current context's + * lexical environment). + */ +extern void ctx_ExitLexicalEnvironments(uint32_t levelsToExit); + +/** + * Exit from levelsToExit variables' contexts (i.e. choose context + * that is levelsToExit from current context as new current context). + */ +extern void ctx_ExitContexts(uint32_t levelsToExit); + +/** + * Create new variable with undefined value. + */ +extern void ctx_NewVariable(ctx_SyntacticReference_t *pVar); + +/** + * Delete specified variable. + */ +extern void ctx_DeleteVariable(ctx_SyntacticReference_t *pVar); + +/** + * Check if specified variable exists + * + * @return true, if exists; + * false - otherwise. + */ +extern bool ctx_DoesVariableExist(ctx_SyntacticReference_t *pVar); + +/** + * Copy variable's/property's/array's element's value. + */ +extern void ctx_CopyVariable(ctx_SyntacticReference_t *pVarFrom, ctx_SyntacticReference_t *pVarTo); + +/** + * Get type of specified of variable/property/array's element. + */ +extern ecma_Type_t ctx_GetVariableType(ctx_SyntacticReference_t *pVar); + +/** + * Get specified variable's/property's/array's element's value. + * + * @return number of bytes, actually copied to the buffer, if variable value was copied successfully; + * negative number, which is calculated as negation of buffer size, that is required + * to hold the variable's value (in case size of buffer is insuficcient). + */ +extern ssize_t ctx_GetVariableValue(ctx_SyntacticReference_t *pVar, uint8_t *pBuffer, size_t bufferSize); + +/** + * Set variable's/property's/array's element's value to one of simple values. + */ +extern void ctx_SetVariableToSimpleValue(ctx_SyntacticReference_t *pVar, ecma_SimpleValue_t value); + +/** + * Set variable's/property's/array's element's value to a Number. + */ +extern void ctx_SetVariableToNumber(ctx_SyntacticReference_t *pVar, ecma_Number_t value); + +/** + * Set variable's/property's/array's element's value to a String. + */ +extern void ctx_SetVariableToString(ctx_SyntacticReference_t *pVar, ecma_Char_t *value, ecma_Length_t length); + +#endif /* !JERRY_CTX_MANAGER_H */ + +/** + * @} + * @} + */ \ No newline at end of file diff --git a/src/defs.h b/src/defs.h new file mode 100644 index 000000000..0a11621d9 --- /dev/null +++ b/src/defs.h @@ -0,0 +1,156 @@ +/* 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 JERRY_DEFS_H +#define JERRY_DEFS_H + +#include +#include +#include + +/** + * Types + */ +typedef unsigned long mword_t; +typedef mword_t uintptr_t; +//typedef mword_t size_t; +typedef signed long ssize_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef signed int int32_t; + +/** + * Attributes + */ +#define __unused __attribute__((unused)) +#define __packed __attribute__((packed)) + +/** + * Constants + */ +#define NULL ((void*)0) + +#define JERRY_BITSINBYTE 8 + +/** + * Asserts + * + * Warning: + * Don't use JERRY_STATIC_ASSERT in headers, because + * __LINE__ may be the same for asserts in a header + * and in an implementation file. + */ +#define JERRY_STATIC_ASSERT_GLUE_( a, b ) a ## b +#define JERRY_STATIC_ASSERT_GLUE( a, b ) JERRY_STATIC_ASSERT_GLUE_( a, b ) +#define JERRY_STATIC_ASSERT( x ) typedef char JERRY_STATIC_ASSERT_GLUE( static_assertion_failed_, __LINE__) [ ( x ) ? 1 : -1 ] + +/** + * Variable that must not be referenced. + * + * May be used for static assertion checks. + */ +extern uint32_t jerry_UnreferencedExpression; + +#ifndef JERRY_NDEBUG +#define JERRY_ASSERT( x ) assert( x ) +#else /* !JERRY_NDEBUG */ +#define JERRY_ASSERT( x ) (void) (x) +#endif /* !JERRY_NDEBUG */ + +/** + * Mark for unreachable points and unimplemented cases + */ +#define JERRY_UNREACHABLE() { JERRY_ASSERT( false); __builtin_trap(); } +#define JERRY_UNIMPLEMENTED() JERRY_UNREACHABLE() + +/** + * sizeof, offsetof, ... + */ +#define JERRY_SIZE_OF_STRUCT_MEMBER( struct_name, member_name) sizeof(((struct_name*)NULL)->member_name) + +/** + * Alignment + */ + +/** + * Aligns @value to @alignment. + * + * Returns maximum positive value, that divides @alignment and is less than or equal to @value + */ +#define JERRY_ALIGNDOWN( value, alignment) ( (alignment) * ( (value) / (alignment) ) ) + +/** + * Aligns @value to @alignment. + * + * Returns minimum positive value, that divides @alignment and is more than or equal to @value + */ +#define JERRY_ALIGNUP( value, alignment) ( (alignment) * ( ((value) + (alignment) - 1) / (alignment) ) ) + +/** + * min, max + */ +#define JERRY_MIN( v1, v2) ( ( v1 < v2 ) ? v1 : v2 ) +#define JERRY_MAX( v1, v2) ( ( v1 < v2 ) ? v2 : v1 ) + +/** + * Bit-fields + */ +inline uint32_t jerry_ExtractBitField(uint32_t value, uint32_t lsb, uint32_t width); +inline uint32_t jerry_SetBitFieldValue(uint32_t value, uint32_t bitFieldValue, uint32_t lsb, uint32_t width); + +/** + * Extract a bit-field from the integer. + * + * @return bit-field's value + */ +inline uint32_t +jerry_ExtractBitField(uint32_t container, /**< container to extract bit-field from */ + uint32_t lsb, /**< least significant bit of the value + * to be extracted */ + uint32_t width) /**< width of the bit-field to be extracted */ { + JERRY_ASSERT(lsb < JERRY_BITSINBYTE * sizeof (uint32_t)); + JERRY_ASSERT((lsb + width) <= JERRY_BITSINBYTE * sizeof (uint32_t)); + + uint32_t shiftedValue = container >> lsb; + uint32_t bitFieldMask = (1u << width) - 1; + + return ( shiftedValue & bitFieldMask); +} /* jerry_ExtractBitField */ + +/** + * Extract a bit-field from the integer. + * + * @return bit-field's value + */ +inline uint32_t +jerry_SetBitFieldValue(uint32_t container, /**< container to insert bit-field to */ + uint32_t newBitFieldValue, /**< value of bit-field to insert */ + uint32_t lsb, /**< least significant bit of the value + * to be extracted */ + uint32_t width) /**< width of the bit-field to be extracted */ { + JERRY_ASSERT(lsb < JERRY_BITSINBYTE * sizeof (uint32_t)); + JERRY_ASSERT((lsb + width) <= JERRY_BITSINBYTE * sizeof (uint32_t)); + JERRY_ASSERT(newBitFieldValue <= (1u << width)); + + uint32_t bitFieldMask = (1u << width) - 1; + uint32_t shiftedBitFieldMask = bitFieldMask << lsb; + uint32_t shiftedNewBitFieldValue = newBitFieldValue << lsb; + + return ( container & ~shiftedBitFieldMask) | shiftedNewBitFieldValue; +} /* jerry_SetBitFieldValue */ + +#endif /* !JERRY_DEFS_H */ diff --git a/src/ecma_alloc.c b/src/ecma_alloc.c new file mode 100644 index 000000000..9ac4f5bbe --- /dev/null +++ b/src/ecma_alloc.c @@ -0,0 +1,82 @@ +/* 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. + */ + +/** \addtogroup ecma ---TODO--- + * @{ + * + * \addtogroup ecmaalloc Routines for allocation/freeing memory for ECMA data types + * @{ + */ + +/** + * Implementation of routins for allocation/freeing memory for ECMA data types. + * + * All allocation routines from this module have the same structure: + * 1. Try to allocate memory. + * 2. If allocation was successful, return pointer to the allocated block. + * 3. Run garbage collection. + * 4. Try to allocate memory. + * 5. If allocation was successful, return pointer to the allocated block; + * else - shutdown engine. + */ + +#include "defs.h" +#include "ecma_alloc.h" +#include "ecma_defs.h" +#include "ecma_gc.h" +#include "mem_poolman.h" + +/** + * Template of an allocation routine. + */ +#define ALLOC( ecmaType) ecma_ ## ecmaType ## _t * \ +ecma_Alloc ## ecmaType (void) \ +{ \ + ecma_ ## ecmaType ## _t *p ## ecmaType = (ecma_ ## ecmaType ## _t *) \ + mem_PoolsAlloc( mem_SizeToPoolChunkType( sizeof(ecma_ ## ecmaType ## _t))); \ + \ + ecma_GCRun(); \ + JERRY_ASSERT( p ## ecmaType != NULL ); \ + \ + return p ## ecmaType; \ +} + +/** + * Free routine template + */ +#define FREE( ecmaType) void \ +ecma_Free ## ecmaType( ecma_ ## ecmaType ## _t *p ## ecmaType) \ +{ \ + mem_PoolsFree( mem_SizeToPoolChunkType( sizeof(ecma_ ## ecmaType ## _t)), \ + (uint8_t*) p ## ecmaType); \ +} + +/** + * Declaration of alloc/free routine for specified ecma-type. + */ +#define DECLARE_ROUTINES_FOR( ecmaType) \ + ALLOC( ecmaType) \ + FREE( ecmaType) + +DECLARE_ROUTINES_FOR (Object) +DECLARE_ROUTINES_FOR (Property) +DECLARE_ROUTINES_FOR (Number) +DECLARE_ROUTINES_FOR (ArrayFirstChunk) +DECLARE_ROUTINES_FOR (ArrayNonFirstChunk) + +/** + * @} + * @} + */ \ No newline at end of file diff --git a/src/ecma_alloc.h b/src/ecma_alloc.h new file mode 100644 index 000000000..8c5db5a42 --- /dev/null +++ b/src/ecma_alloc.h @@ -0,0 +1,93 @@ +/* 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. + */ + +/** \addtogroup ecma ---TODO--- + * @{ + * + * \addtogroup ecmaalloc Routines for allocation/freeing memory for ECMA data types + * @{ + */ + +#ifndef JERRY_ECMA_ALLOC_H +#define JERRY_ECMA_ALLOC_H + +#include "ecma_defs.h" + +/** + * Allocate memory for ecma-object + * + * @return pointer to allocated memory + */ +extern ecma_Object_t *ecma_AllocObject(void); + +/** + * Free memory from an ecma-object + */ +extern void ecma_FreeObject( ecma_Object_t *pObject); + +/** + * Allocate memory for ecma-property + * + * @return pointer to allocated memory + */ +extern ecma_Property_t *ecma_AllocProperty(void); + +/** + * Free memory from an ecma-property + */ +extern void ecma_FreeProperty( ecma_Property_t *pProperty); + +/** + * Allocate memory for ecma-number + * + * @return pointer to allocated memory + */ +extern ecma_Number_t *ecma_AllocNumber(void); + +/** + * Free memory from an ecma-number + */ +extern void ecma_FreeNumber( ecma_Number_t *pNumber); + +/** + * Allocate memory for first chunk of an ecma-array + * + * @return pointer to allocated memory + */ +extern ecma_ArrayFirstChunk_t *ecma_AllocArrayFirstChunk(void); + +/** + * Free memory from first chunk of an ecma-array + */ +extern void ecma_FreeArrayFirstChunk( ecma_ArrayFirstChunk_t *pFirstChunk); + +/** + * Allocate memory for non-first chunk of an ecma-array + * + * @return pointer to allocated memory + */ +extern ecma_ArrayNonFirstChunk_t *ecma_AllocArrayNonFirstChunk(void); + +/** + * Free memory from non-first chunk of an ecma-array + */ +extern void ecma_FreeArrayNonFirstChunk( ecma_ArrayNonFirstChunk_t *pNumber); + +#endif /* JERRY_ECMA_ALLOC_H */ + +/** + * @} + * @} + */ \ No newline at end of file diff --git a/src/ecma_conversion.h b/src/ecma_conversion.h new file mode 100644 index 000000000..3d890cf2d --- /dev/null +++ b/src/ecma_conversion.h @@ -0,0 +1,59 @@ +/* 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. + */ + +/** \addtogroup ecma ---TODO--- + * @{ + * + * \addtogroup ecmaconversion ECMA conversion + * @{ + */ + +#ifndef JERRY_ECMA_CONVERSION_H +#define JERRY_ECMA_CONVERSION_H + +#include "ecma_defs.h" +#include "ecma_helpers.h" + +extern ecma_Object_t* ecma_ToObject( ecma_Value_t value); + +/* + * Stubs + */ + +/** + * Convert value to ecma-object. + * + * See also: + * ECMA-262 5.1, 9.9. + * + * @return pointer to ecma-object descriptor + */ +ecma_Object_t* +ecma_ToObject(ecma_Value_t value) /**< ecma-value */ +{ + if ( value.m_ValueType == ECMA_TYPE_OBJECT ) + { + return ecma_DecompressPointer( value.m_Value); + } + + JERRY_UNIMPLEMENTED(); +} + +#endif /* !JERRY_ECMA_CONVERSION_H */ + +/** + * @} + * @} + */ diff --git a/src/ecma_defs.h b/src/ecma_defs.h new file mode 100644 index 000000000..2a7644e93 --- /dev/null +++ b/src/ecma_defs.h @@ -0,0 +1,317 @@ +/* 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. + */ + +/** \addtogroup ecma ---TODO--- + * @{ + * + * \addtogroup ecmatypes ECMA types + * @{ + */ + +#ifndef JERRY_ECMA_DEFS_H +#define JERRY_ECMA_DEFS_H + +#include "defs.h" +#include "mem_allocator.h" + +/** \addtogroup compressedpointer Compressed pointer + * @{ + */ + +/** + * Ecma-pointer field is used to calculate ecma-value's address. + * + * Ecma-pointer contains value's shifted offset from common Ecma-pointers' base. + * The offset is shifted right by MEM_ALIGNMENT_LOG. + * Least significant MEM_ALIGNMENT_LOG bits of non-shifted offset are zeroes. + */ +#define ECMA_POINTER_FIELD_WIDTH 14 + +/** + * The null value for compressed pointers + */ +#define ECMA_NULL_POINTER 0 + +/** + * @} + */ + +/** + * Type of ecma-value + */ +typedef enum { + ECMA_TYPE_SIMPLE, /**< simple value */ + ECMA_TYPE_NUMBER, /**< 64-bit integer */ + ECMA_TYPE_STRING, /**< pointer to description of a string */ + ECMA_TYPE_OBJECT, /**< pointer to description of an object */ + ECMA_TYPE__COUNT /**< count of types */ +} ecma_Type_t; + +/** + * Simple ecma-values + */ +typedef enum { + ECMA_SIMPLE_VALUE_UNDEFINED, /**< undefined value */ + ECMA_SIMPLE_VALUE_NULL, /**< null value */ + ECMA_SIMPLE_VALUE_FALSE, /**< boolean false */ + ECMA_SIMPLE_VALUE_TRUE, /**< boolean true */ + ECMA_SIMPLE_VALUE__COUNT /** count of simple ecma-values */ +} ecma_SimpleValue_t; + +/** + * Type of ecma-property + */ +typedef enum { + ECMA_PROPERTY_NAMEDDATA, /**< named data property */ + ECMA_PROPERTY_NAMEDACCESSOR, /**< named accessor property */ + ECMA_PROPERTY_INTERNAL /**< internal property */ +} ecma_PropertyType_t; + +/** + * Description of an ecma-value + */ +typedef struct { + /** Value type (ecma_Type_t) */ + uint32_t m_ValueType : 2; + + /** + * Simple value (ecma_SimpleValue_t) or compressed pointer to value (depending on m_ValueType) + */ + uint32_t m_Value : ECMA_POINTER_FIELD_WIDTH; +} __packed ecma_Value_t; + +/** + * Internal properties' identifiers. + */ +typedef enum { + ECMA_INTERNAL_PROPERTY_CLASS, /**< [[Class]] */ + ECMA_INTERNAL_PROPERTY_PROTOTYPE, /**< [[Prototype]] */ + ECMA_INTERNAL_PROPERTY_EXTENSIBLE, /**< [[Extensible]] */ + ECMA_INTERNAL_PROPERTY_SCOPE, /**< [[Scope]] */ + + /** provideThis property of lexical environment */ + ECMA_INTERNAL_PROPERTY_PROVIDE_THIS, + + /** binding object of lexical environment */ + ECMA_INTERNAL_PROPERTY_BINDING_OBJECT, + + /** Part of an array, that is indexed by numbers */ + ECMA_INTERNAL_PROPERTY_NUMBER_INDEXED_ARRAY_VALUES, + + /** Part of an array, that is indexed by strings */ + ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES +} ecma_InternalPropertyId_t; + +/** + * Description of ecma-property. + */ +typedef struct ecma_Property_t { + /** Property's type (ecma_PropertyType_t) */ + uint32_t m_Type : 2; + + /** Compressed pointer to next property */ + uint32_t m_pNextProperty : ECMA_POINTER_FIELD_WIDTH; + + /** Property's details (depending on m_Type) */ + union { + + /** Description of named data property */ + struct __packed ecma_NamedDataProperty_t { + /** Compressed pointer to property's name (pointer to String) */ + uint32_t m_pName : ECMA_POINTER_FIELD_WIDTH; + + /** Attribute 'Writable' */ + uint32_t m_Writable : 1; + + /** Attribute 'Enumerable' */ + uint32_t m_Enumerable : 1; + + /** Attribute 'Configurable' */ + uint32_t m_Configurable : 1; + + /** Value */ + ecma_Value_t m_Value; + } m_NamedDataProperty; + + /** Description of named accessor property */ + struct __packed ecma_NamedAccessorProperty_t { + /** Compressed pointer to property's name (pointer to String) */ + uint32_t m_pName : ECMA_POINTER_FIELD_WIDTH; + + /** Attribute 'Enumerable' */ + uint32_t m_Enumerable : 1; + + /** Attribute 'Configurable' */ + uint32_t m_Configurable : 1; + + /** Compressed pointer to property's getter */ + uint32_t m_pGet : ECMA_POINTER_FIELD_WIDTH; + + /** Compressed pointer to property's setter */ + uint32_t m_pSet : ECMA_POINTER_FIELD_WIDTH; + } m_NamedAccessorProperty; + + /** Description of internal property */ + struct __packed ecma_InternalProperty_t { + /** Internal property's type */ + uint32_t m_InternalPropertyType : 4; + + /** Value (may be a compressed pointer) */ + uint32_t m_Value : ECMA_POINTER_FIELD_WIDTH; + } m_InternalProperty; + } u; +} ecma_Property_t; + +/** + * Description of GC's information layout + */ +typedef struct { + /** + * Flag that indicates if the object is valid for normal usage. + * If the flag is zero, then the object is not valid and is queued for GC. + */ + uint32_t m_IsObjectValid : 1; + + /** Details (depending on m_IsObjectValid) */ + union { + /** + * Number of refs to the object (if m_IsObjectValid). + * + * Note: It is not a pointer. Maximum value of reference counter + * willn't be bigger than overall count of variables/objects/properties, + * which is limited by size of address space allocated for JerryScript + * (and, consequently, by ECMA_POINTER_FIELD_WIDTH). + */ + uint32_t m_Refs : ECMA_POINTER_FIELD_WIDTH; + + /** Compressed pointer to next object in the list of objects, queued for GC (if !m_IsObjectValid) */ + uint32_t m_NextQueuedForGC : ECMA_POINTER_FIELD_WIDTH; + } __packed u; +} ecma_GCInfo_t; + +/** + * Types of lexical environments + */ +typedef enum { + ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE, /**< declarative lexical environment */ + ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND /**< object-bound lexical environment */ +} ecma_LexicalEnvironmentType_t; + +/** + * Description of ECMA-object or lexical environment + * (depending on m_IsLexicalEnvironment). + */ +typedef struct ecma_Object_t { + /** Compressed pointer to property list */ + uint32_t m_pProperties : ECMA_POINTER_FIELD_WIDTH; + + /** Flag indicating whether it is a general object (false) + or a lexical environment (true) */ + uint32_t m_IsLexicalEnvironment : 1; + + /** + * Attributes of either general object or lexical environment + * (depending on m_IsLexicalEnvironment) + */ + union { + /** + * A general object's attributes (if !m_IsLexicalEnvironment) + */ + struct { + /** Attribute 'Extensible' */ + uint32_t m_Extensible : 1; + + /** Compressed pointer to prototype object (ecma_Object_t) */ + uint32_t m_pPrototypeObject : ECMA_POINTER_FIELD_WIDTH; + } __packed m_Object; + + /** + * A lexical environment's attribute (if m_IsLexicalEnvironment) + */ + struct { + /** + * Type of lexical environment (ecma_LexicalEnvironmentType_t). + */ + uint32_t m_Type : 1; + + /** Compressed pointer to outer lexical environment */ + uint32_t m_pOuterReference : ECMA_POINTER_FIELD_WIDTH; + } __packed m_LexicalEnvironment; + + } __packed u_Attributes; + + /** GC's information */ + ecma_GCInfo_t m_GCInfo; +} ecma_Object_t; + +/** + * Description of an ecma-character + */ +typedef uint16_t ecma_Char_t; + +/** + * Description of an ecma-number + */ +typedef double ecma_Number_t; + +/** + * Description of arrays'/strings' length + */ +typedef uint16_t ecma_Length_t; + +/** + * Description of an Array's header + */ +typedef struct { + /** Compressed pointer to next chunk */ + uint16_t m_pNextChunk; + + /** Number of elements in the Array */ + uint16_t m_UnitNumber; +} ecma_ArrayHeader_t; + +/** + * Size of a chunk, containing a String's part, in bytes + */ +#define ECMA_ARRAY_CHUNK_SIZE_IN_BYTES 32 + +/** + * Description of first chunk in a chain of chunks that contains an Array. + */ +typedef struct { + /** Array's header */ + ecma_ArrayHeader_t m_Header; + + /** Elements */ + uint8_t m_Elements[ ECMA_ARRAY_CHUNK_SIZE_IN_BYTES - sizeof (ecma_ArrayHeader_t) ]; +} ecma_ArrayFirstChunk_t; + +/** + * Description of non-first chunk in a chain of chunks that contains an Array + */ +typedef struct { + /** Compressed pointer to next chunk */ + uint16_t m_pNextChunk; + + /** Characters */ + uint8_t m_Elements[ ECMA_ARRAY_CHUNK_SIZE_IN_BYTES - sizeof (uint16_t) ]; +} ecma_ArrayNonFirstChunk_t; + +#endif /* JERRY_ECMA_DEFS_H */ + +/** + * @} + * @} + */ diff --git a/src/ecma_gc.c b/src/ecma_gc.c new file mode 100644 index 000000000..6075fb61c --- /dev/null +++ b/src/ecma_gc.c @@ -0,0 +1,284 @@ +/* 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. + */ + +/** \addtogroup ecma ---TODO--- + * @{ + * + * \addtogroup ecmagc Garbage collector + * @{ + */ + +/** + * Garbage collector implementation + */ + +#include "defs.h" +#include "ecma_alloc.h" +#include "ecma_defs.h" +#include "ecma_gc.h" +#include "ecma_helpers.h" + +/** + * Queue of objects, awaiting for GC + */ +static ecma_Object_t *ecma_GC_Queue; + +/** + * Queue object for GC. + * + * Warning: + * After this operation the object is not longer valid for general use. + */ +static void +ecma_GCQueue( ecma_Object_t *pObject) /**< object */ +{ + JERRY_ASSERT( pObject != NULL ); + JERRY_ASSERT( pObject->m_GCInfo.m_IsObjectValid ); + JERRY_ASSERT( pObject->m_GCInfo.u.m_Refs == 0 ); + + pObject->m_GCInfo.m_IsObjectValid = false; + ecma_SetPointer( pObject->m_GCInfo.u.m_NextQueuedForGC, ecma_GC_Queue); + + ecma_GC_Queue = pObject; +} /* ecma_QueueGC */ + +/** + * Increase reference counter of an object + */ +void +ecma_RefObject(ecma_Object_t *pObject) /**< object */ +{ + JERRY_ASSERT(pObject->m_GCInfo.m_IsObjectValid); + + pObject->m_GCInfo.u.m_Refs++; + + /** + * Check that value was not overflowed + */ + JERRY_ASSERT(pObject->m_GCInfo.u.m_Refs > 0); +} /* ecma_RefObject */ + +/** + * Decrease reference counter of an object + */ +void +ecma_DerefObject(ecma_Object_t *pObject) /**< object */ +{ + JERRY_ASSERT(pObject != NULL); + JERRY_ASSERT(pObject->m_GCInfo.m_IsObjectValid); + JERRY_ASSERT(pObject->m_GCInfo.u.m_Refs > 0); + + pObject->m_GCInfo.u.m_Refs--; + + if ( pObject->m_GCInfo.u.m_Refs == 0 ) + { + ecma_GCQueue( pObject); + } +} /* ecma_DerefObject */ + +/** + * Initialize garbage collector + */ +void +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 + */ +void +ecma_GCRun( void) +{ + while ( ecma_GC_Queue != NULL ) + { + ecma_Object_t *pObject = ecma_GC_Queue; + ecma_GC_Queue = ecma_GetPointer( pObject->m_GCInfo.u.m_NextQueuedForGC); + + JERRY_ASSERT( !pObject->m_GCInfo.m_IsObjectValid ); + + for ( ecma_Property_t *property = ecma_GetPointer( pObject->m_pProperties), *pNextProperty; + 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); + } + + if ( pObject->m_IsLexicalEnvironment ) + { + ecma_Object_t *pOuterLexicalEnvironment = ecma_GetPointer( pObject->u_Attributes.m_LexicalEnvironment.m_pOuterReference); + + if ( pOuterLexicalEnvironment != NULL ) + { + ecma_DerefObject( pOuterLexicalEnvironment); + } + } else + { + ecma_Object_t *pPrototypeObject = ecma_GetPointer( pObject->u_Attributes.m_Object.m_pPrototypeObject); + + if ( pPrototypeObject != NULL ) + { + ecma_DerefObject( pPrototypeObject); + } + } + + ecma_FreeObject( pObject); + } +} /* ecma_RunGC */ + +/** + * @} + * @} + */ diff --git a/src/ecma_gc.h b/src/ecma_gc.h new file mode 100644 index 000000000..c1fe03e98 --- /dev/null +++ b/src/ecma_gc.h @@ -0,0 +1,42 @@ +/* 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. + */ + +/** \addtogroup ecma ---TODO--- + * @{ + * + * \addtogroup ecmagc Garbage collector + * @{ + */ + +#ifndef ECMA_GC_H +#define ECMA_GC_H + +/** + * Garbage collector interface + */ + +#include "ecma_defs.h" + +extern void ecma_GCInit( void); +extern void ecma_RefObject(ecma_Object_t *pObject); +extern void ecma_DerefObject(ecma_Object_t *pObject); +extern void ecma_GCRun( void); + +#endif /* !ECMA_GC_H */ + +/** + * @} + * @} + */ \ No newline at end of file diff --git a/src/ecma_helpers.c b/src/ecma_helpers.c new file mode 100644 index 000000000..dbe84249d --- /dev/null +++ b/src/ecma_helpers.c @@ -0,0 +1,376 @@ +/* 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. + */ + +/** \addtogroup ecma ---TODO--- + * @{ + * + * \addtogroup ecmahelpers Helpers for operations with ECMA data types + * @{ + */ + +/** + * Implementation of helpers for operations with ECMA data types + */ + +#include "ecma_alloc.h" +#include "ecma_defs.h" +#include "ecma_helpers.h" +#include "jerry_libc.h" + +/** + * Compress pointer. + */ +uintptr_t +ecma_CompressPointer(void *pointer) /**< pointer to compress */ +{ + if ( pointer == NULL ) + { + return ECMA_NULL_POINTER; + } + + uintptr_t intPtr = (uintptr_t) pointer; + + JERRY_ASSERT(intPtr % MEM_ALIGNMENT == 0); + + intPtr -= mem_GetBasePointer(); + intPtr >>= MEM_ALIGNMENT_LOG; + + JERRY_ASSERT((intPtr & ~((1u << ECMA_POINTER_FIELD_WIDTH) - 1)) == 0); + + return intPtr; +} /* ecma_CompressPointer */ + +/** + * Decompress pointer. + */ +void* +ecma_DecompressPointer(uintptr_t compressedPointer) /**< pointer to decompress */ +{ + if ( compressedPointer == ECMA_NULL_POINTER ) + { + return NULL; + } + + uintptr_t intPtr = compressedPointer; + + intPtr <<= MEM_ALIGNMENT_LOG; + intPtr += mem_GetBasePointer(); + + return (void*) intPtr; +} /* ecma_DecompressPointer */ + +/** + * Create an object with specified prototype object + * (or NULL prototype if there is not prototype for the object) + * and value of 'Extensible' attribute. + * + * Reference counter's value will be set to one. + * + * @return pointer to the object's descriptor + */ +ecma_Object_t* +ecma_CreateObject( ecma_Object_t *pPrototypeObject, /**< pointer to prototybe of the object (or NULL) */ + bool isExtensible) /**< value of extensible attribute */ +{ + ecma_Object_t *pObject = ecma_AllocObject(); + + pObject->m_pProperties = ECMA_NULL_POINTER; + pObject->m_IsLexicalEnvironment = false; + pObject->m_GCInfo.m_IsObjectValid = true; + + /* The global object is always referenced + * (at least with the ctx_GlobalObject variable) */ + pObject->m_GCInfo.u.m_Refs = 1; + + pObject->u_Attributes.m_Object.m_Extensible = isExtensible; + ecma_SetPointer( pObject->u_Attributes.m_Object.m_pPrototypeObject, pPrototypeObject); + + return pObject; +} /* ecma_CreateObject */ + +/** + * Create a lexical environment with specified outer lexical environment + * (or NULL if the environment is not nested). + * + * Reference counter's value will be set to one. + * + * Warning: after object-bound lexical environment is created, + * caller must create internal properties, that + * specify the bound object and value of 'provideThis'. + * + * @return pointer to the descriptor of lexical environment + */ +ecma_Object_t* +ecma_CreateLexicalEnvironment(ecma_Object_t *pOuterLexicalEnvironment, /**< outer lexical environment */ + ecma_LexicalEnvironmentType_t type) /**< type of lexical environment to create */ +{ + ecma_Object_t *pNewLexicalEnvironment = ecma_AllocObject(); + + pNewLexicalEnvironment->m_IsLexicalEnvironment = true; + pNewLexicalEnvironment->u_Attributes.m_LexicalEnvironment.m_Type = type; + + pNewLexicalEnvironment->m_pProperties = ECMA_NULL_POINTER; + + pNewLexicalEnvironment->m_GCInfo.m_IsObjectValid = true; + pNewLexicalEnvironment->m_GCInfo.u.m_Refs = 1; + + ecma_SetPointer( pNewLexicalEnvironment->u_Attributes.m_LexicalEnvironment.m_pOuterReference, pOuterLexicalEnvironment); + + return pNewLexicalEnvironment; +} /* ecma_CreateLexicalEnvironment */ + +/** + * Create internal property in an object and link it + * into the object's properties' linked-list + * + * @return pointer to newly created property's des + */ +ecma_Property_t* +ecma_CreateInternalProperty(ecma_Object_t *pObject, /**< the object */ + ecma_InternalPropertyId_t propertyId) /**< internal property identifier */ +{ + ecma_Property_t *pNewProperty = ecma_AllocProperty(); + + pNewProperty->m_Type = ECMA_PROPERTY_INTERNAL; + + ecma_SetPointer( pNewProperty->m_pNextProperty, ecma_GetPointer( pObject->m_pProperties)); + ecma_SetPointer( pObject->m_pProperties, pNewProperty); + + pNewProperty->u.m_InternalProperty.m_InternalPropertyType = propertyId; + pNewProperty->u.m_InternalProperty.m_Value = ECMA_NULL_POINTER; + + return pNewProperty; +} /* ecma_CreateInternalProperty */ + +/** + * Find internal property in the object's property set. + * + * @return pointer to the property's descriptor, if it is found, + * NULL - otherwise. + */ +ecma_Property_t* +ecma_FindInternalProperty(ecma_Object_t *pObject, /**< object descriptor */ + ecma_InternalPropertyId_t propertyId) /**< internal property identifier */ +{ + JERRY_ASSERT( pObject != NULL ); + + JERRY_ASSERT( propertyId != ECMA_INTERNAL_PROPERTY_PROTOTYPE + && propertyId != ECMA_INTERNAL_PROPERTY_EXTENSIBLE ); + + for ( ecma_Property_t *pProperty = ecma_GetPointer( pObject->m_pProperties); + pProperty != NULL; + pProperty = ecma_GetPointer( pProperty->m_pNextProperty) ) + { + if ( pProperty->m_Type == ECMA_PROPERTY_INTERNAL ) + { + if ( pProperty->u.m_InternalProperty.m_InternalPropertyType == propertyId ) + { + return pProperty; + } + } + } + + return NULL; +} /* ecma_FindInternalProperty */ + +/** + * Get an internal property. + * + * Warning: + * the property must exist + * + * @return pointer to the property + */ +ecma_Property_t* +ecma_GetInternalProperty(ecma_Object_t *pObject, /**< object descriptor */ + ecma_InternalPropertyId_t propertyId) /**< internal property identifier */ +{ + ecma_Property_t *pProperty = ecma_FindInternalProperty( pObject, propertyId); + + JERRY_ASSERT( pProperty != NULL ); + + return pProperty; +} /* ecma_GetInternalProperty */ + +/** + * 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 */ +{ + JERRY_ASSERT( length == 0 || pString != NULL ); + + ecma_ArrayFirstChunk_t *pStringFirstChunk = ecma_AllocArrayFirstChunk(); + + pStringFirstChunk->m_Header.m_UnitNumber = length; + uint8_t *copyPointer = (uint8_t*) pString; + size_t charsLeft = length; + size_t charsToCopy = JERRY_MIN( length, sizeof (pStringFirstChunk->m_Elements) / sizeof (ecma_Char_t)); + libc_memcpy(pStringFirstChunk->m_Elements, copyPointer, charsToCopy * sizeof (ecma_Char_t)); + charsLeft -= charsToCopy; + copyPointer += charsToCopy * sizeof (ecma_Char_t); + + ecma_ArrayNonFirstChunk_t *pStringNonFirstChunk; + uint16_t *pNextChunkCompressedPointer = &pStringFirstChunk->m_Header.m_pNextChunk; + + while ( charsLeft > 0 ) + { + pStringNonFirstChunk = ecma_AllocArrayNonFirstChunk(); + + size_t charsToCopy = JERRY_MIN( charsLeft, sizeof (pStringNonFirstChunk->m_Elements) / sizeof (ecma_Char_t)); + libc_memcpy(pStringNonFirstChunk->m_Elements, copyPointer, charsToCopy * sizeof (ecma_Char_t)); + charsLeft -= charsToCopy; + copyPointer += charsToCopy * sizeof (ecma_Char_t); + + ecma_SetPointer( *pNextChunkCompressedPointer, pStringNonFirstChunk); + pNextChunkCompressedPointer = &pStringNonFirstChunk->m_pNextChunk; + } + + *pNextChunkCompressedPointer = ECMA_NULL_POINTER; + + return pStringFirstChunk; +} /* ecma_NewEcmaString */ + +/** + * Copy ecma-string's contents to a buffer. + * + * Buffer will contain length of string, in characters, followed by string's characters. + * + * @return number of bytes, actually copied to the buffer, if string's content was copied successfully; + * negative number, which is calculated as negation of buffer size, that is required + * to hold the string's cpntent (in case size of buffer is insuficcient). + */ +ssize_t +ecma_CopyEcmaStringCharsToBuffer(ecma_ArrayFirstChunk_t *pFirstChunk, /**< first chunk of ecma-string */ + uint8_t *pBuffer, /**< destination buffer */ + size_t bufferSize) /**< size of buffer */ +{ + ecma_Length_t stringLength = pFirstChunk->m_Header.m_UnitNumber; + size_t requiredBufferSize = sizeof (ecma_Length_t) + sizeof (ecma_Char_t) * stringLength; + + if ( requiredBufferSize < bufferSize ) + { + return -(ssize_t) requiredBufferSize; + } + + *(ecma_Length_t*) pBuffer = stringLength; + + size_t charsLeft = stringLength; + uint8_t *destPointer = pBuffer + sizeof (ecma_Length_t); + size_t copyChunkChars = JERRY_MIN(sizeof (pFirstChunk->m_Elements) / sizeof (ecma_Char_t), + charsLeft); + libc_memcpy( destPointer, pFirstChunk->m_Elements, copyChunkChars * sizeof (ecma_Char_t)); + destPointer += copyChunkChars * sizeof (ecma_Char_t); + charsLeft -= copyChunkChars; + + ecma_ArrayNonFirstChunk_t *pNonFirstChunk = ecma_GetPointer( pFirstChunk->m_Header.m_pNextChunk); + + while ( charsLeft > 0 ) + { + JERRY_ASSERT( charsLeft < stringLength ); + + copyChunkChars = JERRY_MIN(sizeof (pNonFirstChunk->m_Elements) / sizeof (ecma_Char_t), + charsLeft); + libc_memcpy( destPointer, pNonFirstChunk->m_Elements, copyChunkChars * sizeof (ecma_Char_t)); + destPointer += copyChunkChars * sizeof (ecma_Char_t); + charsLeft -= copyChunkChars; + + pNonFirstChunk = ecma_GetPointer( pNonFirstChunk->m_pNextChunk); + } + + return (ssize_t) requiredBufferSize; +} /* ecma_CopyEcmaStringCharsToBuffer */ + +/** + * Duplicate an ecma-string. + * + * @return pointer to new ecma-string's first chunk + */ +ecma_ArrayFirstChunk_t* +ecma_DuplicateEcmaString( ecma_ArrayFirstChunk_t *pFirstChunk) /**< first chunk of string to duplicate */ +{ + JERRY_ASSERT( pFirstChunk != NULL ); + + ecma_ArrayFirstChunk_t *pFirstChunkCopy = ecma_AllocArrayFirstChunk(); + libc_memcpy( pFirstChunkCopy, pFirstChunk, sizeof (ecma_ArrayFirstChunk_t)); + + ecma_ArrayNonFirstChunk_t *pNonFirstChunk, *pNonFirstChunkCopy; + pNonFirstChunk = ecma_GetPointer( pFirstChunk->m_Header.m_pNextChunk); + uint16_t *pNextPointer = &pFirstChunk->m_Header.m_pNextChunk; + + while ( pNonFirstChunk != NULL ) + { + pNonFirstChunkCopy = ecma_AllocArrayNonFirstChunk(); + ecma_SetPointer( *pNextPointer, pNonFirstChunkCopy); + pNextPointer = &pNonFirstChunkCopy->m_pNextChunk; + + libc_memcpy( pNonFirstChunkCopy, pNonFirstChunk, sizeof (ecma_ArrayNonFirstChunk_t)); + + pNonFirstChunk = ecma_GetPointer( pNonFirstChunk->m_pNextChunk); + } + + *pNextPointer = ECMA_NULL_POINTER; + + return pFirstChunkCopy; +} /* ecma_DuplicateEcmaString */ + +/** + * Compare null-terminated string to ecma-string + * + * @return true - if strings are equal; + * false - otherwise. + */ +bool +ecma_CompareCharBufferToEcmaString(ecma_Char_t *pString, /**< null-terminated string */ + ecma_ArrayFirstChunk_t *pEcmaString) /* ecma-string */ +{ + JERRY_ASSERT( pString != NULL ); + JERRY_ASSERT( pEcmaString != NULL ); + + /* + * TODO: + */ + JERRY_UNIMPLEMENTED(); +} /* ecma_CompareCharBufferToEcmaString */ + +/** + * Free all chunks of an array + */ +void +ecma_FreeArray( ecma_ArrayFirstChunk_t *pFirstChunk) /**< first chunk of the array */ +{ + JERRY_ASSERT( pFirstChunk != NULL ); + + ecma_ArrayNonFirstChunk_t *pNonFirstChunk = ecma_GetPointer( pFirstChunk->m_Header.m_pNextChunk); + + ecma_FreeArrayFirstChunk( pFirstChunk); + + while ( pNonFirstChunk != NULL ) + { + ecma_ArrayNonFirstChunk_t *pNextChunk = ecma_GetPointer( pNonFirstChunk->m_pNextChunk); + + ecma_FreeArrayNonFirstChunk( pNonFirstChunk); + + pNonFirstChunk = pNextChunk; + } +} /* ecma_FreeArray */ + +/** + * @} + * @} + */ diff --git a/src/ecma_helpers.h b/src/ecma_helpers.h new file mode 100644 index 000000000..83f15ed12 --- /dev/null +++ b/src/ecma_helpers.h @@ -0,0 +1,64 @@ +/* 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. + */ + +/** \addtogroup ecma ---TODO--- + * @{ + * + * \addtogroup ecmahelpers Helpers for operations with ECMA data types + * @{ + */ + +#ifndef JERRY_ECMA_HELPERS_H +#define JERRY_ECMA_HELPERS_H + +#include "ecma_defs.h" + +extern uintptr_t ecma_CompressPointer(void *pointer); +extern void* ecma_DecompressPointer(uintptr_t compressedPointer); + +/** + * Get value of pointer from specified compressed pointer field. + */ +#define ecma_GetPointer( field) \ + ecma_DecompressPointer( field) + +/** + * Set value of compressed pointer field so that it will correspond + * to specified nonCompressedPointer. + */ +#define ecma_SetPointer( field, nonCompressedPointer) \ + (field) = ecma_CompressPointer( nonCompressedPointer) & ( ( 1u << ECMA_POINTER_FIELD_WIDTH ) - 1) + +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); + +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_ArrayFirstChunk_t* ecma_NewEcmaString( const ecma_Char_t *pString, ecma_Length_t length); +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); + +extern void ecma_FreeArray( ecma_ArrayFirstChunk_t *pFirstChunk); + +#endif /* !JERRY_ECMA_HELPERS_H */ + +/** + * @} + * @} + */ \ No newline at end of file diff --git a/src/jerry_libc.c b/src/jerry_libc.c new file mode 100644 index 000000000..d07b181b7 --- /dev/null +++ b/src/jerry_libc.c @@ -0,0 +1,107 @@ +/* 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. + */ + +/** + * Jerry libc implementation + */ + +#include "jerry_libc.h" + +#include + +extern int vprintf (__const char *__restrict __format, __builtin_va_list __arg); + +/** + * memset + * + * @return @s + */ +void* +libc_memset(void *s, /**< area to set values in */ + int c, /**< value to set */ + size_t n) /**< area size */ +{ + uint8_t *pArea = s; + for ( size_t index = 0; index < n; index++ ) + { + pArea[ index ] = (uint8_t)c; + } + + return s; +} /* libc_memset */ + +/** + * memcmp + * + * @return 0, if areas are equal; + * -1, if first area's content is lexicographically less, than second area's content; + * 1, otherwise + */ +int +libc_memcmp(const void *s1, /**< first area */ + const void *s2, /**< second area */ + size_t n) /**< area size */ +{ + const uint8_t *pArea1 = s1, *pArea2 = s2; + for ( size_t index = 0; index < n; index++ ) + { + if ( pArea1[ index ] < pArea2[ index ] ) + { + return -1; + } else if ( pArea1[ index ] > pArea2[ index ] ) + { + return 1; + } + } + + return 0; +} /* libc_memcmp */ + +/** + * memcpy + */ +void +libc_memcpy(void *s1, /**< destination */ + const void *s2, /**< source */ + size_t n) /**< bytes number */ +{ + uint8_t *pArea1 = s1; + const uint8_t *pArea2 = s2; + + for ( size_t index = 0; index < n; index++ ) + { + pArea1[ index ] = pArea2[ index ]; + } +} /* libc_memcpy */ + +/** + * printf + * + * @return number of characters printed + */ +int +libc_printf(const char *format, /**< format string */ + ...) /**< parameters' values */ +{ + va_list args; + + va_start( args, format); + + int ret = vprintf( format, args); + + va_end( args); + + return ret; +} /* libc_printf */ diff --git a/src/jerry_libc.h b/src/jerry_libc.h new file mode 100644 index 000000000..74ddac1f1 --- /dev/null +++ b/src/jerry_libc.h @@ -0,0 +1,29 @@ +/* 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. + */ + +/** + * Jerry libc declarations + */ +#ifndef JERRY_LIBC_H +#define JERRY_LIBC_H + +#include "defs.h" + +extern void *libc_memset(void *s, int c, size_t n); +extern int libc_memcmp(const void *s1, const void *s2, size_t n); +extern void libc_memcpy(void *s1, const void *s2, size_t n); +extern int libc_printf(const char *format, ...); + +#endif /* JERRY_LIBC_H */ diff --git a/src/main.c b/src/main.c index b447b8299..393210465 100644 --- a/src/main.c +++ b/src/main.c @@ -22,26 +22,32 @@ #include "parser.h" #include "pretty-printer.h" +#include "ctx_manager.h" +#include "mem_allocator.h" + int main (int argc, char **argv) { bool dump_tokens = false; - bool dump_ast = false; + bool dump_ast = true; const char *file_name = NULL; FILE *file = NULL; + mem_Init (); + ctx_Init (); + if (argc > 0) for (int i = 1; i < argc; i++) - { - if (!strcmp ("-t", argv[i])) - dump_tokens = true; - else if (!strcmp ("-a", argv[i])) - dump_ast = true; - else if (file_name == NULL) - file_name = argv[i]; - else - fatal (ERR_SEVERAL_FILES); - } + { + if (!strcmp ("-t", argv[i])) + dump_tokens = true; + else if (!strcmp ("-a", argv[i])) + dump_ast = true; + else if (file_name == NULL) + file_name = argv[i]; + else + fatal (ERR_SEVERAL_FILES); + } if (file_name == NULL) fatal (ERR_NO_FILES); @@ -55,33 +61,33 @@ main (int argc, char **argv) fatal (ERR_IO); if (dump_tokens) + { + token tok; + lexer_set_file (file); + tok = lexer_next_token (); + pp_reset (); + while (tok.type != TOK_EOF) { - token tok; - lexer_set_file (file); + pp_token (tok); tok = lexer_next_token (); - pp_reset (); - while (tok.type != TOK_EOF) - { - pp_token (tok); - tok = lexer_next_token (); - } } + } if (dump_ast) + { + statement *st; + lexer_set_file (file); + parser_init (); + st = parser_parse_statement (); + assert (st); + while (st->type != STMT_EOF) { - statement *st; - lexer_set_file (file); - parser_init (); + pp_statement (st); st = parser_parse_statement (); assert (st); - while (st->type != STMT_EOF) - { - pp_statement (st); - st = parser_parse_statement (); - assert (st); - } - pp_finish (); } + pp_finish (); + } return 0; -} \ No newline at end of file +} diff --git a/src/mem_allocator.c b/src/mem_allocator.c new file mode 100644 index 000000000..a7ae7b703 --- /dev/null +++ b/src/mem_allocator.c @@ -0,0 +1,53 @@ +/* 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. + */ + +/** + * Allocator implementation + */ + +#include "defs.h" +#include "mem_allocator.h" +#include "mem_heap.h" +#include "mem_poolman.h" +#include "ctx_manager.h" + +/** + * Area for heap + */ +static uint8_t mem_HeapArea[ MEM_HEAP_AREA_SIZE ] __attribute__((aligned(MEM_ALIGNMENT))); + +/** + * Check that heap area is less or equal than 64K. + */ +JERRY_STATIC_ASSERT( MEM_HEAP_AREA_SIZE <= 64 * 1024 ); + +/** + * Initialize memory allocators. + */ +void +mem_Init( void) +{ + mem_HeapInit( mem_HeapArea, sizeof (mem_HeapArea)); + mem_PoolsInit(); +} /* mem_Init */ + +/** + * Get base pointer for allocation area. + */ +uintptr_t +mem_GetBasePointer( void) +{ + return (uintptr_t) mem_HeapArea; +} /* mem_GetBasePointer */ diff --git a/src/mem_allocator.h b/src/mem_allocator.h new file mode 100644 index 000000000..45cdceb1b --- /dev/null +++ b/src/mem_allocator.h @@ -0,0 +1,46 @@ +/* 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. + */ + +/** \addtogroup mem Memory allocation + * @{ + */ + +/** + * Allocator interface + */ +#ifndef JERRY_MEM_ALLOCATOR_H +#define JERRY_MEM_ALLOCATOR_H + +#include "defs.h" +#include "mem_heap.h" + +/** + * Logarithm of required alignment for allocated units/blocks + */ +#define MEM_ALIGNMENT_LOG 2 + +/** + * Required alignment for allocated units/blocks + */ +#define MEM_ALIGNMENT (1 << MEM_ALIGNMENT_LOG) + +extern void mem_Init(void); +uintptr_t mem_GetBasePointer(void); + +#endif /* !JERRY_MEM_ALLOCATOR_H */ + +/** + * @} + */ \ No newline at end of file diff --git a/src/mem_heap.c b/src/mem_heap.c new file mode 100644 index 000000000..06b5701fd --- /dev/null +++ b/src/mem_heap.c @@ -0,0 +1,427 @@ +/* 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. + */ + +/** \addtogroup mem Memory allocation + * @{ + * + * \addtogroup heap Heap + * @{ + */ + +/** + * Heap implementation + */ + +#include "defs.h" +#include "jerry_libc.h" +#include "mem_allocator.h" +#include "mem_heap.h" + +/** + * Magic numbers for heap memory blocks + */ +typedef enum +{ + MEM_MAGIC_NUM_OF_FREE_BLOCK = 0x31d7c809, + MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK = 0x59d75b46 +} mem_MagicNumOfBlock_t; + +/** + * State of the block to initialize (argument of mem_InitBlockHeader) + * + * @see mem_InitBlockHeader + */ +typedef enum +{ + MEM_BLOCK_FREE, /**< initializing free block */ + MEM_BLOCK_ALLOCATED /**< initializing allocated block */ +} mem_BlockState_t; + +/** + * Linked list direction descriptors + */ +typedef enum +{ + MEM_DIRECTION_PREV = 0, /**< direction from right to left */ + MEM_DIRECTION_NEXT = 1, /**< direction from left to right */ + MEM_DIRECTION_COUNT = 2 /**< count of possible directions */ +} mem_Direction_t; + +/** + * Description of heap memory block layout + */ +typedef struct mem_BlockHeader_t +{ + mem_MagicNumOfBlock_t m_MagicNum; /**< magic number - MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK for allocated block + and MEM_MAGIC_NUM_OF_FREE_BLOCK for free block */ + struct mem_BlockHeader_t *m_Neighbours[ MEM_DIRECTION_COUNT ]; /**< neighbour blocks */ + size_t m_SizeInChunks; /**< size of block with header in chunks */ +} mem_BlockHeader_t; + +/** + * Calculate size in bytes of the block space, that can be used to store data + */ +#define mem_GetHeapBlockDataSpaceSizeInBytes( pBlockHeader) ( MEM_HEAP_CHUNK_SIZE * pBlockHeader->m_SizeInChunks - sizeof(mem_BlockHeader_t) ) + +/** + * Calculate size in chunks of heap block from data space size in bytes + */ +#define mem_GetHeapBlockSizeInChunksFromDataSpaceSizeInBytes( size) ( ( sizeof(mem_BlockHeader_t) + size + MEM_HEAP_CHUNK_SIZE - 1 ) / MEM_HEAP_CHUNK_SIZE ) + +/** + * Chunk should have enough space for block header + */ +JERRY_STATIC_ASSERT( MEM_HEAP_CHUNK_SIZE >= sizeof (mem_BlockHeader_t) ); + +/** + * Chunk size should satisfy the required alignment value + */ +JERRY_STATIC_ASSERT( MEM_HEAP_CHUNK_SIZE % MEM_ALIGNMENT == 0 ); + +/** + * Description of heap state + */ +typedef struct +{ + uint8_t* m_HeapStart; /**< first address of heap space */ + size_t m_HeapSize; /**< heap space size */ + mem_BlockHeader_t* m_pFirstBlock; /**< first block of the heap */ + mem_BlockHeader_t* m_pLastBlock; /**< last block of the heap */ +} mem_HeapState_t; + +/** + * Heap state + */ +mem_HeapState_t mem_Heap; + +static void mem_InitBlockHeader( uint8_t *pFirstChunk, + size_t sizeInChunks, + mem_BlockState_t blockState, + mem_BlockHeader_t *pPrevBlock, + mem_BlockHeader_t *pNextBlock); +static void mem_CheckHeap( void); + +/** + * Startup initialization of heap + */ +void +mem_HeapInit( uint8_t *heapStart, /**< first address of heap space */ + size_t heapSize) /**< heap space size */ +{ + JERRY_ASSERT( heapStart != NULL ); + JERRY_ASSERT( heapSize != 0 ); + JERRY_ASSERT( heapSize % MEM_HEAP_CHUNK_SIZE == 0 ); + JERRY_ASSERT( (uintptr_t) heapStart % MEM_ALIGNMENT == 0); + + mem_Heap.m_HeapStart = heapStart; + mem_Heap.m_HeapSize = heapSize; + + mem_InitBlockHeader( mem_Heap.m_HeapStart, + heapSize / MEM_HEAP_CHUNK_SIZE, + MEM_BLOCK_FREE, + NULL, + NULL); + + mem_Heap.m_pFirstBlock = (mem_BlockHeader_t*) mem_Heap.m_HeapStart; + mem_Heap.m_pLastBlock = mem_Heap.m_pFirstBlock; +} /* mem_HeapInit */ + +/** + * Initialize block header + */ +static void +mem_InitBlockHeader( uint8_t *pFirstChunk, /**< address of the first chunk to use for the block */ + size_t sizeInChunks, /**< size of block with header in chunks */ + mem_BlockState_t blockState, /**< state of the block (allocated or free) */ + mem_BlockHeader_t *pPrevBlock, /**< previous block */ + mem_BlockHeader_t *pNextBlock) /**< next block */ +{ + mem_BlockHeader_t *pBlockHeader = (mem_BlockHeader_t*) pFirstChunk; + + if ( blockState == MEM_BLOCK_FREE ) + { + pBlockHeader->m_MagicNum = MEM_MAGIC_NUM_OF_FREE_BLOCK; + } else + { + pBlockHeader->m_MagicNum = MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK; + } + + pBlockHeader->m_Neighbours[ MEM_DIRECTION_PREV ] = pPrevBlock; + pBlockHeader->m_Neighbours[ MEM_DIRECTION_NEXT ] = pNextBlock; + pBlockHeader->m_SizeInChunks = sizeInChunks; +} /* mem_InitFreeBlock */ + +/** + * Allocation of memory region. + * + * To reduce heap fragmentation there are two allocation modes - short-term and long-term. + * + * If allocation is short-term then the beginning of the heap is preferred, else - the end of the heap. + * + * It is supposed, that all short-term allocation is used during relatively short discrete sessions. + * After end of the session all short-term allocated regions are supposed to be freed. + * + * @return pointer to allocated memory block - if allocation is successful,\n + * NULL - if there is not enough memory. + */ +uint8_t* +mem_HeapAllocBlock( size_t sizeInBytes, /**< size of region to allocate in bytes */ + mem_HeapAllocTerm_t allocTerm) /**< expected allocation term */ +{ + mem_BlockHeader_t *pBlock; + mem_Direction_t direction; + + mem_CheckHeap(); + + if ( allocTerm == MEM_HEAP_ALLOC_SHORT_TERM ) + { + pBlock = mem_Heap.m_pFirstBlock; + direction = MEM_DIRECTION_NEXT; + } else + { + pBlock = mem_Heap.m_pLastBlock; + direction = MEM_DIRECTION_PREV; + } + + /* searching for appropriate block */ + while ( pBlock != NULL ) + { + if ( pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK ) + { + if ( mem_GetHeapBlockDataSpaceSizeInBytes( pBlock) >= sizeInBytes ) + { + break; + } + } else + { + JERRY_ASSERT( pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK ); + } + + pBlock = pBlock->m_Neighbours[ direction ]; + } + + if ( pBlock == NULL ) + { + /* not enough free space */ + return NULL; + } + + /* appropriate block found, allocating space */ + size_t newBlockSizeInChunks = mem_GetHeapBlockSizeInChunksFromDataSpaceSizeInBytes( sizeInBytes); + size_t foundBlockSizeInChunks = pBlock->m_SizeInChunks; + + JERRY_ASSERT( newBlockSizeInChunks <= foundBlockSizeInChunks ); + + mem_BlockHeader_t *pPrevBlock = pBlock->m_Neighbours[ MEM_DIRECTION_PREV ]; + mem_BlockHeader_t *pNextBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ]; + + if ( newBlockSizeInChunks < foundBlockSizeInChunks ) + { + uint8_t *pNewFreeBlockFirstChunk = (uint8_t*) pBlock + newBlockSizeInChunks * MEM_HEAP_CHUNK_SIZE; + mem_InitBlockHeader( pNewFreeBlockFirstChunk, + foundBlockSizeInChunks - newBlockSizeInChunks, + MEM_BLOCK_FREE, + pBlock /* there we will place new allocated block */, + pNextBlock); + + mem_BlockHeader_t *pNewFreeBlock = (mem_BlockHeader_t*) pNewFreeBlockFirstChunk; + + if ( pNextBlock == NULL ) + { + mem_Heap.m_pLastBlock = pNewFreeBlock; + } + + pNextBlock = pNewFreeBlock; + } + + mem_InitBlockHeader( (uint8_t*) pBlock, + newBlockSizeInChunks, + MEM_BLOCK_ALLOCATED, + pPrevBlock, + pNextBlock); + + JERRY_ASSERT( mem_GetHeapBlockDataSpaceSizeInBytes( pBlock) >= sizeInBytes ); + + mem_CheckHeap(); + + /* return data space beginning address */ + uint8_t *pDataSpace = (uint8_t*) (pBlock + 1); + JERRY_ASSERT( (uintptr_t) pDataSpace % MEM_ALIGNMENT == 0); + + return pDataSpace; +} /* mem_Alloc */ + +/** + * Free the memory block. + */ +void +mem_HeapFreeBlock( uint8_t *ptr) /**< pointer to beginning of data space of the block */ +{ + /* checking that ptr points to the heap */ + JERRY_ASSERT( ptr >= mem_Heap.m_HeapStart + && ptr <= mem_Heap.m_HeapStart + mem_Heap.m_HeapSize ); + + mem_CheckHeap(); + + mem_BlockHeader_t *pBlock = (mem_BlockHeader_t*) ptr - 1; + mem_BlockHeader_t *pPrevBlock = pBlock->m_Neighbours[ MEM_DIRECTION_PREV ]; + mem_BlockHeader_t *pNextBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ]; + + /* checking magic nums that are neighbour to data space */ + JERRY_ASSERT( pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK ); + if ( pNextBlock != NULL ) + { + JERRY_ASSERT( pNextBlock->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK + || pNextBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK ); + } + + pBlock->m_MagicNum = MEM_MAGIC_NUM_OF_FREE_BLOCK; + + if ( pNextBlock != NULL + && pNextBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK ) + { + /* merge with the next block */ + pBlock->m_SizeInChunks += pNextBlock->m_SizeInChunks; + pNextBlock = pNextBlock->m_Neighbours[ MEM_DIRECTION_NEXT ]; + pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ] = pNextBlock; + if ( pNextBlock != NULL ) + { + pNextBlock->m_Neighbours[ MEM_DIRECTION_PREV ] = pBlock; + } else + { + mem_Heap.m_pLastBlock = pBlock; + } + } + + if ( pPrevBlock != NULL + && pPrevBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK ) + { + /* merge with the previous block */ + pPrevBlock->m_SizeInChunks += pBlock->m_SizeInChunks; + pPrevBlock->m_Neighbours[ MEM_DIRECTION_NEXT ] = pNextBlock; + if ( pNextBlock != NULL ) + { + pNextBlock->m_Neighbours[ MEM_DIRECTION_PREV ] = pBlock->m_Neighbours[ MEM_DIRECTION_PREV ]; + } else + { + mem_Heap.m_pLastBlock = pPrevBlock; + } + } + + mem_CheckHeap(); +} /* mem_Free */ + +/** + * Recommend allocation size based on chunk size. + * + * @return recommended allocation size + */ +size_t +mem_HeapRecommendAllocationSize( size_t minimumAllocationSize) /**< minimum allocation size */ +{ + size_t minimumAllocationSizeWithBlockHeader = minimumAllocationSize + sizeof (mem_BlockHeader_t); + size_t heapChunkAlignedAllocationSize = JERRY_ALIGNUP( minimumAllocationSizeWithBlockHeader, MEM_HEAP_CHUNK_SIZE); + + return heapChunkAlignedAllocationSize - sizeof (mem_BlockHeader_t); +} /* mem_HeapRecommendAllocationSize */ + +/** + * Print heap + */ +void +mem_HeapPrint( bool dumpBlockData) /**< print block with data (true) + or print only block header (false) */ +{ + mem_CheckHeap(); + + libc_printf("Heap: start=%p size=%lu, first block->%p, last block->%p\n", + mem_Heap.m_HeapStart, + mem_Heap.m_HeapSize, + (void*) mem_Heap.m_pFirstBlock, + (void*) mem_Heap.m_pLastBlock); + + for ( mem_BlockHeader_t *pBlock = mem_Heap.m_pFirstBlock; + pBlock != NULL; + pBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ] ) + { + libc_printf("Block (%p): magic num=0x%08x, size in chunks=%lu, previous block->%p next block->%p\n", + (void*) pBlock, + pBlock->m_MagicNum, + pBlock->m_SizeInChunks, + (void*) pBlock->m_Neighbours[ MEM_DIRECTION_PREV ], + (void*) pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ]); + + if ( dumpBlockData ) + { + uint8_t *pBlockData = (uint8_t*) (pBlock + 1); + for ( uint32_t offset = 0; + offset < mem_GetHeapBlockDataSpaceSizeInBytes( pBlock); + offset++ ) + { + libc_printf("%02x ", pBlockData[ offset ]); + } + libc_printf("\n"); + } + } + + libc_printf("\n"); +} /* mem_PrintHeap */ + +/** + * Check heap consistency + */ +static void +mem_CheckHeap( void) +{ +#ifndef JERRY_NDEBUG + JERRY_ASSERT( (uint8_t*) mem_Heap.m_pFirstBlock == mem_Heap.m_HeapStart ); + JERRY_ASSERT( mem_Heap.m_HeapSize % MEM_HEAP_CHUNK_SIZE == 0 ); + + size_t chunksCount = 0; + bool isLastBlockWasMet = false; + for ( mem_BlockHeader_t *pBlock = mem_Heap.m_pFirstBlock; + pBlock != NULL; + pBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ] ) + { + JERRY_ASSERT( pBlock != NULL ); + JERRY_ASSERT( pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_FREE_BLOCK + || pBlock->m_MagicNum == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK ); + + chunksCount += pBlock->m_SizeInChunks; + + mem_BlockHeader_t *pNextBlock = pBlock->m_Neighbours[ MEM_DIRECTION_NEXT ]; + if ( pBlock == mem_Heap.m_pLastBlock ) + { + isLastBlockWasMet = true; + + JERRY_ASSERT( pNextBlock == NULL ); + JERRY_ASSERT( mem_Heap.m_HeapStart + mem_Heap.m_HeapSize + == (uint8_t*) pBlock + pBlock->m_SizeInChunks * MEM_HEAP_CHUNK_SIZE ); + } else + { + JERRY_ASSERT( pNextBlock != NULL ); + JERRY_ASSERT( (uint8_t*) pNextBlock == (uint8_t*) pBlock + pBlock->m_SizeInChunks * MEM_HEAP_CHUNK_SIZE ); + } + } + + JERRY_ASSERT( isLastBlockWasMet ); + JERRY_ASSERT( chunksCount == mem_Heap.m_HeapSize / MEM_HEAP_CHUNK_SIZE ); +#endif /* !JERRY_NDEBUG */ +} /* mem_CheckHeap */ + +/** + * @} + * @} + */ diff --git a/src/mem_heap.h b/src/mem_heap.h new file mode 100644 index 000000000..01407a32f --- /dev/null +++ b/src/mem_heap.h @@ -0,0 +1,52 @@ +/* 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. + */ + +/** \addtogroup mem Memory allocation + * @{ + * + * \addtogroup heap Heap + * @{ + */ + +/** + * Heap allocator interface + */ +#ifndef JERRY_MEM_HEAP_H +#define JERRY_MEM_HEAP_H + +#include "defs.h" + +/** + * Type of allocation (argument of mem_Alloc) + * + * @see mem_HeapAllocBlock + */ +typedef enum { + MEM_HEAP_ALLOC_SHORT_TERM, /**< allocated region will be freed soon */ + MEM_HEAP_ALLOC_LONG_TERM /**< allocated region most likely will not be freed soon */ +} mem_HeapAllocTerm_t; + +extern void mem_HeapInit(uint8_t *heapStart, size_t heapSize); +extern uint8_t* mem_HeapAllocBlock(size_t sizeInBytes, mem_HeapAllocTerm_t allocTerm); +extern void mem_HeapFreeBlock(uint8_t *ptr); +extern size_t mem_HeapRecommendAllocationSize(size_t minimumAllocationSize); +extern void mem_HeapPrint(bool dumpBlockData); + +/** + * @} + * @} + */ + +#endif /* !JERRY_MEM_HEAP_H */ diff --git a/src/mem_pool.c b/src/mem_pool.c new file mode 100644 index 000000000..5480cc6c2 --- /dev/null +++ b/src/mem_pool.c @@ -0,0 +1,257 @@ +/* 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. + */ + +/** \addtogroup mem Memory allocation + * @{ + * + * \addtogroup pool Memory pool + * @{ + */ + +/** + * Memory pool implementation + */ + +#define JERRY_MEM_POOL_INTERNAL + +#include "defs.h" +#include "jerry_libc.h" +#include "mem_allocator.h" +#include "mem_pool.h" + +/** + * Magic number to fill free chunks in debug version + */ +static const uint8_t mem_PoolFreeChunkMagicNum = 0x71; + +/** + * Number of bits in a single bitmap's bits' block. + */ +static const mword_t mem_BitmapBitsInBlock = sizeof (mword_t) * JERRY_BITSINBYTE; + +static void mem_CheckPool( mem_PoolState_t *pPool); + +/** + * Initialization of memory pool. + * + * Pool will be located in the segment [poolStart; poolStart + poolSize). + * Part of pool space will be used for bitmap and the rest will store chunks. + * + * Warning: + * it is incorrect to suppose, that chunk number = poolSize / chunkSize. + */ +void +mem_PoolInit(mem_PoolState_t *pPool, /**< pool */ + size_t chunkSize, /**< size of one chunk */ + uint8_t *poolStart, /**< start of pool space */ + size_t poolSize) /**< pool space size */ +{ + JERRY_ASSERT( pPool != NULL ); + JERRY_ASSERT( (uintptr_t) poolStart % MEM_ALIGNMENT == 0); + JERRY_ASSERT( chunkSize % MEM_ALIGNMENT == 0 ); + + pPool->m_pPoolStart = poolStart; + pPool->m_PoolSize = poolSize; + pPool->m_ChunkSize = chunkSize; + + const size_t bitsInByte = JERRY_BITSINBYTE; + const size_t bitmapAreaSizeAlignment = JERRY_MAX( sizeof (mword_t), MEM_ALIGNMENT); + + /* + * Calculation chunks number + */ + + size_t bitmapAreaSize = 0; + size_t chunksAreaSize = JERRY_ALIGNDOWN( poolSize - bitmapAreaSize, chunkSize); + size_t chunksNumber = chunksAreaSize / chunkSize; + + /* while there is not enough area to hold state of all chunks*/ + while ( bitmapAreaSize * bitsInByte < chunksNumber ) + { + JERRY_ASSERT( bitmapAreaSize + chunksAreaSize <= poolSize ); + + /* correct bitmap area's size and, accordingly, chunks' area's size*/ + + size_t newBitmapAreaSize = bitmapAreaSize + bitmapAreaSizeAlignment; + size_t newChunksAreaSize = JERRY_ALIGNDOWN( poolSize - newBitmapAreaSize, chunkSize); + size_t newChunksNumber = newChunksAreaSize / chunkSize; + + bitmapAreaSize = newBitmapAreaSize; + chunksAreaSize = newChunksAreaSize; + chunksNumber = newChunksNumber; + } + + /* + * Final calculation checks + */ + JERRY_ASSERT( bitmapAreaSize * bitsInByte >= chunksNumber ); + JERRY_ASSERT( chunksAreaSize >= chunksNumber * chunkSize ); + JERRY_ASSERT( bitmapAreaSize + chunksAreaSize <= poolSize ); + + pPool->m_pBitmap = (mword_t*) poolStart; + pPool->m_pChunks = poolStart + bitmapAreaSize; + + JERRY_ASSERT( (uintptr_t) pPool->m_pChunks % MEM_ALIGNMENT == 0 ); + + pPool->m_ChunksNumber = chunksNumber; + + /* + * All chunks are free right after initialization + */ + pPool->m_FreeChunksNumber = chunksNumber; + libc_memset( pPool->m_pBitmap, 0, bitmapAreaSize); + +#ifndef JERRY_NDEBUG + libc_memset( pPool->m_pChunks, mem_PoolFreeChunkMagicNum, chunksAreaSize); +#endif /* JERRY_NDEBUG */ + + mem_CheckPool( pPool); +} /* mem_PoolInit */ + +/** + * Allocate a chunk in the pool + */ +uint8_t* +mem_PoolAllocChunk(mem_PoolState_t *pPool) /**< pool */ +{ + mem_CheckPool( pPool); + + if ( pPool->m_FreeChunksNumber == 0 ) + { + return NULL; + } + + size_t chunkIndex = 0; + size_t bitmapBlockIndex = 0; + + while ( chunkIndex < pPool->m_ChunksNumber ) + { + if ( ~pPool->m_pBitmap[ bitmapBlockIndex ] != 0 ) + { + break; + } else + { + bitmapBlockIndex++; + chunkIndex += mem_BitmapBitsInBlock; + } + } + + if ( chunkIndex >= pPool->m_ChunksNumber ) + { + /* no free chunks */ + return NULL; + } + + /* found bitmap block with a zero bit */ + + mword_t bit = 1; + for ( size_t bitIndex = 0; + bitIndex < mem_BitmapBitsInBlock && chunkIndex < pPool->m_ChunksNumber; + bitIndex++, chunkIndex++, bit <<= 1 ) + { + if ( ~pPool->m_pBitmap[ bitmapBlockIndex ] & bit ) + { + /* found free chunk */ + pPool->m_pBitmap[ bitmapBlockIndex ] |= bit; + + uint8_t *pChunk = &pPool->m_pChunks[ chunkIndex * pPool->m_ChunkSize ]; + pPool->m_FreeChunksNumber--; + + mem_CheckPool( pPool); + + return pChunk; + } + } + + /* that zero bit is at the end of the bitmap and doesn't correspond to any chunk */ + return NULL; +} /* mem_PoolAllocChunk */ + +/** + * Free the chunk in the pool + */ +void +mem_PoolFreeChunk(mem_PoolState_t *pPool, /**< pool */ + uint8_t *pChunk) /**< chunk pointer */ +{ + JERRY_ASSERT( pPool->m_FreeChunksNumber < pPool->m_ChunksNumber ); + JERRY_ASSERT( pChunk >= pPool->m_pChunks && pChunk <= pPool->m_pChunks + pPool->m_ChunksNumber * pPool->m_ChunkSize ); + JERRY_ASSERT( ( (uintptr_t) pChunk - (uintptr_t) pPool->m_pChunks ) % pPool->m_ChunkSize == 0 ); + + mem_CheckPool( pPool); + + size_t chunkIndex = (size_t) (pChunk - pPool->m_pChunks) / pPool->m_ChunkSize; + size_t bitmapBlockIndex = chunkIndex / mem_BitmapBitsInBlock; + size_t bitmapBitInBlock = chunkIndex % mem_BitmapBitsInBlock; + mword_t bitMask = ( 1lu << bitmapBitInBlock ); + +#ifndef JERRY_NDEBUG + libc_memset( (uint8_t*) pChunk, mem_PoolFreeChunkMagicNum, pPool->m_ChunkSize); +#endif /* JERRY_NDEBUG */ + JERRY_ASSERT( pPool->m_pBitmap[ bitmapBlockIndex ] & bitMask ); + + pPool->m_pBitmap[ bitmapBlockIndex ] &= ~bitMask; + pPool->m_FreeChunksNumber++; + + mem_CheckPool( pPool); +} /* mem_PoolFreeChunk */ + +/** + * Check pool state consistency + */ +static void +mem_CheckPool( mem_PoolState_t __unused *pPool) /**< pool (unused #ifdef JERRY_NDEBUG) */ +{ +#ifndef JERRY_NDEBUG + JERRY_ASSERT( pPool->m_ChunksNumber != 0 ); + JERRY_ASSERT( pPool->m_FreeChunksNumber <= pPool->m_ChunksNumber ); + JERRY_ASSERT( (uint8_t*) pPool->m_pBitmap == pPool->m_pPoolStart ); + JERRY_ASSERT( (uint8_t*) pPool->m_pChunks > pPool->m_pPoolStart ); + + uint8_t freeChunkTemplate[ pPool->m_ChunkSize ]; + libc_memset( &freeChunkTemplate, mem_PoolFreeChunkMagicNum, sizeof (freeChunkTemplate)); + + size_t metFreeChunksNumber = 0; + + for ( size_t chunkIndex = 0, bitmapBlockIndex = 0; + chunkIndex < pPool->m_ChunksNumber; + bitmapBlockIndex++ ) + { + JERRY_ASSERT( (uint8_t*) & pPool->m_pBitmap[ bitmapBlockIndex ] < pPool->m_pChunks ); + + mword_t bitmapBlock = pPool->m_pBitmap[ bitmapBlockIndex ]; + + mword_t bitMask = 1; + for ( size_t bitmapBitInBlock = 0; + chunkIndex < pPool->m_ChunksNumber && bitmapBitInBlock < mem_BitmapBitsInBlock; + bitmapBitInBlock++, bitMask <<= 1, chunkIndex++ ) + { + if ( ~bitmapBlock & bitMask ) + { + metFreeChunksNumber++; + + JERRY_ASSERT( libc_memcmp( &pPool->m_pChunks[ chunkIndex * pPool->m_ChunkSize ], freeChunkTemplate, pPool->m_ChunkSize) == 0 ); + } + } + } + + JERRY_ASSERT( metFreeChunksNumber == pPool->m_FreeChunksNumber ); +#endif /* !JERRY_NDEBUG */ +} /* mem_CheckPool */ + +/** + * @} + * @} + */ \ No newline at end of file diff --git a/src/mem_pool.h b/src/mem_pool.h new file mode 100644 index 000000000..6f47a6c46 --- /dev/null +++ b/src/mem_pool.h @@ -0,0 +1,56 @@ +/* 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. + */ + +/** \addtogroup pool Memory pool + * @{ + */ + +#ifndef JERRY_MEM_POOL_INTERNAL +#error "Please, use mem_poolman.h instead of mem_pool.h" +#endif + +#ifndef JERRY_MEM_POOL_H +#define JERRY_MEM_POOL_H + +/** + * State of a memory pool + * + * TODO: + * Compact the struct + */ +typedef struct mem_PoolState_t { + uint8_t *m_pPoolStart; /**< first address of pool space */ + size_t m_PoolSize; /**< pool space size */ + + size_t m_ChunkSize; /**< size of one chunk */ + + mword_t *m_pBitmap; /**< bitmap - pool chunks' state */ + uint8_t *m_pChunks; /**< chunks with data */ + + size_t m_ChunksNumber; /**< number of chunks */ + size_t m_FreeChunksNumber; /**< number of free chunks */ + + struct mem_PoolState_t *m_pNextPool; /**< pointer to the next pool with same chunk size */ +} mem_PoolState_t; + +extern void mem_PoolInit(mem_PoolState_t *pPool, size_t chunkSize, uint8_t *poolStart, size_t poolSize); +extern uint8_t* mem_PoolAllocChunk(mem_PoolState_t *pPool); +extern void mem_PoolFreeChunk(mem_PoolState_t *pPool, uint8_t *pChunk); + +#endif /* JERRY_MEM_POOL_H */ + +/** + * @} + */ diff --git a/src/mem_poolman.c b/src/mem_poolman.c new file mode 100644 index 000000000..b97e40e7e --- /dev/null +++ b/src/mem_poolman.c @@ -0,0 +1,233 @@ +/* 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. + */ + +/** \addtogroup mem Memory allocation + * @{ + * + * \addtogroup poolman Memory pool manager + * @{ + */ + +/** + * Memory pool manager implementation + */ + +#define JERRY_MEM_POOL_INTERNAL + +#include "defs.h" +#include "mem_allocator.h" +#include "mem_heap.h" +#include "mem_pool.h" +#include "mem_poolman.h" + +/** + * Lists of pools for possible chunk sizes + */ +mem_PoolState_t *mem_Pools[ MEM_POOL_CHUNK_TYPE__COUNT ]; + +/** + * Number of free chunks of possible chunk sizes + */ +size_t mem_FreeChunksNumber[ MEM_POOL_CHUNK_TYPE__COUNT ]; + +/** + * Pool, containing pool headers + */ +mem_PoolState_t mem_PoolForPoolHeaders; + +/** + * Space for pool, containing pool headers + */ +uint8_t *mem_SpaceForPoolForPoolHeaders; + +/** + * Get chunk size from chunk type. + * + * @return size (in bytes) of chunk of specified type + */ +static size_t +mem_GetChunkSize( mem_PoolChunkType_t chunkType) /**< chunk type */ +{ + uint32_t chunkTypeId = (uint32_t) chunkType; + + JERRY_ASSERT( chunkTypeId < MEM_POOL_CHUNK_TYPE__COUNT ); + + return ( 1u << ( chunkTypeId + 2 ) ); +} /* mem_GetChunkSize */ + +/** + * Initialize pool manager + */ +void +mem_PoolsInit(void) +{ + for ( uint32_t i = 0; i < MEM_POOL_CHUNK_TYPE__COUNT; i++ ) + { + mem_Pools[ i ] = NULL; + mem_FreeChunksNumber[ i ] = 0; + } + + /** + * Space, at least for four pool headers and a bitmap entry. + * + * TODO: Research. + */ + size_t poolSpaceSize = mem_HeapRecommendAllocationSize( 4 * sizeof (mem_PoolState_t) + sizeof (mword_t) ); + + mem_SpaceForPoolForPoolHeaders = mem_HeapAllocBlock(poolSpaceSize, + MEM_HEAP_ALLOC_LONG_TERM); + + /* + * Get chunk type, checking that there is a type corresponding to specified size. + */ + const mem_PoolChunkType_t chunkType = mem_SizeToPoolChunkType( sizeof(mem_PoolState_t)); + + mem_PoolInit(&mem_PoolForPoolHeaders, + mem_GetChunkSize( chunkType), + mem_SpaceForPoolForPoolHeaders, + poolSpaceSize); +} /* mem_PoolsInit */ + +/** + * Allocate a chunk of specified size + * + * @return pointer to allocated chunk, if allocation was successful, + * or NULL - if not enough memory. + */ +uint8_t* +mem_PoolsAlloc( mem_PoolChunkType_t chunkType) /**< chunk type */ +{ + size_t chunkSize = mem_GetChunkSize( chunkType); + + /** + * If there are no free chunks, allocate new pool. + */ + if ( mem_FreeChunksNumber[ chunkType ] == 0 ) + { + mem_PoolState_t *poolState = (mem_PoolState_t*) mem_PoolAllocChunk( &mem_PoolForPoolHeaders); + + if ( poolState == NULL ) + { + /** + * Not enough space for new pool' header. + */ + return NULL; + } + + /** + * Space, at least for eight chunks and a bitmap entry. + * + * TODO: Research. + */ + size_t poolSpaceSize = mem_HeapRecommendAllocationSize( 8 * chunkSize + sizeof (mword_t) ); + + uint8_t *poolSpace = mem_HeapAllocBlock( poolSpaceSize, + MEM_HEAP_ALLOC_LONG_TERM); + + if ( poolSpace == NULL ) + { + /** + * Not enough memory. + */ + return NULL; + } + + mem_PoolInit( poolState, + chunkSize, + poolSpace, + poolSpaceSize); + + poolState->m_pNextPool = mem_Pools[ chunkType ]; + mem_Pools[ chunkType ] = poolState; + + mem_FreeChunksNumber[ chunkType ] += poolState->m_FreeChunksNumber; + } + + /** + * Now there is definitely at least one pool of specified type with at least one free chunk. + * + * Search for the pool. + */ + mem_PoolState_t *poolState = mem_Pools[ chunkType ]; + + while ( poolState->m_FreeChunksNumber == 0 ) + { + poolState = poolState->m_pNextPool; + + JERRY_ASSERT( poolState != NULL ); + } + + /** + * And allocate chunk within it. + */ + mem_FreeChunksNumber[ chunkType ]--; + + return mem_PoolAllocChunk( poolState); +} /* mem_PoolsAlloc */ + +/** + * Free the chunk + */ +void +mem_PoolsFree( mem_PoolChunkType_t chunkType, /**< the chunk type */ + uint8_t *pChunk) /**< pointer to the chunk */ +{ + mem_PoolState_t *poolState = mem_Pools[ chunkType ], *prevPoolState = NULL; + + /** + * Search for the pool containing specified chunk. + */ + while ( !( pChunk >= poolState->m_pChunks + && pChunk <= poolState->m_pPoolStart + poolState->m_PoolSize ) ) + { + prevPoolState = poolState; + poolState = poolState->m_pNextPool; + + JERRY_ASSERT( poolState != NULL ); + } + + /** + * Free the chunk + */ + mem_PoolFreeChunk( poolState, pChunk); + mem_FreeChunksNumber[ chunkType ]++; + + /** + * If all chunks of the pool are free, free the pool itself. + */ + if ( poolState->m_FreeChunksNumber == poolState->m_ChunksNumber ) + { + if ( prevPoolState != NULL ) + { + prevPoolState->m_pNextPool = poolState->m_pNextPool; + } else + { + mem_Pools[ chunkType ] = poolState->m_pNextPool; + } + + mem_FreeChunksNumber[ chunkType ] -= poolState->m_ChunksNumber; + + mem_HeapFreeBlock( poolState->m_pPoolStart); + + mem_PoolFreeChunk( &mem_PoolForPoolHeaders, (uint8_t*) poolState); + } +} /* mem_PoolsFree */ + +/** + * @} + */ +/** + * @} + */ diff --git a/src/mem_poolman.h b/src/mem_poolman.h new file mode 100644 index 000000000..fec6a3b2e --- /dev/null +++ b/src/mem_poolman.h @@ -0,0 +1,65 @@ +/* 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. + */ + +/** \addtogroup mem Memory allocation + * @{ + */ + +/** \addtogroup poolman Memory pool manager + * @{ + */ + +/** + * Pool manager interface + */ +#ifndef JERRY_MEM_POOLMAN_H +#define JERRY_MEM_POOLMAN_H + +#include "defs.h" + +/** + * Pool chunks's possible sizes + */ +typedef enum { + MEM_POOL_CHUNK_TYPE_4, /**< 4-byte chunk */ + MEM_POOL_CHUNK_TYPE_8, /**< 8-byte chunk */ + MEM_POOL_CHUNK_TYPE_16, /**< 16-byte chunk */ + MEM_POOL_CHUNK_TYPE_32, /**< 32-byte chunk */ + MEM_POOL_CHUNK_TYPE__COUNT /**< count of possible pool chunks' sizes */ +} mem_PoolChunkType_t; + +/** + * Convert size to pool chunk type. + */ +#define mem_SizeToPoolChunkType( size) ((size) == 4 ? MEM_POOL_CHUNK_TYPE_4 : \ + ((size) == 8 ? MEM_POOL_CHUNK_TYPE_8 : \ + ((size) == 16 ? MEM_POOL_CHUNK_TYPE_16 : \ + ((size) == 32 ? MEM_POOL_CHUNK_TYPE_32 : \ + jerry_UnreferencedExpression)))) + + +extern void mem_PoolsInit(void); +extern uint8_t* mem_PoolsAlloc(mem_PoolChunkType_t chunkType); +extern void mem_PoolsFree(mem_PoolChunkType_t chunkType, uint8_t *pChunk); + +#endif /* JERRY_MEM_POOLMAN_H */ + +/** + * @} + */ + +/** + * @} + */