2002-04-17
2002-04-17 00:44:04 by Martin Stjernholm <mast@lysator.liu.se>
-
23b3ec5484e399a939dc8715b2738091d9851add
(161 lines)
(+95/-66)
[
Show
| Annotate
]
Branch: 5.2
Handle the PikeCompile objects properly when delayed resolving p-code in
PCode._eval. This fixes the problem which could give the backtrace 'Cannot
index the NULL value with "resolve"' in situations with concurrent requests.
Rev: server/etc/modules/RXML.pmod/module.pmod:1.281
2:
//
// Created 1999-07-30 by Martin Stjernholm.
//
- // $Id: module.pmod,v 1.280 2002/04/09 10:53:06 mast Exp $
+ // $Id: module.pmod,v 1.281 2002/04/17 00:44:04 mast Exp $
// Kludge: Must use "RXML.refs" somewhere for the whole module to be
// loaded correctly.
2094:
make_p_code = 1;
Parser parser = type->get_parser (
this_object(), tag_set_override, 0,
- stale_safe ? RenewablePCode (type, tag_set) : PCode (type, tag_set));
+ stale_safe ?
+ RenewablePCode (type, this_object(), tag_set) :
+ PCode (type, this_object(), tag_set));
mixed res;
PCode p_code;
2236:
// changed. Never negative.
PikeCompile p_code_comp;
- // The PikeCompile object for collecting any produce Pike byte code
+ // The PikeCompile object for collecting any produced Pike byte code
// during p-code compilation.
static void create (void|TagSet _tag_set, void|RequestID _id)
3296:
PCode p_code = 0;
if (TagSet local_tags = this_object()->local_tags) {
if ((ctx->make_p_code = flags & FLAG_COMPILE_RESULT)) {
- p_code = RenewablePCode (result_type, local_tags);
+ p_code = RenewablePCode (result_type, ctx, local_tags);
p_code->source = [string] elem;
}
subparser = result_type->get_parser (ctx, local_tags, evaler, p_code);
3308:
}
else {
if ((ctx->make_p_code = flags & FLAG_COMPILE_RESULT)) {
- p_code = RenewablePCode (result_type, ctx->tag_set);
+ p_code = RenewablePCode (result_type, ctx, ctx->tag_set);
p_code->source = [string] elem;
}
subparser = result_type->get_parser (
3574:
if (make_p_code) {
fn_text_add = (fn_text = String.Buffer())->add;
fn_text_add ("mixed tmp;\n");
- sub_p_code = PCode (0);
+ 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->tag_set);
+ if (make_p_code) sub_p_code->create (splice_arg_type, ctx, ctx->tag_set);
Parser parser = splice_arg_type->get_parser (ctx, ctx->tag_set, 0,
sub_p_code);
THIS_TAG_DEBUG ("Evaluating splice argument %s\n",
3631:
foreach (indices (raw_args), string arg) {
Type t = atypes[arg] || default_type;
if (t->parser_prog != PNone) {
- sub_p_code->create (t, ctx_tag_set);
+ sub_p_code->create (t, ctx, ctx_tag_set);
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",
3976:
finished = 0; // Continuing an unwound subevaler.
else if (!in_content || in_content == "") {
if (flags & FLAG_GET_EVALED_CONTENT) {
- this_object()->evaled_content = PCode (content_type);
+ this_object()->evaled_content = PCode (content_type, ctx);
this_object()->evaled_content->finish();
}
break eval_content; // No content to handle.
3993:
if (TagSet local_tags =
[object(TagSet)] this_object()->local_tags) {
PCode p_code = unevaled_content =
- ctx->make_p_code && PCode (content_type, local_tags);
+ ctx->make_p_code && PCode (content_type, ctx, local_tags);
if (flags & FLAG_GET_EVALED_CONTENT) {
PCode more_p_code = this_object()->evaled_content =
- PCode (content_type, local_tags, ctx);
+ PCode (content_type, ctx, local_tags, 1);
if (p_code) p_code->p_code = more_p_code;
else p_code = more_p_code;
}
4012:
}
else {
PCode p_code = unevaled_content =
- ctx->make_p_code && PCode (content_type, ctx->tag_set);
+ ctx->make_p_code && PCode (content_type, ctx, ctx->tag_set);
if (flags & FLAG_GET_EVALED_CONTENT) {
PCode more_p_code = this_object()->evaled_content =
- PCode (content_type, ctx->tag_set, ctx);
+ PCode (content_type, ctx, ctx->tag_set, 1);
if (p_code) p_code->p_code = more_p_code;
else p_code = more_p_code;
}
4046:
subevaler = in_content;
if (flags & FLAG_GET_EVALED_CONTENT) {
PCode p_code = this_object()->evaled_content =
- PCode (content_type, subevaler->tag_set, ctx);
+ PCode (content_type, ctx, subevaler->tag_set, 1);
if (subevaler->recover_errors)
p_code->recover_errors = 1;
}
5328:
//! directly, otherwise a new object is created.
{
PCode p_code = 0;
- if (make_p_code) {
- p_code = objectp (make_p_code) ? make_p_code : PCode (this_object(), tag_set);
- if (!ctx->p_code_comp) ctx->p_code_comp = PikeCompile();
- }
+ if (make_p_code)
+ p_code = objectp (make_p_code) ? make_p_code : PCode (this_object(), ctx, tag_set);
Parser p;
if (_p_cache) { // It's a tag set parser.
6697:
#endif
static class PikeCompile
- //! Helper class to paste together a Pike program from strings.
+ //! Helper class to paste together a Pike program from strings. This
+ //! is thread safe.
{
static int idnr = 0;
static inherit String.Buffer: code;
-
+ static inherit Thread.Mutex: mutex;
static mapping(string:mixed) bindings = ([]);
static mapping(string:int) cur_ids = ([]);
static mapping(mixed:mixed) delayed_resolve_places = ([]);
6716:
string add_var (string type, void|string init)
{
string id = "v" + idnr++;
+ string txt;
+
if (init) {
COMP_MSG ("%O add var: %s %s = %O\n", this_object(), type, id, init);
- code::add (sprintf ("%s %s = %s;\n", type, id, init));
+ txt = sprintf ("%s %s = %s;\n", type, id, init);
}
else {
COMP_MSG ("%O add var: %s %s\n", this_object(), type, id);
- code::add (sprintf ("%s %s;\n", type, id));
+ txt = sprintf ("%s %s;\n", type, id);
}
-
+
+ code::add (txt);
+ // Relying on the interpreter lock here.
cur_ids[id] = 1;
-
+
return id;
}
6733:
string id = "f" + idnr++;
COMP_MSG ("%O add func: %s %s (%s)\n{%s}\n",
this_object(), rettype, id, arglist, def);
- code::add (sprintf ("%s %s (%s)\n{%s}\n", rettype, id, arglist, def));
+ string txt = sprintf ("%s %s (%s)\n{%s}\n", rettype, id, arglist, def);
+
+ code::add (txt);
+ // Relying on the interpreter lock here.
cur_ids[id] = 1;
-
+
return id;
}
6758:
#endif
mixed resolved;
if (zero_type (resolved = bindings[what[index]])) {
- #ifdef DEBUG
- if (!cur_ids[what[index]])
- error ("Unknown binding %O.\n", what[index]);
- #endif
- COMP_MSG ("%O delayed_resolve %O\n", this_object(), what[index]);
+
delayed_resolve_places[what] = index;
-
+ COMP_MSG ("%O delayed_resolve %O\n", this_object(), what[index]);
}
else {
- COMP_MSG ("%O delayed_resolve immediately %O\n", this_object(), what[index]);
+
what[index] = resolved;
-
+ COMP_MSG ("%O delayed_resolve immediately %O\n", this_object(), what[index]);
}
}
6791:
object compile()
{
+ Thread.MutexKey lock = mutex::lock();
object compiled = 0;
- if (code::_sizeof()) {
+ // vvv Relying on the interpreter lock from here.
+ string txt = code::get();
+ mapping(string:int) loc_cur_ids = cur_ids;
+ cur_ids = ([]);
+ // ^^^ Relying on the interpreter lock to here.
+
+ if (txt != "") {
COMP_MSG ("%O compile\n", this_object());
- code::add("mixed _encode() { } void _decode(mixed v) { }\n"
+
+ txt +=
+ "mixed _encode() { } void _decode(mixed v) { }\n"
"constant is_RXML_pike_code = 1;\n"
"constant is_RXML_encodable = 1;\n"
#ifdef RXML_OBJ_DEBUG
- // Don't want to encode the cloning of
- // RoxenDebug.ObjectMarker in the __INIT that is
- // dumped, since that debug might not be wanted when
- // the dump is decoded.
+ // Don't want to encode the cloning of RoxenDebug.ObjectMarker
+ // in the __INIT that is dumped, since that debug might not be
+ // wanted when the dump is decoded.
"mapping|object __object_marker = ",
bind (RoxenDebug.ObjectMarker ("object(compiled RXML code)")), ";\n"
#else
6813: Inside #if defined(DEBUG)
LITERAL (OBJ_COUNT)
";}\n"
#endif
- );
+ ;
program res;
- string txt = code::get();
+
#ifdef DEBUG
if (mixed err = catch {
#endif
6830:
compiled = res();
- foreach (indices (cur_ids), string i)
+ foreach (indices (loc_cur_ids), string i)
bindings[i] = compiled[i];
- cur_ids = ([]);
+
}
foreach (indices (delayed_resolve_places), mixed what) {
mixed index = m_delete (delayed_resolve_places, what);
- #ifdef DEBUG
+
if (zero_type (bindings[what[index]]))
- error ("Unknown delayed id %O.\n", what[index]);
- #endif
- COMP_MSG ("%O resolved delayed %O\n", this_object(), what[index]);
+ delayed_resolve_places[what] = index;
+ else {
what[index] = bindings[what[index]];
-
+ COMP_MSG ("%O resolved delayed %O\n", this_object(), what[index]);
}
-
+ }
return compiled;
}
6851:
static void destroy()
{
compile(); // To clean up delayed_resolve_places.
+ #ifdef DEBUG
+ if (sizeof (delayed_resolve_places)) {
+ string errmsg = "Still got unresolved delayed resolve places:\n";
+ foreach (indices (delayed_resolve_places), mixed what) {
+ mixed index = m_delete (delayed_resolve_places, what);
+ errmsg += replace (sprintf (" %O[%O]: %O", what, index, what[index]),
+ "\n", "\n ") + "\n";
}
-
+ error (errmsg);
+ }
+ #endif
+ }
//! @ignore
MARK_OBJECT;
6984:
return piece;
}
- void create (Type _type, void|TagSet _tag_set, void|Context collect_results)
+ void create (Type _type, Context ctx, void|TagSet _tag_set, void|int collect_results)
+ // Not static since this is also used to reset p-code objects.
{
if (collect_results) {
// Yes, the internal interaction between create, reset, the
// context and CTX_ALREADY_GOT_VC is ugly.
flags = COLLECT_RESULTS;
- if (collect_results->misc->variable_changes) flags |= CTX_ALREADY_GOT_VC;
- collect_results->misc->variable_changes = ([]);
+ if (ctx->misc->variable_changes) flags |= CTX_ALREADY_GOT_VC;
+ ctx->misc->variable_changes = ([]);
}
else flags = 0;
if (_type) {
7004:
length = 0;
flags |= UPDATED;
protocol_cache_time = -1;
+ p_code_comp = ctx->p_code_comp || (ctx->p_code_comp = PikeCompile());
if (flags & COLLECT_RESULTS)
PCODE_MSG ("create or reset for result collection\n");
else
7020:
/*static*/ int length;
/*static*/ int flags;
- static constant FULLY_RESOLVED = 0x1;
+
static constant COLLECT_RESULTS = 0x2;
static constant CTX_ALREADY_GOT_VC = 0x4; // Just as ugly as it sounds, but who cares?
static constant UPDATED = 0x8;
7038:
// 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;
+
void add (Context ctx, mixed entry, mixed evaled_value)
{
#ifdef DEBUG
7138:
else {
frame_state = exec[length + 2] = frame->_save();
if (stringp (frame_state[0]))
- ctx->p_code_comp->delayed_resolve (frame_state, 0);
+ p_code_comp->delayed_resolve (frame_state, 0);
RESET_FRAME (frame);
}
7348:
parts[ppos++] = errmsgs; \
} while (0)
- if (flags & FULLY_RESOLVED)
- EVAL_LOOP (;, ;);
- else
+ if (p_code_comp)
EVAL_LOOP ({
array frame_state = exec[pos + 2];
if (stringp (frame->args))
if (stringp (frame_state[0]))
frame->args = frame_state[0] =
- ctx->p_code_comp->resolve (frame_state[0]);
+ p_code_comp->resolve (frame_state[0]);
else
frame->args = frame_state[0];
}, {
array frame_state = exec[pos + 2];
if (stringp (frame_state[0]))
- frame_state[0] = ctx->p_code_comp->resolve (frame_state[0]);
+ frame_state[0] = p_code_comp->resolve (frame_state[0]);
});
-
+ else
+ EVAL_LOOP (;, ;);
ctx->eval_finish();
if (ctx->state_updated > update_count) flags |= UPDATED;
7551:
if (exec[pos + 1]) exec[pos + 1]->args = encode_p_code[pos + 2][0];
}
}
- flags |= FULLY_RESOLVED;
+ p_code_comp = 0;
- return ({P_CODE_VERSION, flags & (COLLECT_RESULTS|FULLY_RESOLVED|FINISHED),
+ return ({P_CODE_VERSION, flags & (COLLECT_RESULTS|FINISHED),
tag_set, tag_set && tag_set->get_hash(),
type, recover_errors, encode_p_code, protocol_cache_time});
}
7616:
if (mixed err = catch {
ctx->make_p_code = 1;
if (!parser) {
- renewed_p_code = PCode (type, tag_set);
+ renewed_p_code = PCode (type, ctx, tag_set);
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);