1 /*
   2  * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2015, Red Hat Inc.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  *
  24  */
  25 
  26 package sun.jvm.hotspot.runtime.aarch64;
  27 
  28 import java.util.*;
  29 import sun.jvm.hotspot.code.*;
  30 import sun.jvm.hotspot.compiler.*;
  31 import sun.jvm.hotspot.debugger.*;
  32 import sun.jvm.hotspot.oops.*;
  33 import sun.jvm.hotspot.runtime.*;
  34 import sun.jvm.hotspot.types.*;
  35 import sun.jvm.hotspot.utilities.*;
  36 
  37 /** Specialization of and implementation of abstract methods of the
  38     Frame class for the aarch64 family of CPUs. */
  39 
  40 public class AARCH64Frame extends Frame {
  41   private static final boolean DEBUG;
  42   static {
  43     DEBUG = System.getProperty("sun.jvm.hotspot.runtime.aarch64.AARCH64Frame.DEBUG") != null;
  44   }
  45 
  46   // All frames
  47   private static final int LINK_OFFSET                =  0;
  48   private static final int RETURN_ADDR_OFFSET         =  1;
  49   private static final int SENDER_SP_OFFSET           =  2;
  50 
  51   // Interpreter frames
  52   private static final int INTERPRETER_FRAME_MIRROR_OFFSET    =  2; // for native calls only
  53   private static final int INTERPRETER_FRAME_SENDER_SP_OFFSET = -1;
  54   private static final int INTERPRETER_FRAME_LAST_SP_OFFSET   = INTERPRETER_FRAME_SENDER_SP_OFFSET - 1;
  55   private static final int INTERPRETER_FRAME_METHOD_OFFSET    = INTERPRETER_FRAME_LAST_SP_OFFSET - 1;
  56   private static       int INTERPRETER_FRAME_MDX_OFFSET;         // Non-core builds only
  57   private static       int INTERPRETER_FRAME_CACHE_OFFSET;
  58   private static       int INTERPRETER_FRAME_LOCALS_OFFSET;
  59   private static       int INTERPRETER_FRAME_BCX_OFFSET;
  60   private static       int INTERPRETER_FRAME_INITIAL_SP_OFFSET;
  61   private static       int INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET;
  62   private static       int INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET;
  63 
  64   // Entry frames
  65   private static       int ENTRY_FRAME_CALL_WRAPPER_OFFSET = -8;
  66 
  67   // Native frames
  68   private static final int NATIVE_FRAME_INITIAL_PARAM_OFFSET =  2;
  69 
  70   private static VMReg fp = new VMReg(29);
  71 
  72   static {
  73     VM.registerVMInitializedObserver(new Observer() {
  74         public void update(Observable o, Object data) {
  75           initialize(VM.getVM().getTypeDataBase());
  76         }
  77       });
  78   }
  79 
  80   private static synchronized void initialize(TypeDataBase db) {
  81     INTERPRETER_FRAME_MDX_OFFSET                  = INTERPRETER_FRAME_METHOD_OFFSET - 1;
  82     INTERPRETER_FRAME_CACHE_OFFSET                = INTERPRETER_FRAME_MDX_OFFSET - 1;
  83     INTERPRETER_FRAME_LOCALS_OFFSET               = INTERPRETER_FRAME_CACHE_OFFSET - 1;
  84     INTERPRETER_FRAME_BCX_OFFSET                  = INTERPRETER_FRAME_LOCALS_OFFSET - 1;
  85     INTERPRETER_FRAME_INITIAL_SP_OFFSET           = INTERPRETER_FRAME_BCX_OFFSET - 1;
  86     INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET    = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
  87     INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
  88   }
  89 
  90 
  91   // an additional field beyond sp and pc:
  92   Address raw_fp; // frame pointer
  93   private Address raw_unextendedSP;
  94 
  95   private AARCH64Frame() {
  96   }
  97 
  98   private void adjustForDeopt() {
  99     if ( pc != null) {
 100       // Look for a deopt pc and if it is deopted convert to original pc
 101       CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc);
 102       if (cb != null && cb.isJavaMethod()) {
 103         NMethod nm = (NMethod) cb;
 104         if (pc.equals(nm.deoptHandlerBegin())) {
 105           if (Assert.ASSERTS_ENABLED) {
 106             Assert.that(this.getUnextendedSP() != null, "null SP in Java frame");
 107           }
 108           // adjust pc if frame is deoptimized.
 109           pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset());
 110           deoptimized = true;
 111         }
 112       }
 113     }
 114   }
 115 
 116   public AARCH64Frame(Address raw_sp, Address raw_fp, Address pc) {
 117     this.raw_sp = raw_sp;
 118     this.raw_unextendedSP = raw_sp;
 119     this.raw_fp = raw_fp;
 120     this.pc = pc;
 121     adjustUnextendedSP();
 122 
 123     // Frame must be fully constructed before this call
 124     adjustForDeopt();
 125 
 126     if (DEBUG) {
 127       System.out.println("AARCH64Frame(sp, fp, pc): " + this);
 128       dumpStack();
 129     }
 130   }
 131 
 132   public AARCH64Frame(Address raw_sp, Address raw_fp) {
 133     this.raw_sp = raw_sp;
 134     this.raw_unextendedSP = raw_sp;
 135     this.raw_fp = raw_fp;
 136     this.pc = raw_sp.getAddressAt(-1 * VM.getVM().getAddressSize());
 137     adjustUnextendedSP();
 138 
 139     // Frame must be fully constructed before this call
 140     adjustForDeopt();
 141 
 142     if (DEBUG) {
 143       System.out.println("AARCH64Frame(sp, fp): " + this);
 144       dumpStack();
 145     }
 146   }
 147 
 148   public AARCH64Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Address pc) {
 149     this.raw_sp = raw_sp;
 150     this.raw_unextendedSP = raw_unextendedSp;
 151     this.raw_fp = raw_fp;
 152     this.pc = pc;
 153     adjustUnextendedSP();
 154 
 155     // Frame must be fully constructed before this call
 156     adjustForDeopt();
 157 
 158     if (DEBUG) {
 159       System.out.println("AARCH64Frame(sp, unextendedSP, fp, pc): " + this);
 160       dumpStack();
 161     }
 162 
 163   }
 164 
 165   public Object clone() {
 166     AARCH64Frame frame = new AARCH64Frame();
 167     frame.raw_sp = raw_sp;
 168     frame.raw_unextendedSP = raw_unextendedSP;
 169     frame.raw_fp = raw_fp;
 170     frame.pc = pc;
 171     frame.deoptimized = deoptimized;
 172     return frame;
 173   }
 174 
 175   public boolean equals(Object arg) {
 176     if (arg == null) {
 177       return false;
 178     }
 179 
 180     if (!(arg instanceof AARCH64Frame)) {
 181       return false;
 182     }
 183 
 184     AARCH64Frame other = (AARCH64Frame) arg;
 185 
 186     return (AddressOps.equal(getSP(), other.getSP()) &&
 187             AddressOps.equal(getUnextendedSP(), other.getUnextendedSP()) &&
 188             AddressOps.equal(getFP(), other.getFP()) &&
 189             AddressOps.equal(getPC(), other.getPC()));
 190   }
 191 
 192   public int hashCode() {
 193     if (raw_sp == null) {
 194       return 0;
 195     }
 196 
 197     return raw_sp.hashCode();
 198   }
 199 
 200   public String toString() {
 201     return "sp: " + (getSP() == null? "null" : getSP().toString()) +
 202          ", unextendedSP: " + (getUnextendedSP() == null? "null" : getUnextendedSP().toString()) +
 203          ", fp: " + (getFP() == null? "null" : getFP().toString()) +
 204          ", pc: " + (pc == null? "null" : pc.toString());
 205   }
 206 
 207   // accessors for the instance variables
 208   public Address getFP() { return raw_fp; }
 209   public Address getSP() { return raw_sp; }
 210   public Address getID() { return raw_sp; }
 211 
 212   // FIXME: not implemented yet
 213   public boolean isSignalHandlerFrameDbg() { return false; }
 214   public int     getSignalNumberDbg()      { return 0;     }
 215   public String  getSignalNameDbg()        { return null;  }
 216 
 217   public boolean isInterpretedFrameValid() {
 218     if (Assert.ASSERTS_ENABLED) {
 219       Assert.that(isInterpretedFrame(), "Not an interpreted frame");
 220     }
 221 
 222     // These are reasonable sanity checks
 223     if (getFP() == null || getFP().andWithMask(0x3) != null) {
 224       return false;
 225     }
 226 
 227     if (getSP() == null || getSP().andWithMask(0x3) != null) {
 228       return false;
 229     }
 230 
 231     if (getFP().addOffsetTo(INTERPRETER_FRAME_INITIAL_SP_OFFSET * VM.getVM().getAddressSize()).lessThan(getSP())) {
 232       return false;
 233     }
 234 
 235     // These are hacks to keep us out of trouble.
 236     // The problem with these is that they mask other problems
 237     if (getFP().lessThanOrEqual(getSP())) {
 238       // this attempts to deal with unsigned comparison above
 239       return false;
 240     }
 241 
 242     if (getFP().minus(getSP()) > 4096 * VM.getVM().getAddressSize()) {
 243       // stack frames shouldn't be large.
 244       return false;
 245     }
 246 
 247     return true;
 248   }
 249 
 250   // FIXME: not applicable in current system
 251   //  void    patch_pc(Thread* thread, address pc);
 252 
 253   public Frame sender(RegisterMap regMap, CodeBlob cb) {
 254     AARCH64RegisterMap map = (AARCH64RegisterMap) regMap;
 255 
 256     if (Assert.ASSERTS_ENABLED) {
 257       Assert.that(map != null, "map must be set");
 258     }
 259 
 260     // Default is we done have to follow them. The sender_for_xxx will
 261     // update it accordingly
 262     map.setIncludeArgumentOops(false);
 263 
 264     if (isEntryFrame())       return senderForEntryFrame(map);
 265     if (isInterpretedFrame()) return senderForInterpreterFrame(map);
 266 
 267     if(cb == null) {
 268       cb = VM.getVM().getCodeCache().findBlob(getPC());
 269     } else {
 270       if (Assert.ASSERTS_ENABLED) {
 271         Assert.that(cb.equals(VM.getVM().getCodeCache().findBlob(getPC())), "Must be the same");
 272       }
 273     }
 274 
 275     if (cb != null) {
 276       return senderForCompiledFrame(map, cb);
 277     }
 278 
 279     // Must be native-compiled frame, i.e. the marshaling code for native
 280     // methods that exists in the core system.
 281     return new AARCH64Frame(getSenderSP(), getLink(), getSenderPC());
 282   }
 283 
 284   private Frame senderForEntryFrame(AARCH64RegisterMap map) {
 285     if (DEBUG) {
 286       System.out.println("senderForEntryFrame");
 287     }
 288     if (Assert.ASSERTS_ENABLED) {
 289       Assert.that(map != null, "map must be set");
 290     }
 291     // Java frame called from C; skip all C frames and return top C
 292     // frame of that chunk as the sender
 293     AARCH64JavaCallWrapper jcw = (AARCH64JavaCallWrapper) getEntryFrameCallWrapper();
 294     if (Assert.ASSERTS_ENABLED) {
 295       Assert.that(!entryFrameIsFirst(), "next Java fp must be non zero");
 296       Assert.that(jcw.getLastJavaSP().greaterThan(getSP()), "must be above this frame on stack");
 297     }
 298     AARCH64Frame fr;
 299     if (jcw.getLastJavaPC() != null) {
 300       fr = new AARCH64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP(), jcw.getLastJavaPC());
 301     } else {
 302       fr = new AARCH64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP());
 303     }
 304     map.clear();
 305     if (Assert.ASSERTS_ENABLED) {
 306       Assert.that(map.getIncludeArgumentOops(), "should be set by clear");
 307     }
 308     return fr;
 309   }
 310 
 311   //------------------------------------------------------------------------------
 312   // frame::adjust_unextended_sp
 313   private void adjustUnextendedSP() {
 314     // If we are returning to a compiled MethodHandle call site, the
 315     // saved_fp will in fact be a saved value of the unextended SP.  The
 316     // simplest way to tell whether we are returning to such a call site
 317     // is as follows:
 318 
 319     CodeBlob cb = cb();
 320     NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull();
 321     if (senderNm != null) {
 322       // If the sender PC is a deoptimization point, get the original
 323       // PC.  For MethodHandle call site the unextended_sp is stored in
 324       // saved_fp.
 325       if (senderNm.isDeoptMhEntry(getPC())) {
 326         // DEBUG_ONLY(verifyDeoptMhOriginalPc(senderNm, getFP()));
 327         raw_unextendedSP = getFP();
 328       }
 329       else if (senderNm.isDeoptEntry(getPC())) {
 330         // DEBUG_ONLY(verifyDeoptOriginalPc(senderNm, raw_unextendedSp));
 331       }
 332       else if (senderNm.isMethodHandleReturn(getPC())) {
 333         raw_unextendedSP = getFP();
 334       }
 335     }
 336   }
 337 
 338   private Frame senderForInterpreterFrame(AARCH64RegisterMap map) {
 339     if (DEBUG) {
 340       System.out.println("senderForInterpreterFrame");
 341     }
 342     Address unextendedSP = addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
 343     Address sp = addressOfStackSlot(SENDER_SP_OFFSET);
 344     // We do not need to update the callee-save register mapping because above
 345     // us is either another interpreter frame or a converter-frame, but never
 346     // directly a compiled frame.
 347     // 11/24/04 SFG. With the removal of adapter frames this is no longer true.
 348     // However c2 no longer uses callee save register for java calls so there
 349     // are no callee register to find.
 350 
 351     if (map.getUpdateMap())
 352       updateMapWithSavedLink(map, addressOfStackSlot(LINK_OFFSET));
 353 
 354     return new AARCH64Frame(sp, unextendedSP, getLink(), getSenderPC());
 355   }
 356 
 357   private void updateMapWithSavedLink(RegisterMap map, Address savedFPAddr) {
 358     map.setLocation(fp, savedFPAddr);
 359   }
 360 
 361   private Frame senderForCompiledFrame(AARCH64RegisterMap map, CodeBlob cb) {
 362     if (DEBUG) {
 363       System.out.println("senderForCompiledFrame");
 364     }
 365 
 366     //
 367     // NOTE: some of this code is (unfortunately) duplicated  AARCH64CurrentFrameGuess
 368     //
 369 
 370     if (Assert.ASSERTS_ENABLED) {
 371       Assert.that(map != null, "map must be set");
 372     }
 373 
 374     // frame owned by optimizing compiler
 375     if (Assert.ASSERTS_ENABLED) {
 376         Assert.that(cb.getFrameSize() >= 0, "must have non-zero frame size");
 377     }
 378     Address senderSP = getUnextendedSP().addOffsetTo(cb.getFrameSize());
 379 
 380     // The return_address is always the word on the stack
 381     Address senderPC = senderSP.getAddressAt(-1 * VM.getVM().getAddressSize());
 382 
 383     // This is the saved value of FP which may or may not really be an FP.
 384     // It is only an FP if the sender is an interpreter frame.
 385     Address savedFPAddr = senderSP.addOffsetTo(- SENDER_SP_OFFSET * VM.getVM().getAddressSize());
 386 
 387     if (map.getUpdateMap()) {
 388       // Tell GC to use argument oopmaps for some runtime stubs that need it.
 389       // For C1, the runtime stub might not have oop maps, so set this flag
 390       // outside of update_register_map.
 391       map.setIncludeArgumentOops(cb.callerMustGCArguments());
 392 
 393       if (cb.getOopMaps() != null) {
 394         OopMapSet.updateRegisterMap(this, cb, map, true);
 395       }
 396 
 397       // Since the prolog does the save and restore of FP there is no oopmap
 398       // for it so we must fill in its location as if there was an oopmap entry
 399       // since if our caller was compiled code there could be live jvm state in it.
 400       updateMapWithSavedLink(map, savedFPAddr);
 401     }
 402 
 403     return new AARCH64Frame(senderSP, savedFPAddr.getAddressAt(0), senderPC);
 404   }
 405 
 406   protected boolean hasSenderPD() {
 407     return true;
 408   }
 409 
 410   public long frameSize() {
 411     return (getSenderSP().minus(getSP()) / VM.getVM().getAddressSize());
 412   }
 413 
 414     public Address getLink() {
 415         try {
 416             if (DEBUG) {
 417                 System.out.println("Reading link at " + addressOfStackSlot(LINK_OFFSET)
 418                         + " = " + addressOfStackSlot(LINK_OFFSET).getAddressAt(0));
 419             }
 420             return addressOfStackSlot(LINK_OFFSET).getAddressAt(0);
 421         } catch (Exception e) {
 422             if (DEBUG)
 423                 System.out.println("Returning null");
 424             return null;
 425         }
 426     }
 427 
 428   // FIXME: not implementable yet
 429   //inline void      frame::set_link(intptr_t* addr)  { *(intptr_t **)addr_at(link_offset) = addr; }
 430 
 431   public Address getUnextendedSP() { return raw_unextendedSP; }
 432 
 433   // Return address:
 434   public Address getSenderPCAddr() { return addressOfStackSlot(RETURN_ADDR_OFFSET); }
 435   public Address getSenderPC()     { return getSenderPCAddr().getAddressAt(0);      }
 436 
 437   // return address of param, zero origin index.
 438   public Address getNativeParamAddr(int idx) {
 439     return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx);
 440   }
 441 
 442   public Address getSenderSP()     { return addressOfStackSlot(SENDER_SP_OFFSET); }
 443 
 444   public Address addressOfInterpreterFrameLocals() {
 445     return addressOfStackSlot(INTERPRETER_FRAME_LOCALS_OFFSET);
 446   }
 447 
 448   private Address addressOfInterpreterFrameBCX() {
 449     return addressOfStackSlot(INTERPRETER_FRAME_BCX_OFFSET);
 450   }
 451 
 452   public int getInterpreterFrameBCI() {
 453     // FIXME: this is not atomic with respect to GC and is unsuitable
 454     // for use in a non-debugging, or reflective, system. Need to
 455     // figure out how to express this.
 456     Address bcp = addressOfInterpreterFrameBCX().getAddressAt(0);
 457     Address methodHandle = addressOfInterpreterFrameMethod().getAddressAt(0);
 458     Method method = (Method)Metadata.instantiateWrapperFor(methodHandle);
 459     return bcpToBci(bcp, method);
 460   }
 461 
 462   public Address addressOfInterpreterFrameMDX() {
 463     return addressOfStackSlot(INTERPRETER_FRAME_MDX_OFFSET);
 464   }
 465 
 466   // FIXME
 467   //inline int frame::interpreter_frame_monitor_size() {
 468   //  return BasicObjectLock::size();
 469   //}
 470 
 471   // expression stack
 472   // (the max_stack arguments are used by the GC; see class FrameClosure)
 473 
 474   public Address addressOfInterpreterFrameExpressionStack() {
 475     Address monitorEnd = interpreterFrameMonitorEnd().address();
 476     return monitorEnd.addOffsetTo(-1 * VM.getVM().getAddressSize());
 477   }
 478 
 479   public int getInterpreterFrameExpressionStackDirection() { return -1; }
 480 
 481   // top of expression stack
 482   public Address addressOfInterpreterFrameTOS() {
 483     return getSP();
 484   }
 485 
 486   /** Expression stack from top down */
 487   public Address addressOfInterpreterFrameTOSAt(int slot) {
 488     return addressOfInterpreterFrameTOS().addOffsetTo(slot * VM.getVM().getAddressSize());
 489   }
 490 
 491   public Address getInterpreterFrameSenderSP() {
 492     if (Assert.ASSERTS_ENABLED) {
 493       Assert.that(isInterpretedFrame(), "interpreted frame expected");
 494     }
 495     return addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
 496   }
 497 
 498   // Monitors
 499   public BasicObjectLock interpreterFrameMonitorBegin() {
 500     return new BasicObjectLock(addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET));
 501   }
 502 
 503   public BasicObjectLock interpreterFrameMonitorEnd() {
 504     Address result = addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET).getAddressAt(0);
 505     if (Assert.ASSERTS_ENABLED) {
 506       // make sure the pointer points inside the frame
 507       Assert.that(AddressOps.gt(getFP(), result), "result must <  than frame pointer");
 508       Assert.that(AddressOps.lte(getSP(), result), "result must >= than stack pointer");
 509     }
 510     return new BasicObjectLock(result);
 511   }
 512 
 513   public int interpreterFrameMonitorSize() {
 514     return BasicObjectLock.size();
 515   }
 516 
 517   // Method
 518   public Address addressOfInterpreterFrameMethod() {
 519     return addressOfStackSlot(INTERPRETER_FRAME_METHOD_OFFSET);
 520   }
 521 
 522   // Constant pool cache
 523   public Address addressOfInterpreterFrameCPCache() {
 524     return addressOfStackSlot(INTERPRETER_FRAME_CACHE_OFFSET);
 525   }
 526 
 527   // Entry frames
 528   public JavaCallWrapper getEntryFrameCallWrapper() {
 529     return new AARCH64JavaCallWrapper(addressOfStackSlot(ENTRY_FRAME_CALL_WRAPPER_OFFSET).getAddressAt(0));
 530   }
 531 
 532   protected Address addressOfSavedOopResult() {
 533     // offset is 2 for compiler2 and 3 for compiler1
 534     return getSP().addOffsetTo((VM.getVM().isClientCompiler() ? 2 : 3) *
 535                                VM.getVM().getAddressSize());
 536   }
 537 
 538   protected Address addressOfSavedReceiver() {
 539     return getSP().addOffsetTo(-4 * VM.getVM().getAddressSize());
 540   }
 541 
 542   private void dumpStack() {
 543     for (Address addr = getSP().addOffsetTo(-4 * VM.getVM().getAddressSize());
 544          AddressOps.lt(addr, getSP());
 545          addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
 546       System.out.println(addr + ": " + addr.getAddressAt(0));
 547     }
 548     System.out.println("-----------------------");
 549     for (Address addr = getSP();
 550          AddressOps.lte(addr, getSP().addOffsetTo(20 * VM.getVM().getAddressSize()));
 551          addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
 552       System.out.println(addr + ": " + addr.getAddressAt(0));
 553     }
 554   }
 555 }