
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
