Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
ed3cd943
Commit
ed3cd943
authored
Jun 21, 2013
by
Ian Lance Taylor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
compiler: Only make function descriptors if needed.
From-SVN: r200273
parent
07a6825b
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
252 additions
and
109 deletions
+252
-109
gcc/go/gofrontend/expressions.cc
+37
-55
gcc/go/gofrontend/expressions.h
+61
-4
gcc/go/gofrontend/go.cc
+3
-0
gcc/go/gofrontend/gogo.cc
+142
-45
gcc/go/gofrontend/gogo.h
+9
-5
No files found.
gcc/go/gofrontend/expressions.cc
View file @
ed3cd943
...
@@ -1385,62 +1385,24 @@ Expression::make_func_reference(Named_object* function, Expression* closure,
...
@@ -1385,62 +1385,24 @@ Expression::make_func_reference(Named_object* function, Expression* closure,
return
new
Func_expression
(
function
,
closure
,
location
);
return
new
Func_expression
(
function
,
closure
,
location
);
}
}
// A function descriptor. A function descriptor is a struct with a
// Class Func_descriptor_expression.
// single field pointing to the function code. This is used for
// functions without closures.
class
Func_descriptor_expression
:
public
Expression
// Constructor.
{
public
:
Func_descriptor_expression
(
Named_object
*
fn
,
Named_object
*
dfn
)
:
Expression
(
EXPRESSION_FUNC_DESCRIPTOR
,
fn
->
location
()),
fn_
(
fn
),
dfn_
(
dfn
),
dvar_
(
NULL
)
{
go_assert
(
!
fn
->
is_function
()
||
!
fn
->
func_value
()
->
needs_closure
());
}
// Make the function descriptor type, so that it can be converted.
static
void
make_func_descriptor_type
();
protected
:
int
do_traverse
(
Traverse
*
)
{
return
TRAVERSE_CONTINUE
;
}
Type
*
do_type
();
void
do_determine_type
(
const
Type_context
*
)
{
}
Expression
*
do_copy
()
{
return
Expression
::
make_func_descriptor
(
this
->
fn_
,
this
->
dfn_
);
}
bool
do_is_addressable
()
const
{
return
true
;
}
tree
Func_descriptor_expression
::
Func_descriptor_expression
(
Named_object
*
fn
)
do_get_tree
(
Translate_context
*
);
:
Expression
(
EXPRESSION_FUNC_DESCRIPTOR
,
fn
->
location
()),
fn_
(
fn
),
dfn_
(
NULL
),
dvar_
(
NULL
)
{
go_assert
(
!
fn
->
is_function
()
||
!
fn
->
func_value
()
->
needs_closure
());
}
void
// Traversal.
do_dump_expression
(
Ast_dump_context
*
context
)
const
{
context
->
ostream
()
<<
"[descriptor "
<<
this
->
fn_
->
name
()
<<
"]"
;
}
private
:
int
// The type of all function descriptors.
Func_descriptor_expression
::
do_traverse
(
Traverse
*
)
static
Type
*
descriptor_type
;
{
return
TRAVERSE_CONTINUE
;
// The function for which this is the descriptor.
}
Named_object
*
fn_
;
// The descriptor function.
Named_object
*
dfn_
;
// The descriptor variable.
Bvariable
*
dvar_
;
};
// All function descriptors have the same type.
// All function descriptors have the same type.
...
@@ -1464,6 +1426,18 @@ Func_descriptor_expression::do_type()
...
@@ -1464,6 +1426,18 @@ Func_descriptor_expression::do_type()
return
Func_descriptor_expression
::
descriptor_type
;
return
Func_descriptor_expression
::
descriptor_type
;
}
}
// Copy a Func_descriptor_expression;
Expression
*
Func_descriptor_expression
::
do_copy
()
{
Func_descriptor_expression
*
fde
=
Expression
::
make_func_descriptor
(
this
->
fn_
);
if
(
this
->
dfn_
!=
NULL
)
fde
->
set_descriptor_wrapper
(
this
->
dfn_
);
return
fde
;
}
// The tree for a function descriptor.
// The tree for a function descriptor.
tree
tree
...
@@ -1519,12 +1493,20 @@ Func_descriptor_expression::do_get_tree(Translate_context* context)
...
@@ -1519,12 +1493,20 @@ Func_descriptor_expression::do_get_tree(Translate_context* context)
return
var_to_tree
(
bvar
);
return
var_to_tree
(
bvar
);
}
}
// Print a function descriptor expression.
void
Func_descriptor_expression
::
do_dump_expression
(
Ast_dump_context
*
context
)
const
{
context
->
ostream
()
<<
"[descriptor "
<<
this
->
fn_
->
name
()
<<
"]"
;
}
// Make a function descriptor expression.
// Make a function descriptor expression.
E
xpression
*
Func_descriptor_e
xpression
*
Expression
::
make_func_descriptor
(
Named_object
*
fn
,
Named_object
*
dfn
)
Expression
::
make_func_descriptor
(
Named_object
*
fn
)
{
{
return
new
Func_descriptor_expression
(
fn
,
dfn
);
return
new
Func_descriptor_expression
(
fn
);
}
}
// Make the function descriptor type, so that it can be converted.
// Make the function descriptor type, so that it can be converted.
...
...
gcc/go/gofrontend/expressions.h
View file @
ed3cd943
...
@@ -32,6 +32,7 @@ class String_expression;
...
@@ -32,6 +32,7 @@ class String_expression;
class
Binary_expression
;
class
Binary_expression
;
class
Call_expression
;
class
Call_expression
;
class
Func_expression
;
class
Func_expression
;
class
Func_descriptor_expression
;
class
Unknown_expression
;
class
Unknown_expression
;
class
Index_expression
;
class
Index_expression
;
class
Map_index_expression
;
class
Map_index_expression
;
...
@@ -161,10 +162,9 @@ class Expression
...
@@ -161,10 +162,9 @@ class Expression
// Make a function descriptor, an immutable struct with a single
// Make a function descriptor, an immutable struct with a single
// field that points to the function code. This may only be used
// field that points to the function code. This may only be used
// with functions that do not have closures. FN is the function for
// with functions that do not have closures. FN is the function for
// which we are making the descriptor. DFN is the descriptor
// which we are making the descriptor.
// function wrapper.
static
Func_descriptor_expression
*
static
Expression
*
make_func_descriptor
(
Named_object
*
fn
);
make_func_descriptor
(
Named_object
*
fn
,
Named_object
*
dfn
);
// Make a reference to the code of a function. This is used to set
// Make a reference to the code of a function. This is used to set
// descriptor and closure fields.
// descriptor and closure fields.
...
@@ -1562,6 +1562,63 @@ class Func_expression : public Expression
...
@@ -1562,6 +1562,63 @@ class Func_expression : public Expression
Expression
*
closure_
;
Expression
*
closure_
;
};
};
// A function descriptor. A function descriptor is a struct with a
// single field pointing to the function code. This is used for
// functions without closures.
class
Func_descriptor_expression
:
public
Expression
{
public
:
Func_descriptor_expression
(
Named_object
*
fn
);
// Set the descriptor wrapper.
void
set_descriptor_wrapper
(
Named_object
*
dfn
)
{
go_assert
(
this
->
dfn_
==
NULL
);
this
->
dfn_
=
dfn
;
}
// Make the function descriptor type, so that it can be converted.
static
void
make_func_descriptor_type
();
protected
:
int
do_traverse
(
Traverse
*
);
Type
*
do_type
();
void
do_determine_type
(
const
Type_context
*
)
{
}
Expression
*
do_copy
();
bool
do_is_addressable
()
const
{
return
true
;
}
tree
do_get_tree
(
Translate_context
*
);
void
do_dump_expression
(
Ast_dump_context
*
context
)
const
;
private
:
// The type of all function descriptors.
static
Type
*
descriptor_type
;
// The function for which this is the descriptor.
Named_object
*
fn_
;
// The descriptor function.
Named_object
*
dfn_
;
// The descriptor variable.
Bvariable
*
dvar_
;
};
// A reference to an unknown name.
// A reference to an unknown name.
class
Unknown_expression
:
public
Parser_expression
class
Unknown_expression
:
public
Parser_expression
...
...
gcc/go/gofrontend/go.cc
View file @
ed3cd943
...
@@ -91,6 +91,9 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
...
@@ -91,6 +91,9 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
// form which is easier to use.
// form which is easier to use.
::
gogo
->
lower_parse_tree
();
::
gogo
->
lower_parse_tree
();
// Create function descriptors as needed.
::
gogo
->
create_function_descriptors
();
// Write out queued up functions for hash and comparison of types.
// Write out queued up functions for hash and comparison of types.
::
gogo
->
write_specific_type_functions
();
::
gogo
->
write_specific_type_functions
();
...
...
gcc/go/gofrontend/gogo.cc
View file @
ed3cd943
...
@@ -1608,14 +1608,6 @@ Lower_parse_tree::function(Named_object* no)
...
@@ -1608,14 +1608,6 @@ Lower_parse_tree::function(Named_object* no)
{
{
no
->
func_value
()
->
set_closure_type
();
no
->
func_value
()
->
set_closure_type
();
// Make sure that every externally visible function has a
// descriptor, so that packages that import this one can refer to
// it.
if
(
!
Gogo
::
is_hidden_name
(
no
->
name
())
&&
!
no
->
func_value
()
->
is_method
()
&&
!
no
->
func_value
()
->
is_descriptor_wrapper
())
no
->
func_value
()
->
descriptor
(
this
->
gogo_
,
no
);
go_assert
(
this
->
function_
==
NULL
);
go_assert
(
this
->
function_
==
NULL
);
this
->
function_
=
no
;
this
->
function_
=
no
;
int
t
=
no
->
func_value
()
->
traverse
(
this
);
int
t
=
no
->
func_value
()
->
traverse
(
this
);
...
@@ -1703,28 +1695,6 @@ Lower_parse_tree::expression(Expression** pexpr)
...
@@ -1703,28 +1695,6 @@ Lower_parse_tree::expression(Expression** pexpr)
void
void
Gogo
::
lower_parse_tree
()
Gogo
::
lower_parse_tree
()
{
{
// Create a function descriptor for any function that is declared in
// this package. This is so that we have a descriptor for functions
// written in assembly. Gather the descriptors first so that we
// don't add declarations while looping over them.
std
::
vector
<
Named_object
*>
fndecls
;
Bindings
*
b
=
this
->
package_
->
bindings
();
for
(
Bindings
::
const_declarations_iterator
p
=
b
->
begin_declarations
();
p
!=
b
->
end_declarations
();
++
p
)
{
Named_object
*
no
=
p
->
second
;
if
(
no
->
is_function_declaration
()
&&
!
no
->
func_declaration_value
()
->
type
()
->
is_method
()
&&
!
Linemap
::
is_predeclared_location
(
no
->
location
()))
fndecls
.
push_back
(
no
);
}
for
(
std
::
vector
<
Named_object
*>::
const_iterator
p
=
fndecls
.
begin
();
p
!=
fndecls
.
end
();
++
p
)
(
*
p
)
->
func_declaration_value
()
->
descriptor
(
this
,
*
p
);
fndecls
.
clear
();
Lower_parse_tree
lower_parse_tree
(
this
,
NULL
);
Lower_parse_tree
lower_parse_tree
(
this
,
NULL
);
this
->
traverse
(
&
lower_parse_tree
);
this
->
traverse
(
&
lower_parse_tree
);
}
}
...
@@ -1763,6 +1733,121 @@ Gogo::lower_constant(Named_object* no)
...
@@ -1763,6 +1733,121 @@ Gogo::lower_constant(Named_object* no)
lower
.
constant
(
no
,
false
);
lower
.
constant
(
no
,
false
);
}
}
// Traverse the tree to create function descriptors as needed.
class
Create_function_descriptors
:
public
Traverse
{
public
:
Create_function_descriptors
(
Gogo
*
gogo
)
:
Traverse
(
traverse_functions
|
traverse_expressions
),
gogo_
(
gogo
)
{
}
int
function
(
Named_object
*
);
int
expression
(
Expression
**
);
private
:
Gogo
*
gogo_
;
};
// Create a descriptor for every top-level exported function.
int
Create_function_descriptors
::
function
(
Named_object
*
no
)
{
if
(
no
->
is_function
()
&&
no
->
func_value
()
->
enclosing
()
==
NULL
&&
!
no
->
func_value
()
->
is_method
()
&&
!
no
->
func_value
()
->
is_descriptor_wrapper
()
&&
!
Gogo
::
is_hidden_name
(
no
->
name
()))
no
->
func_value
()
->
descriptor
(
this
->
gogo_
,
no
);
return
TRAVERSE_CONTINUE
;
}
// If we see a function referenced in any way other than calling it,
// create a descriptor for it.
int
Create_function_descriptors
::
expression
(
Expression
**
pexpr
)
{
Expression
*
expr
=
*
pexpr
;
Func_expression
*
fe
=
expr
->
func_expression
();
if
(
fe
!=
NULL
)
{
// We would not get here for a call to this function, so this is
// a reference to a function other than calling it. We need a
// descriptor.
if
(
fe
->
closure
()
!=
NULL
)
return
TRAVERSE_CONTINUE
;
Named_object
*
no
=
fe
->
named_object
();
if
(
no
->
is_function
()
&&
!
no
->
func_value
()
->
is_method
())
no
->
func_value
()
->
descriptor
(
this
->
gogo_
,
no
);
else
if
(
no
->
is_function_declaration
()
&&
!
no
->
func_declaration_value
()
->
type
()
->
is_method
()
&&
!
Linemap
::
is_predeclared_location
(
no
->
location
()))
no
->
func_declaration_value
()
->
descriptor
(
this
->
gogo_
,
no
);
return
TRAVERSE_CONTINUE
;
}
Call_expression
*
ce
=
expr
->
call_expression
();
if
(
ce
!=
NULL
)
{
Expression
*
fn
=
ce
->
fn
();
if
(
fn
->
func_expression
()
!=
NULL
)
{
// Traverse the arguments but not the function.
Expression_list
*
args
=
ce
->
args
();
if
(
args
!=
NULL
)
{
if
(
args
->
traverse
(
this
)
==
TRAVERSE_EXIT
)
return
TRAVERSE_EXIT
;
}
return
TRAVERSE_SKIP_COMPONENTS
;
}
}
return
TRAVERSE_CONTINUE
;
}
// Create function descriptors as needed. We need a function
// descriptor for all exported functions and for all functions that
// are referenced without being called.
void
Gogo
::
create_function_descriptors
()
{
// Create a function descriptor for any exported function that is
// declared in this package. This is so that we have a descriptor
// for functions written in assembly. Gather the descriptors first
// so that we don't add declarations while looping over them.
std
::
vector
<
Named_object
*>
fndecls
;
Bindings
*
b
=
this
->
package_
->
bindings
();
for
(
Bindings
::
const_declarations_iterator
p
=
b
->
begin_declarations
();
p
!=
b
->
end_declarations
();
++
p
)
{
Named_object
*
no
=
p
->
second
;
if
(
no
->
is_function_declaration
()
&&
!
no
->
func_declaration_value
()
->
type
()
->
is_method
()
&&
!
Linemap
::
is_predeclared_location
(
no
->
location
())
&&
!
Gogo
::
is_hidden_name
(
no
->
name
()))
fndecls
.
push_back
(
no
);
}
for
(
std
::
vector
<
Named_object
*>::
const_iterator
p
=
fndecls
.
begin
();
p
!=
fndecls
.
end
();
++
p
)
(
*
p
)
->
func_declaration_value
()
->
descriptor
(
this
,
*
p
);
fndecls
.
clear
();
Create_function_descriptors
cfd
(
this
);
this
->
traverse
(
&
cfd
);
}
// Look for interface types to finalize methods of inherited
// Look for interface types to finalize methods of inherited
// interfaces.
// interfaces.
...
@@ -3559,7 +3644,9 @@ Function::make_descriptor_wrapper(Gogo* gogo, Named_object* no,
...
@@ -3559,7 +3644,9 @@ Function::make_descriptor_wrapper(Gogo* gogo, Named_object* no,
}
}
gogo
->
add_statement
(
s
);
gogo
->
add_statement
(
s
);
gogo
->
add_block
(
gogo
->
finish_block
(
loc
),
loc
);
Block
*
b
=
gogo
->
finish_block
(
loc
);
gogo
->
add_block
(
b
,
loc
);
gogo
->
lower_block
(
dno
,
b
);
gogo
->
finish_function
(
loc
);
gogo
->
finish_function
(
loc
);
return
dno
;
return
dno
;
...
@@ -3576,13 +3663,18 @@ Function::descriptor(Gogo* gogo, Named_object* no)
...
@@ -3576,13 +3663,18 @@ Function::descriptor(Gogo* gogo, Named_object* no)
go_assert
(
!
this
->
is_descriptor_wrapper_
);
go_assert
(
!
this
->
is_descriptor_wrapper_
);
if
(
this
->
descriptor_
==
NULL
)
if
(
this
->
descriptor_
==
NULL
)
{
{
Named_object
*
dno
;
// Make and record the descriptor first, so that when we lower
if
(
no
->
package
()
!=
NULL
// the descriptor wrapper we don't try to make it again.
||
Linemap
::
is_predeclared_location
(
no
->
location
()))
Func_descriptor_expression
*
descriptor
=
dno
=
NULL
;
Expression
::
make_func_descriptor
(
no
);
else
this
->
descriptor_
=
descriptor
;
dno
=
Function
::
make_descriptor_wrapper
(
gogo
,
no
,
this
->
type_
);
if
(
no
->
package
()
==
NULL
this
->
descriptor_
=
Expression
::
make_func_descriptor
(
no
,
dno
);
&&
!
Linemap
::
is_predeclared_location
(
no
->
location
()))
{
Named_object
*
dno
=
Function
::
make_descriptor_wrapper
(
gogo
,
no
,
this
->
type_
);
descriptor
->
set_descriptor_wrapper
(
dno
);
}
}
}
return
this
->
descriptor_
;
return
this
->
descriptor_
;
}
}
...
@@ -4127,13 +4219,18 @@ Function_declaration::descriptor(Gogo* gogo, Named_object* no)
...
@@ -4127,13 +4219,18 @@ Function_declaration::descriptor(Gogo* gogo, Named_object* no)
go_assert
(
!
this
->
fntype_
->
is_method
());
go_assert
(
!
this
->
fntype_
->
is_method
());
if
(
this
->
descriptor_
==
NULL
)
if
(
this
->
descriptor_
==
NULL
)
{
{
Named_object
*
dno
;
// Make and record the descriptor first, so that when we lower
if
(
no
->
package
()
!=
NULL
// the descriptor wrapper we don't try to make it again.
||
Linemap
::
is_predeclared_location
(
no
->
location
()))
Func_descriptor_expression
*
descriptor
=
dno
=
NULL
;
Expression
::
make_func_descriptor
(
no
);
else
this
->
descriptor_
=
descriptor
;
dno
=
Function
::
make_descriptor_wrapper
(
gogo
,
no
,
this
->
fntype_
);
if
(
no
->
package
()
==
NULL
this
->
descriptor_
=
Expression
::
make_func_descriptor
(
no
,
dno
);
&&
!
Linemap
::
is_predeclared_location
(
no
->
location
()))
{
Named_object
*
dno
=
Function
::
make_descriptor_wrapper
(
gogo
,
no
,
this
->
fntype_
);
descriptor
->
set_descriptor_wrapper
(
dno
);
}
}
}
return
this
->
descriptor_
;
return
this
->
descriptor_
;
}
}
...
...
gcc/go/gofrontend/gogo.h
View file @
ed3cd943
...
@@ -476,6 +476,10 @@ class Gogo
...
@@ -476,6 +476,10 @@ class Gogo
void
void
lower_constant
(
Named_object
*
);
lower_constant
(
Named_object
*
);
// Create all necessary function descriptors.
void
create_function_descriptors
();
// Finalize the method lists and build stub methods for named types.
// Finalize the method lists and build stub methods for named types.
void
void
finalize_methods
();
finalize_methods
();
...
@@ -1164,15 +1168,15 @@ class Function
...
@@ -1164,15 +1168,15 @@ class Function
// is NULL unless we actually need a defer stack.
// is NULL unless we actually need a defer stack.
Temporary_statement
*
defer_stack_
;
Temporary_statement
*
defer_stack_
;
// True if the result variables are named.
// True if the result variables are named.
bool
results_are_named_
;
bool
results_are_named_
:
1
;
// True if this method should not be included in the type descriptor.
// True if this method should not be included in the type descriptor.
bool
nointerface_
;
bool
nointerface_
:
1
;
// True if this function calls the predeclared recover function.
// True if this function calls the predeclared recover function.
bool
calls_recover_
;
bool
calls_recover_
:
1
;
// True if this a thunk built for a function which calls recover.
// True if this a thunk built for a function which calls recover.
bool
is_recover_thunk_
;
bool
is_recover_thunk_
:
1
;
// True if this function already has a recover thunk.
// True if this function already has a recover thunk.
bool
has_recover_thunk_
;
bool
has_recover_thunk_
:
1
;
// True if this function should be put in a unique section. This is
// True if this function should be put in a unique section. This is
// turned on for field tracking.
// turned on for field tracking.
bool
in_unique_section_
:
1
;
bool
in_unique_section_
:
1
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment