2002-07-16 Dietmar Maurer <dietmar@ximian.com>
authorDietmar Maurer <dietmar@mono-cvs.ximian.com>
Tue, 16 Jul 2002 15:27:07 +0000 (15:27 -0000)
committerDietmar Maurer <dietmar@mono-cvs.ximian.com>
Tue, 16 Jul 2002 15:27:07 +0000 (15:27 -0000)
* x86.brg (CALL_VOID): fix bug #27751

* marshal.c (emit_ptr_to_str_conv): first impl.

svn path=/trunk/mono/; revision=5827

mono/jit/ChangeLog
mono/jit/emit-x86.c
mono/jit/jit.c
mono/metadata/ChangeLog
mono/metadata/marshal.c
mono/metadata/metadata.c
mono/metadata/metadata.h
mono/metadata/object.c
mono/tests/marshal2.cs
mono/tests/pinvoke3.cs

index d210e60329f11d9d3f8cce49d1fc1b5bc88897e3..e986bd6e37fc7f426f6185fd5c730b6856d2177c 100644 (file)
@@ -1,5 +1,7 @@
 2002-07-16  Dietmar Maurer  <dietmar@ximian.com>
 
+       * x86.brg (CALL_VOID): fix bug #27751
+
        * jit.c (mono_analyze_stack): adjust valuetype size for pinvoke calls
 
 i2002-07-11  Dietmar Maurer  <dietmar@ximian.com>
index 8acf7b19cb3443746a6982259be6bbb416a85dc7..3d569eaa1443ac9299ecaed391829493e938a64d 100644 (file)
@@ -128,7 +128,7 @@ enter_method (MonoMethod *method, char *ebp)
                
                g_assert (!method->signature->ret->byref);
 
-               size = mono_type_stack_size (method->signature->ret, &align);
+               mono_get_param_info (method->signature, -1, &size, &align);
 
                printf ("VALUERET:%p, ", *((gpointer *)ebp));
                ebp += sizeof (gpointer);
@@ -155,9 +155,8 @@ enter_method (MonoMethod *method, char *ebp)
        }
 
        for (i = 0; i < method->signature->param_count; ++i) {
-               MonoType *type = method->signature->params [i];
                int size, align;
-               size = mono_type_stack_size (type, &align);
+               MonoType *type = mono_get_param_info (method->signature, i, &size, &align);
 
                if (type->byref) {
                        printf ("[BYREF:%p], ", *((gpointer *)ebp)); 
index d818c6e5cf97c0cdb6c6f5d7aa1341d07e1ded1c..61132f3e2b920b7be87dd0b8770f2ef1e536bf5f 100644 (file)
@@ -1388,7 +1388,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
 
                for (i = 0; i < signature->param_count; ++i) {
                        int argvar;
-                       size = mono_type_stack_size (signature->params [i], &align);
+                       mono_get_param_info (signature, i, &size, &align);
                        argvar = arch_allocate_var (cfg, size, align, MONO_ARGVAR, VAL_UNKNOWN);
                        VARINFO (cfg, argvar).isvolatile = 1;
                }
@@ -1865,9 +1865,13 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        ip++;
                        --sp;
                        token = read32 (ip);
-                       class = mono_class_get (image, token);
                        ip += 4;
 
+                       if (method->wrapper_type != MONO_WRAPPER_NONE)
+                               class = (MonoClass *)mono_method_get_wrapper_data (method, token);
+                       else
+                               class = mono_class_get (image, token);
+                               
                        if (cfg->share_code) {
                                t1 = mono_ctree_new (mp, MB_TERM_NEWARR, *sp, NULL);
                                t1->data.p = class;
@@ -1966,9 +1970,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        args_size += sizeof (gpointer); /* this argument */             
 
                        for (k = csig->param_count - 1; k >= 0; k--) {
-                               MonoType *type = cm->signature->params [k];
-
-                               size = mono_type_stack_size (type, &align);
+                               MonoType *type = mono_get_param_info (cm->signature, k, &size, &align);
                                t1 = mono_ctree_new (mp, mono_map_arg_type (type), arg_sp [k], NULL);   
                                t1->data.i = size;
                                ADD_TREE (t1, cli_addr);
@@ -2139,13 +2141,8 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        }
 
                        for (k = nargs - 1; k >= 0; k--) {
-                               MonoType *type = csig->params [k];
+                               MonoType *type = mono_get_param_info (csig, k, &size, NULL);
                                t1 = mono_ctree_new (mp, mono_map_arg_type (type), arg_sp [k], NULL);
-                               if (csig->pinvoke && ISSTRUCT (type)) {
-                                       size = mono_class_native_size (type->data.klass);
-                               } else {
-                                       size = mono_type_stack_size (type, &align);
-                               }
                                t1->data.i = size;
                                ADD_TREE (t1, cli_addr);
                                args_size += size;
index 6e9a80f2572def6990df80731d0759386bc39692..a97860a554425f0f8e1d0b85a36825573b884ae8 100644 (file)
@@ -1,3 +1,6 @@
+2002-07-16  Dietmar Maurer  <dietmar@ximian.com>
+
+       * marshal.c (emit_ptr_to_str_conv): first impl.
 
 Tue Jul 16 12:39:33 CEST 2002 Paolo Molaro <lupus@ximian.com>
 
index c77ae04cc53db6aa45387b84c31f159dae2de04c..e689d13c08274c3c2794a8d034d6d8e688280c94 100644 (file)
@@ -339,6 +339,19 @@ mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
        }
 }
 
+void
+mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
+{
+       if (locnum < 256) {
+               mono_mb_emit_byte (mb, CEE_LDLOCA_S);
+               mono_mb_emit_byte (mb, locnum);
+       } else {
+               mono_mb_emit_byte (mb, CEE_PREFIX1);
+               mono_mb_emit_byte (mb, CEE_LDLOCA);
+               mono_mb_emit_i4 (mb, locnum);
+       }
+}
+
 void
 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
 {
@@ -423,13 +436,90 @@ mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint8 local, gint8 incr)
 }
 
 static void
-emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoMarshalConv conv, int usize, int msize)
+emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, 
+                     int usize, int msize)
 {
-       /* fixme: dont know what do do here - docs say 
-          this does not work for value types  */
+       switch (conv) {
+       case MONO_MARSHAL_CONV_BOOL_I4:
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_byte (mb, CEE_BRFALSE_S);
+               mono_mb_emit_byte (mb, 5);
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDC_I4_1);
+               mono_mb_emit_byte (mb, CEE_STIND_I1);
+               mono_mb_emit_byte (mb, CEE_BR_S);
+               mono_mb_emit_byte (mb, 3);
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+               mono_mb_emit_byte (mb, CEE_STIND_I1);
+               break;
+       case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
+               MonoClass *eclass;
+               int esize;
 
-       g_warning ("not implemented");
-       g_assert_not_reached ();
+               if (type->type == MONO_TYPE_ARRAY)
+                       eclass = mono_class_from_mono_type (type->data.array->type);
+               else if (type->type == MONO_TYPE_SZARRAY) {
+                       eclass = mono_class_from_mono_type (type->data.type);
+               } else {
+                       g_assert_not_reached ();
+               }
+
+               if (eclass->valuetype)
+                       esize = mono_class_instance_size (eclass) - sizeof (MonoObject);
+               else
+                       esize = sizeof (gpointer);
+
+               /* create a new array */
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_icon (mb, msize / esize);
+               mono_mb_emit_byte (mb, CEE_NEWARR);     
+               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eclass));
+               mono_mb_emit_byte (mb, CEE_STIND_I);
+
+               /* copy the elements */
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
+               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_icon (mb, usize);
+               mono_mb_emit_byte (mb, CEE_PREFIX1);
+               mono_mb_emit_byte (mb, CEE_CPBLK);                      
+
+               break;
+       }
+       case MONO_MARSHAL_CONV_STR_BYVALSTR: 
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+               mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
+               mono_mb_emit_byte (mb, CEE_STIND_I);            
+               break;
+       case MONO_MARSHAL_CONV_STR_LPTSTR:
+       case MONO_MARSHAL_CONV_STR_LPSTR:
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+               mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
+               mono_mb_emit_byte (mb, CEE_STIND_I);            
+               break;
+       case MONO_MARSHAL_CONV_STR_LPWSTR:
+       case MONO_MARSHAL_CONV_STR_BSTR:
+       case MONO_MARSHAL_CONV_STR_ANSIBSTR:
+       case MONO_MARSHAL_CONV_STR_TBSTR:
+       case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
+       case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
+       case MONO_MARSHAL_CONV_STR_BYVALWSTR: 
+       case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
+       default:
+               g_warning ("marshalling conversion %d not implemented", conv);
+               g_assert_not_reached ();
+       }
 }
 
 static void
@@ -504,7 +594,8 @@ emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoMarshalConv conv, int usize, in
        }
        case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
        default:
-               g_error ("marshalling conversion %d not implemented", conv);
+               g_warning ("marshalling conversion %d not implemented", conv);
+               g_assert_not_reached ();
        }
 }
 
@@ -594,7 +685,7 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                                break;
                        case MONO_TYPE_VALUETYPE:
                                emit_struct_conv (mb, ftype->data.klass, to_object);
-                               break;
+                               continue;
                        default:
                                g_error ("marshalling type %02x not implemented", ftype->type);
                        }
@@ -602,12 +693,15 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
 
                default:
                        if (to_object) 
-                               emit_ptr_to_str_conv (mb, conv, usize, msize);
+                               emit_ptr_to_str_conv (mb, ftype, conv, usize, msize);
                        else
                                emit_str_to_ptr_conv (mb, conv, usize, msize);  
                }
 
-               if (!last_field) {
+               if (to_object) {
+                       mono_mb_emit_add_to_local (mb, 0, usize);
+                       mono_mb_emit_add_to_local (mb, 1, msize);
+               } else {
                        mono_mb_emit_add_to_local (mb, 0, msize);
                        mono_mb_emit_add_to_local (mb, 1, usize);
                }               
@@ -1339,7 +1433,7 @@ handle_enum:
                mono_mb_emit_managed_call (mb, method, strsig);         
        } else 
                mono_mb_emit_managed_call (mb, method, NULL);
-
+       
        switch (sig->ret->type) {
        case MONO_TYPE_VOID:
                if (!method->string_ctor)
@@ -1437,7 +1531,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
        MonoClass *klass;
        MonoMethod *res;
        GHashTable *cache;
-       int i, sigsize;
+       int i, sigsize, *tmp_locals;
 
        g_assert (method != NULL);
 
@@ -1450,10 +1544,21 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
        mb = mono_mb_new (method->klass, method->name);
        mb->method->wrapper_type = MONO_WRAPPER_NATIVE_TO_MANAGED;
 
+       /* allocate local 0 (pointer) src_ptr */
+       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       /* allocate local 1 (pointer) dst_ptr */
+       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       /* allocate local 2 (boolean) delete_old */
+       mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
+
+       mono_mb_emit_byte (mb, CEE_LDNULL);
+       mono_mb_emit_byte (mb, CEE_STLOC_2);
+
        /* we copy the signature, so that we can modify it */
        sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
        csig = g_memdup (sig, sigsize);
        csig->hasthis = 0;
+       csig->pinvoke = 1;
 
        /* fixme: howto handle this ? */
        if (sig->hasthis) {
@@ -1470,6 +1575,46 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
                }
        } 
 
+
+       /* we first do all conversions */
+       tmp_locals = alloca (sizeof (int) * sig->param_count);
+       for (i = 0; i < sig->param_count; i ++) {
+               MonoType *t = sig->params [i];
+
+               tmp_locals [i] = 0;
+
+               switch (t->type) {
+               case MONO_TYPE_VALUETYPE:
+                       
+                       klass = sig->params [i]->data.klass;
+                       if (klass->enumtype)
+                               break;
+
+                       tmp_locals [i] = mono_mb_add_local (mb, &klass->byval_arg);
+
+                       mono_mb_emit_ldarg_addr (mb, i);
+                       mono_mb_emit_byte (mb, CEE_STLOC_0);
+                       mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
+                       mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+                       /* emit valuetype convnversion code code */
+                       emit_struct_conv (mb, klass, TRUE);
+                       break;
+               case MONO_TYPE_STRING:
+
+                       tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+
+                       csig->params [i] = &mono_defaults.int_class->byval_arg;
+                       mono_mb_emit_ldarg (mb, i);
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
+                       mono_mb_emit_stloc (mb, tmp_locals [i]);
+                       break;  
+               }
+
+       }
+
        for (i = 0; i < sig->param_count; i++) {
                MonoType *t = sig->params [i];
 
@@ -1495,11 +1640,8 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
                        mono_mb_emit_ldarg (mb, i);
                        break;
                case MONO_TYPE_STRING:
-                       csig->params [i] = &mono_defaults.int_class->byval_arg;
-                       mono_mb_emit_ldarg (mb, i);
-                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-                       mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
-                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
+                       g_assert (tmp_locals [i]);
+                       mono_mb_emit_ldloc (mb, tmp_locals [i]);
                        break;  
                case MONO_TYPE_CLASS:  
                case MONO_TYPE_ARRAY:
@@ -1515,7 +1657,8 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
                                break;
                        }
 
-                       g_assert_not_reached ();
+                       g_assert (tmp_locals [i]);
+                       mono_mb_emit_ldloc (mb, tmp_locals [i]);
                        break;
                default:
                        g_warning ("type 0x%02x unknown", t->type);     
@@ -1663,7 +1806,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                        mono_mb_emit_byte (mb, CEE_STLOC_1);
 
                        /* emit valuetype convnversion code code */
-                       emit_struct_conv (mb, sig->params [i]->data.klass, FALSE);
+                       emit_struct_conv (mb, klass, FALSE);
                        break;
                case MONO_TYPE_STRING:
                        csig->params [argnum] = &mono_defaults.int_class->byval_arg;
@@ -1928,7 +2071,8 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass)
        mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
        /* allocate local 2 (boolean) delete_old */
        mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
-       mono_mb_emit_byte (mb, CEE_LDARG_2);
+
+       mono_mb_emit_byte (mb, CEE_LDNULL);
        mono_mb_emit_byte (mb, CEE_STLOC_2);
 
        /* initialize src_ptr to point to the start of object data */
index bffd8db808745e381a3675f9dcbc65df008b4254..10003353c3524384771049121a8507f4c5e819d4 100644 (file)
@@ -2176,6 +2176,33 @@ mono_type_stack_size (MonoType *t, gint *align)
        return 0;
 }
 
+MonoType *
+mono_get_param_info (MonoMethodSignature *sig, int param_num, int *size, int *align)
+{
+       MonoType *type;
+       int s, a;
+
+       if (!size)
+               size = &s;
+
+       if (!align)
+               align = &a;
+
+       if (param_num == -1)
+               type = sig->ret;
+       else
+               type = sig->params [param_num];
+       
+       if (sig->pinvoke && !type->byref && type->type == MONO_TYPE_VALUETYPE && 
+           !type->data.klass->enumtype) {
+               *size = mono_class_native_size (type->data.klass);
+       } else {
+               *size = mono_type_stack_size (type, align);
+       }
+
+       return type;
+}
+
 /*
  * mono_metadata_type_hash:
  * @t1: a type
index ff81fe406abc2239402716c5d2fd91d6a004d556..04f3f77b601118fe121beffb6e13f637adda299d 100644 (file)
@@ -323,14 +323,20 @@ MonoType      *mono_metadata_parse_field_type  (MonoImage      *m,
                                                short            field_flags,
                                                const char      *ptr,
                                                const char      **rptr);
-MonoType      *mono_type_create_from_typespec (MonoImage        *image, 
-                                              guint32           type_spec);
+MonoType      *mono_type_create_from_typespec  (MonoImage        *image, 
+                                               guint32           type_spec);
 void           mono_metadata_free_type         (MonoType        *type);
 int            mono_type_size                  (MonoType        *type, 
                                                int             *alignment);
 int            mono_type_stack_size            (MonoType        *type, 
                                                int             *alignment);
 
+MonoType      *mono_get_param_info             (MonoMethodSignature *sig, 
+                                               int                  param_num, 
+                                               int                 *size, 
+                                               int                 *align);
+
+
 guint          mono_metadata_type_hash         (MonoType *t1);
 gboolean       mono_metadata_type_equal        (MonoType *t1, MonoType *t2);
 
index d8f499303935c4023ab8dba5c8c75fe1ff1d8170..e146496bc6964f82ede8643175d8f1cfeaa8cdd4 100644 (file)
@@ -926,7 +926,10 @@ mono_string_new_wrapper (const char *text)
 {
        MonoDomain *domain = mono_domain_get ();
 
-       return mono_string_new (domain, text);
+       if (text)
+               return mono_string_new (domain, text);
+
+       return NULL;
 }
 
 /**
@@ -1499,11 +1502,11 @@ mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoAr
        int i, j, type, size, align;
        
        for (i = 0, j = 0; i < sig->param_count; i++) {
-               size = mono_type_stack_size (sig->params [i], &align);
-               
-               if (sig->params [i]->byref) {
+               MonoType *pt = mono_get_param_info (sig, i, &size, &align);
+
+               if (pt->byref) {
                        char *arg = mono_array_get (out_args, gpointer, j);
-                       type = sig->params [i]->type;
+                       type = pt->type;
                        
                        switch (type) {
                        case MONO_TYPE_VOID:
index bb19ef2e5a1b2f9402fef980d1103f020d717cfc..a98fbdfbb46296a261ecd0885f4e69ad748981ef 100755 (executable)
@@ -19,6 +19,7 @@ public class Test {
                [MarshalAs (UnmanagedType.ByValArray, SizeConst=2)] public short[] a1;
                [MarshalAs (UnmanagedType.ByValTStr, SizeConst=4)] public string s1;
                public SimpleStruct2 emb1;
+               public string s2;
        }
        
        public unsafe static int Main () {
@@ -27,7 +28,7 @@ public class Test {
                int size = Marshal.SizeOf (typeof (SimpleStruct));
                
                Console.WriteLine ("SimpleStruct:" + size);
-               if (size != 32)
+               if (size != 36)
                        return 1;
                
                IntPtr p = Marshal.AllocHGlobal (size);
@@ -42,7 +43,8 @@ public class Test {
                ss.emb1 = new SimpleStruct2 ();
                ss.emb1.a = 3;
                ss.emb1.b = 4;
-                               
+               ss.s2 = "just a test";
+               
                Marshal.StructureToPtr (ss, p, false);
                if (Marshal.ReadInt32 (p, 0) != 1)
                        return 1;
@@ -68,10 +70,42 @@ public class Test {
                        return 1;
                if (Marshal.ReadInt32 (p, 28) != 4)
                        return 1;
+               if (Marshal.ReadInt32 (p, 32) == 0)
+                       return 1;
 
                object o = cp;
                Marshal.PtrToStructure (p, o);
                cp = (SimpleStruct)o;
+
+               if (cp.a != 1)
+                       return 2;
+
+               if (cp.bool1 != true)
+                       return 2;
+
+               if (cp.bool2 != false)
+                       return 2;
+
+               if (cp.b != 2)
+                       return 2;
+
+               if (cp.a1 [0] != 6)
+                       return 2;
+               
+               if (cp.a1 [1] != 5)
+                       return 2;
+
+               if (cp.s1 != "abc")
+                       return 3;
+               
+               if (cp.emb1.a != 3)
+                       return 2;
+
+               if (cp.emb1.b != 4)
+                       return 2;
+
+               if (cp.s2 != "just a test")
+                       return 2;
                
                return 0;
        }
index fe1914aa3aa42094bb8af538a28eb2c5562825d3..7b16f5483f2b45875f2a297262dc227e99065f1c 100755 (executable)
@@ -13,7 +13,7 @@ public class Test {
 
        public static int delegate_test (SimpleStruct ss)
        {
-               Console.WriteLine ("Delegate: " + ss);
+               Console.WriteLine ("delegate called");
                
                if (!ss.a && ss.b && !ss.c && ss.d == "TEST")
                        return 0;