summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfche <fche>2006-04-25 17:40:53 +0000
committerfche <fche>2006-04-25 17:40:53 +0000
commit1b07c728305a32a8d1fa1bb5da9d428e34dddf4e (patch)
treef86471e86673dbd7ce49f755f7d980aec43a5a58
parentfe7e582fac54df14452fa017529bf642f2047e5f (diff)
downloadsystemtap-steved-1b07c728305a32a8d1fa1bb5da9d428e34dddf4e.tar.gz
systemtap-steved-1b07c728305a32a8d1fa1bb5da9d428e34dddf4e.tar.xz
systemtap-steved-1b07c728305a32a8d1fa1bb5da9d428e34dddf4e.zip
2006-04-25 Frank Ch. Eigler <fche@elastic.org>
PR 2427. * staptree.cxx (varuse_collecting_visitor::visit_embeddedcode): Support /* pure */ declaration. Stop using __tvar_ naming hack. (v_c_u::visit_print_format): Mark sprint and sprintf as side-effect-free. (deep_copy_visitor::visit_print_format): Propagate raw_components. * stap.1.in: Document declaration. * elaborate.cxx (semantic_pass_opt2): Verbose message tweak. (dead_stmtexpr_remover): Extend for more aggressive optimization. * tapsets.cxx (dwarf,mark_var_expanding_copy_visotor): Add /* pure */ declaration to rvalue expansions. * tapset/*.stp: Added /* pure */ declarations to many functions. * testsuite/parseok/unparsers.stp: Propagate guru mode flag. * testsuite/buildok/twentyfour.stp: New test.
-rw-r--r--ChangeLog17
-rw-r--r--elaborate.cxx56
-rw-r--r--stap.1.in11
-rw-r--r--staptree.cxx28
-rw-r--r--tapset/aux_syscalls.stp36
-rw-r--r--tapset/context.stp34
-rw-r--r--tapset/conversions.stp8
-rw-r--r--tapset/endian.stp14
-rw-r--r--tapset/errno.stp4
-rw-r--r--tapset/return.stp2
-rw-r--r--tapset/string.stp6
-rw-r--r--tapset/timestamp.stp8
-rw-r--r--tapsets.cxx24
-rwxr-xr-xtestsuite/buildok/twentyfour.stp14
-rwxr-xr-xtestsuite/parseok/unparser.stp8
15 files changed, 178 insertions, 92 deletions
diff --git a/ChangeLog b/ChangeLog
index 968abc24..542c5311 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2006-04-25 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 2427.
+ * staptree.cxx (varuse_collecting_visitor::visit_embeddedcode):
+ Support /* pure */ declaration. Stop using __tvar_ naming hack.
+ (v_c_u::visit_print_format): Mark sprint and sprintf as
+ side-effect-free.
+ (deep_copy_visitor::visit_print_format): Propagate raw_components.
+ * stap.1.in: Document declaration.
+ * elaborate.cxx (semantic_pass_opt2): Verbose message tweak.
+ (dead_stmtexpr_remover): Extend for more aggressive optimization.
+ * tapsets.cxx (dwarf,mark_var_expanding_copy_visotor): Add
+ /* pure */ declaration to rvalue expansions.
+ * tapset/*.stp: Added /* pure */ declarations to many functions.
+ * testsuite/parseok/unparsers.stp: Propagate guru mode flag.
+ * testsuite/buildok/twentyfour.stp: New test.
+
2006-04-24 Frank Ch. Eigler <fche@elastic.org>
PR 2599.
diff --git a/elaborate.cxx b/elaborate.cxx
index 61e63cb1..976becd6 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -21,6 +21,9 @@ extern "C" {
#include <cassert>
#include <set>
#include <vector>
+#include <algorithm>
+#include <iterator>
+
using namespace std;
@@ -1247,7 +1250,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
{
if (s.verbose>2)
clog << "Eliding unused local variable "
- << l->name << " in probe #" << i << endl;
+ << l->name << " in " << s.probes[i]->name << endl;
s.probes[i]->locals.erase(s.probes[i]->locals.begin() + j);
relaxed_p = false;
// don't increment j
@@ -1379,6 +1382,7 @@ struct dead_stmtexpr_remover: public traversing_visitor
systemtap_session& session;
bool& relaxed_p;
statement** current_stmt; // pointer to current stmt* being iterated
+ set<vardecl*> focal_vars; // vars considered subject to side-effects
dead_stmtexpr_remover(systemtap_session& s, bool& r):
session(s), relaxed_p(r), current_stmt(0) {}
@@ -1421,7 +1425,23 @@ dead_stmtexpr_remover::visit_expr_statement (expr_statement *s)
varuse_collecting_visitor vut;
s->value->visit (& vut);
- if (vut.written.empty() && !vut.embedded_seen)
+
+ // Note that side-effect-freeness is not simply this test:
+ //
+ // (vut.written.empty() && !vut.embedded_seen)
+ //
+ // That's because the vut.written list may consist of local
+ // variables of called functions. Visible side-effects occur if
+ // *our* locals, or any *globals* are written-to.
+
+
+ set<vardecl*> intersection;
+ insert_iterator<set<vardecl*> > int_it (intersection, intersection.begin());
+ set_intersection (vut.written.begin(), vut.written.end(),
+ focal_vars.begin(), focal_vars.end(),
+ int_it);
+
+ if (intersection.empty() && ! vut.embedded_seen)
{
if (session.verbose>2)
clog << "Eliding side-effect-free expression "
@@ -1437,6 +1457,15 @@ dead_stmtexpr_remover::visit_expr_statement (expr_statement *s)
relaxed_p = false;
}
+ else if(session.verbose>3)
+ {
+ clog << "keeping expression " << *s->tok
+ << " because it writes: ";
+ for (std::set<vardecl*>::iterator k = intersection.begin();
+ k != intersection.end(); k++)
+ clog << (*k)->name << " ";
+ clog << "and/or embedded: " << vut.embedded_seen << endl;
+ }
}
@@ -1450,9 +1479,25 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
// This instance may be reused for multiple probe/function body trims.
for (unsigned i=0; i<s.probes.size(); i++)
- s.probes[i]->body->visit (& duv);
+ {
+ duv.focal_vars.clear ();
+ duv.focal_vars.insert (s.globals.begin(),
+ s.globals.end());
+ duv.focal_vars.insert (s.probes[i]->locals.begin(),
+ s.probes[i]->locals.end());
+ s.probes[i]->body->visit (& duv);
+ }
for (unsigned i=0; i<s.functions.size(); i++)
- s.functions[i]->body->visit (& duv);
+ {
+ duv.focal_vars.clear ();
+ duv.focal_vars.insert (s.functions[i]->locals.begin(),
+ s.functions[i]->locals.end());
+ duv.focal_vars.insert (s.functions[i]->formal_args.begin(),
+ s.functions[i]->formal_args.end());
+ duv.focal_vars.insert (s.globals.begin(),
+ s.globals.end());
+ s.functions[i]->body->visit (& duv);
+ }
}
@@ -1974,9 +2019,6 @@ typeresolution_info::visit_functioncall (functioncall* e)
if (e->type == pe_stats)
invalid (e->tok, e->type);
- // XXX: but what about functions that return no value,
- // and are used only as an expression-statement for side effects?
-
// now resolve the function parameters
if (e->args.size() != e->referent->formal_args.size())
unresolved (e->tok); // symbol resolution should prevent this
diff --git a/stap.1.in b/stap.1.in
index c3ce0725..387fe640 100644
--- a/stap.1.in
+++ b/stap.1.in
@@ -646,10 +646,13 @@ with "$") are found and have their run-time locations decoded.
.PP
Next, all probes and functions are analyzed for optimization
opportunities, in order to remove variables, expressions, and
-functions that have no useful value and no side-effect. Since this
-process can hide latent code errors such as type mismatches or invalid
-$target variables, it sometimes may be useful to disable the
-optimizations with the
+functions that have no useful value and no side-effect. Embedded-C
+functions are assumed to have side-effects unless they include the
+magic string
+.BR /*\ pure\ */ .
+Since this optimization can hide latent code errors such as type
+mismatches or invalid $target variables, it sometimes may be useful
+to disable the optimizations with the
.BR \-u
option.
.PP
diff --git a/staptree.cxx b/staptree.cxx
index 2f62198f..75c2c17d 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -1495,19 +1495,19 @@ functioncall_traversing_visitor::visit_functioncall (functioncall* e)
void
varuse_collecting_visitor::visit_embeddedcode (embeddedcode *s)
{
- // In order to elide unused but correct functions generated to
- // get $target variables, we encode our knowledge that such
- // functions are side-effect-free. We tell them apart from ordinary
- // tapset embedded-C functions by the naming prefix. XXX Something
- // apart from this heuristic would be nice. XXX Similarly, some
- // tapset embedded-C functions are pure and disposable, like
- // substr().
+ // We want to elide embedded-C functions when possible. For
+ // example, each $target variable access is expanded to an
+ // embedded-C function call. Yet, for safety reasons, we should
+ // presume that embedded-C functions have intentional side-effects.
+ //
+ // To tell these two types of functions apart, we apply a
+ // Kludge(tm): we look for a magic string within the function body.
+ // $target variables as rvalues will have this; lvalues won't.
+ // Also, explicit side-effect-free tapset functions will have this.
assert (current_function); // only they get embedded code
- string name = current_function->name;
- if (name.length() > 10 && name.substr(0, 10) == "_tvar_get_")
+ if (s->code.find ("/* pure */") != string::npos)
return;
- // NB: setter functions naturally have side-effects
embedded_seen = true;
}
@@ -1520,7 +1520,12 @@ varuse_collecting_visitor::visit_print_format (print_format* e)
// are implemented as statement-expressions containing a
// print_format. They have side-effects, but not via the
// embedded-code detection method above.
- embedded_seen = true;
+ //
+ // But sprint and sprintf don't have side-effects.
+
+ if (e->print_to_stream)
+ embedded_seen = true; // a proxy for "has unknown side-effects"
+
functioncall_traversing_visitor::visit_print_format (e);
}
@@ -2185,6 +2190,7 @@ deep_copy_visitor::visit_print_format (print_format* e)
n->tok = e->tok;
n->print_with_format = e->print_with_format;
n->print_to_stream = e->print_to_stream;
+ n->raw_components = e->raw_components;
n->components = e->components;
for (unsigned i = 0; i < e->args.size(); ++i)
{
diff --git a/tapset/aux_syscalls.stp b/tapset/aux_syscalls.stp
index 37e9ddf9..b1e2c446 100644
--- a/tapset/aux_syscalls.stp
+++ b/tapset/aux_syscalls.stp
@@ -3,7 +3,7 @@
# copy and decode it and return a string.
#
function _struct_timeval_u:string(uaddr:long)
-%{
+%{ /* pure */
struct timeval tv;
char *ptr = (char *)(unsigned long)THIS->uaddr;
@@ -18,7 +18,7 @@ function _struct_timeval_u:string(uaddr:long)
%}
function _struct_timeval:string(addr:long)
-%{
+%{ /* pure */
struct timeval *tv;
char *ptr = (char *)(unsigned long)THIS->addr;
@@ -31,7 +31,7 @@ function _struct_timeval:string(addr:long)
%}
function _struct_timezone_u:string(uaddr:long)
-%{
+%{ /* pure */
struct timezone tz;
char *ptr = (char *)(unsigned long)THIS->uaddr;
@@ -46,7 +46,7 @@ function _struct_timezone_u:string(uaddr:long)
%}
function _struct_timespec_u:string(uaddr:long)
-%{
+%{ /* pure */
struct timespec ts;
char *ptr = (char *)(unsigned long)THIS->uaddr;
@@ -62,7 +62,7 @@ function _struct_timespec_u:string(uaddr:long)
%}
function _struct_timespec:string(addr:long)
-%{
+%{ /* pure */
struct timespec *ts;
char *ptr = (char *)(unsigned long)THIS->addr;
@@ -76,7 +76,7 @@ function _struct_timespec:string(addr:long)
%}
function _struct_itimerspec_u:string(uaddr:long)
-%{
+%{ /* pure */
struct itimerspec its;
char *ptr = (char *)(unsigned long)THIS->uaddr;
@@ -93,7 +93,7 @@ function _struct_itimerspec_u:string(uaddr:long)
%}
function _struct_itimerval_u:string(uaddr:long)
-%{
+%{ /* pure */
struct itimerval itv;
char *ptr = (char *)(unsigned long)THIS->uaddr;
@@ -110,7 +110,7 @@ function _struct_itimerval_u:string(uaddr:long)
%}
function _struct_itimerval:string(addr:long)
-%{
+%{ /* pure */
struct itimerval *itv;
char *ptr = (char *)(unsigned long)THIS->addr;
@@ -196,7 +196,7 @@ void _stp_sockaddr_str(char *str, const int strlen, char *buf, int len)
%}
function _struct_sockaddr_u:string(uaddr:long, len:long)
-%{
+%{ /* pure */
char *ptr = (char *)(unsigned long)THIS->uaddr;
if (ptr == NULL)
strlcpy (THIS->__retvalue, "NULL", MAXSTRINGLEN);
@@ -211,7 +211,7 @@ function _struct_sockaddr_u:string(uaddr:long, len:long)
%}
function _signal_name:string(sig:long)
-%{
+%{ /* pure */
int sig = THIS->sig;
char *res = 0;
@@ -308,7 +308,7 @@ function _signal_name:string(sig:long)
%}
function _struct_rlimit_u:string(uaddr:long)
-%{
+%{ /* pure */
struct rlimit rl;
char *ptr = (char *)(unsigned long)THIS->uaddr;
@@ -324,7 +324,7 @@ function _struct_rlimit_u:string(uaddr:long)
%}
function _fildes_u:string (uaddr:long)
-%{
+%{ /* pure */
int fd[2];
char *ptr = (char *)(unsigned long)THIS->uaddr;
@@ -339,7 +339,7 @@ function _fildes_u:string (uaddr:long)
%}
function _fd_set_u:string(uaddr:long)
-%{
+%{ /* pure */
fd_set fdset;
char *ptr = (char *)(unsigned long)THIS->uaddr;
@@ -355,7 +355,7 @@ function _fd_set_u:string(uaddr:long)
function _semctl_cmd:string(cmd:long)
-%{
+%{ /* pure */
int cmd = THIS->cmd;
char *res = 0;
@@ -407,7 +407,7 @@ function _semctl_cmd:string(cmd:long)
%}
function __sem_flags:string(semflg:long)
-%{
+%{ /* pure */
long semflg = THIS->semflg;
char *str = THIS->__retvalue;
@@ -420,7 +420,7 @@ function __sem_flags:string(semflg:long)
%}
function __fork_flags:string(flags:long)
-%{
+%{ /* pure */
long flags = THIS->flags;
char *str = THIS->__retvalue;
if (flags & CLONE_FS)
@@ -456,7 +456,7 @@ function __fork_flags:string(flags:long)
/* This function copies an argv from userspace. */
function __get_argv:string(a:long)
-%{
+%{ /* pure */
char __user *__user *argv = (char __user *__user *)(long)THIS->a;
char __user *vstr;
int space, rc, len = MAXSTRINGLEN;
@@ -518,7 +518,7 @@ function __get_argv:string(a:long)
* the string it points to. Should be rarely necessary.
*/
function __string:string (a:long)
-%{
+%{ /* pure */
char *str =(char *)(long)THIS->a;
strlcpy(THIS->__retvalue, str, MAXSTRINGLEN);
%}
diff --git a/tapset/context.stp b/tapset/context.stp
index a93b36b3..221c853b 100644
--- a/tapset/context.stp
+++ b/tapset/context.stp
@@ -18,7 +18,7 @@ function print_backtrace () %{
}
%}
-function backtrace:string () %{
+function backtrace:string () %{ /* pure */
if (CONTEXT->regs) {
/* XXX: this won't be necessary when runtime and translator */
/* agree on what a string is. */
@@ -29,47 +29,47 @@ function backtrace:string () %{
strlcpy (THIS->__retvalue, "", MAXSTRINGLEN);
%}
-function execname:string () %{
+function execname:string () %{ /* pure */
strlcpy (THIS->__retvalue, current->comm, MAXSTRINGLEN);
%}
-function pid:long () %{
+function pid:long () %{ /* pure */
THIS->__retvalue = current->tgid;
%}
-function tid:long () %{
+function tid:long () %{ /* pure */
THIS->__retvalue = current->pid;
%}
-function ppid:long () %{
+function ppid:long () %{ /* pure */
THIS->__retvalue = current->parent->tgid;
%}
-function pexecname:string () %{
+function pexecname:string () %{ /* pure */
strlcpy (THIS->__retvalue, current->parent->comm, MAXSTRINGLEN);
%}
-function gid:long () %{
+function gid:long () %{ /* pure */
THIS->__retvalue = current->gid;
%}
-function egid:long () %{
+function egid:long () %{ /* pure */
THIS->__retvalue = current->egid;
%}
-function uid:long () %{
+function uid:long () %{ /* pure */
THIS->__retvalue = current->uid;
%}
-function euid:long () %{
+function euid:long () %{ /* pure */
THIS->__retvalue = current->euid;
%}
-function cpuid:long () %{
+function cpuid:long () %{ /* pure */
THIS->__retvalue = current->thread_info->cpu;
%}
-function cpu:long () %{
+function cpu:long () %{ /* pure */
THIS->__retvalue = current->thread_info->cpu; /* smp_processor_id()? */
%}
@@ -84,11 +84,11 @@ function print_stack(stk:string) %{
}
%}
-function pp:string () %{
+function pp:string () %{ /* pure */
strlcpy (THIS->__retvalue, CONTEXT->probe_point, MAXSTRINGLEN);
%}
-function probefunc:string () %{
+function probefunc:string () %{ /* pure */
char *start = strstr(CONTEXT->probe_point, "function(\"");
if (start) {
char *ptr = start+10;
@@ -100,7 +100,7 @@ function probefunc:string () %{
}
%}
-function is_return:long () %{
+function is_return:long () %{ /* pure */
char *ptr = strrchr(CONTEXT->probe_point, '.');
if (ptr) {
if (strcmp(ptr+1,"return") == 0)
@@ -108,11 +108,11 @@ function is_return:long () %{
}
%}
-function target:long () %{
+function target:long () %{ /* pure */
THIS->__retvalue = _stp_target;
%}
-function returnval:long () %{
+function returnval:long () %{ /* pure */
if (CONTEXT->regs) {
#if defined (__i386__)
THIS->__retvalue = CONTEXT->regs->eax;
diff --git a/tapset/conversions.stp b/tapset/conversions.stp
index b05d7a8e..7a664a58 100644
--- a/tapset/conversions.stp
+++ b/tapset/conversions.stp
@@ -6,15 +6,15 @@
// Public License (GPL); either version 2, or (at your option) any
// later version.
-function hexstring:string (num:long) %{
+function hexstring:string (num:long) %{ /* pure */
snprintf (THIS->__retvalue, MAXSTRINGLEN, "0x%llx", (long long) THIS->num);
%}
-function string:string (num:long) %{
+function string:string (num:long) %{ /* pure */
snprintf (THIS->__retvalue, MAXSTRINGLEN, "%lld", (long long) THIS->num);
%}
-function kernel_string:string (addr:long) %{
+function kernel_string:string (addr:long) %{ /* pure */
char *destination = THIS->__retvalue;
deref_string (destination, THIS->addr, MAXSTRINGLEN);
goto success;
@@ -30,7 +30,7 @@ success: ;
# NB: accessing user space is hazardous from certain kernel contexts.
# Errors should be returned when this is detected.
-function user_string:string (addr:long) %{
+function user_string:string (addr:long) %{ /* pure */
long rc = _stp_strncpy_from_user (THIS->__retvalue,
(const char __user*) (uintptr_t) THIS->addr,
MAXSTRINGLEN);
diff --git a/tapset/endian.stp b/tapset/endian.stp
index ddcc2546..fc2c8937 100644
--- a/tapset/endian.stp
+++ b/tapset/endian.stp
@@ -2,30 +2,30 @@
# val: 0 - native (default)
# 1 - little endian
# 2 - big endian
-function set_endian:long (val:long) %{
+function set_endian:long (val:long) %{ /* pure */
_stp_endian = THIS->val;
%}
-function big_endian2:long (val:long) %{
+function big_endian2:long (val:long) %{ /* pure */
THIS->__retvalue = cpu_to_be16(THIS->val);
%}
-function big_endian4:long (val:long) %{
+function big_endian4:long (val:long) %{ /* pure */
THIS->__retvalue = cpu_to_be32(THIS->val);
%}
-function big_endian8:long (val:long) %{
+function big_endian8:long (val:long) %{ /* pure */
THIS->__retvalue = cpu_to_be64(THIS->val);
%}
-function little_endian2:long (val:long) %{
+function little_endian2:long (val:long) %{ /* pure */
THIS->__retvalue = cpu_to_le16(THIS->val);
%}
-function little_endian4:long (val:long) %{
+function little_endian4:long (val:long) %{ /* pure */
THIS->__retvalue = cpu_to_le32(THIS->val);
%}
-function little_endian8:long (val:long) %{
+function little_endian8:long (val:long) %{ /* pure */
THIS->__retvalue = cpu_to_le64(THIS->val);
%}
diff --git a/tapset/errno.stp b/tapset/errno.stp
index d3ab90e3..10c4532e 100644
--- a/tapset/errno.stp
+++ b/tapset/errno.stp
@@ -343,7 +343,7 @@ const char * const errlist[] = {
const int Maxerrno = sizeof(errlist)/sizeof(char *);
%}
-function errno_str:string (err:long) %{
+function errno_str:string (err:long) %{ /* pure */
long e = THIS->err;
if (e < 0 && e > -Maxerrno && errlist[-e])
strlcpy (THIS->__retvalue, errlist[-e], MAXSTRINGLEN);
@@ -352,7 +352,7 @@ function errno_str:string (err:long) %{
%}
/* for syscall tapset. set returnp = 1 for decimal, 2 for hex */
-function returnstr:string (returnp:long) %{
+function returnstr:string (returnp:long) %{ /* pure */
long ret;
if (CONTEXT->regs) {
diff --git a/tapset/return.stp b/tapset/return.stp
index 8f13e08a..98ff8a73 100644
--- a/tapset/return.stp
+++ b/tapset/return.stp
@@ -1,4 +1,4 @@
-function retval:long() %{
+function retval:long() %{ /* pure */
if (CONTEXT->regs) {
#if defined (__i386__)
THIS->__retvalue = CONTEXT->regs->eax;
diff --git a/tapset/string.stp b/tapset/string.stp
index 249ff831..19b8f81f 100644
--- a/tapset/string.stp
+++ b/tapset/string.stp
@@ -8,7 +8,7 @@
* @param s string
* @return Returns the length of the string.
*/
-function strlen:long(s:string) %{
+function strlen:long(s:string) %{ /* pure */
THIS->__retvalue=strlen(THIS->s);
%}
@@ -17,7 +17,7 @@ function strlen:long(s:string) %{
* @param str string
* @return Returns the length of the string.
*/
-function substr:string(str:string,start:long,stop:long) %{
+function substr:string(str:string,start:long,stop:long) %{ /* pure */
int len=strlen(THIS->str);
if(THIS->start<0 || THIS->stop<0 ||
THIS->start>len || THIS->stop>len ||
@@ -39,7 +39,7 @@ function substr:string(str:string,start:long,stop:long) %{
* @param s2 string
* @return Returns 1 if s2 is in s1.
*/
-function isinstr:long(s1:string,s2:string) %{
+function isinstr:long(s1:string,s2:string) %{ /* pure */
if(strstr(THIS->s1,THIS->s2)!=NULL)
THIS->__retvalue = 1;
else
diff --git a/tapset/timestamp.stp b/tapset/timestamp.stp
index ee9478cb..67e2e73a 100644
--- a/tapset/timestamp.stp
+++ b/tapset/timestamp.stp
@@ -13,28 +13,28 @@
// return processor cycle counter (if any)
-function get_cycles:long () %{
+function get_cycles:long () %{ /* pure */
cycles_t c = get_cycles();
THIS->__retvalue = (int64_t) c;
%}
// return in microseconds since epoch
-function gettimeofday_us:long () %{
+function gettimeofday_us:long () %{ /* pure */
struct timeval tm;
do_gettimeofday (& tm);
THIS->__retvalue = (tm.tv_sec * 1000000ULL) + (tm.tv_usec);
%}
// return in milliseconds since epoch
-function gettimeofday_ms:long () %{
+function gettimeofday_ms:long () %{ /* pure */
struct timeval tm;
do_gettimeofday (& tm);
THIS->__retvalue = (tm.tv_sec * 1000ULL) + (tm.tv_usec / 1000);
%}
// return in seconds since epoch
-function gettimeofday_s:long () %{
+function gettimeofday_s:long () %{ /* pure */
struct timeval tm;
do_gettimeofday (& tm);
THIS->__retvalue = tm.tv_sec;
diff --git a/tapsets.cxx b/tapsets.cxx
index 07daf865..50386480 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -2598,9 +2598,7 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
if (lvalue && !q.sess.guru_mode)
throw semantic_error("write to target variable not permitted", e->tok);
- // NB: This naming convention is used by varuse_collecting_visitor
- // to make elision of these functions possible.
- string fname = (string(lvalue ? "_tvar_set" : "_tvar_get")
+ string fname = (string(lvalue ? "_dwarf_tvar_set" : "_dwarf_tvar_get")
+ "_" + e->base_name.substr(1)
+ "_" + lex_cast<string>(tick++));
@@ -2615,6 +2613,8 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
e->components,
lvalue,
fdecl->type);
+ if (! lvalue)
+ ec->code += "/* pure */";
}
catch (const semantic_error& er)
{
@@ -3454,18 +3454,18 @@ mark_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e)
fdecl->tok = e->tok;
embeddedcode *ec = new embeddedcode;
ec->tok = e->tok;
- bool lvalue = is_active_lvalue(e);
- if (lvalue) throw semantic_error("write to marker parameter not permitted", e->tok);
+ if (is_active_lvalue (e))
+ throw semantic_error("write to marker parameter not permitted", e->tok);
- // NB: This naming convention is used by varuse_collecting_visitor
- // to make elision of these functions possible.
- string fname = (string(lvalue ? "_tvar_set" : "_tvar_get")
- + "_" + e->base_name.substr(1)
- + "_" + lex_cast<string>(tick++));
+ string fname = string("_mark_tvar_get")
+ + "_" + e->base_name.substr(1)
+ + "_" + lex_cast<string>(tick++);
- ec->code = string("THIS->__retvalue = CONTEXT->locals[0].") + probe_name
- + string(".__mark_arg") + lex_cast<string>(argnum) + string (";");
+ ec->code = string("THIS->__retvalue = CONTEXT->locals[0].")
+ + probe_name + string(".__mark_arg")
+ + lex_cast<string>(argnum) + string (";");
+ ec->code += "/* pure */";
fdecl->name = fname;
fdecl->body = ec;
fdecl->type = (argtype == 'N' ? pe_long :
diff --git a/testsuite/buildok/twentyfour.stp b/testsuite/buildok/twentyfour.stp
new file mode 100755
index 00000000..a889fe56
--- /dev/null
+++ b/testsuite/buildok/twentyfour.stp
@@ -0,0 +1,14 @@
+#! stap -gp4
+
+# If the optimizer is working, this function will get elided,
+# and thus will compile successfully.
+
+function pure() %{ /* pure */
+#error "should have been elided"
+%}
+
+
+probe begin
+{
+ pure ()
+}
diff --git a/testsuite/parseok/unparser.stp b/testsuite/parseok/unparser.stp
index 710c4636..b5deb146 100755
--- a/testsuite/parseok/unparser.stp
+++ b/testsuite/parseok/unparser.stp
@@ -14,8 +14,12 @@ do
do
if head -1 $file | grep -q stap
then
- echo $file
- ./stap -p1 $file | ./stap -p1 - > /dev/null
+ if head -1 $file | fgrep -q -- g # guru mode
+ then guru=-g
+ else guru=
+ fi
+ echo $file $guru
+ ./stap $guru -p1 $file | ./stap $guru -p1 - > /dev/null
fi
done
done