protected sealed override void EmitCode(NodeFactory factory, ref ARMEmitter encoder, bool relocsOnly) { // First load the generic context into the context register. EmitLoadGenericContext(factory, ref encoder, relocsOnly); Register contextRegister = GetContextRegister(ref encoder); switch (_id) { case ReadyToRunHelperId.GetNonGCStaticBase: { ARMDebug.EmitNYIAssert(factory, ref encoder, "GetNonGCStaticBase EmitCode is not implemented"); /* *** ***NOT TESTED!!! *** ***Debug.Assert(contextRegister == encoder.TargetRegister.Arg0); *** ***MetadataType target = (MetadataType)_target; *** ***if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) ***{ ***EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); ***encoder.EmitRET(); ***} ***else ***{ ***EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, _lookupSignature, relocsOnly); ***encoder.EmitMOV(encoder.TargetRegister.Result, encoder.TargetRegister.Arg0); *** ***// We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. ***int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); ***encoder.EmitSUB(encoder.TargetRegister.Arg0, ((byte)(cctorContextSize))); ***// If we get the required state it will be necessary to restore the original value before returning ***encoder.EmitPUSH(encoder.TargetRegister.Arg0); *** ***// cmp [r0 + ptrSize], 1 ***encoder.EmitLDR(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, ((short)factory.Target.PointerSize)); ***encoder.EmitCMP(encoder.TargetRegister.Arg0, ((byte)1)); ***// return with restoring register ***encoder.EmitRETIfEqualPOP(encoder.TargetRegister.Arg0); *** ***// just restore after cmp ***encoder.EmitPOP(encoder.TargetRegister.Arg0); *** ***encoder.EmitLDR(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0); ***encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); ***encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); ***}
protected sealed override void EmitCode(NodeFactory factory, ref ARMEmitter encoder, bool relocsOnly) { // First load the generic context into the context register. EmitLoadGenericContext(factory, ref encoder, relocsOnly); Register contextRegister = GetContextRegister(ref encoder); switch (_id) { case ReadyToRunHelperId.GetNonGCStaticBase: { Debug.Assert(contextRegister == encoder.TargetRegister.Arg0); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); MetadataType target = (MetadataType)_target; if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); encoder.EmitLDR(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg0, ((short)(factory.Target.PointerSize - cctorContextSize))); encoder.EmitCMP(encoder.TargetRegister.Arg1, ((byte)1)); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitSUB(encoder.TargetRegister.Arg0, ((byte)(cctorContextSize))); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } } break; case ReadyToRunHelperId.GetGCStaticBase: { Debug.Assert(contextRegister == encoder.TargetRegister.Arg0); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg0); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Result); encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Result); MetadataType target = (MetadataType)_target; if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg2, nonGcRegionLookup, relocsOnly); int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, ((short)(factory.Target.PointerSize - cctorContextSize))); encoder.EmitCMP(encoder.TargetRegister.Arg3, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitMOV(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg2); encoder.EmitSUB(encoder.TargetRegister.Arg0, cctorContextSize); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } } break; case ReadyToRunHelperId.GetThreadStaticBase: { Debug.Assert(contextRegister == encoder.TargetRegister.Arg0); MetadataType target = (MetadataType)_target; // Look up the index cell EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg1, _lookupSignature, relocsOnly); ISymbolNode helperEntrypoint; if (factory.TypeSystemContext.HasLazyStaticConstructor(target)) { // There is a lazy class constructor. We need the non-GC static base because that's where the // class constructor context lives. GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg2, nonGcRegionLookup, relocsOnly); int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); encoder.EmitSUB(encoder.TargetRegister.Arg2, cctorContextSize); helperEntrypoint = factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase); } else { helperEntrypoint = factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType); } // First arg: address of the TypeManager slot that provides the helper with // information about module index and the type manager instance (which is used // for initialization on first access). encoder.EmitLDR(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg1); // Second arg: index of the type in the ThreadStatic section of the modules encoder.EmitLDR(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg1, factory.Target.PointerSize); encoder.EmitJMP(helperEntrypoint); } break; case ReadyToRunHelperId.DelegateCtor: { ARMDebug.EmitNYIAssert(factory, ref encoder, "DelegateCtor EmitCode is not implemented"); /* *** ***NOT TESTED!!! *** ***// This is a weird helper. Codegen populated Arg0 and Arg1 with the values that the constructor ***// method expects. Codegen also passed us the generic context in Arg2. ***// We now need to load the delegate target method into Arg2 (using a dictionary lookup) ***// and the optional 4th parameter, and call the ctor. *** ***Debug.Assert(contextRegister == encoder.TargetRegister.Arg2); *** ***var target = (DelegateCreationInfo)_target; *** ***EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2, _lookupSignature, relocsOnly); *** ***if (target.Thunk != null) ***{ ***Debug.Assert(target.Constructor.Method.Signature.Length == 3); ***encoder.EmitMOV(encoder.TargetRegister.Arg3, target.Thunk); ***} ***else ***{ ***Debug.Assert(target.Constructor.Method.Signature.Length == 2); ***} *** ***encoder.EmitJMP(target.Constructor); */ }
protected sealed override void EmitCode(NodeFactory factory, ref ARMEmitter encoder, bool relocsOnly) { ARMDebug.EmitNYIAssert(factory, ref encoder, "EmitCode is not implemented"); }