2002-04-03
2002-04-03 12:02:04 by Martin Stjernholm <mast@lysator.liu.se>
-
6f773774c5998767763ab6d5bda56ab0acbb1f7c
(303 lines)
(+183/-120)
[
Show
| Annotate
]
Branch: 5.2
Fixed a race that could occur when two result p-code objects were created
simultaneously from the same source p-code. Also modified the p-code
version scheme slightly to avoid accidental equal values between different
Roxen releases.
Rev: server/etc/modules/RXML.pmod/PXml.pike:1.63
Rev: server/etc/modules/RXML.pmod/module.pmod:1.277
Rev: server/etc/modules/RXML.pmod/utils.pmod:1.29
2:
//
// Created 1999-07-30 by Martin Stjernholm.
//
- // $Id: module.pmod,v 1.276 2002/03/27 20:45:01 mast Exp $
+ // $Id: module.pmod,v 1.277 2002/04/03 12:02:03 mast Exp $
// Kludge: Must use "RXML.refs" somewhere for the whole module to be
// loaded correctly.
1262:
TagSet shared_tag_set (RoxenModule|Configuration owner, string name, void|array(Tag) tags)
//! If a tag set with the given owner and name exists, it's returned.
- //! Otherwise a new tag set is created with them. @[tags] is passed
+ //! Otherwise a new tag set is created with them. @[tags] is passed
//! along to its @[RXML.TagSet.create] function in that case. Note
//! that @[owner] may be zero to get a tag set that is global.
{
2012:
return unwind_state && unwind_state->reason == "streaming";
}
- void handle_exception (mixed err, PCode|Parser evaluator, void|int compile_error)
+ void handle_exception (mixed err, PCode|Parser evaluator, void|PCode p_code_error)
//! This function gets any exception that is catched during
- //! evaluation. evaluator is the object that catched the error.
+ //! evaluation. evaluator is the object that catched the error. If
+ //! p_code_error is set, a CompiledError object will be added to it
+ //! if the error was reported.
{
error_count++;
2035:
sprintf ("with scope %O", err->target) :
sprintf ("%O", err->target)));
ctx->frame = 0;
- handle_exception (err, evaluator, compile_error);
+ handle_exception (err, evaluator, p_code_error);
}
throw (err);
}
2058:
else
msg = err->msg;
if (evaluator->report_error (msg)) {
- if (PCode p_code = compile_error && evaluator->p_code) {
+ if (p_code_error) {
CompiledError comp_err = CompiledError (err);
- p_code->add (RXML_CONTEXT, comp_err, comp_err);
+ p_code_error->add (RXML_CONTEXT, comp_err, comp_err);
}
return;
}
2076:
void|int stale_safe,
void|TagSet tag_set_override)
//! Parses and evaluates @[to_parse] with @[type] in this context.
- //! At the same time, p-code is collected to reevaluate it later. An
+ //! At the same time, p-code is collected for later reevaluation. An
//! array is returned which contains the result in the first element
//! and the generated @[RXML.PCode] object in the second. If
//! @[stale_safe] is nonzero, the p-code object will be an instance
2091:
if (!tag_set_override) tag_set_override = tag_set;
make_p_code = 1;
Parser parser = type->get_parser (
- this_object(), tag_set_override, 0, stale_safe ? RenewablePCode (0) : PCode (0));
+ this_object(), tag_set_override, 0,
+ stale_safe ? RenewablePCode (type, tag_set) : PCode (type, tag_set));
mixed res;
PCode p_code;
2099:
parser->write_end (to_parse);
res = parser->eval();
p_code = parser->p_code;
+ p_code->finish();
};
type->give_back (parser, tag_set_override);
3290:
else {
{
PCode p_code = 0;
+ if (TagSet local_tags = this_object()->local_tags) {
if ((ctx->make_p_code = flags & FLAG_COMPILE_RESULT)) {
- p_code = RenewablePCode (0);
+ p_code = RenewablePCode (result_type, local_tags);
p_code->source = [string] elem;
}
- if (this_object()->local_tags) {
- subparser = result_type->get_parser (
- ctx, [object(TagSet)] this_object()->local_tags, evaler, p_code);
+ subparser = result_type->get_parser (ctx, local_tags, evaler, p_code);
subparser->_local_tag_set = 1;
THIS_TAG_DEBUG ("Exec[%d]: Parsing%s string %s with %O "
"from local_tags\n", i,
3304:
format_short (elem), subparser);
}
else {
+ if ((ctx->make_p_code = flags & FLAG_COMPILE_RESULT)) {
+ p_code = RenewablePCode (result_type, ctx->tag_set);
+ p_code->source = [string] elem;
+ }
subparser = result_type->get_parser (
ctx, ctx->tag_set, evaler, p_code);
THIS_TAG_DEBUG ("Exec[%d]: Parsing%s string %s with %O\n", i,
3312:
}
if (evaler->recover_errors && !(flags & FLAG_DONT_RECOVER)) {
subparser->recover_errors = 1;
- if (p_code) p_code->set_recover_errors (1);
+ if (p_code) p_code->recover_errors = 1;
}
}
subparser->finish ([string] elem); // Might unwind.
3364:
}
else if (([object] elem)->is_RXML_PCode) {
THIS_TAG_DEBUG ("Exec[%d]: Evaluating p-code %O\n", i, elem);
- piece = ([object(PCode)] elem)->_eval (ctx);
+ piece = ([object(PCode)] elem)->_eval (ctx, 0);
CONVERT_VALUE (piece, ([object(PCode)] elem)->type,
piece, result_type,
"Converting p-code result from %s "
3508:
EVAL_ARGS_FUNC|string _prepare (Context ctx, Type type,
mapping(string:string) raw_args,
- PCode p_code)
+ int make_p_code)
// 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
3564:
function(string...:void) fn_text_add;
PCode sub_p_code = 0;
PikeCompile comp;
- if (p_code) {
+ if (make_p_code) {
fn_text_add = (fn_text = String.Buffer())->add;
fn_text_add ("mixed tmp;\n");
sub_p_code = PCode (0);
3573:
if (splice_arg) {
// Note: This assumes an XML-like parser.
+ sub_p_code->create (splice_arg_type, 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",
3590: Inside #if defined(MODULE_DEBUG)
throw_fatal (err);
}
#endif
- if (p_code)
+ if (make_p_code)
if (tag)
fn_text_add (
"return ", comp->bind (tag->_eval_splice_args), "(ctx,",
3611:
}
else {
args = raw_args;
- if (p_code) fn_text_add ("return ([\n");
+ if (make_p_code) fn_text_add ("return ([\n");
}
#ifdef MODULE_DEBUG
3619:
#endif
TagSet ctx_tag_set = ctx->tag_set;
Type default_type = tag ? tag->def_arg_type : t_any_text (PNone);
- if (p_code)
+ if (make_p_code)
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);
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",
3664:
}
#endif
- if (p_code) {
+ if (make_p_code) {
fn_text_add ("]);\n");
func = comp->add_func (
"mapping(string:mixed)", "object ctx, object evaler", fn_text->get());
3833:
#endif
THIS_TAG_TOP_DEBUG ("Evaluating%s unparsed\n",
ctx->make_p_code ? " and compiling" : "");
- if (PCode p_code = ctx->make_p_code &&
- (evaler->is_RXML_PCode ? evaler : evaler->p_code)) {
+ if (ctx->make_p_code) {
if (!ctx->p_code_comp) ctx->p_code_comp = PikeCompile();
- in_args = _prepare (ctx, type, args && args + ([]), p_code);
+ in_args = _prepare (ctx, type, args && args + ([]), 1);
PCODE_UPDATE_MSG ("%O: P-code update since args has been compiled.\n",
this_object());
ctx->state_updated++;
3948:
for (; iter > 0; iter-- DO_IF_DEBUG (, debug_iter++)) {
eval_content:
{
+ PCode unevaled_content = 0;
finished++;
if (subevaler)
finished = 0; // Continuing an unwound subevaler.
3967:
// likely we'll loop again.
ctx->make_p_code = 1;
{
- PCode p_code = ctx->make_p_code && PCode (0);
+ if (TagSet local_tags =
+ [object(TagSet)] this_object()->local_tags) {
+ PCode p_code = unevaled_content =
+ ctx->make_p_code && PCode (content_type, local_tags);
if (flags & FLAG_GET_EVALED_CONTENT) {
- PCode evaled_content =
- this_object()->evaled_content = PCode (0, 0, ctx);
- if (p_code) p_code->p_code = evaled_content;
- else p_code = evaled_content;
+ PCode more_p_code = this_object()->evaled_content =
+ PCode (content_type, local_tags, ctx);
+ if (p_code) p_code->p_code = more_p_code;
+ else p_code = more_p_code;
}
- if (this_object()->local_tags) {
+
subevaler = content_type->get_parser (
- ctx, [object(TagSet)] this_object()->local_tags,
- evaler, p_code);
+ ctx, local_tags, evaler, p_code);
subevaler->_local_tag_set = 1;
THIS_TAG_DEBUG ("Iter[%d]: Parsing%s%s content %s "
"with %O from local_tags\n", debug_iter,
3987:
format_short (in_content), subevaler);
}
else {
+ PCode p_code = unevaled_content =
+ ctx->make_p_code && PCode (content_type, ctx->tag_set);
+ if (flags & FLAG_GET_EVALED_CONTENT) {
+ PCode more_p_code = this_object()->evaled_content =
+ PCode (content_type, ctx->tag_set, ctx);
+ if (p_code) p_code->p_code = more_p_code;
+ else p_code = more_p_code;
+ }
subevaler = content_type->get_parser (
ctx, ctx->tag_set, evaler, p_code);
THIS_TAG_DEBUG ("Iter[%d]: Parsing%s%s content %s "
4000:
}
if (evaler->recover_errors && !(flags & FLAG_DONT_RECOVER)) {
subevaler->recover_errors = 1;
- if (p_code) p_code->set_recover_errors (1);
+ if (unevaled_content)
+ unevaled_content->recover_errors = 1;
+ if (flags & FLAG_GET_EVALED_CONTENT)
+ this_object()->evaled_content->recover_errors = 1;
}
}
subevaler->finish (in_content); // Might unwind.
4010:
else {
subevaler = in_content;
if (flags & FLAG_GET_EVALED_CONTENT) {
- PCode p_code = subevaler->p_code = this_object()->evaled_content =
+ PCode p_code = this_object()->evaled_content =
PCode (content_type, subevaler->tag_set, ctx);
if (subevaler->recover_errors)
- p_code->set_recover_errors (1);
+ p_code->recover_errors = 1;
}
THIS_TAG_DEBUG ("Iter[%d]: Evaluating%s with compiled content\n",
debug_iter,
4062:
else { // No streaming.
piece = nil;
if (finished) {
- mixed res = subevaler->_eval (ctx); // Might unwind.
+ mixed res = subevaler->_eval (
+ ctx,
+ flags & FLAG_GET_EVALED_CONTENT &&
+ this_object()->evaled_content); // Might unwind.
if (content_type->sequential)
SET_SEQUENTIAL (res, content, "content");
else if (res != nil)
4075:
finished = 1;
} while (1); // Only loops when an unwound subevaler has been recovered.
- if (PCode p_code = subevaler->p_code) {
- p_code->finish();
- if (stringp (in_content) && ctx->make_p_code) {
- in_content = p_code;
+ if (flags & FLAG_GET_EVALED_CONTENT)
+ this_object()->evaled_content->finish();
+ if (unevaled_content) {
+ unevaled_content->finish();
+ in_content = unevaled_content;
PCODE_UPDATE_MSG ("%O: P-code update since content "
"has been compiled.\n", this_object());
ctx->state_updated++;
- }
- subevaler->p_code = 0;
+
ctx->make_p_code = orig_make_p_code; // Reset before do_return.
}
flags |= FLAG_MAY_CACHE_RESULT;
4760:
LEAVE_CONTEXT();
}
- mixed handle_var (TagSetParser|PCode evaler, string varref, Type want_type)
+ mixed handle_var (string varref, Type want_type)
// Parses and evaluates a possible variable reference, with the
// appropriate error handling.
{
- // Note: VarRef.get more or less duplicates this.
+ // Note: VarRef.get more or less duplicates this; this is never
+ // called from p-code.
string encoding;
array(string|int) splitted;
4785:
"(Use ':' in front to quote a "
"character reference containing dots.)\n"));
err->current_var = "&" + varref + ";";
- context->handle_exception (err, this_object(), 1);
+ context->handle_exception (err, this_object(), p_code);
val = nil;
}
4826:
context->handle_exception (err, this_object()); // May throw.
})) {
VarRef varref = VarRef (splitted[0], splitted[1..], encoding, want_type);
- if (PCode p_code = evaler->p_code)
- p_code->add (context, varref, varref);
+ if (p_code) p_code->add (context, varref, varref);
FRAME_DEPTH_MSG ("%*s%O frame_depth increase line %d\n",
context->frame_depth, "", varref, __LINE__);
context->frame_depth--;
4836:
val = nil;
}
- if (PCode p_code = evaler->p_code)
+ if (p_code)
p_code->add (context,
VarRef (splitted[0], splitted[1..], encoding, want_type), val);
}
4865:
PCode p_code;
//! Must be set to a new @[PCode] object before a stream is fed
- //! which should be compiled to p-code. The object will receive the
- //! compiled code during evaluation and can be used to repeat the
- //! evaluation after the stream is finished.
+ //! which should be compiled to p-code. The object can be used to
+ //! repeat the evaluation after the stream is finished.
//! @decl int unwind_safe;
//!
4959:
// Internals:
- mixed _eval (Context ignored) {return eval();}
+ mixed _eval (Context ignored, PCode more_p_code)
// To be call compatible with PCode.
-
+ {
+ #ifdef DEBUG
+ if (more_p_code)
+ // Since parsers can do evaluation already in feed() and
+ // finish(), we can't add an extra p-code object here to compile
+ // to. But allow it if it's already in the p-code chain.
+ check_p_code: {
+ for (PCode p = p_code; p; p = p->p_code)
+ if (more_p_code == p) break check_p_code;
+ error ("New PCode object registered too late in parser.\n");
+ }
+ #endif
+ return eval();
+ }
Parser _next_free;
// Used to link together unused parser objects for reuse.
5031:
TagSet tag_set;
//! The tag set used for parsing.
- PCode p_code;
-
+
//! In addition to the type, the tag set is part of the static
//! configuration.
optional void reset (Context ctx, Type type, PCode p_code,
5098:
constant name = "none";
- PCode p_code;
-
+
int feed (string in)
{
add (in);
5282:
{
PCode p_code = 0;
if (make_p_code) {
- if (objectp (make_p_code)) (p_code = make_p_code)->reset (this_object(), tag_set);
- else p_code = PCode (this_object(), tag_set);
+ p_code = objectp (make_p_code) ? make_p_code : PCode (this_object(), tag_set);
if (!ctx->p_code_comp) ctx->p_code_comp = PikeCompile();
}
6848:
//! Nonzero if error recovery is allowed. Should be the same as the
//! setting in the parser used to create this object.
- PCode p_code = 0;
+ PCode p_code;
//! Another chained PCode object to update while this one is
- //! compiled or evaluated. Typically only useful if one p-code
- //! object collects the unevaluated data and the other the results.
- //! It's assumed that at most one PCode object in a chain collects
- //! results.
+ //! compiled. Typically only useful if one p-code object collects
+ //! the unevaluated data and the other the results. It's assumed
+ //! that at most one PCode object in a chain collects results.
Context new_context (void|RequestID id)
//! Creates a new context for evaluating the p-code in this object.
6913:
m_delete (context->unwind_state, "reason");
if (!sizeof (context->unwind_state)) context->unwind_state = 0;
}
- piece = _eval (context); // Might unwind.
+ piece = _eval (context, 0); // Might unwind.
}) {
if (objectp (err) && ([object] err)->thrown_at_unwind) {
if (!eval_piece && context->incomplete_eval()) {
6939:
return piece;
}
- static void create (Type _type, void|TagSet _tag_set, void|Context collect_results)
+ void create (Type _type, void|TagSet _tag_set, void|Context collect_results)
{
if (collect_results) {
// Yes, the internal interaction between create, reset, the
// context and CTX_ALREADY_GOT_VC is ugly.
- flags |= COLLECT_RESULTS;
+ flags = COLLECT_RESULTS;
if (collect_results->misc->variable_changes) flags |= CTX_ALREADY_GOT_VC;
collect_results->misc->variable_changes = ([]);
}
-
+ else flags = 0;
if (_type) {
// _type is 0 if we're being decoded or created without full
// init (collect_results still needs to be handled, though).
type = _type;
- protocol_cache_time = -1;
+
if ((tag_set = _tag_set)) generation = _tag_set->generation;
-
+ p_code = 0;
exec = allocate (16);
-
+ length = 0;
flags |= UPDATED;
-
+ protocol_cache_time = -1;
if (flags & COLLECT_RESULTS)
- PCODE_MSG ("create for result collection\n");
+ PCODE_MSG ("create or reset for result collection\n");
else
- PCODE_MSG ("create for content collection\n");
+ PCODE_MSG ("create or reset for content collection\n");
}
}
6968:
// Note: The frame state at exec[pos + 2] for frames might be shared
// between PCode instances.
- static array exec = 0;
- static int length = 0;
+ /*static*/ array exec;
+ /*static*/ int length;
- static int flags = 0;
+ /*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;
-
+ static constant FINISHED = 0x10;
- static int generation;
+ /*static*/ int generation;
// The generation of tag_set when the p-code object was generated.
// Known punt: We should track and check the generations of any
// nested tag sets so that is_stale always is reliable. But due to
// the extensive dependencies in the global rxml_tag_set that won't
// be a problem in practice, so we avoid the overhead.
- static int protocol_cache_time;
+ /*static*/ int protocol_cache_time;
// The ctx->id->misc->cacheable setting when result collected p-code
// is finished. It's reinstated on entry whenever the p-code is used
// to ensure that the protocol cache doesn't overcache.
- void reset (Type _type, void|TagSet _tag_set)
- {
- type = _type;
- protocol_cache_time = -1;
- if ((tag_set = _tag_set)) generation = _tag_set->generation;
- exec = allocate (16);
- length = 0;
- flags &= ~FULLY_RESOLVED;
- if (flags & COLLECT_RESULTS)
- PCODE_MSG ("reset for result collection\n");
- else
- PCODE_MSG ("reset for content collection\n");
- if (p_code) p_code->reset (_type, _tag_set);
- }
-
+
void add (Context ctx, mixed entry, mixed evaled_value)
{
-
+ #ifdef DEBUG
+ if (flags & FINISHED)
+ error ("Adding an entry %s to finished p-code.\n", format_short (entry));
+ #endif
+
if (flags & COLLECT_RESULTS) {
PCODE_MSG ("adding result value %s\n", format_short (evaled_value));
if (ctx->misc[" _ok"] != ctx->misc[" _prev_ok"])
7040:
void add_frame (Context ctx, Frame frame, mixed evaled_value,
void|int cache_frame, void|array frame_state)
{
+ #ifdef DEBUG
+ if (flags & FINISHED)
+ error ("Adding a frame %O to finished p-code.\n", frame);
+ #endif
+
add_frame: {
int frame_flags = frame->flags;
7116:
if (p_code) p_code->add_frame (ctx, frame, evaled_value, cache_frame, frame_state);
}
- void set_recover_errors (int val)
- {
- recover_errors = val;
- if (p_code) p_code->set_recover_errors (val);
- }
-
+
void finish()
{
-
+ #ifdef DEBUG
+ if (flags & FINISHED)
+ error ("Attempt to finish already finished p-code.\n");
+ #endif
+
if (flags & COLLECT_RESULTS) {
Context ctx = RXML_CONTEXT;
7199:
}
if (length != sizeof (exec)) exec = exec[..length - 1];
- if (p_code) p_code->finish(), p_code = 0;
+ p_code = 0;
+ flags |= FINISHED;
}
- mixed _eval (Context ctx)
+ mixed _eval (Context ctx, PCode new_p_code)
//! Like @[eval], but assumes the given context is current. Mostly
//! for internal use.
{
7210:
array parts;
int ppos = 0;
int update_count = ctx->state_updated;
+ #ifdef DEBUG
+ if (!(flags & FINISHED)) report_warning ("Evaluating unfinished p-code.\n");
+ if (p_code)
+ error ("Chained p-code may only be set while a PCode object is being compiled.\n");
+ #endif
#if 0
// This check doesn't work in some "chicken-and-egg" cases when
7269:
exec[pos + 1] = exec[pos + 2] = nil; \
flags |= UPDATED; \
update_count = ++ctx->state_updated; \
- if (p_code) p_code->add_frame (ctx, frame, item, 1); \
+ if (new_p_code) new_p_code->add_frame (ctx, frame, item, 1); \
} \
else { \
if (ctx->state_updated > update_count) { \
7281:
RESET_FRAME (frame); \
/* Race here, but it doesn't matter much. */ \
exec[pos + 1] = frame; \
- if (p_code) p_code->add_frame (ctx, frame, item, 0); \
+ if (new_p_code) new_p_code->add_frame (ctx, frame, item, 0); \
} \
else \
- if (p_code) p_code->add_frame (ctx, frame, item, 1); \
+ if (new_p_code) new_p_code->add_frame (ctx, frame, item, 1); \
} \
pos += 2; \
break chained_p_code_add; \
} \
else if (item->is_RXML_p_code_entry) \
item = item->get (ctx); /* Might unwind. */ \
- if (p_code) p_code->add (ctx, item, item); \
+ if (new_p_code) new_p_code->add (ctx, item, item); \
} \
if (item != nil) \
parts[ppos++] = item; \
7342:
item, ctx->state_updated, update_count);
ctx->state_updated = update_count;
- if (p_code)
+ if (new_p_code)
if (objectp (item) && item->is_RXML_p_code_frame)
- p_code->add_frame (ctx, frame, PCode, 1);
+ new_p_code->add_frame (ctx, frame, PCode, 1);
else
- p_code->add (ctx, item, item);
+ new_p_code->add (ctx, item, item);
err = catch {
ctx->handle_exception (err, this_object()); // May throw.
7432:
return 1;
}
+ static void _take (PCode other)
+ {
+ // Relying on the interpreter lock in this function.
+ type = other->type;
+ tag_set = other->tag_set;
+ recover_errors = other->recover_errors;
+ exec = other->exec, other->exec = 0;
+ length = other->length;
+ flags = other->flags;
+ generation = other->generation;
+ protocol_cache_time = other->protocol_cache_time;
+ }
+
//! @ignore
MARK_OBJECT;
//! @endignore
7462:
return intro + ")" + OBJ_COUNT;
}
- constant P_CODE_VERSION = 6;
- // Version spec encoded with the p-code, so that we can detect and
- // reject incompatible p-code dumps even when the encoded format
- // hasn't changed in an obvious way.
+ constant P_CODE_VERSION = 2.7;
+ // Version spec encoded with the p-code, so we can detect and reject
+ // incompatible p-code dumps even when the encoded format hasn't
+ // changed in an obvious way.
+ //
+ // The integer part is increased for every roxen version, and the
+ // fraction part is increased for every incompatible p-code change.
mixed _encode()
{
-
+ #ifdef DEBUG
+ if (!(flags & FINISHED)) report_warning ("Encoding unfinished p-code.\n");
+ #endif
if (length != sizeof (exec)) exec = exec[..length - 1];
array encode_p_code = exec + ({});
for (int pos = 0; pos < length; pos++) {
7485:
}
flags |= FULLY_RESOLVED;
- return ({P_CODE_VERSION, flags & (COLLECT_RESULTS|FULLY_RESOLVED),
+ return ({P_CODE_VERSION, flags & (COLLECT_RESULTS|FULLY_RESOLVED|FINISHED),
tag_set, tag_set && tag_set->get_hash(),
type, recover_errors, encode_p_code, protocol_cache_time});
}
7535:
// Internals:
- mixed _eval (Context ctx)
+ mixed _eval (Context ctx, PCode new_p_code)
{
if (::is_stale()) {
Parser parser = 0;
7543:
[parser] = m_delete (ctx->unwind_state, this_object());
int orig_make_p_code = ctx->make_p_code;
+ PCode renewed_p_code;
mixed res;
if (mixed err = catch {
ctx->make_p_code = 1;
if (!parser) {
- parser = type->get_parser (ctx, tag_set, 0, this_object()); // Calls reset().
+ renewed_p_code = PCode (type, 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);
parser->finish (source); // Might unwind.
}
else parser->finish(); // Might unwind.
7562:
else throw (err);
}
+ renewed_p_code->finish();
+ if (new_p_code) new_p_code->finish();
+ renewed_p_code->flags |= UPDATED;
+ _take (renewed_p_code); // Assumed to be atomic.
+
type->give_back (parser, tag_set);
return res;
}
else
- return ::_eval (ctx);
+ return ::_eval (ctx, new_p_code);
}
array _encode()