2002-10-02
2002-10-02 23:10:26 by Martin Stjernholm <mast@lysator.liu.se>
-
ef02a42deef9772e6cc5e04bb677d27206c474c6
(193 lines)
(+145/-48)
[
Show
| Annotate
]
Branch: 5.2
More controlled reuse of PikeCompile objects (it's not good to store
them in the context since several p-code objects with very different
life lengths can be created/updated in the same context). Also a fix
in the delayed resolve of arg functions (a frame that gets stored in
result p-code and that got FLAG_DONT_CACHE_RESULT set from inner tags
won't have a delayed resolved arg function at the time it's added, but
might get it later on). These two things fixes [bug 3235 (#3235)], which was
introduced in the previous revision (thus it's 3.3 only).
Also added some more debug checks in PikeCompile.
Rev: server/etc/modules/RXML.pmod/module.pmod:1.292
2:
//
// Created 1999-07-30 by Martin Stjernholm.
//
- // $Id: module.pmod,v 1.291 2002/09/03 16:36:46 mast Exp $
+ // $Id: module.pmod,v 1.292 2002/10/02 23:10:26 mast Exp $
// Kludge: Must use "RXML.refs" somewhere for the whole module to be
// loaded correctly.
2151:
eval_finished = 1;
#endif
if (tag_set) tag_set->call_eval_finish_funs (this_object());
- if (p_code_comp) p_code_comp->compile(); // Fix all delayed resolves.
+
}
}
2238:
// Nonzero if the persistent state of the evaluated rxml has
// changed. Never negative.
- PikeCompile p_code_comp;
- // The PikeCompile object for collecting any produced Pike byte code
- // during p-code compilation.
-
+
PCode evaled_p_code;
// The p-code object of the innermost frame that collects evaled
// content (i.e. got FLAG_GET_EVALED_CONTENT set).
3630:
EVAL_ARGS_FUNC|string _prepare (Context ctx, Type type,
mapping(string:string) raw_args,
- int make_p_code)
+ PikeCompile comp)
// Evaluates raw_args simultaneously as generating the
// EVAL_ARGS_FUNC function. The result of the evaluations is stored
// in args. Might be destructive on raw_args. No evaluation of
3685:
String.Buffer fn_text;
function(string...:void) fn_text_add;
PCode sub_p_code = 0;
- PikeCompile comp;
- if (make_p_code) {
+ if (comp) {
fn_text_add = (fn_text = String.Buffer())->add;
fn_text_add ("mixed tmp;\n");
sub_p_code = PCode (0, 0);
- comp = ctx->p_code_comp;
+
}
if (splice_arg) {
// Note: This assumes an XML-like parser.
- if (make_p_code) sub_p_code->create (splice_arg_type, ctx, ctx->tag_set);
+ if (comp)
+ sub_p_code->create (splice_arg_type, ctx, ctx->tag_set, 0, comp);
Parser parser = splice_arg_type->get_parser (ctx, ctx->tag_set, 0,
sub_p_code);
THIS_TAG_DEBUG ("Evaluating splice argument %s\n",
3713: Inside #if defined(MODULE_DEBUG)
throw_fatal (err);
}
#endif
- if (make_p_code)
+ if (comp)
if (tag)
fn_text_add (
"return ", comp->bind (tag->_eval_splice_args), "(ctx,",
3734:
}
else {
args = raw_args;
- if (make_p_code) fn_text_add ("return ([\n");
+ if (comp) fn_text_add ("return ([\n");
}
#ifdef MODULE_DEBUG
3742:
#endif
TagSet ctx_tag_set = ctx->tag_set;
Type default_type = tag ? tag->def_arg_type : t_any_text (PNone);
- if (make_p_code)
+ if (comp)
foreach (indices (raw_args), string arg) {
Type t = atypes[arg] || default_type;
if (t->parser_prog != PNone) {
- sub_p_code->create (t, ctx, ctx_tag_set);
+ sub_p_code->create (t, ctx, ctx_tag_set, 0, comp);
Parser parser = t->get_parser (ctx, ctx_tag_set, 0, sub_p_code);
THIS_TAG_DEBUG ("Evaluating and compiling "
"argument value %s with %O\n",
3788:
}
#endif
- if (make_p_code) {
+ if (comp) {
fn_text_add ("]);\n");
func = comp->add_func (
"mapping(string:mixed)", "object ctx, object evaler", fn_text->get());
3865:
// since it handles unwinding and rewinding.
{
RequestID id = ctx->id;
+ PikeCompile comp;
// Unwind state data:
#define EVSTAT_NONE 0
3975: Inside #if defined(DEBUG)
if (content && !stringp (content))
fatal_error ("content is not a string in unparsed frame: %O.\n", content);
#endif
- THIS_TAG_TOP_DEBUG ("Evaluating%s unparsed\n",
- ctx->make_p_code ? " and compiling" : "");
+
if (ctx->make_p_code) {
- if (!ctx->p_code_comp) ctx->p_code_comp = PikeCompile();
- in_args = _prepare (ctx, type, args && args + ([]), 1);
+ if (evaler->is_RXML_PCode) {
+ if (!(comp = evaler->p_code_comp)) {
+ comp = evaler->p_code_comp = PikeCompile();
+ THIS_TAG_TOP_DEBUG ("Evaluating and compiling unparsed"
+ " (with new %O in %O)\n", comp, evaler);
+ }
+ else
+ THIS_TAG_TOP_DEBUG ("Evaluating and compiling unparsed"
+ " (with old %O in %O)\n", comp, evaler);
+ }
+ else {
+ if (!evaler->p_code) {
+ #ifdef DEBUG
+ fatal_error ("Frame is being compiled but evaler %O "
+ "doesn't have a PCode object\n", evaler);
+ #endif
+ // Handle this gracefully if we're not using debug since this
+ // situation can occur easily by mistake if a context is used
+ // recursively.
+ comp = PikeCompile();
+ THIS_TAG_TOP_DEBUG ("Evaluating and compiling unparsed"
+ " (with new temporary %O)\n", comp);
+ }
+ else
+ if (!(comp = evaler->p_code->p_code_comp)) {
+ comp = evaler->p_code->p_code_comp = PikeCompile();
+ THIS_TAG_TOP_DEBUG ("Evaluating and compiling unparsed"
+ " (with new %O in %O in %O)\n",
+ comp, evaler->p_code, evaler);
+ }
+ else
+ THIS_TAG_TOP_DEBUG ("Evaluating and compiling unparsed"
+ " (with old %O in %O in %O)\n",
+ comp, evaler->p_code, evaler);
+ }
+ in_args = _prepare (ctx, type, args && args + ([]), comp);
PCODE_UPDATE_MSG ("%O: P-code update since args has been compiled.\n",
this_object());
ctx->state_updated++;
}
- else
+ else {
+ THIS_TAG_TOP_DEBUG ("Evaluating unparsed\n");
_prepare (ctx, type, args && args + ([]), 0);
-
+ }
in_content = content;
if (!in_content || in_content == "") flags |= FLAG_MAY_CACHE_RESULT;
}
4112:
else if (!in_content || in_content == "") {
if (flags & FLAG_GET_EVALED_CONTENT) {
- this_object()->evaled_content = PCode (content_type, ctx);
+ this_object()->evaled_content =
+ PCode (content_type, ctx, 0, 0,
+ evaler->p_code_comp ||
+ evaler->p_code && evaler->p_code->p_code_comp);
this_object()->evaled_content->finish();
}
break eval_content; // No content to handle.
4139:
ctx->make_p_code = 1;
if (TagSet local_tags =
[object(TagSet)] this_object()->local_tags) {
- PCode p_code = unevaled_content =
- ctx->make_p_code && PCode (content_type, ctx, local_tags);
-
+
if (flags & FLAG_GET_EVALED_CONTENT)
-
+ // Do not pass on a PikeCompile object here since
+ // the result p-code will typically have a
+ // different lifespan than the content p-code.
this_object()->evaled_content = ctx->evaled_p_code =
PCode (content_type, ctx, local_tags, 1);
-
+
+ PCode p_code = unevaled_content =
+ ctx->make_p_code &&
+ PCode (content_type, ctx, local_tags, 0,
+ ctx->evaled_p_code ? ctx->evaled_p_code->p_code_comp :
+ evaler->p_code_comp ||
+ evaler->p_code && evaler->p_code->p_code_comp);
+ // Must use the same PikeCompile object for both
+ // content and result collection since
+ // FLAG_DONT_CACHE_RESULT frames in the result p-code
+ // will resolve to the same compiled args function.
+
if (PCode evaled_p_code = ctx->evaled_p_code)
if (p_code) p_code->p_code = evaled_p_code;
else p_code = evaled_p_code;
4162:
}
else {
- PCode p_code = unevaled_content =
- ctx->make_p_code && PCode (content_type, ctx, ctx->tag_set);
-
+
if (flags & FLAG_GET_EVALED_CONTENT)
-
+ // Do not pass on a PikeCompile object here since
+ // the result p-code will typically have a
+ // different lifespan than the content p-code.
this_object()->evaled_content = ctx->evaled_p_code =
PCode (content_type, ctx, ctx->tag_set, 1);
-
+
+ PCode p_code = unevaled_content =
+ ctx->make_p_code &&
+ PCode (content_type, ctx, ctx->tag_set, 0,
+ ctx->evaled_p_code ? ctx->evaled_p_code->p_code_comp :
+ evaler->p_code_comp ||
+ evaler->p_code && evaler->p_code->p_code_comp);
+ // Must use the same PikeCompile object for both
+ // content and result collection since
+ // FLAG_DONT_CACHE_RESULT frames in the result p-code
+ // will resolve to the same compiled args function.
+
if (PCode evaled_p_code = ctx->evaled_p_code)
if (p_code) p_code->p_code = evaled_p_code;
else p_code = evaled_p_code;
4200:
else {
subevaler = in_content;
+ #ifdef DEBUG
+ if (!evaler->is_RXML_PCode)
+ fatal_error ("Expected the evaler %O to "
+ "be a PCode object here.\n", evaler);
+ #endif
if (flags & FLAG_GET_EVALED_CONTENT) {
PCode p_code =
this_object()->evaled_content = ctx->evaled_p_code =
- PCode (content_type, ctx, subevaler->tag_set, 1);
+ PCode (content_type, ctx, subevaler->tag_set, 1,
+ evaler->p_code_comp);
if (subevaler->recover_errors)
p_code->recover_errors = 1;
}
4365:
if (id && ctx->misc != ctx->id->misc->defines) \
fatal_error ("ctx->misc != ctx->id->misc->defines\n"); \
); \
- if (in_args) args = in_args; \
+ if (in_args) { \
+ args = in_args; \
+ if (stringp (in_args)) \
+ comp->delayed_resolve (this_object(), "args"); \
+ } \
if (in_content) content = in_content; \
ctx->make_p_code = orig_make_p_code; \
if (orig_tag_set) ctx->tag_set = orig_tag_set; \
4930:
context->unwind_state->top = err;
break eval;
}
- if (context->p_code_comp)
+ if (p_code && p_code->p_code_comp)
// Fix all delayed resolves in any ongoing p-code compilation.
- context->p_code_comp->compile();
+ p_code->p_code_comp->compile();
LEAVE_CONTEXT();
throw_fatal (err);
}
4971:
context->unwind_state->top = err;
break eval;
}
- if (context->p_code_comp)
+ if (p_code && p_code->p_code_comp)
// Fix all delayed resolves in any ongoing p-code compilation.
- context->p_code_comp->compile();
+ p_code->p_code_comp->compile();
LEAVE_CONTEXT();
throw_fatal (err);
}
5198:
return eval();
}
+ constant p_code_comp = 0;
+ // To ensure that this identifier is free; other code might do
+ // evaler->p_code_comp, where evaler is either a Parser or a PCode.
+
Parser _next_free;
// Used to link together unused parser objects for reuse.
6914:
# define COMP_MSG(X...) do {} while (0)
#endif
+ #ifdef DEBUG
+ static int p_comp_count = 0;
+ #endif
+
static class PikeCompile
//! Helper class to paste together a Pike program from strings. This
//! is thread safe.
{
-
+ #ifdef DEBUG
+ static string pcid = "pc" + ++p_comp_count;
+ #endif
static int idnr = 0;
static inherit String.Buffer: code;
static inherit Thread.Mutex: mutex;
6927:
string bind (mixed val)
{
- string id = "b" + idnr++;
+ string id =
+ #ifdef DEBUG
+ pcid +
+ #endif
+ "b" + idnr++;
COMP_MSG ("%O bind %O to %s\n", this_object(), val, id);
bindings[id] = val;
return id;
6935:
string add_var (string type, void|string init)
{
- string id = "v" + idnr++;
+ string id =
+ #ifdef DEBUG
+ pcid +
+ #endif
+ "v" + idnr++;
string txt;
if (init) {
6956:
string add_func (string rettype, string arglist, string def)
{
- string id = "f" + idnr++;
+ string id =
+ #ifdef DEBUG
+ pcid +
+ #endif
+ "f" + idnr++;
COMP_MSG ("%O add func: %s %s (%s)\n{%s}\n",
this_object(), rettype, id, arglist, def);
string txt = sprintf ("%s %s (%s)\n{%s}\n", rettype, id, arglist, def);
6971:
mixed resolve (string id)
{
COMP_MSG ("%O resolve %O\n", this_object(), id);
+ #ifdef DEBUG
+ if (!has_prefix (id, pcid))
+ error ("Resolve id %O does not belong to this object.\n", id);
+ #endif
if (zero_type (bindings[id])) {
compile();
#ifdef DEBUG
6985: Inside #if defined(DEBUG)
#ifdef DEBUG
if (!zero_type (delayed_resolve_places[what]))
error ("Multiple indices per thing to delay resolve not handled.\n");
+ if (!stringp (what[index]) || !has_prefix (what[index], pcid))
+ error ("Resolve id %O does not belong to this object.\n", what[index]);
#endif
mixed resolved;
if (zero_type (resolved = bindings[what[index]])) {
7227:
return piece;
}
- void create (Type _type, Context ctx, void|TagSet _tag_set, void|int collect_results)
+ void create (Type _type, Context ctx, void|TagSet _tag_set, void|int collect_results,
+ void|PikeCompile _p_code_comp)
// Not static since this is also used to reset p-code objects.
{
if (collect_results) {
7248:
length = 0;
flags |= UPDATED;
protocol_cache_time = -1;
- p_code_comp = ctx->p_code_comp || (ctx->p_code_comp = PikeCompile());
+ p_code_comp = _p_code_comp || PikeCompile();
if (flags & COLLECT_RESULTS)
- PCODE_MSG ("create or reset for result collection\n");
+ PCODE_MSG ("create or reset for result collection (with %s %O)\n",
+ _p_code_comp ? "old" : "new", p_code_comp);
else
- PCODE_MSG ("create or reset for content collection\n");
+ PCODE_MSG ("create or reset for content collection (with %s %O)\n",
+ _p_code_comp ? "old" : "new", p_code_comp);
}
}
7282:
// is finished. It's reinstated on entry whenever the p-code is used
// to ensure that the protocol cache doesn't overcache.
- static PikeCompile p_code_comp;
+ PikeCompile p_code_comp;
+ // This is inherited by nested PCode instances to make the
+ // compilation units larger.
void add (Context ctx, mixed entry, mixed evaled_value)
{
7389:
exec[length + 2] = frame_state;
else {
frame_state = exec[length + 2] = frame->_save();
- if (stringp (frame->args)) {
- p_code_comp->delayed_resolve (frame, "args");
+ if (stringp (frame->args))
p_code_comp->delayed_resolve (frame_state, 0);
- }
+
RESET_FRAME (frame);
}
7403:
else
exec[length] = frame = exec[length]->_clone_empty();
frame->_restore (exec[length + 2]);
- if (stringp (frame->args))
- p_code_comp->delayed_resolve (frame, "args");
+
frame->flags = frame_flags;
exec[length + 1] = frame;
}
7888:
if (mixed err = catch {
ctx->make_p_code = 1;
if (!parser) {
- renewed_p_code = PCode (type, ctx, tag_set);
+ renewed_p_code = PCode (type, ctx, tag_set, 0, p_code_comp);
renewed_p_code->recover_errors = recover_errors;
renewed_p_code->p_code = new_p_code;
parser = type->get_parser (ctx, tag_set, 0, renewed_p_code);