• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

i-net-software / JWebAssembly / 534

pending completion
534

push

travis-ci-com

Horcrux7
replace static constructor für MethodHandles.

1 of 1 new or added line in 1 file covered. (100.0%)

5933 of 6826 relevant lines covered (86.92%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/de/inetsoftware/jwebassembly/module/nativecode/ReplacementForClass.java
1
/*
2
   Copyright 2020 - 2023 Volker Berlin (i-net software)
3

4
   Licensed under the Apache License, Version 2.0 (the "License");
5
   you may not use this file except in compliance with the License.
6
   You may obtain a copy of the License at
7

8
       http://www.apache.org/licenses/LICENSE-2.0
9

10
   Unless required by applicable law or agreed to in writing, software
11
   distributed under the License is distributed on an "AS IS" BASIS,
12
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
   See the License for the specific language governing permissions and
14
   limitations under the License.
15

16
*/
17
package de.inetsoftware.jwebassembly.module.nativecode;
18

19
import static de.inetsoftware.jwebassembly.module.TypeManager.BOOLEAN;
20
import static de.inetsoftware.jwebassembly.module.TypeManager.BYTE;
21
import static de.inetsoftware.jwebassembly.module.TypeManager.CHAR;
22
import static de.inetsoftware.jwebassembly.module.TypeManager.DOUBLE;
23
import static de.inetsoftware.jwebassembly.module.TypeManager.FLOAT;
24
import static de.inetsoftware.jwebassembly.module.TypeManager.INT;
25
import static de.inetsoftware.jwebassembly.module.TypeManager.LONG;
26
import static de.inetsoftware.jwebassembly.module.TypeManager.SHORT;
27
import static de.inetsoftware.jwebassembly.module.TypeManager.TYPE_DESCRIPTION_ARRAY_TYPE;
28
import static de.inetsoftware.jwebassembly.module.TypeManager.TYPE_DESCRIPTION_INSTANCEOF_OFFSET;
29
import static de.inetsoftware.jwebassembly.module.TypeManager.TYPE_DESCRIPTION_TYPE_NAME;
30
import static de.inetsoftware.jwebassembly.module.TypeManager.VOID;
31

32
import java.io.InputStream;
33
import java.lang.reflect.Constructor;
34
import java.lang.reflect.Field;
35
import java.lang.reflect.Method;
36
import java.lang.reflect.Type;
37
import java.util.Map;
38

39
import de.inetsoftware.jwebassembly.api.annotation.Partial;
40
import de.inetsoftware.jwebassembly.api.annotation.Replace;
41
import de.inetsoftware.jwebassembly.api.annotation.WasmTextCode;
42
import de.inetsoftware.jwebassembly.module.TypeManager;
43

44
/**
45
 * Replacement for java.lang.Class
46
 *
47
 * @param <T> the type of the class modeled by this {@code Class}
48
 * @author Volker Berlin
49
 */
50
@Partial( "java/lang/Class" )
51
class ReplacementForClass<T> {
52

53
    /**
54
     * The pointer in the memory for the class/type description.
55
     */
56
    final int vtable;
57

58
    final int classIdx;
59

60
    private static void registerNatives() {}
×
61

62
    /**
63
     * Create a instance
64
     * 
65
     * @param vtable
66
     *            the pointer in the memory for the class/type description.
67
     * @param classIdx
68
     *            the class index, the ID of the class
69
     */
70
    private ReplacementForClass( int vtable, int classIdx ) {
×
71
        this.vtable = vtable;
×
72
        this.classIdx = classIdx;
×
73
    }
×
74

75
    /**
76
     * Replacement for {@link Object#getClass()}. The documentation of the memory of the type description is done in method:
77
     * {@link TypeManager.StructType#writeToStream(java.io.ByteArrayOutputStream, java.util.function.ToIntFunction)}
78
     * 
79
     * @param obj
80
     *            the instance
81
     * @return the class
82
     */
83
    @WasmTextCode( "local.get 0 " // THIS
84
                    + "struct.get java/lang/Object .vtable " // vtable is on index 0
85
                    + "local.tee 1 " // save the vtable location
86
                    + "i32.const " + TYPE_DESCRIPTION_INSTANCEOF_OFFSET + " " // vtable is on index 0
87
                    + "i32.add " //
88
                    + "call $java/lang/Class.getIntFromMemory(I)I " //
89
                    + "local.get 1 " // get the vtable location
90
                    + "i32.add " //
91
                    + "i32.const 4 " // length of instanceof
92
                    + "i32.add " //
93
                    + "call $java/lang/Class.getIntFromMemory(I)I " // first entry in instanceof is ever the id of the Class self
94
                    + "call $java/lang/Class.classConstant(I)Ljava/lang/Class; " //
95
                    + "return " //
96
    )
97
    @Replace( "java/lang/Object.getClass()Ljava/lang/Class;" )
98
    private static native ReplacementForClass<?> getClassObject( Object obj );
99

100
    /**
101
     * WASM code
102
     * <p>
103
     * Get a constant Class from the table.
104
     * 
105
     * @param classIdx
106
     *            the id/index of the Class.
107
     * @return the string
108
     * @see TypeManager#getClassConstantFunction()
109
     */
110
    private static ReplacementForClass<?> classConstant( int classIdx ) {
111
        ReplacementForClass<?> clazz = getClassFromTable( classIdx );
×
112
        if( clazz != null ) {
×
113
            return clazz;
×
114
        }
115

116
        /*
117
            The memory/data section has the follow content:
118
             ┌──────────────────────────────────┐
119
             | Type/Class descriptions (vtable) |
120
             ├──────────────────────────────────┤
121
             | Type/Class table                 |
122
             ├──────────────────────────────────┤
123
             | String table                     |
124
             └──────────────────────────────────┘
125
        */
126
        int vtable = getIntFromMemory( classIdx * 4 + typeTableMemoryOffset() );
×
127
        clazz = new ReplacementForClass<>( vtable, classIdx );
×
128
        // save the string for future use
129
        setClassIntoTable( classIdx, clazz );
×
130
        return clazz;
×
131
    }
132

133
    /**
134
     * WASM code
135
     * <p>
136
     * Get a Class instance from the Class table. Should be inlined from the optimizer.
137
     * 
138
     * @param classIdx
139
     *            the id/index of the Class.
140
     * @return the string or null if not already set.
141
     */
142
    @WasmTextCode( "local.get 0 " + //
143
                    "table.get 2 " + // table 2 is used for classes
144
                    "return" )
145
    private static native ReplacementForClass<?> getClassFromTable( int classIdx );
146

147
    /**
148
     * WASM code
149
     * <p>
150
     * Set a Class instance in the Class table. Should be inlined from the optimizer.
151
     * 
152
     * @param strIdx
153
     *            the id/index of the string.
154
     * @param clazz
155
     *            the Class instance
156
     */
157
    @WasmTextCode( "local.get 0 " + //
158
                    "local.get 1 " + //
159
                    "table.set 2 " + // table 2 is used for classes
160
                    "return" )
161
    private static native void setClassIntoTable( int strIdx, ReplacementForClass<?> clazz );
162

163
    /**
164
     * WASM code
165
     * <p>
166
     * Placeholder for a synthetic function. Should be inlined from the optimizer.
167
     * 
168
     * @return the memory offset of the string data in the element section
169
     */
170
    private static native int typeTableMemoryOffset();
171

172
    /**
173
     * WASM code
174
     * <p>
175
     * Load an i32 from memory. The offset must be aligned. Should be inlined from the optimizer.
176
     * 
177
     * @param pos
178
     *            the memory position
179
     * @return the value from the memory
180
     */
181
    @WasmTextCode( "local.get 0 " + //
182
                    "i32.load offset=0 align=4 " + //
183
                    "return" )
184
    private static native int getIntFromMemory( int pos );
185

186
    /**
187
     * Replacement of the Java method forName(String)
188
     * 
189
     * @param className
190
     *            the fully qualified name of the desired class.
191
     * @return the {@code Class} object for the class with the specified name.
192
     */
193
    public static Class<?> forName( String className ) throws ClassNotFoundException {
194
        throw new ClassNotFoundException( className ); // TODO
×
195
    }
196

197
    /**
198
     * Replacement of the Java method forName(String)
199
     * 
200
     * @param name
201
     *            the fully qualified name of the desired class.
202
     * @return the {@code Class} object for the class with the specified name.
203
     */
204
    public static Class<?> forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException {
205
        return forName( name );
×
206
    }
207

208
    /**
209
     * Replacement of the Java 9 method forName(Module,String)
210
     * 
211
     * @param module
212
     *            the module
213
     * @param name
214
     *            the fully qualified name of the desired class.
215
     * @return the {@code Class} object for the class with the specified name.
216
     */
217
    @Replace( "java/lang/Class.forName(Ljava/lang/Module;Ljava/lang/String;)Ljava/lang/Class;" )
218
    public static Class<?> forName( Object module, String name ) {
219
        return null;
×
220
    }
221

222
    /**
223
     * Replacement of the Java method newInstance()
224
     * 
225
     * @return a newly allocated instance of the class represented by this object.
226
     */
227
    public T newInstance() throws InstantiationException, IllegalAccessException {
228
        throw new InstantiationException( getName() ); // TODO
×
229
    }
230

231
    /**
232
     * Replacement of the Java method isInstance()
233
     * 
234
     * @param obj
235
     *            the object to check
236
     * @return true if {@code obj} is an instance of this class
237
     */
238
    @WasmTextCode( "unreachable" ) // TODO
239
    public native boolean isInstance( Object obj );
240

241
    /**
242
     * Replacement of the Java method isAssignableFrom()
243
     * 
244
     * @param cls
245
     *            the class to check
246
     * @return true, if type {@code cls} can be assigned to objects of this class
247
     */
248
    @WasmTextCode( "unreachable" ) // TODO
249
    public native boolean isAssignableFrom( ReplacementForClass<?> cls );
250

251
    /**
252
     * Replacement of the Java method isInterface()
253
     *
254
     * @return  {@code true} if this object represents an interface;
255
     */
256
    @WasmTextCode( "unreachable" ) // TODO
257
    public native boolean isInterface();
258

259
    /**
260
     * Replacement of the Java method isArray()
261
     * @return {@code true} if this object represents an array class;
262
     */
263
    public boolean isArray() {
264
        int classIdx = getIntFromMemory( vtable + TYPE_DESCRIPTION_ARRAY_TYPE );
×
265
        return classIdx >= 0;
×
266
    }
267

268
    /**
269
     * Replacement of the Java method {@link Class#isPrimitive()}
270
     * 
271
     * @return true if and only if this class represents a primitive type
272
     */
273
    public boolean isPrimitive() {
274
        // the first 9 classes are primitive classes
275
        return classIdx <= VOID;
×
276
    }
277

278
    /**
279
     * Replacement for {@link Class#getName()}
280
     * 
281
     * @return the name
282
     */
283
    public String getName() {
284
        return StringTable.stringConstant( getIntFromMemory( vtable + TYPE_DESCRIPTION_TYPE_NAME ) );
×
285
    }
286

287
    /**
288
     * Replacement of the Java method getClassLoader()
289
     */
290
    public ClassLoader getClassLoader() {
291
        return null;
×
292
    }
293

294
    /**
295
     * Replacement of the Java method getClassLoader0()
296
     */
297
    ClassLoader getClassLoader0() {
298
        return null;
×
299
    }
300

301
    /**
302
     * Replacement of the Java methods getSuperclass()
303
     */
304
    @WasmTextCode( "unreachable" ) // TODO
305
    public native Class<? super T> getSuperclass();
306

307
    /**
308
     * Replacement of the Java methods getPackage()
309
     */
310
    public Package getPackage() {
311
        return null;
×
312
    }
313

314
    /**
315
     * Replacement of the Java method getInterfaces()
316
     * @return an array of interfaces implemented by this class.
317
     */
318
    public Class<?>[] getInterfaces() { //TODO
319
        return new Class<?>[0];
×
320
    }
321

322
    /**
323
     * Replacement of the Java method getGenericInterfaces()
324
     * @return an array of interfaces implemented by this class
325
     */
326
    public Type[] getGenericInterfaces() { // TODO
327
        return getInterfaces();
×
328
    }
329

330
    /**
331
     * Replacement of the native Java method getComponentType()
332
     */
333
    public ReplacementForClass<?> getComponentType() {
334
        int classIdx = getIntFromMemory( vtable + TYPE_DESCRIPTION_ARRAY_TYPE );
×
335
        return classIdx >= 0 ? classConstant( classIdx ) : null;
×
336
    }
337

338
    /**
339
     * Replacement of the native Java method getModifiers()
340
     */
341
    public int getModifiers() {
342
        return 0;
×
343
    }
344

345
    /**
346
     * Gets the signers of this class.
347
     */
348
    public Object[] getSigners() {
349
        return null;
×
350
    }
351

352
    /**
353
     * Get the declaring class
354
     * @return the declaring class for this class
355
     */
356
    private Class<?> getDeclaringClass0() {
357
        return null;
×
358
    }
359

360
    /**
361
     * Replacement of the Java method getSimpleName()
362
     * 
363
     * @return the simple name of the underlying class
364
     */
365
    public String getSimpleName() {
366
        if( isArray() )
×
367
            return getComponentType().getSimpleName() + "[]";
×
368

369
        String simpleName = getName();
×
370
        int index = simpleName.lastIndexOf( '$' ) + 1;
×
371
        if( index == 0 ) { // top level class
×
372
            return simpleName.substring( simpleName.lastIndexOf( '.' ) + 1 ); // strip the package name
×
373
        }
374

375
        // Remove leading "\$[0-9]*" from the name
376
        int length = simpleName.length();
×
377
        while( index < length ) {
×
378
            char ch = simpleName.charAt( index );
×
379
            if( '0' <= ch && ch <= '9' ) {
×
380
                index++;
×
381
            } else  {
382
                break;
383
            }
384
        }
×
385
        // Eventually, this is the empty string iff this is an anonymous class
386
        return simpleName.substring( index );
×
387
    }
388

389
    /**
390
     * Replacement of the Java method getTypeName()
391
     * 
392
     * @return an informative string for the name of this type
393
     */
394
    public String getTypeName() {
395
        if (isArray()) {
×
396
            try {
397
                ReplacementForClass<?> cl = this;
×
398
                int dimensions = 0;
×
399
                while (cl.isArray()) {
×
400
                    dimensions++;
×
401
                    cl = cl.getComponentType();
×
402
                }
403
                StringBuilder sb = new StringBuilder();
×
404
                sb.append(cl.getName());
×
405
                for (int i = 0; i < dimensions; i++) {
×
406
                    sb.append("[]");
×
407
                }
408
                return sb.toString();
×
409
            } catch (Throwable e) { /*FALLTHRU*/ }
×
410
        }
411
        return getName();
×
412
    }
413

414
    /**
415
     * Replacement of the Java method getCanonicalName()
416
     * 
417
     * @return the canonical name of the underlying class
418
     */
419
    public String getCanonicalName() {
420
        String canonicalName;
421
        if( isArray() ) {
×
422
            canonicalName = getComponentType().getCanonicalName();
×
423
            if( canonicalName != null )
×
424
                return canonicalName + "[]";
×
425
            else
426
                return null;
×
427
        }
428
        canonicalName = getName();
×
429
        int idx = canonicalName.indexOf( '$' );
×
430
        if( idx >= 0 ) {
×
431
            idx++;
×
432
            if( idx < canonicalName.length() ) {
×
433
                char ch = canonicalName.charAt( idx );
×
434
                if( '0' <= ch && ch <= '9' ) {
×
435
                    return null;
×
436
                }
437
            }
438
            return canonicalName.replace( '$', '.' );
×
439
        }
440
        return canonicalName;
×
441
    }
442

443
    /**
444
     * Returns an array containing {@code Method} objects reflecting all the
445
     * public methods of the class or interface represented by this {@code
446
     * Class} object
447
     */
448
    @WasmTextCode( "unreachable" ) // TODO
449
    public native Method[] getMethods();
450

451
    /**
452
     * Replacement of the Java method getMethod()
453
     */
454
    @WasmTextCode( "unreachable" ) // TODO
455
    public native Method getMethod(String name, Class<?>... parameterTypes);
456

457
    /**
458
     * Returns a {@code Constructor} object that reflects the specified
459
     * public constructor of the class represented by this {@code Class}
460
     * object.
461
     */
462
    @WasmTextCode( "unreachable" ) // TODO
463
    public native Constructor<T> getConstructor(Class<?>... parameterTypes);
464

465
    /**
466
     * Returns an array of {@code Field} objects reflecting all the fields
467
     */
468
    @WasmTextCode( "unreachable" ) // TODO
469
    public native Field[] getDeclaredFields();
470

471
    /**
472
     * Returns an array containing {@code Method} objects reflecting all the
473
     * declared methods of the class or interface represented by this {@code
474
     * Class} object
475
     */
476
    @WasmTextCode( "unreachable" ) // TODO
477
    public native Method[] getDeclaredMethods();
478

479
    /**
480
     * Returns an array of {@code Constructor} objects reflecting all the
481
     * constructors declared by the class represented by this
482
     */
483
    @WasmTextCode( "unreachable" ) // TODO
484
    public native Constructor<?>[] getDeclaredConstructors();
485

486
    /**
487
     * Replacement of the Java method getDeclaredField()
488
     */
489
    @WasmTextCode( "unreachable" ) // TODO
490
    public native Field getDeclaredField(String name);
491

492
    /**
493
     * Replacement of the Java method getDeclaredMethod()
494
     */
495
    @WasmTextCode( "unreachable" ) // TODO
496
    public native Method getDeclaredMethod(String name, Class<?>... parameterTypes);
497

498
    /**
499
     * Replacement of the Java method getDeclaredConstructor()
500
     */
501
    @WasmTextCode( "unreachable" ) // TODO
502
    public native Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes);
503

504
    /**
505
     * Replacement of the Java method getResourceAsStream()
506
     */
507
    public InputStream getResourceAsStream(String name) {
508
        return null; //TODO
×
509
    }
510

511
    /**
512
     * Returns the {@code ProtectionDomain} of this class.
513
     */
514
    public java.security.ProtectionDomain getProtectionDomain() {
515
        return new java.security.ProtectionDomain(null, null);
×
516
    }
517

518
    /**
519
     * Replacement of the native Java method {@link Class#getPrimitiveClass}
520
     * 
521
     * @param name
522
     *            the class name
523
     * @return the class
524
     * @see TypeManager#PRIMITIVE_CLASSES
525
     */
526
    static ReplacementForClass<?> getPrimitiveClass( String name ) {
527
        switch( name ) {
×
528
            case "boolean":
529
                return classConstant( BOOLEAN );
×
530
            case "byte":
531
                return classConstant( BYTE );
×
532
            case "char":
533
                return classConstant( CHAR );
×
534
            case "double":
535
                return classConstant( DOUBLE );
×
536
            case "float":
537
                return classConstant( FLOAT );
×
538
            case "int":
539
                return classConstant( INT );
×
540
            case "long":
541
                return classConstant( LONG );
×
542
            case "short":
543
                return classConstant( SHORT );
×
544
            case "void":
545
                return classConstant( VOID );
×
546
        }
547
        return null;
×
548
    }
549

550
    /**
551
     * Replacement of the native Java method {@link Class#desiredAssertionStatus()}
552
     * 
553
     * @return the desired assertion status of the specified class.
554
     */
555
    public boolean desiredAssertionStatus() {
556
        return false;
×
557
    }
558

559
    /**
560
     * Replacement of the Java method enumConstantDirectory()
561
     *
562
     * Returns a map from simple name to enum constant.  This package-private
563
     * method is used internally by Enum to implement
564
     */
565
    @WasmTextCode( "unreachable" ) // TODO
566
    native Map<String, T> enumConstantDirectory();
567

568
    /**
569
     * Replacement of the Java method cast(Object)
570
     *
571
     * @param obj the object to be cast
572
     * @return the object after casting, or null if obj is null
573
     */
574
    @SuppressWarnings("unchecked")
575
    public T cast(Object obj) {
576
        if (obj != null && !isInstance(obj))
×
577
            throw new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + getName());
×
578
        return (T) obj;
×
579
    }
580

581
    /**
582
     * Replacement of the Java method asSubclass(Class)
583
     *
584
     * @param clazz
585
     *            the class of the type to cast this class object to
586
     * @return this
587
     */
588
    @SuppressWarnings( "unchecked" )
589
    public <U> ReplacementForClass<? extends U> asSubclass( ReplacementForClass<U> clazz ) {
590
        if( clazz.isAssignableFrom( this ) )
×
591
            return (ReplacementForClass<? extends U>)this;
×
592
        else
593
            throw new ClassCastException( this.toString() );
×
594
    }
595
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc