ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/State.xs
(Generate patch)

Comparing Coro/Coro/State.xs (file contents):
Revision 1.115 by root, Fri Dec 1 13:36:08 2006 UTC vs.
Revision 1.118 by root, Fri Dec 1 19:58:53 2006 UTC

130 int valgrind_id; 130 int valgrind_id;
131#endif 131#endif
132} coro_cctx; 132} coro_cctx;
133 133
134enum { 134enum {
135 CF_RUNNING, /* coroutine is running */ 135 CF_RUNNING = 0x0001, /* coroutine is running */
136 CF_READY, /* coroutine is ready */ 136 CF_READY = 0x0002, /* coroutine is ready */
137 CF_NEW = 0x0004, /* ahs never been switched to */
137}; 138};
138 139
139/* this is a structure representing a perl-level coroutine */ 140/* this is a structure representing a perl-level coroutine */
140struct coro { 141struct coro {
141 /* the c coroutine allocated to this perl coroutine, if any */ 142 /* the c coroutine allocated to this perl coroutine, if any */
280} 281}
281 282
282#define SB do { 283#define SB do {
283#define SE } while (0) 284#define SE } while (0)
284 285
285#define LOAD(state) load_state((state)); 286#define LOAD(state) load_state ((state))
286#define SAVE(state,flags) save_state((state),(flags)); 287#define SAVE(state,flags) save_state ((state),(flags))
287 288
288#define REPLACE_SV(sv,val) SB SvREFCNT_dec(sv); (sv) = (val); (val) = 0; SE 289#define REPLACE_SV(sv,val) SB SvREFCNT_dec (sv); (sv) = (val); (val) = 0; SE
289 290
290static void 291static void
291load_state(Coro__State c) 292load_state (Coro__State c)
292{ 293{
293#define VAR(name,type) PL_ ## name = c->name; 294#define VAR(name,type) PL_ ## name = c->name;
294# include "state.h" 295# include "state.h"
295#undef VAR 296#undef VAR
296 297
313 PUTBACK; 314 PUTBACK;
314 } 315 }
315} 316}
316 317
317static void 318static void
318save_state(Coro__State c, int flags) 319save_state (Coro__State c, int flags)
319{ 320{
320 { 321 {
321 dSP; 322 dSP;
322 I32 cxix = cxstack_ix; 323 I32 cxix = cxstack_ix;
323 PERL_CONTEXT *ccstk = cxstack; 324 PERL_CONTEXT *ccstk = cxstack;
334 { 335 {
335 while (cxix >= 0) 336 while (cxix >= 0)
336 { 337 {
337 PERL_CONTEXT *cx = &ccstk[cxix--]; 338 PERL_CONTEXT *cx = &ccstk[cxix--];
338 339
339 if (CxTYPE(cx) == CXt_SUB) 340 if (CxTYPE (cx) == CXt_SUB)
340 { 341 {
341 CV *cv = cx->blk_sub.cv; 342 CV *cv = cx->blk_sub.cv;
342 343
343 if (CvDEPTH (cv)) 344 if (CvDEPTH (cv))
344 { 345 {
345 EXTEND (SP, 3); 346 EXTEND (SP, 3);
346 347
347 PUSHs ((SV *)CvPADLIST(cv)); 348 PUSHs ((SV *)CvPADLIST (cv));
348 PUSHs (INT2PTR (SV *, CvDEPTH (cv))); 349 PUSHs (INT2PTR (SV *, CvDEPTH (cv)));
349 PUSHs ((SV *)cv); 350 PUSHs ((SV *)cv);
350 351
351 CvDEPTH (cv) = 0; 352 CvDEPTH (cv) = 0;
352 get_padlist (cv); 353 get_padlist (cv);
353 } 354 }
354 } 355 }
355#ifdef CXt_FORMAT 356#ifdef CXt_FORMAT
356 else if (CxTYPE(cx) == CXt_FORMAT) 357 else if (CxTYPE (cx) == CXt_FORMAT)
357 { 358 {
358 /* I never used formats, so how should I know how these are implemented? */ 359 /* I never used formats, so how should I know how these are implemented? */
359 /* my bold guess is as a simple, plain sub... */ 360 /* my bold guess is as a simple, plain sub... */
360 croak ("CXt_FORMAT not yet handled. Don't switch coroutines from within formats"); 361 croak ("CXt_FORMAT not yet handled. Don't switch coroutines from within formats");
361 } 362 }
389 * not usually need a lot of stackspace. 390 * not usually need a lot of stackspace.
390 */ 391 */
391static void 392static void
392coro_init_stacks () 393coro_init_stacks ()
393{ 394{
394 PL_curstackinfo = new_stackinfo(96, 1024/sizeof(PERL_CONTEXT) - 1); 395 PL_curstackinfo = new_stackinfo(128, 1024/sizeof(PERL_CONTEXT));
395 PL_curstackinfo->si_type = PERLSI_MAIN; 396 PL_curstackinfo->si_type = PERLSI_MAIN;
396 PL_curstack = PL_curstackinfo->si_stack; 397 PL_curstack = PL_curstackinfo->si_stack;
397 PL_mainstack = PL_curstack; /* remember in case we switch stacks */ 398 PL_mainstack = PL_curstack; /* remember in case we switch stacks */
398 399
399 PL_stack_base = AvARRAY(PL_curstack); 400 PL_stack_base = AvARRAY(PL_curstack);
400 PL_stack_sp = PL_stack_base; 401 PL_stack_sp = PL_stack_base;
401 PL_stack_max = PL_stack_base + AvMAX(PL_curstack); 402 PL_stack_max = PL_stack_base + AvMAX(PL_curstack);
402 403
403 New(50,PL_tmps_stack,96,SV*); 404 New(50,PL_tmps_stack,128,SV*);
404 PL_tmps_floor = -1; 405 PL_tmps_floor = -1;
405 PL_tmps_ix = -1; 406 PL_tmps_ix = -1;
406 PL_tmps_max = 96; 407 PL_tmps_max = 128;
407 408
408 New(54,PL_markstack,16,I32); 409 New(54,PL_markstack,32,I32);
409 PL_markstack_ptr = PL_markstack; 410 PL_markstack_ptr = PL_markstack;
410 PL_markstack_max = PL_markstack + 16; 411 PL_markstack_max = PL_markstack + 32;
411 412
412#ifdef SET_MARK_OFFSET 413#ifdef SET_MARK_OFFSET
413 SET_MARK_OFFSET; 414 SET_MARK_OFFSET;
414#endif 415#endif
415 416
416 New(54,PL_scopestack,16,I32); 417 New(54,PL_scopestack,32,I32);
417 PL_scopestack_ix = 0; 418 PL_scopestack_ix = 0;
418 PL_scopestack_max = 16; 419 PL_scopestack_max = 32;
419 420
420 New(54,PL_savestack,96,ANY); 421 New(54,PL_savestack,64,ANY);
421 PL_savestack_ix = 0; 422 PL_savestack_ix = 0;
422 PL_savestack_max = 96; 423 PL_savestack_max = 64;
423 424
424#if !PERL_VERSION_ATLEAST (5,9,0) 425#if !PERL_VERSION_ATLEAST (5,9,0)
425 New(54,PL_retstack,8,OP*); 426 New(54,PL_retstack,16,OP*);
426 PL_retstack_ix = 0; 427 PL_retstack_ix = 0;
427 PL_retstack_max = 8; 428 PL_retstack_max = 16;
428#endif 429#endif
429} 430}
430 431
431/* 432/*
432 * destroy the stacks, the callchain etc... 433 * destroy the stacks, the callchain etc...
485 * emulate part of the perl startup here. 486 * emulate part of the perl startup here.
486 */ 487 */
487 488
488 coro_init_stacks (); 489 coro_init_stacks ();
489 490
490 PL_curcop = 0; 491 PL_curcop = &PL_compiling;
491 PL_in_eval = 0; 492 PL_in_eval = EVAL_NULL;
492 PL_curpm = 0; 493 PL_curpm = 0;
494 PL_localizing = 0;
495 PL_dirty = 0;
496 PL_restartop = 0;
493 497
494 { 498 {
495 dSP; 499 dSP;
496 LOGOP myop; 500 LOGOP myop;
497 501
510 PUSHMARK (SP); 514 PUSHMARK (SP);
511 XPUSHs ((SV *)get_cv ("Coro::State::_coro_init", FALSE)); 515 XPUSHs ((SV *)get_cv ("Coro::State::_coro_init", FALSE));
512 PUTBACK; 516 PUTBACK;
513 PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); 517 PL_op = PL_ppaddr[OP_ENTERSUB](aTHX);
514 SPAGAIN; 518 SPAGAIN;
515
516 ENTER; /* necessary e.g. for dounwind */
517 } 519 }
520
521 ENTER; /* necessary e.g. for dounwind */
518} 522}
519 523
520static void 524static void
521free_coro_mortal () 525free_coro_mortal ()
522{ 526{
688 ((coro_cctx *)prev)->idle_sp = STACKLEVEL; 692 ((coro_cctx *)prev)->idle_sp = STACKLEVEL;
689 else if (prev != next) 693 else if (prev != next)
690 { 694 {
691 coro_cctx *prev__cctx; 695 coro_cctx *prev__cctx;
692 696
693 if (!prev->cctx) 697 if (prev->flags & CF_NEW)
694 { 698 {
695 /* create a new empty context */ 699 /* create a new empty context */
696 Newz (0, prev->cctx, 1, coro_cctx); 700 Newz (0, prev->cctx, 1, coro_cctx);
697 prev->cctx->inuse = 1; 701 prev->cctx->inuse = 1;
702 prev->flags &= ~CF_NEW;
698 prev->flags |= CF_RUNNING; 703 prev->flags |= CF_RUNNING;
699 } 704 }
700 705
706 /*TODO: must not croak here */
701 if (!prev->flags & CF_RUNNING) 707 if (!prev->flags & CF_RUNNING)
702 croak ("Coro::State::transfer called with non-running prev Coro::State, but can only transfer from running states"); 708 croak ("Coro::State::transfer called with non-running prev Coro::State, but can only transfer from running states");
703 709
704 if (next->flags & CF_RUNNING) 710 if (next->flags & CF_RUNNING)
705 croak ("Coro::State::transfer called with running next Coro::State, but can only transfer to inactive states"); 711 croak ("Coro::State::transfer called with running next Coro::State, but can only transfer to inactive states");
707 prev->flags &= ~CF_RUNNING; 713 prev->flags &= ~CF_RUNNING;
708 next->flags |= CF_RUNNING; 714 next->flags |= CF_RUNNING;
709 715
710 LOCK; 716 LOCK;
711 717
712 if (next->mainstack) 718 if (next->flags & CF_NEW)
713 {
714 /* coroutine already started */
715 SAVE (prev, flags);
716 LOAD (next);
717 }
718 else
719 { 719 {
720 /* need to start coroutine */ 720 /* need to start coroutine */
721 next->flags &= ~CF_NEW;
721 /* first get rid of the old state */ 722 /* first get rid of the old state */
722 SAVE (prev, -1); 723 SAVE (prev, -1);
723 /* setup coroutine call */ 724 /* setup coroutine call */
724 setup_coro (next); 725 setup_coro (next);
725 /* need a new stack */ 726 /* need a new stack */
726 assert (!next->stack); 727 assert (!next->stack);
727 } 728 }
729 else
730 {
731 /* coroutine already started */
732 SAVE (prev, flags);
733 LOAD (next);
734 }
728 735
729 prev__cctx = prev->cctx; 736 prev__cctx = prev->cctx;
730 737
731 /* possibly "free" the cctx */ 738 /* possibly "free" the cctx */
732 if (prev__cctx->idle_sp == STACKLEVEL) 739 if (prev__cctx->idle_sp == STACKLEVEL && 0)
733 { 740 {
734 /* I assume that STACKLEVEL is a stronger indicator than PL_top_env changes */ 741 /* I assume that STACKLEVEL is a stronger indicator than PL_top_env changes */
735 assert (PL_top_env == prev__cctx->top_env); 742 assert (PL_top_env == prev__cctx->top_env);
736 743
744 prev->cctx = 0;
745
737 cctx_put (prev__cctx); 746 cctx_put (prev__cctx);
738 prev->cctx = 0; 747 prev__cctx->inuse = 0;
739 } 748 }
740 749
741 if (!next->cctx) 750 if (!next->cctx)
751 {
742 next->cctx = cctx_get (); 752 next->cctx = cctx_get ();
753 assert (!next->cctx->inuse);
754 next->cctx->inuse = 1;
755 }
743 756
744 if (prev__cctx != next->cctx) 757 if (prev__cctx != next->cctx)
745 { 758 {
746 assert ( prev__cctx->inuse);
747 assert (!next->cctx->inuse);
748
749 prev__cctx->inuse = 0;
750 next->cctx->inuse = 1;
751
752 prev__cctx->top_env = PL_top_env; 759 prev__cctx->top_env = PL_top_env;
753 PL_top_env = next->cctx->top_env; 760 PL_top_env = next->cctx->top_env;
754 coro_transfer (&prev__cctx->cctx, &next->cctx->cctx); 761 coro_transfer (&prev__cctx->cctx, &next->cctx->cctx);
755 } 762 }
756 763
772coro_state_destroy (struct coro *coro) 779coro_state_destroy (struct coro *coro)
773{ 780{
774 if (coro->refcnt--) 781 if (coro->refcnt--)
775 return; 782 return;
776 783
777 if (coro->flags & CF_RUNNING)
778 croak ("FATAL: tried to destroy currently running coroutine");
779
780 if (coro->mainstack && coro->mainstack != main_mainstack) 784 if (coro->mainstack && coro->mainstack != main_mainstack)
781 { 785 {
782 struct coro temp; 786 struct coro temp;
787
788 if (coro->flags & CF_RUNNING)
789 croak ("FATAL: tried to destroy currently running coroutine");
783 790
784 SAVE ((&temp), TRANSFER_SAVE_ALL); 791 SAVE ((&temp), TRANSFER_SAVE_ALL);
785 LOAD (coro); 792 LOAD (coro);
786 793
787 coro_destroy_stacks (); 794 coro_destroy_stacks ();
859} 866}
860 867
861static void 868static void
862api_transfer (SV *prev, SV *next, int flags) 869api_transfer (SV *prev, SV *next, int flags)
863{ 870{
864 dTHX;
865 struct transfer_args ta; 871 struct transfer_args ta;
866 872
867 prepare_transfer (&ta, prev, next, flags); 873 prepare_transfer (&ta, prev, next, flags);
868 TRANSFER (ta); 874 TRANSFER (ta);
869} 875}
876#define PRIO_LOW -1 882#define PRIO_LOW -1
877#define PRIO_IDLE -3 883#define PRIO_IDLE -3
878#define PRIO_MIN -4 884#define PRIO_MIN -4
879 885
880/* for Coro.pm */ 886/* for Coro.pm */
881static GV *coro_current, *coro_idle; 887static SV *coro_current;
882static AV *coro_ready [PRIO_MAX-PRIO_MIN+1]; 888static AV *coro_ready [PRIO_MAX-PRIO_MIN+1];
883static int coro_nready; 889static int coro_nready;
884 890
885static void 891static void
886coro_enq (SV *coro_sv) 892coro_enq (SV *coro_sv)
919 coro = SvSTATE (coro_sv); 925 coro = SvSTATE (coro_sv);
920 926
921 if (coro->flags & CF_READY) 927 if (coro->flags & CF_READY)
922 return 0; 928 return 0;
923 929
930#if 0 /* this is actually harmless */
924 if (coro->flags & CF_RUNNING) 931 if (coro->flags & CF_RUNNING)
925 croak ("Coro::ready called on currently running coroutine"); 932 croak ("Coro::ready called on currently running coroutine");
933#endif
926 934
927 coro->flags |= CF_READY; 935 coro->flags |= CF_READY;
928 936
929 LOCK; 937 LOCK;
930 coro_enq (SvREFCNT_inc (coro_sv)); 938 coro_enq (SvREFCNT_inc (coro_sv));
940} 948}
941 949
942static void 950static void
943prepare_schedule (struct transfer_args *ta) 951prepare_schedule (struct transfer_args *ta)
944{ 952{
945 SV *current, *prev, *next; 953 SV *prev, *next;
946
947 current = GvSV (coro_current);
948 954
949 for (;;) 955 for (;;)
950 { 956 {
951 LOCK; 957 LOCK;
952 next = coro_deq (PRIO_MIN); 958 next = coro_deq (PRIO_MIN);
961 ENTER; 967 ENTER;
962 SAVETMPS; 968 SAVETMPS;
963 969
964 PUSHMARK (SP); 970 PUSHMARK (SP);
965 PUTBACK; 971 PUTBACK;
966 call_sv (GvSV (coro_idle), G_DISCARD); 972 call_sv (get_sv ("Coro::idle", FALSE), G_DISCARD);
967 973
968 FREETMPS; 974 FREETMPS;
969 LEAVE; 975 LEAVE;
970 } 976 }
971 } 977 }
972 978
973 prev = SvRV (current); 979 prev = SvRV (coro_current);
974 SvRV (current) = next; 980 SvRV_set (coro_current, next);
975 981
976 /* free this only after the transfer */ 982 /* free this only after the transfer */
977 LOCK; 983 LOCK;
978 free_coro_mortal (); 984 free_coro_mortal ();
979 UNLOCK; 985 UNLOCK;
980 coro_mortal = prev; 986 coro_mortal = prev;
981 987
988 assert (!SvROK(prev));//D
989 assert (!SvROK(next));//D
990
982 ta->prev = SvSTATE (prev); 991 ta->prev = SvSTATE (prev);
983 ta->next = SvSTATE (next); 992 ta->next = SvSTATE (next);
984 ta->flags = TRANSFER_SAVE_ALL; 993 ta->flags = TRANSFER_SAVE_ALL;
985 994
995 assert (ta->flags & CF_READY);
986 ta->next->flags &= ~CF_READY; 996 ta->next->flags &= ~CF_READY;
987} 997}
988 998
989static void 999static void
990prepare_cede (struct transfer_args *ta) 1000prepare_cede (struct transfer_args *ta)
991{ 1001{
992 api_ready (GvSV (coro_current)); 1002 api_ready (coro_current);
993 1003
994 prepare_schedule (ta); 1004 prepare_schedule (ta);
995} 1005}
996 1006
997static void 1007static void
998api_schedule (void) 1008api_schedule (void)
999{ 1009{
1000 dTHX;
1001 struct transfer_args ta; 1010 struct transfer_args ta;
1002 1011
1003 prepare_schedule (&ta); 1012 prepare_schedule (&ta);
1004 TRANSFER (ta); 1013 TRANSFER (ta);
1005} 1014}
1006 1015
1007static void 1016static void
1008api_cede (void) 1017api_cede (void)
1009{ 1018{
1010 dTHX;
1011 struct transfer_args ta; 1019 struct transfer_args ta;
1012 1020
1013 prepare_cede (&ta); 1021 prepare_cede (&ta);
1014 TRANSFER (ta); 1022 TRANSFER (ta);
1015} 1023}
1047 HV *hv; 1055 HV *hv;
1048 int i; 1056 int i;
1049 1057
1050 Newz (0, coro, 1, struct coro); 1058 Newz (0, coro, 1, struct coro);
1051 coro->args = newAV (); 1059 coro->args = newAV ();
1060 coro->flags = CF_NEW;
1052 1061
1053 hv = newHV (); 1062 hv = newHV ();
1054 sv_magicext ((SV *)hv, 0, PERL_MAGIC_ext, &coro_state_vtbl, (char *)coro, 0)->mg_flags |= MGf_DUP; 1063 sv_magicext ((SV *)hv, 0, PERL_MAGIC_ext, &coro_state_vtbl, (char *)coro, 0)->mg_flags |= MGf_DUP;
1055 RETVAL = sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1)); 1064 RETVAL = sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1));
1056 1065
1064_set_stacklevel (...) 1073_set_stacklevel (...)
1065 ALIAS: 1074 ALIAS:
1066 Coro::State::transfer = 1 1075 Coro::State::transfer = 1
1067 Coro::schedule = 2 1076 Coro::schedule = 2
1068 Coro::cede = 3 1077 Coro::cede = 3
1069 Coro::Cont::yield = 4
1070 CODE: 1078 CODE:
1071{ 1079{
1072 struct transfer_args ta; 1080 struct transfer_args ta;
1073 1081
1074 switch (ix) 1082 switch (ix)
1079 ta.flags = TRANSFER_SET_STACKLEVEL; 1087 ta.flags = TRANSFER_SET_STACKLEVEL;
1080 break; 1088 break;
1081 1089
1082 case 1: 1090 case 1:
1083 if (items != 3) 1091 if (items != 3)
1084 croak ("Coro::State::transfer(prev,next,flags) expects three arguments, not %d", items); 1092 croak ("Coro::State::transfer (prev,next,flags) expects three arguments, not %d", items);
1085 1093
1086 prepare_transfer (&ta, ST (0), ST (1), SvIV (ST (2))); 1094 prepare_transfer (&ta, ST (0), ST (1), SvIV (ST (2)));
1087 break; 1095 break;
1088 1096
1089 case 2: 1097 case 2:
1091 break; 1099 break;
1092 1100
1093 case 3: 1101 case 3:
1094 prepare_cede (&ta); 1102 prepare_cede (&ta);
1095 break; 1103 break;
1096
1097 case 4:
1098 {
1099 SV *yieldstack;
1100 SV *sv;
1101 AV *defav = GvAV (PL_defgv);
1102
1103 yieldstack = *hv_fetch (
1104 (HV *)SvRV (GvSV (coro_current)),
1105 "yieldstack", sizeof ("yieldstack") - 1,
1106 0
1107 );
1108
1109 /* set up @_ -- ugly */
1110 av_clear (defav);
1111 av_fill (defav, items - 1);
1112 while (items--)
1113 av_store (defav, items, SvREFCNT_inc (ST(items)));
1114
1115 sv = av_pop ((AV *)SvRV (yieldstack));
1116 ta.prev = SvSTATE (*av_fetch ((AV *)SvRV (sv), 0, 0));
1117 ta.next = SvSTATE (*av_fetch ((AV *)SvRV (sv), 1, 0));
1118 ta.flags = 0;
1119 SvREFCNT_dec (sv);
1120 }
1121 break;
1122
1123 } 1104 }
1124 1105
1125 TRANSFER (ta); 1106 TRANSFER (ta);
1126} 1107}
1127 1108
1171 newCONSTSUB (coro_stash, "PRIO_NORMAL", newSViv (PRIO_NORMAL)); 1152 newCONSTSUB (coro_stash, "PRIO_NORMAL", newSViv (PRIO_NORMAL));
1172 newCONSTSUB (coro_stash, "PRIO_LOW", newSViv (PRIO_LOW)); 1153 newCONSTSUB (coro_stash, "PRIO_LOW", newSViv (PRIO_LOW));
1173 newCONSTSUB (coro_stash, "PRIO_IDLE", newSViv (PRIO_IDLE)); 1154 newCONSTSUB (coro_stash, "PRIO_IDLE", newSViv (PRIO_IDLE));
1174 newCONSTSUB (coro_stash, "PRIO_MIN", newSViv (PRIO_MIN)); 1155 newCONSTSUB (coro_stash, "PRIO_MIN", newSViv (PRIO_MIN));
1175 1156
1176 coro_current = gv_fetchpv ("Coro::current", TRUE, SVt_PV); 1157 coro_current = get_sv ("Coro::current", FALSE);
1177 coro_idle = gv_fetchpv ("Coro::idle" , TRUE, SVt_PV); 1158 SvREADONLY_on (coro_current);
1178 1159
1179 for (i = PRIO_MAX - PRIO_MIN + 1; i--; ) 1160 for (i = PRIO_MAX - PRIO_MIN + 1; i--; )
1180 coro_ready[i] = newAV (); 1161 coro_ready[i] = newAV ();
1181 1162
1182 { 1163 {
1237 CODE: 1218 CODE:
1238 RETVAL = coro_nready; 1219 RETVAL = coro_nready;
1239 OUTPUT: 1220 OUTPUT:
1240 RETVAL 1221 RETVAL
1241 1222
1223void
1224_set_current (SV *current)
1225 PROTOTYPE: $
1226 CODE:
1227 SvREFCNT_dec (SvRV (coro_current));
1228 SvRV_set (coro_current, SvREFCNT_inc (SvRV (current)));
1229
1242MODULE = Coro::State PACKAGE = Coro::AIO 1230MODULE = Coro::State PACKAGE = Coro::AIO
1243 1231
1244SV * 1232SV *
1245_get_state () 1233_get_state ()
1246 CODE: 1234 CODE:

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines