1548 lines
40 KiB
PHP
1548 lines
40 KiB
PHP
|
|
||
|
struct SymbolTree_Root
|
||
|
attributes db ? ; SYMTREE_#
|
||
|
flags db ? ; NAMESPACE_#
|
||
|
parameters db ? ; SPECPARM_#
|
||
|
reserved db ?
|
||
|
parent_branch dd ? ; pointer to namespace SymbolTree_Foliage
|
||
|
current_label dd ? ; pointer to selected SymbolTree_Foliage
|
||
|
chain dd ? ; pointer to another SymbolTree_Root
|
||
|
; root_node SymbolTree_Node
|
||
|
ends
|
||
|
|
||
|
struct SymbolTree_Node
|
||
|
branches rd 1 shl TREE_NODE_BITS
|
||
|
ends
|
||
|
|
||
|
struct SymbolTree_LocalNode
|
||
|
branches rd 1 shl LOCAL_TREE_NODE_BITS
|
||
|
ends
|
||
|
|
||
|
struct SymbolTree_Foliage
|
||
|
name_kind db ? ; NAME_#
|
||
|
flags db ? ; FOLIAGE_#
|
||
|
reserved dw ?
|
||
|
name_length dd ?
|
||
|
name_data dd ?
|
||
|
root dd ? ; pointer to SymbolTree_Root
|
||
|
next dd ? ; pointer to another SymbolTree_Foliage
|
||
|
child_namespace dd ? ; pointer to descendant SymbolTree_Root
|
||
|
; first_leaf SymbolTree_Leaf
|
||
|
ends
|
||
|
|
||
|
struct SymbolTree_Leaf
|
||
|
class db ? ; SYMCLASS_#
|
||
|
flags db ? ; SYM_#
|
||
|
extra_flags db ? ; SYMX_#
|
||
|
reserved db ?
|
||
|
definition dd ? ; pointer to ValueDefinition
|
||
|
retired_definition dd ?
|
||
|
last_use_pass dd ?
|
||
|
next dd ? ; pointer to another SymbolTree_Leaf within SymbolTree_Foliage
|
||
|
branch dd ? ; pointer to SymbolTree_Foliage
|
||
|
fallback_neighbour dd ? ; pointer to another SymbolTree_Leaf
|
||
|
fallback_parent dd ? ; pointer to another SymbolTree_Leaf
|
||
|
ends
|
||
|
|
||
|
struct ValueDefinition
|
||
|
type db ? ; VALTYPE_#
|
||
|
flags db ? ; VAL_#
|
||
|
attribute db ?
|
||
|
reserved db ?
|
||
|
pass dd ?
|
||
|
value dd ?
|
||
|
value_length dd ?
|
||
|
block_length dd ?
|
||
|
reference_count dd ? ; number of distinct references to current value
|
||
|
previous dd ? ; pointer to another ValueDefinition
|
||
|
interlink dd ?
|
||
|
ends
|
||
|
|
||
|
TREE_HEIGHT = 4
|
||
|
TREE_NODE_BITS = 5
|
||
|
LOCAL_TREE_HEIGHT = 1
|
||
|
LOCAL_TREE_NODE_BITS = 6
|
||
|
|
||
|
FNV_PRIME = 16777619
|
||
|
FNV_OFFSET = 2166136261
|
||
|
|
||
|
SYMTREE_LOCAL = 1
|
||
|
SYMTREE_WITH_CASEINSENSITIVE_PARAMETERS = 2
|
||
|
|
||
|
NAMESPACE_UNATTACHED = 1
|
||
|
NAMESPACE_LABEL_FORWARDING = 2
|
||
|
NAMESPACE_CALM = 10h
|
||
|
NAMESPACE_LOCAL = 20h
|
||
|
|
||
|
SPECPARM_COUNTER = 1
|
||
|
SPECPARM_LIMIT = 2
|
||
|
|
||
|
FOLIAGE_WITH_TOKEN = 1
|
||
|
|
||
|
NAME_CASESENSITIVE = 0
|
||
|
NAME_CASEINSENSITIVE = 1
|
||
|
NAME_NUMERIC = 2
|
||
|
NAME_ABSTRACT = 3
|
||
|
|
||
|
SYMCLASS_EXPRESSION = 0
|
||
|
SYMCLASS_INSTRUCTION = 1
|
||
|
SYMCLASS_STRUCTURE = 2
|
||
|
SYMCLASS_PARAMETER = 3
|
||
|
SYMCLASS_CALM_LOCATION = 10h
|
||
|
|
||
|
SYM_CONSTANT = 1
|
||
|
SYM_VARIABLE = 2
|
||
|
SYM_PREDICTED = 4
|
||
|
SYM_PREDICTED_DEFINED = 8
|
||
|
SYM_USAGE_PREDICTED = 10h
|
||
|
SYM_PREDICTED_USED = 20h
|
||
|
SYM_LINK = 40h
|
||
|
SYM_LINK_PREDICTED = 80h
|
||
|
|
||
|
SYMX_INSTRUCTION_PREDICTED = 1
|
||
|
|
||
|
VALTYPE_RESERVED = 0
|
||
|
VALTYPE_SYMBOLIC = 1
|
||
|
VALTYPE_NUMERIC = 2
|
||
|
VALTYPE_STRING = 3
|
||
|
VALTYPE_FLOAT = 4
|
||
|
VALTYPE_ELEMENT = 5
|
||
|
VALTYPE_AREA = 6
|
||
|
VALTYPE_CALM = 7
|
||
|
VALTYPE_SYMBOLIC_SEQUENCE = 11h
|
||
|
VALTYPE_NUMERIC_SEQUENCE = 12h
|
||
|
VALTYPE_PLAIN = 20h
|
||
|
VALTYPE_NATIVE_COMMAND = 40h
|
||
|
VALTYPE_NATIVE_COMPARATOR = 41h
|
||
|
VALTYPE_NATIVE_FUNCTION = 42h
|
||
|
VALTYPE_NATIVE_PREPOSITION = 43h
|
||
|
|
||
|
VAL_INTERNAL = 1
|
||
|
VAL_IN_USE = 2
|
||
|
VAL_UNCONDITIONAL = 4
|
||
|
VAL_NONRECURSIVE = 8
|
||
|
VAL_SHIFTABLE = 10h
|
||
|
VAL_DETACHED = 20h
|
||
|
|
||
|
RECOGNIZE_CASE_INSENSITIVE = 1
|
||
|
RECOGNIZE_DEFINITION = 2
|
||
|
|
||
|
recognize_symbol:
|
||
|
; in:
|
||
|
; ebx - SymbolTree_Root (namespace), null for standard recognition regime
|
||
|
; ecx = name length
|
||
|
; esi - name followed by two hashes (as in name token)
|
||
|
; dl = SYMCLASS_#
|
||
|
; dh = any combination of RECOGNIZE_# flags
|
||
|
; [recognition_context.base_namespace] - namespace for standard recognition regime
|
||
|
; [name_volatile] = non-zero when name is provided in a temporary storage
|
||
|
; [name_token] = null or pointer to the contents of a preprocessed token
|
||
|
; out:
|
||
|
; ebx - SymbolTree_Leaf
|
||
|
; edx - SymbolTree_Foliage
|
||
|
; edi - SymbolTree_Root
|
||
|
; [name_volatile] zeroed when name has been moved to persistent storage
|
||
|
; note:
|
||
|
; when RECOGNIZE_DEFINITION option is not selected and no defined symbol of requested class is found,
|
||
|
; the provided result is as if RECOGNIZE_DEFINITION option was specified and expression class requested
|
||
|
mov [symbol_class],dl
|
||
|
test dh,RECOGNIZE_DEFINITION
|
||
|
setnz [symbol_expected]
|
||
|
or [symbol_required],1
|
||
|
test dh,RECOGNIZE_CASE_INSENSITIVE
|
||
|
mov al,NAME_CASEINSENSITIVE
|
||
|
mov edx,[esi+ecx+4]
|
||
|
mov [case_insensitive_hash],edx
|
||
|
jnz name_kind_ok
|
||
|
mov al,NAME_CASESENSITIVE
|
||
|
mov edx,[esi+ecx]
|
||
|
mov [case_sensitive_hash],edx
|
||
|
name_kind_ok:
|
||
|
mov [name_kind],al
|
||
|
test ebx,ebx
|
||
|
jz standard_recognition
|
||
|
call scan_namespace
|
||
|
jnc symbol_recognized
|
||
|
mov [kept_symbol],ebx
|
||
|
mov [kept_symbol_flags],al
|
||
|
mov edi,[symbol_root]
|
||
|
cmp [name_kind],NAME_CASEINSENSITIVE
|
||
|
je no_defined_symbol
|
||
|
mov [current_symbol],ebx
|
||
|
mov ebx,[ebx+SymbolTree_Leaf.fallback_neighbour]
|
||
|
test ebx,ebx
|
||
|
jnz check_namespace_fallback
|
||
|
mov [name_kind],NAME_CASEINSENSITIVE
|
||
|
mov edx,[case_insensitive_hash]
|
||
|
mov ebx,edi
|
||
|
call scan_namespace
|
||
|
mov eax,[current_symbol]
|
||
|
mov [eax+SymbolTree_Leaf.fallback_neighbour],ebx
|
||
|
jc no_defined_symbol
|
||
|
symbol_recognized:
|
||
|
mov edi,[symbol_root]
|
||
|
retn
|
||
|
standard_recognition:
|
||
|
mov ebx,[recognition_context.base_namespace]
|
||
|
call scan_namespace
|
||
|
jnc symbol_recognized
|
||
|
mov [kept_symbol],ebx
|
||
|
mov [kept_symbol_flags],al
|
||
|
mov edi,[symbol_root]
|
||
|
find_in_wider_scope:
|
||
|
mov edx,[case_insensitive_hash]
|
||
|
mov [current_symbol],ebx
|
||
|
cmp [name_kind],NAME_CASEINSENSITIVE
|
||
|
je find_in_namespace_chain
|
||
|
mov ebx,[ebx+SymbolTree_Leaf.fallback_neighbour]
|
||
|
test ebx,ebx
|
||
|
jnz check_fallback_neighbour
|
||
|
mov [name_kind],NAME_CASEINSENSITIVE
|
||
|
mov ebx,[symbol_root]
|
||
|
call scan_namespace
|
||
|
mov eax,[current_symbol]
|
||
|
mov [eax+SymbolTree_Leaf.fallback_neighbour],ebx
|
||
|
jnc symbol_recognized
|
||
|
no_neighbour_found:
|
||
|
mov ebx,[current_symbol]
|
||
|
mov [name_kind],NAME_CASESENSITIVE
|
||
|
mov edx,[case_sensitive_hash]
|
||
|
find_in_namespace_chain:
|
||
|
mov ebx,[ebx+SymbolTree_Leaf.fallback_parent]
|
||
|
test ebx,ebx
|
||
|
jnz check_fallback_parent
|
||
|
mov edi,[symbol_root]
|
||
|
mov ebx,[edi+SymbolTree_Root.parent_branch]
|
||
|
test ebx,ebx
|
||
|
jz no_defined_symbol
|
||
|
mov ebx,[ebx+SymbolTree_Foliage.root]
|
||
|
call scan_namespace
|
||
|
mov eax,[current_symbol]
|
||
|
mov [eax+SymbolTree_Leaf.fallback_parent],ebx
|
||
|
jc find_in_wider_scope
|
||
|
mov edi,[symbol_root]
|
||
|
retn
|
||
|
check_fallback_neighbour:
|
||
|
call get_available_value
|
||
|
jc no_neighbour_found
|
||
|
fallback_neighbour_ok:
|
||
|
mov edx,[ebx+SymbolTree_Leaf.branch]
|
||
|
mov edi,[edx+SymbolTree_Foliage.root]
|
||
|
retn
|
||
|
check_fallback_parent:
|
||
|
call get_available_value
|
||
|
mov edx,[ebx+SymbolTree_Leaf.branch]
|
||
|
mov edi,[edx+SymbolTree_Foliage.root]
|
||
|
mov [symbol_root],edi
|
||
|
jc find_in_wider_scope
|
||
|
retn
|
||
|
check_namespace_fallback:
|
||
|
call get_available_value
|
||
|
jnc fallback_neighbour_ok
|
||
|
no_defined_symbol:
|
||
|
cmp [symbol_class],SYMCLASS_EXPRESSION
|
||
|
je return_kept_symbol
|
||
|
mov [symbol_class],SYMCLASS_EXPRESSION
|
||
|
or [symbol_expected],1
|
||
|
mov ebx,[kept_symbol]
|
||
|
mov ebx,[ebx+SymbolTree_Leaf.branch]
|
||
|
mov edi,[ebx+SymbolTree_Foliage.root]
|
||
|
jmp scan_symbol_branch
|
||
|
return_kept_symbol:
|
||
|
mov ebx,[kept_symbol]
|
||
|
mov edx,[ebx+SymbolTree_Leaf.branch]
|
||
|
mov edi,[edx+SymbolTree_Foliage.root]
|
||
|
mov al,[kept_symbol_flags]
|
||
|
mov [ebx+SymbolTree_Leaf.flags],al
|
||
|
retn
|
||
|
|
||
|
scan_namespace:
|
||
|
; in:
|
||
|
; ebx - SymbolTree_Root
|
||
|
; edx = hash
|
||
|
; ecx = name length
|
||
|
; esi - name
|
||
|
; [name_kind] = NAME_#
|
||
|
; [name_volatile] = non-zero when name is provided in a temporary storage
|
||
|
; [name_token] = null or pointer to the contents of a preprocessed token
|
||
|
; [symbol_class] = SYMCLASS_#
|
||
|
; [symbol_required] = non-zero when symbol needs to be added if not found
|
||
|
; [symbol_expected] = non-zero when symbol needs not be checked for its value availability
|
||
|
; out:
|
||
|
; ebx - SymbolTree_Leaf, null when nothing found
|
||
|
; edx - SymbolTree_Foliage, null when no such branch exists
|
||
|
; [symbol_root] - SymbolTree_Root
|
||
|
; [symbol_branch] - SymbolTree_Foliage
|
||
|
; [name_volatile] zeroed when name has been moved to persistent storage
|
||
|
; when [symbol_expected] = 0:
|
||
|
; cf set when symbol not found or has no defined value
|
||
|
; al = copy of symbol prediction flags before they were affected by this function
|
||
|
; when [symbol_expected] = 1:
|
||
|
; cf set when symbol not found
|
||
|
; preserves: ecx, [esi]
|
||
|
mov [symbol_root],ebx
|
||
|
test [ebx+SymbolTree_Root.attributes],SYMTREE_LOCAL
|
||
|
jnz scan_local_namespace
|
||
|
add ebx,sizeof.SymbolTree_Root
|
||
|
if TREE_HEIGHT > 1
|
||
|
mov edi,TREE_HEIGHT
|
||
|
follow_tree:
|
||
|
mov eax,edx
|
||
|
and eax,(1 shl TREE_NODE_BITS)-1
|
||
|
shr edx,TREE_NODE_BITS
|
||
|
lea ebx,[ebx+eax*4]
|
||
|
else
|
||
|
and edx,(1 shl TREE_NODE_BITS)-1
|
||
|
lea ebx,[ebx+edx*4]
|
||
|
end if
|
||
|
mov eax,[ebx]
|
||
|
test eax,eax
|
||
|
jz unregistered_hash
|
||
|
mov ebx,eax
|
||
|
if TREE_HEIGHT > 1
|
||
|
dec edi
|
||
|
jnz follow_tree
|
||
|
end if
|
||
|
scan_foliage_branches:
|
||
|
movzx eax,[name_kind]
|
||
|
cmp [ebx+SymbolTree_Foliage.name_kind],al
|
||
|
jne next_foliage_branch
|
||
|
cmp [ebx+SymbolTree_Foliage.name_length],ecx
|
||
|
jne next_foliage_branch
|
||
|
mov edi,[ebx+SymbolTree_Foliage.name_data]
|
||
|
cmp esi,edi
|
||
|
je scan_symbol_branch
|
||
|
cmp al,NAME_ABSTRACT
|
||
|
je next_foliage_branch
|
||
|
jecxz scan_symbol_branch
|
||
|
repe cmpsb
|
||
|
jne names_not_identical
|
||
|
mov esi,edi
|
||
|
mov ecx,[ebx+SymbolTree_Foliage.name_length]
|
||
|
sub esi,ecx
|
||
|
and [name_volatile],0
|
||
|
mov edx,[name_token]
|
||
|
test edx,edx
|
||
|
jz scan_symbol_branch
|
||
|
test [ebx+SymbolTree_Foliage.flags],FOLIAGE_WITH_TOKEN
|
||
|
jz use_token_for_foliage
|
||
|
sub esi,4
|
||
|
mov eax,[edx]
|
||
|
mov [edx],esi
|
||
|
mov [eax+4+ecx+8],esi
|
||
|
add esi,4
|
||
|
jmp scan_symbol_branch
|
||
|
use_token_for_foliage:
|
||
|
mov esi,[edx]
|
||
|
add esi,4
|
||
|
mov [ebx+SymbolTree_Foliage.name_data],esi
|
||
|
or [ebx+SymbolTree_Foliage.flags],FOLIAGE_WITH_TOKEN
|
||
|
jmp scan_symbol_branch
|
||
|
hash_collision:
|
||
|
add esi,ecx
|
||
|
mov ecx,[ebx+SymbolTree_Foliage.name_length]
|
||
|
sub esi,ecx
|
||
|
next_foliage_branch:
|
||
|
mov eax,[ebx+SymbolTree_Foliage.next]
|
||
|
test eax,eax
|
||
|
jz unregistered_name
|
||
|
mov ebx,eax
|
||
|
jmp scan_foliage_branches
|
||
|
names_not_identical:
|
||
|
cmp al,NAME_CASEINSENSITIVE
|
||
|
jne hash_collision
|
||
|
dec esi
|
||
|
dec edi
|
||
|
inc ecx
|
||
|
case_insensitive_compare:
|
||
|
lodsb
|
||
|
mov dl,[characters+eax]
|
||
|
mov al,[edi]
|
||
|
inc edi
|
||
|
dec ecx
|
||
|
cmp dl,[characters+eax]
|
||
|
jne hash_collision
|
||
|
test ecx,ecx
|
||
|
jnz case_insensitive_compare
|
||
|
mov ecx,[ebx+SymbolTree_Foliage.name_length]
|
||
|
sub esi,ecx
|
||
|
scan_symbol_branch:
|
||
|
; in:
|
||
|
; ebx - SymbolTree_Foliage
|
||
|
; [symbol_class] = SYMCLASS_#
|
||
|
; [symbol_required] = non-zero when symbol needs to be added if not found
|
||
|
; [symbol_expected] = non-zero when symbol needs not be checked for its value availability
|
||
|
; out:
|
||
|
; ebx - SymbolTree_Leaf, null when nothing found
|
||
|
; edx - SymbolTree_Foliage
|
||
|
; [symbol_branch] - SymbolTree_Foliage
|
||
|
; when [symbol_expected] = 0:
|
||
|
; cf set when symbol not found or has no defined value
|
||
|
; al = copy of symbol prediction flags before they were affected by this function
|
||
|
; when [symbol_expected] = 1:
|
||
|
; cf set when symbol not found
|
||
|
; preserves: ecx, esi, edi
|
||
|
mov [symbol_branch],ebx
|
||
|
add ebx,sizeof.SymbolTree_Foliage
|
||
|
mov dl,[symbol_class]
|
||
|
scan_leaves:
|
||
|
mov al,[ebx+SymbolTree_Leaf.class]
|
||
|
cmp al,dl
|
||
|
je leaf_found
|
||
|
mov eax,[ebx+SymbolTree_Leaf.next]
|
||
|
test eax,eax
|
||
|
jz leaves_scanned
|
||
|
mov ebx,eax
|
||
|
jmp scan_leaves
|
||
|
leaf_found:
|
||
|
cmp [symbol_expected],0
|
||
|
jne symbol_found
|
||
|
call get_available_value
|
||
|
jnc symbol_found
|
||
|
no_defined_symbol_found:
|
||
|
mov edx,[symbol_branch]
|
||
|
stc
|
||
|
retn
|
||
|
symbol_found:
|
||
|
mov edx,[symbol_branch]
|
||
|
clc
|
||
|
retn
|
||
|
leaves_scanned:
|
||
|
mov al,[symbol_required]
|
||
|
or al,[symbol_expected]
|
||
|
jnz attach_symbol_leaf
|
||
|
xor ebx,ebx
|
||
|
jmp no_defined_symbol_found
|
||
|
unregistered_name:
|
||
|
cmp [symbol_required],0
|
||
|
je name_not_found
|
||
|
push ecx
|
||
|
lea ebx,[ebx+SymbolTree_Foliage.next]
|
||
|
jmp attach_foliage_branch
|
||
|
name_not_found:
|
||
|
xor ebx,ebx
|
||
|
xor edx,edx
|
||
|
stc
|
||
|
retn
|
||
|
unregistered_hash:
|
||
|
cmp [symbol_required],0
|
||
|
je name_not_found
|
||
|
push ecx
|
||
|
if TREE_HEIGHT > 1
|
||
|
expand_tree:
|
||
|
dec edi
|
||
|
jz attach_foliage_branch
|
||
|
mov ecx,sizeof.SymbolTree_Node
|
||
|
call create_tree_element
|
||
|
mov [ebx],eax
|
||
|
mov ebx,eax
|
||
|
mov eax,edx
|
||
|
and eax,(1 shl TREE_NODE_BITS)-1
|
||
|
shr edx,TREE_NODE_BITS
|
||
|
lea ebx,[ebx+eax*4]
|
||
|
jmp expand_tree
|
||
|
end if
|
||
|
attach_foliage_branch:
|
||
|
mov ecx,sizeof.SymbolTree_Foliage + sizeof.SymbolTree_Leaf
|
||
|
call create_tree_element
|
||
|
mov [ebx],eax
|
||
|
mov [symbol_branch],eax
|
||
|
mov ebx,eax
|
||
|
pop ecx
|
||
|
mov eax,[symbol_root]
|
||
|
mov [ebx+SymbolTree_Foliage.root],eax
|
||
|
mov al,[name_kind]
|
||
|
mov [ebx+SymbolTree_Foliage.name_kind],al
|
||
|
mov [ebx+SymbolTree_Foliage.name_length],ecx
|
||
|
cmp al,NAME_ABSTRACT
|
||
|
je symbol_name_stored
|
||
|
mov edx,[name_token]
|
||
|
test edx,edx
|
||
|
jnz symbol_name_from_token
|
||
|
cmp [name_volatile],0
|
||
|
je symbol_name_stored
|
||
|
call store_string
|
||
|
and [name_volatile],0
|
||
|
jmp symbol_name_stored
|
||
|
symbol_name_from_token:
|
||
|
or [ebx+SymbolTree_Foliage.flags],FOLIAGE_WITH_TOKEN
|
||
|
mov esi,[edx]
|
||
|
add esi,4
|
||
|
symbol_name_stored:
|
||
|
mov [ebx+SymbolTree_Foliage.name_data],esi
|
||
|
lea ebx,[ebx+sizeof.SymbolTree_Foliage]
|
||
|
jmp fill_new_symbol_leaf
|
||
|
attach_symbol_leaf:
|
||
|
push ecx
|
||
|
mov ecx,sizeof.SymbolTree_Leaf
|
||
|
call create_tree_element
|
||
|
mov [ebx+SymbolTree_Leaf.next],eax
|
||
|
mov ebx,eax
|
||
|
pop ecx
|
||
|
fill_new_symbol_leaf:
|
||
|
mov al,[symbol_class]
|
||
|
mov [ebx+SymbolTree_Leaf.class],al
|
||
|
mov edx,[symbol_branch]
|
||
|
cmp al,SYMCLASS_PARAMETER
|
||
|
jne namespace_flags_updated
|
||
|
cmp [name_kind],NAME_CASEINSENSITIVE
|
||
|
jne namespace_flags_updated
|
||
|
mov eax,[edx+SymbolTree_Foliage.root]
|
||
|
or [eax+SymbolTree_Root.attributes],SYMTREE_WITH_CASEINSENSITIVE_PARAMETERS
|
||
|
namespace_flags_updated:
|
||
|
mov [ebx+SymbolTree_Leaf.branch],edx
|
||
|
cmp [symbol_expected],0
|
||
|
jne symbol_found
|
||
|
xor al,al
|
||
|
or [ebx+SymbolTree_Leaf.flags],SYM_PREDICTED
|
||
|
jmp no_defined_symbol_found
|
||
|
scan_local_namespace:
|
||
|
add ebx,sizeof.SymbolTree_Root
|
||
|
if LOCAL_TREE_HEIGHT > 1
|
||
|
mov edi,LOCAL_TREE_HEIGHT
|
||
|
follow_local_tree:
|
||
|
mov eax,edx
|
||
|
and eax,(1 shl LOCAL_TREE_NODE_BITS)-1
|
||
|
shr edx,LOCAL_TREE_NODE_BITS
|
||
|
lea ebx,[ebx+eax*4]
|
||
|
else
|
||
|
and edx,(1 shl LOCAL_TREE_NODE_BITS)-1
|
||
|
lea ebx,[ebx+edx*4]
|
||
|
end if
|
||
|
mov eax,[ebx]
|
||
|
test eax,eax
|
||
|
jz local_unregistered_hash
|
||
|
mov ebx,eax
|
||
|
if LOCAL_TREE_HEIGHT > 1
|
||
|
dec edi
|
||
|
jnz follow_local_tree
|
||
|
end if
|
||
|
jmp scan_foliage_branches
|
||
|
local_unregistered_hash:
|
||
|
cmp [symbol_required],0
|
||
|
je name_not_found
|
||
|
push ecx
|
||
|
if LOCAL_TREE_HEIGHT > 1
|
||
|
expand_local_tree:
|
||
|
dec edi
|
||
|
jz attach_foliage_branch
|
||
|
mov ecx,sizeof.SymbolTree_LocalNode
|
||
|
call create_tree_element
|
||
|
mov [ebx],eax
|
||
|
mov ebx,eax
|
||
|
mov eax,edx
|
||
|
and eax,(1 shl LOCAL_TREE_NODE_BITS)-1
|
||
|
shr edx,LOCAL_TREE_NODE_BITS
|
||
|
lea ebx,[ebx+eax*4]
|
||
|
jmp expand_local_tree
|
||
|
else
|
||
|
jmp attach_foliage_branch
|
||
|
end if
|
||
|
|
||
|
get_abstract_symbol:
|
||
|
; in:
|
||
|
; eax:ecx = symbol identifier
|
||
|
; ebx - SymbolTree_Root, null for local scope
|
||
|
; dl = SYMCLASS_#
|
||
|
; out:
|
||
|
; ebx - SymbolTree_Leaf
|
||
|
; edx - SymbolTree_Foliage
|
||
|
; edi - SymbolTree_Root
|
||
|
mov [symbol_class],dl
|
||
|
test ebx,ebx
|
||
|
jnz scope_selected
|
||
|
mov ebx,[current_context.base_namespace]
|
||
|
scope_selected:
|
||
|
mov esi,eax
|
||
|
mov edx,FNV_OFFSET
|
||
|
mov [minor_identifier],ecx
|
||
|
mov ecx,4
|
||
|
hash_major_identifier:
|
||
|
xor dl,al
|
||
|
imul edx,FNV_PRIME
|
||
|
shr eax,8
|
||
|
loop hash_major_identifier
|
||
|
mov eax,[minor_identifier]
|
||
|
mov ecx,4
|
||
|
hash_minor_identifier:
|
||
|
xor dl,al
|
||
|
imul edx,FNV_PRIME
|
||
|
shr eax,8
|
||
|
loop hash_minor_identifier
|
||
|
mov ecx,[minor_identifier]
|
||
|
mov [name_kind],NAME_ABSTRACT
|
||
|
or [symbol_required],1
|
||
|
or [symbol_expected],1
|
||
|
call scan_namespace
|
||
|
mov edi,[symbol_root]
|
||
|
retn
|
||
|
|
||
|
create_tree_element:
|
||
|
; in: ecx = length of element
|
||
|
; out: eax - pointer to allocated and zeroed memory
|
||
|
; preserves: ebx, ecx, edx, esi, edi
|
||
|
sub [tree_reserve_length],ecx
|
||
|
jc expand_tree_reserve
|
||
|
mov eax,[tree_reserve]
|
||
|
add [tree_reserve],ecx
|
||
|
retn
|
||
|
expand_tree_reserve:
|
||
|
push ecx edx edi
|
||
|
mov ecx,10000h
|
||
|
call malloc_fixed
|
||
|
mov edx,eax
|
||
|
xchg edx,[tree_blocks]
|
||
|
mov [eax],edx
|
||
|
lea edi,[eax+4]
|
||
|
sub ecx,4
|
||
|
mov [tree_reserve],edi
|
||
|
mov [tree_reserve_length],ecx
|
||
|
mov edx,eax
|
||
|
xor eax,eax
|
||
|
shr ecx,2
|
||
|
rep stosd
|
||
|
mov eax,edx
|
||
|
pop edi edx ecx
|
||
|
jmp create_tree_element
|
||
|
|
||
|
store_string:
|
||
|
; in: esi - string, ecx = length
|
||
|
; out: esi - stored string
|
||
|
; preserves: ebx, ecx, edi
|
||
|
cmp ecx,[storage_free_space_length]
|
||
|
ja expand_storage
|
||
|
storage_ready:
|
||
|
push ecx edi
|
||
|
mov edi,[storage_free_space]
|
||
|
add [storage_free_space],ecx
|
||
|
sub [storage_free_space_length],ecx
|
||
|
move_to_storage:
|
||
|
mov eax,edi
|
||
|
shr ecx,1
|
||
|
jnc movsb_ok
|
||
|
movsb
|
||
|
movsb_ok:
|
||
|
shr ecx,1
|
||
|
jnc movsw_ok
|
||
|
movsw
|
||
|
movsw_ok:
|
||
|
rep movsd
|
||
|
mov esi,eax
|
||
|
pop edi ecx
|
||
|
retn
|
||
|
expand_storage:
|
||
|
cmp ecx,100h
|
||
|
jae store_long_string
|
||
|
push ecx
|
||
|
mov ecx,10000h
|
||
|
call malloc_fixed
|
||
|
mov edx,eax
|
||
|
xchg edx,[storage_blocks]
|
||
|
mov [eax],edx
|
||
|
add eax,4
|
||
|
sub ecx,4
|
||
|
mov [storage_free_space],eax
|
||
|
mov [storage_free_space_length],ecx
|
||
|
pop ecx
|
||
|
jmp storage_ready
|
||
|
store_long_string:
|
||
|
push ecx
|
||
|
add ecx,4
|
||
|
call malloc_fixed
|
||
|
mov edx,[storage_blocks]
|
||
|
test edx,edx
|
||
|
jz long_first_string
|
||
|
mov ecx,eax
|
||
|
xchg ecx,[edx]
|
||
|
mov [eax],ecx
|
||
|
long_string_storage_ready:
|
||
|
add eax,4
|
||
|
mov ecx,[esp]
|
||
|
push edi
|
||
|
mov edi,eax
|
||
|
jmp move_to_storage
|
||
|
long_first_string:
|
||
|
mov [storage_blocks],eax
|
||
|
mov [eax],edx
|
||
|
jmp long_string_storage_ready
|
||
|
|
||
|
get_symbol_namespace:
|
||
|
; in:
|
||
|
; edx - SymbolTree_Foliage
|
||
|
; out:
|
||
|
; ebx - SymbolTree_Root of child namespace
|
||
|
; preserves: edx, esi, edi
|
||
|
mov ebx,[edx+SymbolTree_Foliage.child_namespace]
|
||
|
test ebx,ebx
|
||
|
jnz symbol_namespace_ok
|
||
|
mov ecx,sizeof.SymbolTree_Root + sizeof.SymbolTree_Node
|
||
|
call create_tree_element
|
||
|
mov [eax+SymbolTree_Root.parent_branch],edx
|
||
|
mov [edx+SymbolTree_Foliage.child_namespace],eax
|
||
|
mov ebx,eax
|
||
|
symbol_namespace_ok:
|
||
|
retn
|
||
|
get_local_namespace:
|
||
|
; same as get_symbol_namespace
|
||
|
mov ebx,[edx+SymbolTree_Foliage.child_namespace]
|
||
|
test ebx,ebx
|
||
|
jnz symbol_namespace_ok
|
||
|
mov ecx,sizeof.SymbolTree_Root + sizeof.SymbolTree_LocalNode
|
||
|
call create_tree_element
|
||
|
or [eax+SymbolTree_Root.attributes],SYMTREE_LOCAL
|
||
|
or [eax+SymbolTree_Root.flags],NAMESPACE_LOCAL
|
||
|
mov [edx+SymbolTree_Foliage.child_namespace],eax
|
||
|
mov ebx,eax
|
||
|
retn
|
||
|
|
||
|
get_local_anchor:
|
||
|
; in:
|
||
|
; eax = instruction identifier
|
||
|
; ecx = context identifier
|
||
|
; out:
|
||
|
; edx - SymbolTree_Foliage where a local namespace can be anchored
|
||
|
xor ebx,ebx
|
||
|
mov dl,SYMCLASS_PARAMETER
|
||
|
call get_abstract_symbol
|
||
|
mov eax,[ebx+SymbolTree_Leaf.definition]
|
||
|
test eax,eax
|
||
|
jz create_anchor_counter
|
||
|
mov ecx,[current_pass]
|
||
|
cmp ecx,[eax+ValueDefinition.pass]
|
||
|
je increment_anchor_counter
|
||
|
mov [eax+ValueDefinition.pass],ecx
|
||
|
and [eax+ValueDefinition.value],0
|
||
|
jmp increment_anchor_counter
|
||
|
create_anchor_counter:
|
||
|
mov ecx,sizeof.ValueDefinition
|
||
|
call create_tree_element
|
||
|
mov [ebx+SymbolTree_Leaf.definition],eax
|
||
|
inc [eax+ValueDefinition.reference_count]
|
||
|
mov [eax+ValueDefinition.type],VALTYPE_PLAIN
|
||
|
mov ecx,[current_pass]
|
||
|
mov [eax+ValueDefinition.pass],ecx
|
||
|
increment_anchor_counter:
|
||
|
mov ecx,[eax+ValueDefinition.value]
|
||
|
inc [eax+ValueDefinition.value]
|
||
|
jecxz local_anchor_ready
|
||
|
mov eax,ebx
|
||
|
xor ebx,ebx
|
||
|
mov dl,SYMCLASS_PARAMETER
|
||
|
call get_abstract_symbol
|
||
|
local_anchor_ready:
|
||
|
retn
|
||
|
|
||
|
get_available_value:
|
||
|
; in:
|
||
|
; ebx - SymbolTree_Leaf
|
||
|
; out:
|
||
|
; cf set if symbol is not considered defined
|
||
|
; edx - ValueDefinition
|
||
|
; al = copy of symbol prediction flags before they were affected by this function
|
||
|
; preserves: ebx, ecx, esi, edi
|
||
|
mov edx,[ebx+SymbolTree_Leaf.definition]
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
jnz get_variable_value
|
||
|
test edx,edx
|
||
|
jz symbol_predicted_undefined
|
||
|
mov al,[edx+ValueDefinition.flags]
|
||
|
test al,VAL_INTERNAL
|
||
|
jnz symbol_defined
|
||
|
not al
|
||
|
test al,VAL_IN_USE + VAL_NONRECURSIVE
|
||
|
jz symbol_undefined
|
||
|
mov eax,[current_pass]
|
||
|
sub eax,[edx+ValueDefinition.pass]
|
||
|
jz symbol_defined
|
||
|
cmp eax,1
|
||
|
ja symbol_predicted_undefined
|
||
|
symbol_predicted_defined:
|
||
|
mov al,[ebx+SymbolTree_Leaf.flags]
|
||
|
or [ebx+SymbolTree_Leaf.flags],SYM_PREDICTED + SYM_PREDICTED_DEFINED
|
||
|
; clc
|
||
|
retn
|
||
|
symbol_defined:
|
||
|
mov al,[ebx+SymbolTree_Leaf.flags]
|
||
|
clc
|
||
|
retn
|
||
|
symbol_predicted_undefined:
|
||
|
mov al,[ebx+SymbolTree_Leaf.flags]
|
||
|
or al,SYM_PREDICTED
|
||
|
and al,not SYM_PREDICTED_DEFINED
|
||
|
xchg [ebx+SymbolTree_Leaf.flags],al
|
||
|
stc
|
||
|
retn
|
||
|
get_variable_value:
|
||
|
test edx,edx
|
||
|
jz symbol_undefined
|
||
|
inspect_definition:
|
||
|
test [edx+ValueDefinition.flags],VAL_INTERNAL
|
||
|
jnz symbol_defined
|
||
|
test [edx+ValueDefinition.flags],VAL_IN_USE
|
||
|
jnz try_previous_definition
|
||
|
mov eax,[current_pass]
|
||
|
cmp eax,[edx+ValueDefinition.pass]
|
||
|
je symbol_defined
|
||
|
cmp edx,[ebx+SymbolTree_Leaf.definition]
|
||
|
je retire_outdated_definition
|
||
|
try_previous_definition:
|
||
|
mov edx,[edx+ValueDefinition.previous]
|
||
|
test edx,edx
|
||
|
jnz inspect_definition
|
||
|
symbol_undefined:
|
||
|
mov al,[ebx+SymbolTree_Leaf.flags]
|
||
|
stc
|
||
|
retn
|
||
|
retire_outdated_definition:
|
||
|
mov eax,edx
|
||
|
dec [edx+ValueDefinition.reference_count]
|
||
|
xchg edx,[ebx+SymbolTree_Leaf.retired_definition]
|
||
|
xchg edx,[eax+ValueDefinition.previous]
|
||
|
mov [ebx+SymbolTree_Leaf.definition],edx
|
||
|
jmp get_variable_value
|
||
|
|
||
|
mark_symbol_as_used:
|
||
|
; in:
|
||
|
; ebx - SymbolTree_Leaf
|
||
|
; edx - ValueDefinition, null when value is unavailable but used nonetheless
|
||
|
; preserves: ebx, ecx, edx, esi, edi
|
||
|
; note:
|
||
|
; normally setting SymbolTree_Leaf.last_use_pass is enough, but this function
|
||
|
; improves prediction quality of USED operator;
|
||
|
mov eax,[current_pass]
|
||
|
mov [ebx+SymbolTree_Leaf.last_use_pass],eax
|
||
|
test edx,edx
|
||
|
jz mark_used_fallbacks
|
||
|
retn
|
||
|
mark_used_fallbacks:
|
||
|
push ebx edx
|
||
|
mark_fallback_neighbour:
|
||
|
mov edx,[ebx+SymbolTree_Leaf.fallback_neighbour]
|
||
|
test edx,edx
|
||
|
jz mark_fallback_parent
|
||
|
mov [edx+SymbolTree_Leaf.last_use_pass],eax
|
||
|
mark_fallback_parent:
|
||
|
mov ebx,[ebx+SymbolTree_Leaf.fallback_parent]
|
||
|
test ebx,ebx
|
||
|
jz used_fallbacks_marked
|
||
|
mov [ebx+SymbolTree_Leaf.last_use_pass],eax
|
||
|
jmp mark_fallback_neighbour
|
||
|
used_fallbacks_marked:
|
||
|
pop edx ebx
|
||
|
retn
|
||
|
|
||
|
use_available_value:
|
||
|
; same as get_available_value, but also includes operation of mark_symbol_as_used
|
||
|
mov eax,[current_pass]
|
||
|
mov [ebx+SymbolTree_Leaf.last_use_pass],eax
|
||
|
call get_available_value
|
||
|
jc use_unavailable_value
|
||
|
retn
|
||
|
use_unavailable_value:
|
||
|
call mark_used_fallbacks
|
||
|
stc
|
||
|
retn
|
||
|
|
||
|
create_constant_value_definition:
|
||
|
; in:
|
||
|
; ebx - SymbolTree_Leaf
|
||
|
; out:
|
||
|
; edx - ValueDefinition possibly containing value to update, null if definition forbidden
|
||
|
; preserves: ebx, esi, edi
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
jnz symbol_already_defined
|
||
|
or [ebx+SymbolTree_Leaf.flags],SYM_CONSTANT
|
||
|
mov eax,[ebx+SymbolTree_Leaf.definition]
|
||
|
test eax,eax
|
||
|
jz add_value_definition
|
||
|
test [eax+ValueDefinition.flags],VAL_INTERNAL
|
||
|
jnz symbol_already_defined
|
||
|
mov ecx,[eax+ValueDefinition.pass]
|
||
|
cmp ecx,[current_pass]
|
||
|
jne reset_value
|
||
|
symbol_already_defined:
|
||
|
mov edx,_conflicting_definition
|
||
|
call register_error
|
||
|
xor edx,edx
|
||
|
retn
|
||
|
update_value_definition:
|
||
|
; in:
|
||
|
; ebx - SymbolTree_Leaf
|
||
|
; out:
|
||
|
; edx - ValueDefinition possibly containing value to update, null if definition forbidden
|
||
|
; preserves: ebx, esi, edi
|
||
|
mov eax,[ebx+SymbolTree_Leaf.definition]
|
||
|
test eax,eax
|
||
|
jz add_value_definition
|
||
|
test [eax+ValueDefinition.flags],VAL_INTERNAL
|
||
|
jnz value_redefinition
|
||
|
mov ecx,[eax+ValueDefinition.pass]
|
||
|
cmp ecx,[current_pass]
|
||
|
jne reset_value
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_CONSTANT or SYM_LINK
|
||
|
jnz constant_redefined
|
||
|
mov edx,eax
|
||
|
or [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_PREDICTED
|
||
|
jz dynamic_value_definition_ready
|
||
|
and [ebx+SymbolTree_Leaf.flags],not SYM_PREDICTED
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_PREDICTED_DEFINED
|
||
|
jz dynamic_value_definition_ready
|
||
|
or [next_pass_needed],1
|
||
|
dynamic_value_definition_ready:
|
||
|
cmp [edx+ValueDefinition.reference_count],1
|
||
|
ja dynamic_value_in_use
|
||
|
retn
|
||
|
dynamic_value_in_use:
|
||
|
mov eax,[edx+ValueDefinition.previous]
|
||
|
mov [ebx+SymbolTree_Leaf.definition],eax
|
||
|
dec [edx+ValueDefinition.reference_count]
|
||
|
mov eax,edx
|
||
|
xchg eax,[ebx+SymbolTree_Leaf.retired_definition]
|
||
|
mov [edx+ValueDefinition.previous],eax
|
||
|
create_value_definition:
|
||
|
; in:
|
||
|
; ebx - SymbolTree_Leaf
|
||
|
; out:
|
||
|
; edx - ValueDefinition possibly containing value to update, null if definition forbidden
|
||
|
; preserves: ebx, esi, edi
|
||
|
mov eax,[ebx+SymbolTree_Leaf.definition]
|
||
|
test eax,eax
|
||
|
jz add_value_definition
|
||
|
test [eax+ValueDefinition.flags],VAL_INTERNAL
|
||
|
jnz value_redefinition
|
||
|
mov ecx,[eax+ValueDefinition.pass]
|
||
|
cmp ecx,[current_pass]
|
||
|
je value_redefinition
|
||
|
reset_value:
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_LINK
|
||
|
jnz reset_link_value
|
||
|
mov edx,[ebx+SymbolTree_Leaf.retired_definition]
|
||
|
retire_previous_values:
|
||
|
dec [eax+ValueDefinition.reference_count]
|
||
|
xchg edx,[eax+ValueDefinition.previous]
|
||
|
xchg eax,edx
|
||
|
test eax,eax
|
||
|
jz previous_values_retired
|
||
|
test [eax+ValueDefinition.flags],VAL_INTERNAL
|
||
|
jz retire_previous_values
|
||
|
previous_values_retired:
|
||
|
mov [ebx+SymbolTree_Leaf.definition],edx
|
||
|
xchg eax,[edx+ValueDefinition.previous]
|
||
|
mov [ebx+SymbolTree_Leaf.retired_definition],eax
|
||
|
cmp [edx+ValueDefinition.reference_count],0
|
||
|
jne add_value_definition
|
||
|
inc [edx+ValueDefinition.reference_count]
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
jnz reset_value_type
|
||
|
retn
|
||
|
reset_link_value:
|
||
|
and [ebx+SymbolTree_Leaf.flags],not (SYM_LINK or SYM_LINK_PREDICTED)
|
||
|
mov eax,[ebx+SymbolTree_Leaf.last_use_pass]
|
||
|
cmp eax,[current_pass]
|
||
|
jne reset_current_link_value
|
||
|
or [next_pass_needed],1
|
||
|
reset_current_link_value:
|
||
|
xor eax,eax
|
||
|
xchg eax,[ebx+SymbolTree_Leaf.definition]
|
||
|
dec [eax+ValueDefinition.reference_count]
|
||
|
jnz reset_previous_link_value
|
||
|
test [eax+ValueDefinition.flags],VAL_DETACHED
|
||
|
jz reset_previous_link_value
|
||
|
mov ecx,eax
|
||
|
xchg eax,[retired_definition]
|
||
|
mov [ecx+ValueDefinition.previous],eax
|
||
|
reset_previous_link_value:
|
||
|
xor eax,eax
|
||
|
xchg eax,[ebx+SymbolTree_Leaf.retired_definition]
|
||
|
test eax,eax
|
||
|
jz add_value_definition
|
||
|
dec [eax+ValueDefinition.reference_count]
|
||
|
jnz add_value_definition
|
||
|
test [eax+ValueDefinition.flags],VAL_DETACHED
|
||
|
jz add_value_definition
|
||
|
mov ecx,eax
|
||
|
xchg eax,[retired_definition]
|
||
|
mov [ecx+ValueDefinition.previous],eax
|
||
|
jmp add_value_definition
|
||
|
constant_redefined:
|
||
|
mov edx,_conflicting_definition
|
||
|
call register_error
|
||
|
xor edx,edx
|
||
|
retn
|
||
|
value_redefinition:
|
||
|
cmp [eax+ValueDefinition.type],VALTYPE_ELEMENT
|
||
|
je constant_redefined
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_CONSTANT or SYM_LINK
|
||
|
jnz constant_redefined
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
jnz add_value_definition
|
||
|
or [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_PREDICTED
|
||
|
jz add_value_definition
|
||
|
and [ebx+SymbolTree_Leaf.flags],not SYM_PREDICTED
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_PREDICTED_DEFINED
|
||
|
jz add_value_definition
|
||
|
or [next_pass_needed],1
|
||
|
add_value_definition:
|
||
|
lea ecx,[ebx+SymbolTree_Leaf.retired_definition]
|
||
|
retrieve_retired_value:
|
||
|
mov eax,[ecx]
|
||
|
test eax,eax
|
||
|
jz new_value_definition
|
||
|
cmp [eax+ValueDefinition.reference_count],0
|
||
|
jne retired_value_immutable
|
||
|
inc [eax+ValueDefinition.reference_count]
|
||
|
mov edx,[eax+ValueDefinition.previous]
|
||
|
mov [ecx],edx
|
||
|
mov [eax+ValueDefinition.type],VALTYPE_RESERVED
|
||
|
jmp adopt_value_definition
|
||
|
retired_value_immutable:
|
||
|
lea ecx,[eax+ValueDefinition.previous]
|
||
|
jmp retrieve_retired_value
|
||
|
new_value_definition:
|
||
|
mov ecx,sizeof.ValueDefinition
|
||
|
call create_tree_element
|
||
|
mov ecx,eax
|
||
|
xchg ecx,[value_definition_chain]
|
||
|
mov [eax+ValueDefinition.interlink],ecx
|
||
|
assert VALTYPE_RESERVED = 0
|
||
|
inc [eax+ValueDefinition.reference_count]
|
||
|
adopt_value_definition:
|
||
|
mov edx,eax
|
||
|
xchg eax,[ebx+SymbolTree_Leaf.definition]
|
||
|
mov [edx+ValueDefinition.previous],eax
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
jnz reset_value_type
|
||
|
test eax,eax
|
||
|
jz value_definition_ready
|
||
|
mov ecx,eax
|
||
|
xchg ecx,[ebx+SymbolTree_Leaf.retired_definition]
|
||
|
xchg ecx,[eax+ValueDefinition.previous]
|
||
|
mov [edx+ValueDefinition.previous],ecx
|
||
|
; test ecx,ecx
|
||
|
; jnz internal_error
|
||
|
mov ecx,[eax+ValueDefinition.pass]
|
||
|
mov [edx+ValueDefinition.pass],ecx
|
||
|
mov cl,[eax+ValueDefinition.type]
|
||
|
mov [edx+ValueDefinition.type],cl
|
||
|
mov ecx,[eax+ValueDefinition.value_length]
|
||
|
mov [edx+ValueDefinition.value_length],ecx
|
||
|
jecxz value_definition_ready
|
||
|
push esi edi
|
||
|
mov esi,[eax+ValueDefinition.value]
|
||
|
mov edi,[edx+ValueDefinition.value]
|
||
|
cmp ecx,[edx+ValueDefinition.block_length]
|
||
|
jbe duplicate_value
|
||
|
push edx
|
||
|
cmp [edx+ValueDefinition.block_length],0
|
||
|
je reallocate_for_duplicate
|
||
|
push ecx
|
||
|
xor eax,eax
|
||
|
xchg eax,[edx+ValueDefinition.value]
|
||
|
call mfree
|
||
|
pop ecx
|
||
|
reallocate_for_duplicate:
|
||
|
mov edi,ecx
|
||
|
call malloc
|
||
|
pop edx
|
||
|
mov [edx+ValueDefinition.value],eax
|
||
|
mov [edx+ValueDefinition.block_length],ecx
|
||
|
mov ecx,edi
|
||
|
mov edi,eax
|
||
|
duplicate_value:
|
||
|
rep movsb
|
||
|
pop edi esi
|
||
|
value_definition_ready:
|
||
|
retn
|
||
|
reset_value_type:
|
||
|
mov [edx+ValueDefinition.type],VALTYPE_RESERVED
|
||
|
retn
|
||
|
|
||
|
remove_value_definition:
|
||
|
; in:
|
||
|
; ebx - SymbolTree_Leaf
|
||
|
; edx - ValueDefinition, null to remove the present value
|
||
|
; edi - SymbolTree_Leaf where to move the value, null for plain remove
|
||
|
; out:
|
||
|
; cf set if there was no value to remove
|
||
|
; when cf = 0:
|
||
|
; edx - ValueDefinition that got removed
|
||
|
; preserves: ebx, esi, edi
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
jnz variable_ready
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_CONSTANT or SYM_LINK
|
||
|
jnz cannot_apply_to_constant
|
||
|
or [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_PREDICTED
|
||
|
jz variable_ready
|
||
|
and [ebx+SymbolTree_Leaf.flags],not SYM_PREDICTED
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_PREDICTED_DEFINED
|
||
|
jz variable_ready
|
||
|
or [next_pass_needed],1
|
||
|
variable_ready:
|
||
|
lea ecx,[ebx+SymbolTree_Leaf.definition]
|
||
|
test edx,edx
|
||
|
jnz find_definition_to_remove
|
||
|
mov edx,[ecx]
|
||
|
test edx,edx
|
||
|
jz no_definition_to_remove
|
||
|
test [edx+ValueDefinition.flags],VAL_INTERNAL
|
||
|
jnz no_definition_to_remove
|
||
|
cmp [edx+ValueDefinition.type],VALTYPE_RESERVED
|
||
|
je no_definition_to_remove
|
||
|
mov eax,[edx+ValueDefinition.pass]
|
||
|
cmp eax,[current_pass]
|
||
|
jne no_definition_to_remove
|
||
|
remove_definition:
|
||
|
mov eax,[edx+ValueDefinition.previous]
|
||
|
test edi,edi
|
||
|
jnz move_definition
|
||
|
mov [ecx],eax
|
||
|
mov eax,[ebx+SymbolTree_Leaf.retired_definition]
|
||
|
mov [edx+ValueDefinition.previous],eax
|
||
|
dec [edx+ValueDefinition.reference_count]
|
||
|
mov [ebx+SymbolTree_Leaf.retired_definition],edx
|
||
|
clc
|
||
|
retn
|
||
|
move_definition:
|
||
|
cmp edi,edx
|
||
|
je definition_moved
|
||
|
test [edi+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
jnz append_moved_definition
|
||
|
test [edi+SymbolTree_Leaf.flags],SYM_CONSTANT or SYM_LINK
|
||
|
jnz cannot_apply_to_constant
|
||
|
or [edi+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
test [edi+SymbolTree_Leaf.flags],SYM_PREDICTED
|
||
|
jz append_moved_definition
|
||
|
and [ebx+SymbolTree_Leaf.flags],not SYM_PREDICTED
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_PREDICTED_DEFINED
|
||
|
jz append_moved_definition
|
||
|
or [next_pass_needed],1
|
||
|
append_moved_definition:
|
||
|
mov [ecx],eax
|
||
|
mov eax,[edi+SymbolTree_Leaf.definition]
|
||
|
mov [edx+ValueDefinition.previous],eax
|
||
|
mov [edi+SymbolTree_Leaf.definition],edx
|
||
|
definition_moved:
|
||
|
clc
|
||
|
retn
|
||
|
find_definition_to_remove:
|
||
|
mov eax,[ecx]
|
||
|
cmp eax,edx
|
||
|
je remove_definition
|
||
|
test eax,eax
|
||
|
jz no_definition_to_remove
|
||
|
lea ecx,[eax+ValueDefinition.previous]
|
||
|
jmp find_definition_to_remove
|
||
|
cannot_apply_to_constant:
|
||
|
mov edx,_cannot_apply_to_constant
|
||
|
call register_error
|
||
|
no_definition_to_remove:
|
||
|
stc
|
||
|
retn
|
||
|
|
||
|
assign_value:
|
||
|
; in:
|
||
|
; ebx - SymbolTree_Leaf
|
||
|
; edx - ValueDefinition prepared to receive the new value
|
||
|
; esi - value
|
||
|
; ecx = length of value
|
||
|
; [value_type] = VALTYPE_#
|
||
|
; preserves: ebx, edx
|
||
|
; notes:
|
||
|
; with VALTYPE_PLAIN ecx must be zero and esi should contain the value directly
|
||
|
; if esi is null, requested length is allocated but not filled
|
||
|
and [edx+ValueDefinition.flags],0
|
||
|
mov eax,[current_pass]
|
||
|
sub eax,[edx+ValueDefinition.pass]
|
||
|
add [edx+ValueDefinition.pass],eax
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
jnz reuse_value_block
|
||
|
cmp eax,[current_pass]
|
||
|
je reuse_value_block
|
||
|
mov edi,[ebx+SymbolTree_Leaf.last_use_pass]
|
||
|
cmp edi,[current_pass]
|
||
|
jne reuse_value_block
|
||
|
cmp ecx,[edx+ValueDefinition.value_length]
|
||
|
je update_value
|
||
|
or [next_pass_needed],1
|
||
|
reuse_value_block:
|
||
|
mov [edx+ValueDefinition.value_length],ecx
|
||
|
mov edi,[edx+ValueDefinition.value]
|
||
|
cmp ecx,[edx+ValueDefinition.block_length]
|
||
|
jbe write_value
|
||
|
push edx
|
||
|
push ecx
|
||
|
cmp [edx+ValueDefinition.block_length],0
|
||
|
je new_value
|
||
|
xor eax,eax
|
||
|
xchg eax,[edx+ValueDefinition.value]
|
||
|
call mfree
|
||
|
new_value:
|
||
|
pop ecx
|
||
|
call malloc
|
||
|
pop edx
|
||
|
mov [edx+ValueDefinition.value],eax
|
||
|
mov [edx+ValueDefinition.block_length],ecx
|
||
|
mov edi,eax
|
||
|
write_value:
|
||
|
mov al,[value_type]
|
||
|
mov [edx+ValueDefinition.type],al
|
||
|
cmp al,VALTYPE_PLAIN
|
||
|
je write_plain_value
|
||
|
test esi,esi
|
||
|
jz value_written
|
||
|
mov ecx,[edx+ValueDefinition.value_length]
|
||
|
rep movsb
|
||
|
value_written:
|
||
|
retn
|
||
|
write_plain_value:
|
||
|
xchg esi,[edx+ValueDefinition.value]
|
||
|
cmp [edx+ValueDefinition.block_length],0
|
||
|
je value_written
|
||
|
and [edx+ValueDefinition.block_length],0
|
||
|
mov eax,esi
|
||
|
call mfree
|
||
|
jmp value_written
|
||
|
rewrite_value:
|
||
|
or [next_pass_needed],1
|
||
|
jmp write_value
|
||
|
update_value:
|
||
|
mov edi,[edx+ValueDefinition.value]
|
||
|
cmp eax,1
|
||
|
ja rewrite_value
|
||
|
mov al,[value_type]
|
||
|
cmp [edx+ValueDefinition.type],al
|
||
|
jne rewrite_value
|
||
|
jecxz value_written
|
||
|
test esi,esi
|
||
|
jz rewrite_value
|
||
|
cmp al,VALTYPE_SYMBOLIC
|
||
|
je update_symbolic_value
|
||
|
cmp al,VALTYPE_PLAIN
|
||
|
je update_plain_value
|
||
|
mov ecx,[edx+ValueDefinition.value_length]
|
||
|
repe cmpsb
|
||
|
je value_updated
|
||
|
inc ecx
|
||
|
dec esi
|
||
|
dec edi
|
||
|
or [next_pass_needed],1
|
||
|
rep movsb
|
||
|
value_updated:
|
||
|
retn
|
||
|
update_symbolic_value:
|
||
|
mov ecx,[edx+ValueDefinition.value_length]
|
||
|
push edx
|
||
|
call compare_symbolic_values
|
||
|
pop edx
|
||
|
jecxz value_updated
|
||
|
value_changed:
|
||
|
rep movsb
|
||
|
changed_value_updated:
|
||
|
or [next_pass_needed],1
|
||
|
retn
|
||
|
update_plain_value:
|
||
|
mov eax,esi
|
||
|
xchg eax,[edx+ValueDefinition.value]
|
||
|
cmp eax,esi
|
||
|
jne changed_value_updated
|
||
|
retn
|
||
|
|
||
|
expand_value:
|
||
|
; in:
|
||
|
; edx - ValueDefinition
|
||
|
; ebx = number of additional zero bytes to append to the value
|
||
|
; preserves: ebx, edx, esi
|
||
|
mov eax,[edx+ValueDefinition.value_length]
|
||
|
mov edi,[edx+ValueDefinition.value]
|
||
|
add edi,eax
|
||
|
add eax,ebx
|
||
|
jc out_of_memory
|
||
|
cmp eax,[edx+ValueDefinition.block_length]
|
||
|
jbe append_zero_bytes
|
||
|
push eax
|
||
|
bsr ecx,eax
|
||
|
dec cl
|
||
|
shr eax,cl
|
||
|
inc eax
|
||
|
shl eax,cl
|
||
|
mov ecx,eax
|
||
|
pop eax
|
||
|
cmp ecx,eax
|
||
|
jbe out_of_memory
|
||
|
mov eax,[edx+ValueDefinition.value]
|
||
|
push edx
|
||
|
call realloc
|
||
|
pop edx
|
||
|
mov [edx+ValueDefinition.value],eax
|
||
|
mov [edx+ValueDefinition.block_length],ecx
|
||
|
mov edi,eax
|
||
|
add edi,[edx+ValueDefinition.value_length]
|
||
|
append_zero_bytes:
|
||
|
add [edx+ValueDefinition.value_length],ebx
|
||
|
xor al,al
|
||
|
mov ecx,ebx
|
||
|
rep stosb
|
||
|
retn
|
||
|
|
||
|
update_value_link:
|
||
|
; in:
|
||
|
; ebx - SymbolTree_Leaf
|
||
|
; edx - ValueDefinition to link
|
||
|
; preserves: ebx, edx
|
||
|
; note: value must be from the current pass
|
||
|
mov eax,[ebx+SymbolTree_Leaf.definition]
|
||
|
test eax,eax
|
||
|
jz values_detached
|
||
|
mov ecx,[eax+ValueDefinition.pass]
|
||
|
cmp ecx,[current_pass]
|
||
|
je symbol_already_defined
|
||
|
test [ebx+SymbolTree_Leaf.flags],SYM_LINK
|
||
|
jnz update_established_link
|
||
|
detach_and_retire_values:
|
||
|
test eax,eax
|
||
|
jz values_detached
|
||
|
dec [eax+ValueDefinition.reference_count]
|
||
|
or [eax+ValueDefinition.flags],VAL_DETACHED
|
||
|
mov ecx,eax
|
||
|
xchg eax,[retired_definition]
|
||
|
xchg eax,[ecx+ValueDefinition.previous]
|
||
|
jmp detach_and_retire_values
|
||
|
values_detached:
|
||
|
mov [ebx+SymbolTree_Leaf.definition],eax
|
||
|
mov eax,[ebx+SymbolTree_Leaf.retired_definition]
|
||
|
detach_retired_values:
|
||
|
test eax,eax
|
||
|
jz retired_values_detached
|
||
|
or [eax+ValueDefinition.flags],VAL_DETACHED
|
||
|
mov ecx,eax
|
||
|
xchg eax,[retired_definition]
|
||
|
xchg eax,[ecx+ValueDefinition.previous]
|
||
|
jmp detach_retired_values
|
||
|
retired_values_detached:
|
||
|
mov [ebx+SymbolTree_Leaf.retired_definition],eax
|
||
|
or [ebx+SymbolTree_Leaf.flags],SYM_LINK
|
||
|
jmp link_new_value
|
||
|
update_established_link:
|
||
|
mov ecx,[current_pass]
|
||
|
cmp ecx,[ebx+SymbolTree_Leaf.last_use_pass]
|
||
|
jne link_new_value
|
||
|
or [ebx+SymbolTree_Leaf.flags],SYM_LINK_PREDICTED
|
||
|
link_new_value:
|
||
|
; cmp ecx,[edx+ValueDefinition.pass]
|
||
|
; jne internal_error
|
||
|
mov eax,edx
|
||
|
inc [eax+ValueDefinition.reference_count]
|
||
|
xchg eax,[ebx+SymbolTree_Leaf.definition]
|
||
|
xchg eax,[ebx+SymbolTree_Leaf.retired_definition]
|
||
|
test eax,eax
|
||
|
jz link_updated
|
||
|
dec [eax+ValueDefinition.reference_count]
|
||
|
jnz link_updated
|
||
|
test [eax+ValueDefinition.flags],VAL_DETACHED
|
||
|
jz link_updated
|
||
|
mov ecx,eax
|
||
|
xchg eax,[retired_definition]
|
||
|
mov [ecx+ValueDefinition.previous],eax
|
||
|
link_updated:
|
||
|
retn
|
||
|
|
||
|
detect_mispredictions:
|
||
|
; in: ebx - SymbolTree_Root
|
||
|
; note:
|
||
|
; while it is looking for mispredicted definitions, it also prepares the tree for the next pass
|
||
|
mov edx,[tree_stack_base]
|
||
|
browse_from_root:
|
||
|
xor eax,eax
|
||
|
mov [ebx+SymbolTree_Root.current_label],eax
|
||
|
and [ebx+SymbolTree_Root.flags],not NAMESPACE_LABEL_FORWARDING
|
||
|
test [ebx+SymbolTree_Root.attributes],SYMTREE_LOCAL
|
||
|
jnz browse_local_tree
|
||
|
add ebx,sizeof.SymbolTree_Root
|
||
|
mov eax,[tree_stack_end]
|
||
|
sub eax,TREE_HEIGHT*8+16
|
||
|
cmp edx,eax
|
||
|
jbe tree_stack_prepared
|
||
|
mov eax,[tree_stack_base]
|
||
|
sub edx,eax
|
||
|
mov ecx,[tree_stack_end]
|
||
|
sub ecx,eax
|
||
|
add ecx,TREE_HEIGHT*8+16
|
||
|
push edx
|
||
|
call grow_stack
|
||
|
pop edx
|
||
|
add edx,eax
|
||
|
mov [tree_stack_base],eax
|
||
|
add eax,ecx
|
||
|
mov [tree_stack_end],eax
|
||
|
tree_stack_prepared:
|
||
|
mov ecx,TREE_HEIGHT
|
||
|
browse_node:
|
||
|
mov edi,ebx
|
||
|
dec cl
|
||
|
browse_branch:
|
||
|
cmp dword [edi],0
|
||
|
je branch_browsed
|
||
|
test cl,cl
|
||
|
jnz deeper_node
|
||
|
mov esi,[edi]
|
||
|
browse_foliage:
|
||
|
mov eax,[esi+SymbolTree_Foliage.child_namespace]
|
||
|
test eax,eax
|
||
|
jz subtree_browsed
|
||
|
mov [edx],ebx
|
||
|
mov [edx+4],ecx
|
||
|
mov [edx+8],esi
|
||
|
mov [edx+12],edi
|
||
|
add edx,16
|
||
|
mov ebx,eax
|
||
|
jmp browse_from_root
|
||
|
browse_local_tree:
|
||
|
add ebx,sizeof.SymbolTree_Root
|
||
|
mov eax,[tree_stack_end]
|
||
|
sub eax,LOCAL_TREE_HEIGHT*8+16
|
||
|
cmp edx,eax
|
||
|
jbe local_tree_stack_prepared
|
||
|
mov eax,[tree_stack_base]
|
||
|
sub edx,eax
|
||
|
mov ecx,[tree_stack_end]
|
||
|
sub ecx,eax
|
||
|
add ecx,LOCAL_TREE_HEIGHT*8+16
|
||
|
push edx
|
||
|
call grow_stack
|
||
|
pop edx
|
||
|
add edx,eax
|
||
|
mov [tree_stack_base],eax
|
||
|
add eax,ecx
|
||
|
mov [tree_stack_end],eax
|
||
|
local_tree_stack_prepared:
|
||
|
mov ecx,LOCAL_TREE_HEIGHT + 1 shl 8
|
||
|
jmp browse_node
|
||
|
subtree_browsed:
|
||
|
mov eax,esi
|
||
|
add eax,sizeof.SymbolTree_Foliage
|
||
|
inspect_leaf:
|
||
|
test [eax+SymbolTree_Leaf.flags],SYM_LINK_PREDICTED
|
||
|
jz link_prediction_ok
|
||
|
push eax ecx edx esi edi
|
||
|
mov edx,[eax+SymbolTree_Leaf.definition]
|
||
|
mov ecx,[eax+SymbolTree_Leaf.retired_definition]
|
||
|
mov esi,dword [edx+ValueDefinition.type]
|
||
|
sub esi,dword [ecx+ValueDefinition.type]
|
||
|
test esi,0FFh
|
||
|
jnz link_value_mispredicted
|
||
|
mov esi,[ecx+ValueDefinition.value]
|
||
|
mov ecx,[ecx+ValueDefinition.value_length]
|
||
|
mov edi,[edx+ValueDefinition.value]
|
||
|
mov edx,[edx+ValueDefinition.value_length]
|
||
|
cmp ecx,edx
|
||
|
jne link_value_mispredicted
|
||
|
jecxz reset_link_prediction
|
||
|
repe cmpsb
|
||
|
je reset_link_prediction
|
||
|
link_value_mispredicted:
|
||
|
or [next_pass_needed],1
|
||
|
reset_link_prediction:
|
||
|
and [eax+SymbolTree_Leaf.flags],not SYM_LINK_PREDICTED
|
||
|
pop edi esi edx ecx eax
|
||
|
link_prediction_ok:
|
||
|
test [eax+SymbolTree_Leaf.flags],SYM_VARIABLE
|
||
|
jnz inspect_next_leaf
|
||
|
and [eax+SymbolTree_Leaf.flags],not SYM_CONSTANT
|
||
|
test [eax+SymbolTree_Leaf.flags],SYM_PREDICTED or SYM_USAGE_PREDICTED
|
||
|
jz inspect_next_leaf
|
||
|
push edx
|
||
|
test [eax+SymbolTree_Leaf.flags],SYM_PREDICTED
|
||
|
jz definition_prediction_ok
|
||
|
mov edx,[eax+SymbolTree_Leaf.definition]
|
||
|
test edx,edx
|
||
|
jz detect_misprediction_of_undefined
|
||
|
test [edx+ValueDefinition.flags],VAL_INTERNAL
|
||
|
jnz detect_misprediction_of_defined
|
||
|
mov edx,[edx+ValueDefinition.pass]
|
||
|
cmp edx,[current_pass]
|
||
|
je detect_misprediction_of_defined
|
||
|
detect_misprediction_of_undefined:
|
||
|
test [eax+SymbolTree_Leaf.flags],SYM_PREDICTED_DEFINED
|
||
|
jz reset_prediction
|
||
|
or [next_pass_needed],1
|
||
|
jmp reset_prediction
|
||
|
detect_misprediction_of_defined:
|
||
|
test [eax+SymbolTree_Leaf.flags],SYM_PREDICTED_DEFINED
|
||
|
jnz reset_prediction
|
||
|
or [next_pass_needed],1
|
||
|
reset_prediction:
|
||
|
and [eax+SymbolTree_Leaf.flags],not SYM_PREDICTED
|
||
|
definition_prediction_ok:
|
||
|
test [eax+SymbolTree_Leaf.flags],SYM_USAGE_PREDICTED
|
||
|
jz usage_prediction_ok
|
||
|
mov edx,[eax+SymbolTree_Leaf.last_use_pass]
|
||
|
cmp edx,[current_pass]
|
||
|
je detect_misprediction_of_used
|
||
|
detect_misprediction_of_unused:
|
||
|
test [eax+SymbolTree_Leaf.flags],SYM_PREDICTED_USED
|
||
|
jz reset_usage_prediction
|
||
|
or [next_pass_needed],1
|
||
|
jmp reset_usage_prediction
|
||
|
detect_misprediction_of_used:
|
||
|
test [eax+SymbolTree_Leaf.flags],SYM_PREDICTED_USED
|
||
|
jnz reset_usage_prediction
|
||
|
or [next_pass_needed],1
|
||
|
reset_usage_prediction:
|
||
|
and [eax+SymbolTree_Leaf.flags],not SYM_USAGE_PREDICTED
|
||
|
usage_prediction_ok:
|
||
|
pop edx
|
||
|
jmp inspect_next_leaf
|
||
|
inspect_next_leaf:
|
||
|
mov eax,[eax+SymbolTree_Leaf.next]
|
||
|
test eax,eax
|
||
|
jnz inspect_leaf
|
||
|
mov esi,[esi+SymbolTree_Foliage.next]
|
||
|
test esi,esi
|
||
|
jnz browse_foliage
|
||
|
branch_browsed:
|
||
|
test ch,ch
|
||
|
jnz local_branch_browsed
|
||
|
add edi,4
|
||
|
lea eax,[ebx+sizeof.SymbolTree_Node]
|
||
|
cmp edi,eax
|
||
|
jne browse_branch
|
||
|
inc cl
|
||
|
cmp cl,TREE_HEIGHT
|
||
|
je tree_browsed
|
||
|
sub edx,8
|
||
|
mov ebx,[edx]
|
||
|
mov edi,[edx+4]
|
||
|
jmp branch_browsed
|
||
|
local_branch_browsed:
|
||
|
add edi,4
|
||
|
lea eax,[ebx+sizeof.SymbolTree_LocalNode]
|
||
|
cmp edi,eax
|
||
|
jne browse_branch
|
||
|
inc cl
|
||
|
cmp cl,LOCAL_TREE_HEIGHT
|
||
|
je tree_browsed
|
||
|
sub edx,8
|
||
|
mov ebx,[edx]
|
||
|
mov edi,[edx+4]
|
||
|
jmp local_branch_browsed
|
||
|
deeper_node:
|
||
|
mov [edx],ebx
|
||
|
mov [edx+4],edi
|
||
|
add edx,8
|
||
|
mov ebx,[edi]
|
||
|
jmp browse_node
|
||
|
tree_browsed:
|
||
|
cmp edx,[tree_stack_base]
|
||
|
je complete_tree_browsed
|
||
|
sub edx,16
|
||
|
mov ebx,[edx]
|
||
|
mov ecx,[edx+4]
|
||
|
mov esi,[edx+8]
|
||
|
mov edi,[edx+12]
|
||
|
jmp subtree_browsed
|
||
|
complete_tree_browsed:
|
||
|
retn
|