diff options
| author | Cliff Click <cliffc@acm.org> | 2025-04-13 19:51:04 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2025-04-13 19:51:04 -0700 |
| commit | 40a6f7b90e9e5d42bdacabb1c9e93fab5d27f63d (patch) | |
| tree | 93d563ab5134dc23b2e08f712bb9f1d78501020d | |
| parent | 450dd5169ebbfd8664d073b0d8baea201dae0ed2 (diff) | |
| download | Simple-40a6f7b90e9e5d42bdacabb1c9e93fab5d27f63d.tar.gz Simple-40a6f7b90e9e5d42bdacabb1c9e93fab5d27f63d.zip | |
EvalRISC5 handles calloc
Patch calls to calloc with a sentinel; emulator spots call to sentinel and mimics calloc on the internal heap.
7 files changed, 123 insertions, 326 deletions
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java index fb46a6a2..8f0a97c8 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java @@ -343,25 +343,19 @@ public class CodeGen { // --------------------------- // Encoding public int _tEncode; - public boolean _JIT; - public Encoding _encoding; - public void preEncode() { } // overridden by M2 + public Encoding _encoding; // Encoding object + public void preEncode() { } // overridden by alternative ports public CodeGen encode(boolean jit) { assert _phase == Phase.RegAlloc; _phase = Phase.Encoding; long t0 = System.currentTimeMillis(); _encoding = new Encoding(this); - _JIT = jit; preEncode(); - _encoding.encode(); + _encoding.encode(jit); _tEncode = (int)(System.currentTimeMillis() - t0); return this; } - public CodeGen encode() { - return encode(false); - } - // Encoded binary, no relocation info - public byte[] binary() { return _encoding.bits(); } + public CodeGen encode() { return encode(false); } // --------------------------- // Exporting to external formats diff --git a/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java index 48b9ea5f..74c128be 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java @@ -153,7 +153,7 @@ public class Encoding { _bigCons.put(relo,new Relo(relo,t,(byte)off,(byte)elf)); } - void encode() { + void encode(boolean jit) { // Basic block layout: invert branches to keep blocks in-order; insert // unconditional jumps. Attempt to keep backwards branches taken, // forwards not-taken (this is the default prediction on most @@ -171,6 +171,9 @@ public class Encoding { // Patch RIP-relative and local encodings now. patchLocalRelocations(); + // If JIT'ing (in memory execution), patch the global relocations now + if( jit ) + patchGlobalRelocations(); } // Basic block layout: invert branches to keep blocks in-order; insert @@ -416,9 +419,26 @@ public class Encoding { void patchLocalRelocations() { // Walk the local code-address relocations for( Node src : _internals.keySet() ) { + int start = _opStart[src._nid]; Node dst = _internals.get(src); int target = _opStart[dst._nid]; + ((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start); + } + } + + // A series of libc/external calls that Simple can link against in a JIT. + // Since no runtime in the JVM process, using magic numbers for the CPU + // emulators to pick up on. + public static int SENTINAL_CALLOC = -2; + + void patchGlobalRelocations() { + for( Node src : _externals.keySet() ) { int start = _opStart[src._nid]; + String dst = _externals.get(src); + int target = switch( dst ) { + case "calloc" -> SENTINAL_CALLOC; + default -> throw Utils.TODO(); + }; ((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start); } } diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java index dfa40cad..0ca76d3f 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java @@ -5,14 +5,12 @@ import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.print.ASMPrinter; -public class NewRISC extends NewNode implements MachNode { +public class NewRISC extends NewNode implements MachNode, RIPRelSize { // A pre-zeroed chunk of memory. NewRISC( NewNode nnn ) { super(nnn); } @Override public String op() { return "alloc"; } - @Override public RegMask regmap(int i) { - return i==1 ? riscv.A0_MASK : null; // Size input or mem aliases - } - @Override public RegMask outregmap(int i) { return i == 1 ? riscv.A0_MASK : null; } + @Override public RegMask regmap(int i) { return i==1 ? riscv.A1_MASK : null; } + @Override public RegMask outregmap(int i) { return i==1 ? riscv.A0_MASK : null; } @Override public RegMask outregmap() { return null; } @Override public RegMask killmap() { return riscv.riscCallerSave(); } @@ -21,13 +19,36 @@ public class NewRISC extends NewNode implements MachNode { enc.external(this,"calloc"); // A1 is a caller-save, allowed to crush building external address // auipc - enc.add4(riscv.u_type(riscv.OP_AUIPC, riscv.A1, 0)); - enc.add4(riscv.i_type(riscv.OP_JALR, riscv.RPC, 0, riscv.A1, 0)); + enc.add4(riscv.i_type(riscv.OP_IMM , riscv.A0 , 0, riscv.ZERO, 1)); + enc.add4(riscv.u_type(riscv.OP_AUIPC, riscv.A2 , 0)); + enc.add4(riscv.i_type(riscv.OP_JALR , riscv.RPC, 0, riscv.A2, 0)); + } + + // Patch is for running "new" in a JIT. + // Delta is from opcode start + @Override public byte encSize(int delta) { return 4*3; } + + // Patch is for running "new" in a JIT. + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + // Odd-number patches are JIT emulator targets. + if( (delta&3)!=0 ) { + //enc.patch4(opStart+4, riscv.i_type(riscv.OP_IMM, riscv.ZERO , 0, riscv.ZERO, 0)); + //enc.patch4(opStart,riscv.j_type(riscv.OP_JAL, riscv.RPC, opStart+delta)); + + int imm20 = delta>>12; + if( ((delta>>11)&1)==1 ) imm20++; // Correct accidental sign extension + int imm12 = delta&0xFFF; + enc.patch4(opStart+4,riscv.u_type(riscv.OP_AUIPC, riscv.A2 , imm20)); + enc.patch4(opStart+8,riscv.i_type(riscv.OP_JALR , riscv.RPC, 0, riscv.A2, imm12)); + } else + throw Utils.TODO(); } // General form: "alloc #bytes PC" @Override public void asm(CodeGen code, SB sb) { - sb.p("auipc a1=#calloc\n"); - sb.p("call a1+#calloc, a0"); + sb.p("ldi a1=#1\n"); + sb.p("auipc a2=#calloc\n"); + sb.p("call a2+#calloc, a0"); } } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java index bd3783ed..d67bd43d 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java @@ -98,8 +98,27 @@ public class Chapter21Test { @Test public void testStringExport() throws IOException { TestC.run("stringHash"); } @Test public void testSieve() throws IOException { - String primes = "25[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, ]"; - TestC.run("sieve",primes); + // The primes + int[] primes = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, }; + SB sb = new SB().p(primes.length).p("["); + for( int prime : primes ) + sb.p(prime).p(", "); + String sprimes = sb.p("]").toString(); + + // Compile, link against native C; expect the above string of primes to be printed out by C + TestC.run("sieve",sprimes); + + // Evaluate on RISC5 emulator; expect return of a array of primes in + // the simulated heap. + EvalRisc5 R5 = TestRisc5.build("sieve", 100); + int trap = R5.step(10000); + assertEquals(0,trap); + // Return register A0 holds sieve(100) + int ary = (int)R5.regs[riscv.A0]; + // Memory layout starting at ary(length,pad, prime1, primt2, prime3, prime4) + assertEquals(primes.length, R5.ld4s(ary)); + for( int i=0; i<primes.length; i++ ) + assertEquals(primes[i], R5.ld4s(ary + 4 + i*4)); } @Test public void testFibExport() throws IOException { diff --git a/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java b/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java index cb5417d8..eed596e8 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java @@ -8,23 +8,34 @@ * Load code into memory and go! */ -public class EvalRisc5 { +import com.seaofnodes.simple.codegen.Encoding; + +import java.util.Arrays; + + public class EvalRisc5 { // Memory image, always 0-based public final byte[] _buf; - EvalRisc5( byte[] buf ) { _buf=buf; } + // GPRs + final long[] regs; + + // PC + int _pc; - //#ifndef MINIRV32_CUSTOM_MEMORY_BUS - // #define MINIRV32_STORE4( ofs, val ) *(int*)(_buf + ofs) = val - // #define MINIRV32_STORE2( ofs, val ) *(uint16_t*)(_buf + ofs) = val - // #define MINIRV32_STORE1( ofs, val ) *(uint8_t*)(_buf + ofs) = val - // #define MINIRV32_LOAD4( ofs ) *(int*)(_buf + ofs) - // #define MINIRV32_LOAD2( ofs ) *(uint16_t*)(_buf + ofs) - // #define MINIRV32_LOAD1( ofs ) *(uint8_t*)(_buf + ofs) - // #define MINIRV32_LOAD2_SIGNED( ofs ) *(int16_t*)(_buf + ofs) - // #define MINIRV32_LOAD1_SIGNED( ofs ) *(int8_t*)(_buf + ofs) - //#endif + // Start of free memory for allocation + int _heap; + + // Cycle counters + int _cycle; + + EvalRisc5( byte[] buf, int stackSize ) { + _buf = buf; + regs = new long[32]; + // Stack grows down, heap grows up + regs[2/*RSP*/] = _heap = stackSize; + _pc = 0; + } // Little endian public int ld1s(int x) { return _buf[x ] ; } @@ -39,16 +50,6 @@ public class EvalRisc5 { public void st4(int x, int val) { st2(x,val); st2(x+2,val>>16); } public void st8(int x, long val) { st4(x,(int)val); st2(x+4,(int)(val>>32)); } - - // GPRs - final long[] regs = new long[32]; - - // PC - int _pc; - - // Cycle counters - int _cycle; - // Note: only a few bits are used. (Machine = 3, User = 0) // Bits 0..1 = privilege. // Bit 2 = WFI (Wait for interrupt) @@ -76,6 +77,7 @@ public class EvalRisc5 { break; } + // Load instruction from image buffer at PC ir = ld4s( pc ); int rdid = (ir >> 7) & 0x1f; @@ -95,14 +97,24 @@ public class EvalRisc5 { } case 0x67: { // JALR (0b1100111) int imm = ir >> 20; + int imm_se = imm | (( (imm & 0x800)!=0 ) ? 0xfffff000 : 0); rval = pc + 4; pc = ( ((int)regs[ (ir >> 15) & 0x1f ] + imm_se) & ~1) - 4; // Return from top-level ; exit sim if( pc+4==0 ) { - if( rdid!=0 ) regs[rdid] = rval; + if( rdid!=0 ) regs[rdid] = rval; // Write PC into register before exit break outer; } + // Inline CALLOC effect + if( pc == Encoding.SENTINAL_CALLOC ) { + int size = (int)(regs[10]*regs[11]); + regs[10] = _heap; // Return next free address + // Pre-zeroed; epsilon (null) collector, never recycles memory so always zero + // Arrays.fill(_buf,_heap,_heap+size, (byte) 0 ); + _heap += size; + pc = (int)(rval - 4); // Unwind PC, as-if returned from calloc + } break; } case 0x63: { // Branch (0b1100011) @@ -142,6 +154,7 @@ public class EvalRisc5 { case 3: rval = ld8 ( rsval ); break; case 4: rval = ld1z( rsval ); break; case 5: rval = ld2z( rsval ); break; + case 6: rval = ld4s( rsval ); break; default: trap = (2+1); } } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java b/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java index 9c64fe9f..8b9b8884 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java @@ -18,17 +18,13 @@ public abstract class TestRisc5 { public static EvalRisc5 build( String dir, String file, int arg ) throws IOException { // Compile and export Simple String src = Files.readString(Path.of(dir+"/"+file+".smp")); - CodeGen code = new CodeGen(src).driver(CodeGen.Phase.Encoding,"riscv", "SystemV"); + CodeGen code = new CodeGen(src).driver(CodeGen.Phase.RegAlloc,"riscv", "SystemV").encode(true); // Image - byte[] image = new byte[1<<20]; // A megabyte - EvalRisc5 R5 = new EvalRisc5(image); + byte[] image = new byte[1<<20]; // A megabyte (1024*1024 bytes) + EvalRisc5 R5 = new EvalRisc5(image, 1<<16); // Code at offset 0 System.arraycopy(code._encoding.bits(), 0, image, 0, code._encoding.bits().length); - // Program start - R5._pc = 0; - // Stack starts at 64K and goes down (runs into code) - R5.regs[riscv.SP] = 1<<16; // Initial incoming int arg R5.regs[riscv.A0] = arg; // malloc memory starts at 64K and goes up diff --git a/chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp b/chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp index c1c50c03..3d01f80f 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp +++ b/chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp @@ -1,277 +1,11 @@ // -*- mode: java; -*- -while(-----arg) { - while(-arg) { - while(-----arg*---0) { - int N=--false==false<--arg; - while(N<-4==N) { - N=N+N; - } - } - { - int kzEl_r7EYz=3*----0!=-arg<(37*--97!=0/arg==arg)<=-(--arg!=0); - while(kzEl_r7EYz<---1) { - kzEl_r7EYz=kzEl_r7EYz+kzEl_r7EYz*arg>=24; - if(7) continue; - kzEl_r7EYz=false; - if(-kzEl_r7EYz+arg<-3) continue; - else { - while(kzEl_r7EYz) continue; - arg=----3; - kzEl_r7EYz=-(-----arg*1>-kzEl_r7EYz); - int v2uF_4ba=9; - } - } - } - int pjcp7rv=arg; - { - int m2ya3=--arg-pjcp7rv; - while(m2ya3<-----pjcp7rv>=pjcp7rv+--pjcp7rv!=---pjcp7rv!=-arg<---(-m2ya3)>m2ya3<=-----true>14!=--m2ya3) { - m2ya3=m2ya3+-(--0<=false<pjcp7rv/arg<=-true); - while((--m2ya3)<--arg<-----arg*false!=arg<pjcp7rv*arg) { - pjcp7rv=-3+-arg; - break; - } - while(-3) { - while(67+0-61) m2ya3=m2ya3; - if(----pjcp7rv==---(---arg)) pjcp7rv=0!=-23; - else pjcp7rv=----89; - while(m2ya3!=m2ya3<pjcp7rv) m2ya3=1; - while(--arg<=pjcp7rv) pjcp7rv=-32<=-m2ya3+62; - } - break; - } - } - { - int arg=-1<-9!=(-arg>=-pjcp7rv>=arg<=arg); - while(arg<-arg) { - arg=arg+--arg; - { - while((--93)--pjcp7rv*-pjcp7rv+arg) arg=0-(6>=(--(---41/(0))!=--pjcp7rv)>=---2*33); - pjcp7rv=11; - int c=pjcp7rv; - if(--107) break; - else break; - } - } - } - pjcp7rv=pjcp7rv; - int aR0Wkua=-pjcp7rv==pjcp7rv; - { - if(-0!=-0) while(-true) break; - else { - while(aR0Wkua) pjcp7rv=-0/pjcp7rv; - pjcp7rv=pjcp7rv; - } - } +while(0) { + int v0=0; + while(1>>arg+0>>>0<=0) { + v0=1+arg/0; + while(1) + if(0/--v0+arg) 0; + v0=-21; } - if(-arg) { - { - int Isdlt0fr91=0!=arg; - while(Isdlt0fr91<-Isdlt0fr91==-Isdlt0fr91+true) { - Isdlt0fr91=Isdlt0fr91+-1!=true; - if(-arg) if(--arg<=Isdlt0fr91) Isdlt0fr91=-Isdlt0fr91; - int i=---arg<---arg!=--40; - { - int jVX43Ln4Dm=-(6)==-Isdlt0fr91/----0; - while(jVX43Ln4Dm<--(3-3)) { - jVX43Ln4Dm=jVX43Ln4Dm+-0<25; - i=24<--(jVX43Ln4Dm); - } - } - i=(arg!=----false>=7); - int Te=5>-arg; - break; - } - } - arg=arg!=--true/arg; - { - int UX=arg; - while(UX<-3*arg) { - UX=UX+arg/-1; - arg=-3--(-UX--47<arg==--arg==arg)/arg--UX>=-arg; - if(---12) while(-UX) break; - break; - } - } - continue; - } - if(arg) arg=--0; - else if(1) continue; - int DtTlhjYq=19==arg; - { - arg=--DtTlhjYq<=(DtTlhjYq/---DtTlhjYq<=-DtTlhjYq); - if(---arg) continue; - else { - int Zsl=40; - while(Zsl<--Zsl--false>((Zsl))==Zsl!=--DtTlhjYq-DtTlhjYq-DtTlhjYq) { - Zsl=Zsl+arg; - } - } - if((arg)) if(-DtTlhjYq) { - } - else while(((2)==3*arg/DtTlhjYq)<=0==---arg) return false; - else { - int lwbF=arg>=0; - while(lwbF<57) { - lwbF=lwbF+--(-arg+lwbF)>=-2>=arg!=arg; - arg=----0+0; - while(49) break; - if(true) DtTlhjYq=-----arg; - DtTlhjYq=0!=-----(0); - } - } - arg=---arg!=DtTlhjYq/--0; - DtTlhjYq=-DtTlhjYq/(--arg<arg); - if(32) { - int q=-DtTlhjYq; - while(q<arg*(0*q)/0) { - q=q+DtTlhjYq; - DtTlhjYq=arg; - } - } - else if(--arg) if(15) break; - else arg=0==arg<=-55>DtTlhjYq; - else { - } - DtTlhjYq=-0; - { - while((0)<-arg) DtTlhjYq=-DtTlhjYq; - } - if(30/--(arg)>=0) DtTlhjYq=-0>=arg; - else { - int Y2wcIQJ=--DtTlhjYq*---11; - if(arg==arg) { - Y2wcIQJ=-----Y2wcIQJ; - Y2wcIQJ=Y2wcIQJ<7; - if(DtTlhjYq) arg=arg; - else break; - while(-arg!=-31==(false<=-15>=-DtTlhjYq+--6*-----Y2wcIQJ<=---arg!=-Y2wcIQJ<=---0<-arg*--Y2wcIQJ)) DtTlhjYq=arg!=3; - } - continue; - } - arg=DtTlhjYq; - arg=--3/(---arg)>=80>=-DtTlhjYq<=DtTlhjYq; - arg=51+---(-true)!=arg!=----1==-DtTlhjYq; - if(11<=arg) if((arg)+79<32+(-arg)) continue; - else if(true==DtTlhjYq) break; - break; - } -} -if(arg!=62==arg) { - while(---arg) { - { - int bhmDacPM=arg/arg; - while(bhmDacPM<arg) { - bhmDacPM=bhmDacPM+80*((-bhmDacPM)/---bhmDacPM>1)<bhmDacPM-2!=7; - arg=-0; - arg=bhmDacPM>=-arg+-arg; - break; - } - } - int arg=true; - arg=arg<=arg; - { - int KlC=30; - while(KlC<-2) { - KlC=KlC+-1!=25<=-KlC>KlC>----0; - int Ij=arg>=-arg<=---10; - { - int LAbgurVa2R=-arg!=Ij; - while(LAbgurVa2R<-true) { - LAbgurVa2R=LAbgurVa2R+Ij; - KlC=-LAbgurVa2R; - Ij=42*(-Ij>true); - while(Ij) arg=KlC; - KlC=-----7>-(--KlC<--7)==-LAbgurVa2R; - } - } - int a=Ij<=-KlC; - if(Ij) { - int r1W=a!=-false; - } - else { - arg=56>=Ij; - while(54) break; - arg=8>=-(a<--Ij)/a>=-a-KlC; - } - int Yt_T=KlC; - arg=KlC; - } - } - if(----false/--arg/12+-----0) if(-9+-arg) while(arg!=(arg)) arg=--1>=-71-arg!=---(--arg*11+102)/--arg; - else if(----arg) continue; - if(-arg-arg) { - arg=-(-arg)*--(-3)<(-7==-arg----arg); - { - int arg=arg; - while(arg<-0>arg==-arg-(-arg>1+11)) { - arg=arg+6-arg!=--0>---30>=---arg<=arg/(3)+---arg; - } - } - arg=-arg+arg; - arg=--47+-arg<1>arg*(-arg==-arg--0>3); - arg=(----arg)!=arg+--59; - arg=--4+arg==-(arg)-arg; - } - else { - while(--true-----true*-25+-18>arg>=-----(-arg)---13) { - arg=-0+--true<false; - continue; - } - arg=true<=arg; - break; - } - arg=arg*22<--(0+-arg); - { - continue; - } - } - arg=1*---((3<=true)==---2); - arg=7+-(-1); - return arg+--true; -} -else { - int o3ypEsewxM=-(---arg); - int vzXB=(-(---11<=--o3ypEsewxM>=--0))<=-0/-arg; - int L=-arg; - int B4mHcrf=---vzXB; - int oZWGdzZl=-o3ypEsewxM; - int K6tQqa1=11; - while(0!=--L) { - int sdZfTM=vzXB*true+K6tQqa1; - while(sdZfTM<false) { - sdZfTM=sdZfTM+arg; - sdZfTM=oZWGdzZl; - K6tQqa1=-K6tQqa1; - arg=---K6tQqa1; - while((3+-K6tQqa1)<oZWGdzZl) { - if(-----(-1)) sdZfTM=-false; - {} - } - K6tQqa1=vzXB!=-(B4mHcrf+-7>false); - sdZfTM=vzXB; - } - } - L=false; - while(31) B4mHcrf=arg; - oZWGdzZl=-0<--oZWGdzZl<=--2; - if(K6tQqa1>=20<=46) { - if(-1+-L) if(oZWGdzZl) { - int wmhv=-----0; - } - int arg=0; - o3ypEsewxM=---(oZWGdzZl); - return -oZWGdzZl/0; - } - else if(arg) { - int yKk5=B4mHcrf>=4>K6tQqa1<-B4mHcrf/o3ypEsewxM; - return -K6tQqa1; - } - else { - if(---0) { - {} - {} - } - return o3ypEsewxM; - } } +while(0) {} |
