-#define FORCE_SETs(sv) STMT_START { sv_setsv(TARG, (sv)); SETTARG; } STMT_END
-
-#define tryAMAGICun(meth) tryAMAGICunW(meth,SETsvUN,0,RETURN)
-#define tryAMAGICunSET(meth) tryAMAGICunW(meth,SETs,0,RETURN)
-#define tryAMAGICunTARGET(meth, shift) \
- STMT_START { dSP; sp--; /* get TARGET from below PL_stack_sp */ \
- { dTARGETSTACKED; \
- { dSP; tryAMAGICunW(meth,FORCE_SETs,shift,RETURN);}}} STMT_END
-
-#define setAGAIN(ref) \
- STMT_START { \
- sv = ref; \
- if (!SvROK(ref)) \
- Perl_croak(aTHX_ "Overloaded dereference did not return a reference"); \
- if (ref != arg && SvRV(ref) != SvRV(arg)) { \
- arg = ref; \
- goto am_again; \
- } \
+#define tryAMAGICun_MG(method, flags) STMT_START { \
+ if ( (SvFLAGS(TOPs) & (SVf_ROK|SVs_GMG)) \
+ && Perl_try_amagic_un(aTHX_ method, flags)) \
+ return NORMAL; \
+ } STMT_END
+#define tryAMAGICbin_MG(method, flags) STMT_START { \
+ if ( ((SvFLAGS(TOPm1s)|SvFLAGS(TOPs)) & (SVf_ROK|SVs_GMG)) \
+ && Perl_try_amagic_bin(aTHX_ method, flags)) \
+ return NORMAL; \
+ } STMT_END
+
+#define AMG_CALLunary(sv,meth) \
+ amagic_call(sv,&PL_sv_undef, meth, AMGf_noright | AMGf_unary)
+
+/* No longer used in core. Use AMG_CALLunary instead */
+#define AMG_CALLun(sv,meth) AMG_CALLunary(sv, CAT2(meth,_amg))
+
+#define tryAMAGICunTARGET(meth, shift, jump) \
+ tryAMAGICunTARGET_flags(meth, shift, jump, 0)
+#define tryAMAGICunTARGETlist(meth, shift, jump) \
+ tryAMAGICunTARGET_flags(meth, shift, jump, AMGf_want_list)
+#define tryAMAGICunTARGET_flags(meth, shift, jump, flags) \
+ STMT_START { \
+ dSP; \
+ SV *tmpsv; \
+ SV *arg= sp[shift]; \
+ int gimme = GIMME_V; \
+ if (SvAMAGIC(arg) && \
+ (tmpsv = amagic_call(arg, &PL_sv_undef, meth, \
+ flags | AMGf_noright | AMGf_unary))) { \
+ SPAGAIN; \
+ sp += shift; \
+ if (gimme == G_VOID) { \
+ (void)POPs; /* XXX ??? */ \
+ } \
+ else if ((flags & AMGf_want_list) && gimme == G_ARRAY) { \
+ int i; \
+ I32 len; \
+ assert(SvTYPE(tmpsv) == SVt_PVAV); \
+ len = av_len((AV *)tmpsv) + 1; \
+ (void)POPs; /* get rid of the arg */ \
+ EXTEND(sp, len); \
+ for (i = 0; i < len; ++i) \
+ PUSHs(av_shift((AV *)tmpsv)); \
+ } \
+ else { /* AMGf_want_scalar */ \
+ dATARGET; /* just use the arg's location */ \
+ sv_setsv(TARG, tmpsv); \
+ if (opASSIGN) \
+ sp--; \
+ SETTARG; \
+ } \
+ PUTBACK; \
+ if (jump) { \
+ OP *jump_o = NORMAL->op_next; \
+ while (jump_o->op_type == OP_NULL) \
+ jump_o = jump_o->op_next; \
+ assert(jump_o->op_type == OP_ENTERSUB); \
+ PL_markstack_ptr--; \
+ return jump_o->op_next; \
+ } \
+ return NORMAL; \
+ } \
+ } STMT_END
+
+/* This is no longer used anywhere in the core. You might wish to consider
+ calling amagic_deref_call() directly, as it has a cleaner interface. */
+#define tryAMAGICunDEREF(meth) \
+ STMT_START { \
+ sv = amagic_deref_call(*sp, CAT2(meth,_amg)); \
+ SPAGAIN; \