Permalink
Browse files

Make handlers for repossession conflicts possible.

This allows a language where such issues may arise to provide its own
handler for them. If it doesn't, we just flag up the error as before.
  • Loading branch information...
1 parent b571803 commit 7a24af63679a56d20d171ca66b36b6cc758ae7da @jnthn jnthn committed Nov 15, 2012
Showing with 73 additions and 14 deletions.
  1. +16 −7 src/6model/serialization.c
  2. +4 −1 src/6model/serialization.h
  3. +8 −1 src/QAST/CompUnit.nqp
  4. +26 −3 src/QAST/Compiler.nqp
  5. +1 −1 src/QAST/Operations.nqp
  6. +18 −1 src/ops/nqp.ops
View
@@ -1695,12 +1695,20 @@ static void repossess(PARROT_INTERP, SerializationReader *reader, INTVAL i) {
PMC *orig_sc = locate_sc(interp, reader, read_int32(table_row, 8));
PMC *orig_obj = SC_get_object(interp, orig_sc, read_int32(table_row, 12));
- /* Make sure we don't have a reposession conflict. */
- if (SC_PMC(orig_obj) != orig_sc)
- Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
- "Object conflict detected during deserialization\n"
- "(Probable attempt to load two modules that cannot be loaded together).");
-
+ /* If we have a reposession conflict, make a copy of the original object
+ * and reference it from the conflicts list. Push the original (about to
+ * be overwritten) object reference too. */
+ if (SC_PMC(orig_obj) != orig_sc) {
+ PMC *backup = REPR(orig_obj)->allocate(interp, STABLE(orig_obj));
+ if (IS_CONCRETE(orig_obj))
+ REPR(orig_obj)->copy_to(interp, STABLE(orig_obj), OBJECT_BODY(orig_obj), OBJECT_BODY(backup));
+ else
+ MARK_AS_TYPE_OBJECT(backup);
+ PARROT_GC_WRITE_BARRIER(interp, backup);
+ VTABLE_push_pmc(interp, reader->repo_conflicts_list, backup);
+ VTABLE_push_pmc(interp, reader->repo_conflicts_list, orig_obj);
+ }
+
/* Clear it up, since we'll re-allocate all the bits inside
* it on deserialization. */
STABLE(orig_obj)->REPR->gc_free(interp, orig_obj);
@@ -1753,7 +1761,7 @@ static void do_parrot_vtable_fixup_if_needed(PARROT_INTERP, PMC *obj, STRING *me
/* Takes serialized data, an empty SerializationContext to deserialize it into,
* a strings heap and the set of static code refs for the compilation unit.
* Deserializes the data into the required objects and STables. */
-void Serialization_deserialize(PARROT_INTERP, PMC *sc, PMC *string_heap, PMC *static_codes, STRING *data) {
+void Serialization_deserialize(PARROT_INTERP, PMC *sc, PMC *string_heap, PMC *static_codes, PMC *repo_conflicts, STRING *data) {
PMC *stables = PMCNULL;
PMC *objects = PMCNULL;
INTVAL scodes = VTABLE_elements(interp, static_codes);
@@ -1768,6 +1776,7 @@ void Serialization_deserialize(PARROT_INTERP, PMC *sc, PMC *string_heap, PMC *st
reader->stables_list = stables;
reader->objects_list = objects;
reader->contexts_list = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
+ reader->repo_conflicts_list = repo_conflicts;
reader->root.sc = sc;
reader->root.string_heap = string_heap;
reader->root.dependent_scs = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
@@ -62,6 +62,9 @@ typedef struct SerializationReader {
PMC *codes_list;
PMC *contexts_list;
+ /* The object repossession conflicts list. */
+ PMC *repo_conflicts_list;
+
/* Current offsets for the data chunks (also correspond to the amount of
* data written in to them). */
Parrot_Int4 stables_data_offset;
@@ -150,4 +153,4 @@ typedef struct SerializationWriter {
/* Core serialize and deserialize functions. */
STRING * Serialization_serialize(PARROT_INTERP, PMC *sc, PMC *empty_string_heap);
-void Serialization_deserialize(PARROT_INTERP, PMC *sc, PMC *string_heap, PMC *codes_static, STRING *data);
+void Serialization_deserialize(PARROT_INTERP, PMC *sc, PMC *string_heap, PMC *codes_static, PMC *repo_conflicts, STRING *data);
View
@@ -12,10 +12,14 @@ class QAST::CompUnit is QAST::Node {
# case, just before everything else in this compilation unit).
has @!pre_deserialize;
- # Taks we should run after deserialization (or, in the non-precompiled
+ # Tasks we should run after deserialization (or, in the non-precompiled
# case, right after the pre-deserialize tasks).
has @!post_deserialize;
+ # Call to the repossession conflict resolution mechanism, to be invoked
+ # on deserialization.
+ has $!repo_conflict_resolver;
+
# The HLL name.
has $!hll;
@@ -41,6 +45,9 @@ class QAST::CompUnit is QAST::Node {
@!post_deserialize := @value[0] if @value;
nqp::isnull(@!post_deserialize) ?? [] !! @!post_deserialize
}
+ method repo_conflict_resolver(*@value) {
+ @value ?? ($!repo_conflict_resolver := @value[0]) !! $!repo_conflict_resolver
+ }
method code_ref_blocks(*@value) {
$!code_ref_blocks := @value[0] if @value; $!code_ref_blocks
}
View
@@ -275,7 +275,8 @@ class QAST::Compiler is HLL::Compiler {
# If we need to do deserialization, emit code for that.
if $comp_mode {
- $block.push(self.deserialization_code($cu.sc(), $cu.code_ref_blocks()));
+ $block.push(self.deserialization_code($cu.sc(), $cu.code_ref_blocks(),
+ $cu.repo_conflict_resolver()));
}
# Add post-deserialization tasks.
@@ -306,7 +307,7 @@ class QAST::Compiler is HLL::Compiler {
$block_post
}
- method deserialization_code($sc, @code_ref_blocks) {
+ method deserialization_code($sc, @code_ref_blocks, $repo_conf_res) {
# Serialize it.
my $sh := pir::new__Ps('ResizableStringArray');
my $serialized := pir::nqp_serialize_sc__SPP($sc, $sh);
@@ -328,6 +329,17 @@ class QAST::Compiler is HLL::Compiler {
# Code references.
my $cr_past := QAST::Op.new( :op('list_b'), |@code_ref_blocks );
+ # Handle repossession conflict resolution code, if any.
+ if $repo_conf_res {
+ $repo_conf_res.push(QAST::Var.new( :name('conflicts'), :scope('local') ));
+ }
+ else {
+ $repo_conf_res := QAST::Op.new(
+ :op('die_s'),
+ QAST::SVal.new( :value('Repossession conflicts occurred during deserialization') )
+ );
+ }
+
# Overall deserialization QAST.
QAST::Stmt.new(
QAST::Op.new(
@@ -341,11 +353,22 @@ class QAST::Compiler is HLL::Compiler {
QAST::SVal.new( :value($sc.description) )
),
QAST::Op.new(
+ :op('bind'),
+ QAST::Var.new( :name('conflicts'), :scope('local'), :decl('var') ),
+ QAST::Op.new( :op('list') )
+ ),
+ QAST::Op.new(
:op('deserialize'),
QAST::SVal.new( :value($serialized) ),
QAST::Var.new( :name('cur_sc'), :scope('local') ),
$sh_ast,
- QAST::Block.new( :blocktype('immediate'), $cr_past )
+ QAST::Block.new( :blocktype('immediate'), $cr_past ),
+ QAST::Var.new( :name('conflicts'), :scope('local') )
+ ),
+ QAST::Op.new(
+ :op('if'),
+ QAST::Var.new( :name('conflicts'), :scope('local') ),
+ $repo_conf_res
)
)
}
View
@@ -1617,7 +1617,7 @@ QAST::Operations.add_core_pirop_mapping('setcodeobj', 'set_sub_code_object', '1P
# serialization context related opcodes
QAST::Operations.add_core_pirop_mapping('sha1', 'nqp_sha1', 'Ss');
QAST::Operations.add_core_pirop_mapping('createsc', 'nqp_create_sc', 'Ps');
-QAST::Operations.add_core_pirop_mapping('deserialize', 'nqp_deserialize_sc', 'vsPPP');
+QAST::Operations.add_core_pirop_mapping('deserialize', 'nqp_deserialize_sc', 'vsPPPP');
# process related opcodes
QAST::Operations.add_core_pirop_mapping('exit', 'exit', '0i', :inlinable(1));
View
@@ -2558,7 +2558,24 @@ the compilation unit's static code refs in the list in $4.
*/
inline op nqp_deserialize_sc(in STR, invar PMC, invar PMC, invar PMC) :base_core {
- Serialization_deserialize(interp, $2, $3, $4, $1);
+ PMC *conlist_throwaway = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
+ Serialization_deserialize(interp, $2, $3, $4, conlist_throwaway, $1);
+}
+
+/*
+
+=item nqp_deserialize_sc
+
+Deserializes the data in $1, populating the serialization context located in $2.
+Expects to find any required strings in the string heap, passed in $3, and any of
+the compilation unit's static code refs in the list in $4. $5 should be a list that
+will be populated with the object repossession conflict list.
+
+=cut
+
+*/
+inline op nqp_deserialize_sc(in STR, invar PMC, invar PMC, invar PMC, invar PMC) :base_core {
+ Serialization_deserialize(interp, $2, $3, $4, $5, $1);
}
/*

0 comments on commit 7a24af6

Please sign in to comment.