Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ option(NO_GRAPHICS "Build without graphics support (console-only)" OFF)
# Core sources (always included)
set(CORE_SOURCES
${PROJECT_SOURCE_DIR}/src/actionmodern/action.c
${PROJECT_SOURCE_DIR}/src/actionmodern/object.c
${PROJECT_SOURCE_DIR}/src/actionmodern/variables.c
${PROJECT_SOURCE_DIR}/src/memory/heap.c
${PROJECT_SOURCE_DIR}/src/utils.c
Expand Down
44 changes: 42 additions & 2 deletions include/actionmodern/action.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,26 +61,66 @@

extern ActionVar* temp_val;

void initTime();
void initTime(SWFAppContext* app_context);

void pushVar(SWFAppContext* app_context, ActionVar* p);

// Arithmetic Operations
void actionAdd(SWFAppContext* app_context);
void actionSubtract(SWFAppContext* app_context);
void actionMultiply(SWFAppContext* app_context);
void actionDivide(SWFAppContext* app_context);

// Comparison Operations
void actionEquals(SWFAppContext* app_context);
void actionLess(SWFAppContext* app_context);
void actionAnd(SWFAppContext* app_context);
void actionOr(SWFAppContext* app_context);
void actionNot(SWFAppContext* app_context);

// String Operations
void actionStringEquals(SWFAppContext* app_context, char* a_str, char* b_str);
void actionStringLength(SWFAppContext* app_context, char* v_str);
void actionStringAdd(SWFAppContext* app_context, char* a_str, char* b_str);

// Variable Operations
void actionGetVariable(SWFAppContext* app_context);
void actionSetVariable(SWFAppContext* app_context);

// Utility Operations
void actionTrace(SWFAppContext* app_context);
void actionGetTime(SWFAppContext* app_context);
void actionGetTime(SWFAppContext* app_context);

// Object Operations
void actionGetMember(SWFAppContext* app_context);
void actionSetMember(SWFAppContext* app_context);
void actionTypeof(SWFAppContext* app_context, char* str_buffer);
void actionEnumerate(SWFAppContext* app_context, char* str_buffer);
void actionEnumerate2(SWFAppContext* app_context, char* str_buffer);
void actionDelete(SWFAppContext* app_context);
void actionDelete2(SWFAppContext* app_context, char* str_buffer);
void actionNewObject(SWFAppContext* app_context);
void actionNewMethod(SWFAppContext* app_context);
void actionInitObject(SWFAppContext* app_context);
void actionInstanceOf(SWFAppContext* app_context);
void actionExtends(SWFAppContext* app_context);

// Array Operations
void actionInitArray(SWFAppContext* app_context);

// Function Operations
void actionDefineLocal(SWFAppContext* app_context);
void actionDeclareLocal(SWFAppContext* app_context);
void actionCallFunction(SWFAppContext* app_context, char* str_buffer);
void actionCallMethod(SWFAppContext* app_context, char* str_buffer);
void actionReturn(SWFAppContext* app_context);

// Stack/Register Operations
void actionStoreRegister(SWFAppContext* app_context, u8 register_num);
void actionPushRegister(SWFAppContext* app_context, u8 register_num);

// Function Definitions
void actionDefineFunction(SWFAppContext* app_context, const char* name, void (*func)(SWFAppContext*), u32 param_count);

typedef ActionVar (*Function2Ptr)(SWFAppContext* app_context, ActionVar* args, u32 arg_count, ActionVar* registers, void* this_obj);
void actionDefineFunction2(SWFAppContext* app_context, const char* name, Function2Ptr func, u32 param_count, u8 register_count, u16 flags);
180 changes: 180 additions & 0 deletions include/actionmodern/object.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#pragma once

#include <common.h>
#include <actionmodern/variables.h>

// Forward declaration
typedef struct SWFAppContext SWFAppContext;

/**
* ASObject - ActionScript Object with Reference Counting
*
* This structure implements compile-time reference counting for object/array opcodes.
* The recompiler (SWFRecomp) emits inline refcount increment/decrement operations,
* providing deterministic memory management without runtime GC.
*/

// Forward declaration for property structure
typedef struct ASProperty ASProperty;

/**
* Property Attribute Flags (ECMA-262 compliant)
*
* These flags control property behavior during enumeration, deletion, and assignment.
*/
#define PROPERTY_FLAG_ENUMERABLE 0x01 // Property appears in for..in loops (default for user properties)
#define PROPERTY_FLAG_WRITABLE 0x02 // Property can be modified (default for user properties)
#define PROPERTY_FLAG_CONFIGURABLE 0x04 // Property can be deleted (default for user properties)

// Default flags for user-created properties (fully mutable and enumerable)
#define PROPERTY_FLAGS_DEFAULT (PROPERTY_FLAG_ENUMERABLE | PROPERTY_FLAG_WRITABLE | PROPERTY_FLAG_CONFIGURABLE)

// Flags for DontEnum properties (internal/built-in properties)
#define PROPERTY_FLAGS_DONTENUM (PROPERTY_FLAG_WRITABLE | PROPERTY_FLAG_CONFIGURABLE)

typedef struct ASObject
{
u32 refcount; // Reference count (starts at 1 on allocation)
u32 num_properties; // Number of properties allocated
u32 num_used; // Number of properties actually used
ASProperty* properties; // Dynamic array of properties

// Interface support (for ActionScript 2.0 implements keyword)
u32 interface_count; // Number of interfaces this class implements
struct ASObject** interfaces; // Array of interface constructors
} ASObject;

struct ASProperty
{
char* name; // Property name (heap-allocated)
u32 name_length; // Length of property name
u8 flags; // Property attribute flags (PROPERTY_FLAG_*)
ActionVar value; // Property value (can be any type)
};

/**
* Global Objects
*
* Global singleton objects available in ActionScript.
*/

// Global object (_global in ActionScript)
// Initialized on first use via initTime()
extern ASObject* global_object;

/**
* Object Lifecycle Primitives
*
* These functions are called by generated code to manage object lifetimes.
*/

// Allocate new object with initial capacity
// Returns object with refcount = 1
ASObject* allocObject(SWFAppContext* app_context, u32 initial_capacity);

// Increment reference count
// Should be called when:
// - Storing object in a variable
// - Adding object to an array/container
// - Assigning object to a property
// - Returning object from a function
void retainObject(ASObject* obj);

// Decrement reference count, free if zero
// Should be called when:
// - Popping object from stack (if not stored)
// - Overwriting a variable that held an object
// - Removing object from array
// - Function/scope cleanup
void releaseObject(SWFAppContext* app_context, ASObject* obj);

/**
* Property Management
*
* Functions for manipulating object properties.
*/

// Get property by name (returns NULL if not found)
ActionVar* getProperty(ASObject* obj, const char* name, u32 name_length);

// Get property by name with prototype chain traversal (returns NULL if not found)
// Walks up the __proto__ chain to find inherited properties
ActionVar* getPropertyWithPrototype(ASObject* obj, const char* name, u32 name_length);

// Set property by name (creates if not exists)
// Handles refcount management if value is an object
void setProperty(SWFAppContext* app_context, ASObject* obj, const char* name, u32 name_length, ActionVar* value);

// Delete property by name (returns true if deleted or not found, false if protected)
// Handles refcount management if value is an object
bool deleteProperty(SWFAppContext* app_context, ASObject* obj, const char* name, u32 name_length);

/**
* Interface Management (ActionScript 2.0)
*
* Functions for implementing interface support via the implements keyword.
*/

// Set the list of interfaces that a constructor implements
// Used by ActionImplementsOp (0x2C)
// Takes ownership of the interfaces array
void setInterfaceList(SWFAppContext* app_context, ASObject* constructor, ASObject** interfaces, u32 count);

// Check if an object implements a specific interface
// Returns 1 if the object's constructor implements the interface, 0 otherwise
// Performs recursive check for interface inheritance
int implementsInterface(ASObject* obj, ASObject* interface_ctor);

// Get the constructor function for an object
// Returns the constructor property if it exists, NULL otherwise
ASObject* getConstructor(ASObject* obj);

/**
* ASArray - ActionScript Array with Reference Counting
*
* Arrays store elements in a dynamic array with automatic growth.
* Like objects, arrays use reference counting for memory management.
*/

typedef struct ASArray
{
u32 refcount; // Reference count (starts at 1 on allocation)
u32 length; // Number of elements in the array
u32 capacity; // Allocated capacity
ActionVar* elements; // Dynamic array of elements
} ASArray;

/**
* Array Lifecycle Primitives
*/

// Allocate new array with initial capacity
// Returns array with refcount = 1
ASArray* allocArray(SWFAppContext* app_context, u32 initial_capacity);

// Increment reference count for array
void retainArray(ASArray* arr);

// Decrement reference count for array, free if zero
void releaseArray(SWFAppContext* app_context, ASArray* arr);

// Get element at index (returns NULL if out of bounds)
ActionVar* getArrayElement(ASArray* arr, u32 index);

// Set element at index (grows array if needed)
void setArrayElement(SWFAppContext* app_context, ASArray* arr, u32 index, ActionVar* value);

/**
* Debug/Testing Functions
*/

#ifdef DEBUG
// Verify object refcount matches expected value (assertion)
void assertRefcount(ASObject* obj, u32 expected);

// Print object state for debugging
void printObject(ASObject* obj);

// Print array state for debugging
void printArray(ASArray* arr);
#endif
10 changes: 9 additions & 1 deletion include/actionmodern/stackvalue.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ typedef enum
{
ACTION_STACK_VALUE_STRING = 0,
ACTION_STACK_VALUE_F32 = 1,
ACTION_STACK_VALUE_NULL = 2,
ACTION_STACK_VALUE_UNDEFINED = 3,
ACTION_STACK_VALUE_REGISTER = 4,
ACTION_STACK_VALUE_BOOLEAN = 5,
ACTION_STACK_VALUE_F64 = 6,
ACTION_STACK_VALUE_STR_LIST = 10
ACTION_STACK_VALUE_I32 = 7,
ACTION_STACK_VALUE_STR_LIST = 10,
ACTION_STACK_VALUE_OBJECT = 11,
ACTION_STACK_VALUE_ARRAY = 12,
ACTION_STACK_VALUE_FUNCTION = 13
} ActionStackValueType;
6 changes: 4 additions & 2 deletions include/libswf/tag.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
#include <swf.h>

// Core tag functions - always available
void tagInit(SWFAppContext* app_context);
void tagInit();
void tagSetBackgroundColor(u8 red, u8 green, u8 blue);
void tagShowFrame(SWFAppContext* app_context);

#ifndef NO_GRAPHICS
// Graphics-only tag functions
void tagDefineShape(SWFAppContext* app_context, CharacterType type, size_t char_id, size_t shape_offset, size_t shape_size);
void tagDefineText(SWFAppContext* app_context, size_t char_id, size_t text_start, size_t text_size, u32 transform_start, u32 cxform_id);
void tagPlaceObject2(SWFAppContext* app_context, size_t depth, size_t char_id, u32 transform_id);
void defineBitmap(size_t offset, size_t size, u32 width, u32 height);
void finalizeBitmaps();
void finalizeBitmaps();
#endif
13 changes: 12 additions & 1 deletion include/memory/heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <swf.h>

#define HALLOC(s) heap_alloc(app_context, s);
#define HCALLOC(n, s) heap_calloc(app_context, n, s);
#define FREE(p) heap_free(app_context, p);

/**
Expand All @@ -28,6 +29,16 @@ void heap_init(SWFAppContext* app_context, size_t size);
*/
void* heap_alloc(SWFAppContext* app_context, size_t size);

/**
* Allocate zeroed memory from the heap
*
* @param app_context Main app context
* @param count Number of elements
* @param size Size of each element
* @return Pointer to zeroed allocated memory, or NULL on failure
*/
void* heap_calloc(SWFAppContext* app_context, size_t count, size_t size);

/**
* Free memory allocated by heap_alloc() or heap_calloc()
*
Expand All @@ -42,7 +53,7 @@ void heap_free(SWFAppContext* app_context, void* ptr);
* Shutdown the heap system
*
* Frees all heap arenas. Should be called at program exit.
*
*
* @param app_context Main app context
*/
void heap_shutdown(SWFAppContext* app_context);
Loading