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

i-net-software / JWebAssembly / 521

pending completion
521

push

travis-ci-com

Horcrux7
Unsafe code for AtomicReference

5 of 5 new or added lines in 2 files covered. (100.0%)

5772 of 6694 relevant lines covered (86.23%)

0.86 hits per line

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

6.96
/src/de/inetsoftware/jwebassembly/module/UnsafeManager.java
1
/*
2
 * Copyright 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
package de.inetsoftware.jwebassembly.module;
17

18
import java.util.HashMap;
19
import java.util.List;
20

21
import javax.annotation.Nonnull;
22

23
import de.inetsoftware.jwebassembly.WasmException;
24
import de.inetsoftware.jwebassembly.module.StackInspector.StackValue;
25
import de.inetsoftware.jwebassembly.module.WasmInstruction.Type;
26
import de.inetsoftware.jwebassembly.wasm.AnyType;
27
import de.inetsoftware.jwebassembly.wasm.ValueType;
28
import de.inetsoftware.jwebassembly.wasm.VariableOperator;
29

30
/**
31
 * Replace Unsafe operations with simpler WASM operations which does not need reflections.
32
 * 
33
 * In Java a typical Unsafe code look like:
34
 * 
35
 * <pre>
36
 * <code>
37
 * private static final Unsafe UNSAFE = Unsafe.getUnsafe();
38
 * private static final long FIELD_OFFSET = UNSAFE.objectFieldOffset(Foobar.class.getDeclaredField("field"));
39
 * 
40
 * ...
41
 * 
42
 * UNSAFE.compareAndSwapInt(this, FIELD_OFFSET, expect, update);
43
 * </code>
44
 * </pre>
45
 * 
46
 * Because WASM does not support reflection the native code of UNSAFE can't simple replaced. That this manager convert
47
 * this to the follow pseudo code in WASM:
48
 * 
49
 * <pre>
50
 * <code>
51
 * Foobar..compareAndSwapInt(this, FIELD_OFFSET, expect, update);
52
 * 
53
 * ...
54
 * 
55
 * boolean .compareAndSwapInt(Object obj, long fieldOffset, int expect, int update ) {
56
 *     if( obj.field == expect ) {
57
 *         obj.field = update;
58
 *         return true;
59
 *     }
60
 *     return false;
61
 * }
62
 * </code>
63
 * </pre>
64
 * 
65
 * @author Volker Berlin
66
 */
67
class UnsafeManager {
68

69
    /** Unsafe class bane in Java 8 */
70
    static final String                              UNSAFE_8  = "sun/misc/Unsafe";
71

72
    /** Unsafe class bane in Java 11 */
73
    static final String                              UNSAFE_11 = "jdk/internal/misc/Unsafe";
74

75
    @Nonnull
76
    private final FunctionManager                    functions;
77

78
    private final HashMap<FunctionName, UnsafeState> unsafes   = new HashMap<>();
1✔
79

80
    /**
81
     * Create an instance of the manager
82
     * 
83
     * @param functions
84
     *            The function manager to register the synthetic functions.
85
     */
86
    UnsafeManager( @Nonnull FunctionManager functions ) {
1✔
87
        this.functions = functions;
1✔
88
    }
1✔
89

90
    /**
91
     * Replace any Unsafe API call with direct field access.
92
     * 
93
     * @param instructions
94
     *            the instruction list of a function/method
95
     */
96
    void replaceUnsafe( List<WasmInstruction> instructions ) {
97
        // search for Unsafe function calls
98
        for( int i = 0; i < instructions.size(); i++ ) {
1✔
99
            WasmInstruction instr = instructions.get( i );
1✔
100
            switch( instr.getType() ) {
1✔
101
                case CallVirtual:
102
                case Call:
103
                    WasmCallInstruction callInst = (WasmCallInstruction)instr;
1✔
104
                    switch( callInst.getFunctionName().className ) {
1✔
105
                        case UNSAFE_8:
106
                        case UNSAFE_11:
107
                            patch( instructions, i, callInst );
×
108
                            break;
109
                    }
110
                    break;
1✔
111
                default:
112
            }
113
        }
114
    }
1✔
115

116
    /**
117
     * Patch in the instruction list an Unsafe method call. It does not change the count of instructions.
118
     * 
119
     * @param instructions
120
     *            the instruction list of a function/method
121
     * @param idx
122
     *            the index in the instructions
123
     * @param callInst
124
     *            the method call to Unsafe
125
     */
126
    private void patch( List<WasmInstruction> instructions, int idx, WasmCallInstruction callInst ) {
127
        FunctionName name = callInst.getFunctionName();
×
128
        switch( name.signatureName ) {
×
129
            case "sun/misc/Unsafe.getUnsafe()Lsun/misc/Unsafe;":
130
            case "jdk/internal/misc/Unsafe.getUnsafe()Ljdk/internal/misc/Unsafe;":
131
                patch_getUnsafe( instructions, idx );
×
132
                break;
×
133
            case "sun/misc/Unsafe.objectFieldOffset(Ljava/lang/reflect/Field;)J":
134
            case "jdk/internal/misc/Unsafe.objectFieldOffset(Ljava/lang/reflect/Field;)J":
135
                patch_objectFieldOffset_Java8( instructions, idx, callInst );
×
136
                break;
×
137
            case "jdk/internal/misc/Unsafe.objectFieldOffset(Ljava/lang/Class;Ljava/lang/String;)J":
138
                patch_objectFieldOffset_Java11( instructions, idx, callInst );
×
139
                break;
×
140
            case "sun/misc/Unsafe.arrayBaseOffset(Ljava/lang/Class;)I":
141
            case "jdk/internal/misc/Unsafe.arrayBaseOffset(Ljava/lang/Class;)I":
142
                patch_arrayBaseOffset( instructions, idx, callInst );
×
143
                break;
×
144
            case "sun/misc/Unsafe.arrayIndexScale(Ljava/lang/Class;)I":
145
            case "jdk/internal/misc/Unsafe.arrayIndexScale(Ljava/lang/Class;)I":
146
                patch_arrayIndexScale( instructions, idx, callInst );
×
147
                break;
×
148
            case "sun/misc/Unsafe.getAndAddInt(Ljava/lang/Object;JI)I":
149
            case "sun/misc/Unsafe.getAndSetInt(Ljava/lang/Object;JI)I":
150
            case "sun/misc/Unsafe.putOrderedInt(Ljava/lang/Object;JI)V":
151
            case "sun/misc/Unsafe.getAndAddLong(Ljava/lang/Object;JJ)J":
152
            case "sun/misc/Unsafe.getAndSetLong(Ljava/lang/Object;JJ)J":
153
            case "sun/misc/Unsafe.putOrderedLong(Ljava/lang/Object;JJ)V":
154
            case "sun/misc/Unsafe.getObjectVolatile(Ljava/lang/Object;J)Ljava/lang/Object;":
155
            case "sun/misc/Unsafe.putOrderedObject(Ljava/lang/Object;JLjava/lang/Object;)V":
156
            case "sun/misc/Unsafe.getAndSetObject(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;":
157
            case "jdk/internal/misc/Unsafe.getAndAddInt(Ljava/lang/Object;JI)I":
158
            case "jdk/internal/misc/Unsafe.getAndSetInt(Ljava/lang/Object;JI)I":
159
            case "jdk/internal/misc/Unsafe.putIntRelease(Ljava/lang/Object;JI)V":
160
            case "jdk/internal/misc/Unsafe.getAndAddLong(Ljava/lang/Object;JJ)J":
161
            case "jdk/internal/misc/Unsafe.getAndSetLong(Ljava/lang/Object;JJ)J":
162
            case "jdk/internal/misc/Unsafe.putLongRelease(Ljava/lang/Object;JJ)V":
163
            case "jdk/internal/misc/Unsafe.putLongVolatile(Ljava/lang/Object;JJ)V":
164
            case "jdk/internal/misc/Unsafe.putObject(Ljava/lang/Object;JLjava/lang/Object;)V":
165
            case "jdk/internal/misc/Unsafe.getObjectAcquire(Ljava/lang/Object;J)Ljava/lang/Object;":
166
                patchFieldFunction( instructions, idx, callInst, name, 2 );
×
167
                break;
×
168
            case "sun/misc/Unsafe.compareAndSwapInt(Ljava/lang/Object;JII)Z":
169
            case "sun/misc/Unsafe.compareAndSwapLong(Ljava/lang/Object;JJJ)Z":
170
            case "sun/misc/Unsafe.compareAndSwapObject(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z":
171
            case "jdk/internal/misc/Unsafe.compareAndSetInt(Ljava/lang/Object;JII)Z":
172
            case "jdk/internal/misc/Unsafe.compareAndSetLong(Ljava/lang/Object;JJJ)Z":
173
            case "jdk/internal/misc/Unsafe.compareAndSetObject(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z":
174
                patchFieldFunction( instructions, idx, callInst, name, 3 );
×
175
                break;
×
176
            case "jdk/internal/misc/Unsafe.getLongUnaligned(Ljava/lang/Object;J)J":
177
            case "jdk/internal/misc/Unsafe.getIntUnaligned(Ljava/lang/Object;J)I":
178
            case "jdk/internal/misc/Unsafe.getCharUnaligned(Ljava/lang/Object;JZ)C":
179
            case "jdk/internal/misc/Unsafe.getIntUnaligned(Ljava/lang/Object;JZ)I":
180
                patch_getLongUnaligned( instructions, idx, callInst, name );
×
181
                break;
×
182
            case "jdk/internal/misc/Unsafe.isBigEndian()Z":
183
                patch_isBigEndian( instructions, idx, callInst );
×
184
                break;
×
185
            case "jdk/internal/misc/Unsafe.shouldBeInitialized(Ljava/lang/Class;)Z":
186
                replaceWithConstNumber( instructions, idx, callInst, 2, 0 );
×
187
                break;
×
188
            case "jdk/internal/misc/Unsafe.storeFence()V":
189
                remove( instructions, idx, callInst, 1 );
×
190
                break;
×
191
            case "jdk/internal/misc/Unsafe.ensureClassInitialized(Ljava/lang/Class;)V":
192
            case "jdk/internal/misc/Unsafe.unpark(Ljava/lang/Object;)V":
193
                remove( instructions, idx, callInst, 2 );
×
194
                break;
×
195
            case "jdk/internal/misc/Unsafe.park(ZJ)V":
196
                remove( instructions, idx, callInst, 3 );
×
197
                break;
×
198
            default:
199
                throw new WasmException( "Unsupported Unsafe method: " + name.signatureName, -1 );
×
200
        }
201
    }
×
202

203
    /**
204
     * Replace a call to Unsafe.getUnsafe() with a NOP operation.
205
     * 
206
     * @param instructions
207
     *            the instruction list of a function/method
208
     * @param idx
209
     *            the index in the instructions
210
     */
211
    private void patch_getUnsafe( List<WasmInstruction> instructions, int idx ) {
212
        WasmInstruction instr = instructions.get( idx + 1 );
×
213

214
        int to = idx + (instr.getType() == Type.Global ? 2 : 1);
×
215

216
        nop( instructions, idx, to );
×
217
    }
×
218

219
    /**
220
     * Find the field on which the offset is assign: long FIELD_OFFSET = UNSAFE.objectFieldOffset(...
221
     * 
222
     * @param instructions
223
     *            the instruction list of a function/method
224
     * @param idx
225
     *            the index in the instructions
226
     * @return the state
227
     */
228
    @Nonnull
229
    private UnsafeState findUnsafeState( List<WasmInstruction> instructions, int idx ) {
230
        // find the field on which the offset is assign: long FIELD_OFFSET = UNSAFE.objectFieldOffset(...
231
        WasmInstruction instr;
232
        idx++;
×
233
        INSTR: do {
234
            instr = instructions.get( idx );
×
235
            switch( instr.getType() ) {
×
236
                case Convert:
237
                    idx++;
×
238
                    continue INSTR;
×
239
                case Global:
240
                    break;
×
241
                case Jump:
242
                    int pos = ((JumpInstruction)instr).getJumpPosition();
×
243
                    for( idx++; idx < instructions.size(); idx++) {
×
244
                        instr = instructions.get( idx );
×
245
                        if( instr.getCodePosition() >= pos ) {
×
246
                            break;
×
247
                        }
248
                    }
249
                    continue INSTR;
250
                default:
251
                    throw new WasmException( "Unsupported assign operation for Unsafe field offset: " + instr.getType(), -1 );
×
252
            }
253
            break;
254
        } while( true );
255
        FunctionName fieldNameWithOffset = ((WasmGlobalInstruction)instr).getFieldName();
×
256
        UnsafeState state = unsafes.get( fieldNameWithOffset );
×
257
        if( state == null ) {
×
258
            unsafes.put( fieldNameWithOffset, state = new UnsafeState() );
×
259
        }
260
        return state;
×
261
    }
262

263
    /**
264
     * Get the class name from the stack value. It is searching a WasmConstClassInstruction that produce the value of
265
     * the stack value.
266
     * 
267
     * @param instructions
268
     *            the instruction list of a function/method
269
     * @param stackValue
270
     *            the stack value (instruction and position that produce an stack value)
271
     * @return the class name like: java/lang/String
272
     */
273
    @Nonnull
274
    private static String getClassConst( List<WasmInstruction> instructions, StackValue stackValue ) {
275
        WasmInstruction instr = stackValue.instr;
×
276
        switch( instr.getType() ) {
×
277
            case Local:
278
                int slot = ((WasmLocalInstruction)instr).getSlot();
×
279
                for( int i = stackValue.idx - 1; i >= 0; i-- ) {
×
280
                    instr = instructions.get( i );
×
281
                    if( instr.getType() == Type.Local ) {
×
282
                        WasmLocalInstruction loadInstr = (WasmLocalInstruction)instr;
×
283
                        if( loadInstr.getSlot() == slot && loadInstr.getOperator() == VariableOperator.set ) {
×
284
                            stackValue = StackInspector.findInstructionThatPushValue( instructions.subList( 0, i ), 1, instr.getCodePosition() );
×
285
                            instr = stackValue.instr;
×
286
                            break;
×
287
                        }
288

289
                    }
290
                }
291
                break;
×
292
            default:
293
        }
294
        return ((WasmConstClassInstruction)instr).getValue();
×
295
    }
296

297
    /**
298
     * Patch a method call to Unsafe.objectFieldOffset() and find the parameter for other patch operations.
299
     * 
300
     * @param instructions
301
     *            the instruction list
302
     * @param idx
303
     *            the index in the instructions
304
     * @param callInst
305
     *            the method call to Unsafe
306
     */
307
    private void patch_objectFieldOffset_Java8( List<WasmInstruction> instructions, int idx, WasmCallInstruction callInst ) {
308
        UnsafeState state = findUnsafeState( instructions, idx );
×
309

310
        // objectFieldOffset() has 2 parameters THIS(Unsafe) and a Field
311
        List<WasmInstruction> paramInstructions = instructions.subList( 0, idx );
×
312
        int from = StackInspector.findInstructionThatPushValue( paramInstructions, 2, callInst.getCodePosition() ).idx;
×
313

314
        StackValue stackValue = StackInspector.findInstructionThatPushValue( paramInstructions, 1, callInst.getCodePosition() );
×
315
        WasmInstruction instr = stackValue.instr;
×
316
        WasmCallInstruction fieldInst = (WasmCallInstruction)instr;
×
317

318
        FunctionName fieldFuncName = fieldInst.getFunctionName();
×
319
        switch( fieldFuncName.signatureName ) {
×
320
            case "java/lang/Class.getDeclaredField(Ljava/lang/String;)Ljava/lang/reflect/Field;":
321
                stackValue = StackInspector.findInstructionThatPushValue( instructions.subList( 0, stackValue.idx ), 1, fieldInst.getCodePosition() );
×
322
                state.fieldName = ((WasmConstStringInstruction)stackValue.instr).getValue();
×
323

324
                // find the class value on which getDeclaredField is called
325
                stackValue = StackInspector.findInstructionThatPushValue( instructions.subList( 0, stackValue.idx ), 1, fieldInst.getCodePosition() );
×
326
                state.typeName = getClassConst( instructions, stackValue );
×
327
                break;
×
328

329
            default:
330
                throw new WasmException( "Unsupported Unsafe method to get target field: " + fieldFuncName.signatureName, -1 );
×
331
        }
332

333
        nop( instructions, from, idx + 2 );
×
334
    }
×
335

336
    /**
337
     * Patch a method call to Unsafe.objectFieldOffset() and find the parameter for other patch operations.
338
     * 
339
     * @param instructions
340
     *            the instruction list
341
     * @param idx
342
     *            the index in the instructions
343
     * @param callInst
344
     *            the method call to Unsafe
345
     */
346
    private void patch_objectFieldOffset_Java11( List<WasmInstruction> instructions, int idx, WasmCallInstruction callInst ) {
347
        UnsafeState state = findUnsafeState( instructions, idx );
×
348

349
        // objectFieldOffset() has 3 parameters THIS(Unsafe), class and the fieldname
350
        List<WasmInstruction> paramInstructions = instructions.subList( 0, idx );
×
351
        int from = StackInspector.findInstructionThatPushValue( paramInstructions, 3, callInst.getCodePosition() ).idx;
×
352

353
        StackValue stackValue = StackInspector.findInstructionThatPushValue( paramInstructions, 1, callInst.getCodePosition() );
×
354
        state.fieldName = ((WasmConstStringInstruction)stackValue.instr).getValue();
×
355

356
        // find the class value on which getDeclaredField is called
357
        stackValue = StackInspector.findInstructionThatPushValue( paramInstructions, 2, callInst.getCodePosition() );
×
358
        state.typeName = getClassConst( instructions, stackValue );
×
359

360
        nop( instructions, from, idx + 2 );
×
361
    }
×
362

363
    /**
364
     * Patch a method call to Unsafe.arrayBaseOffset() and find the parameter for other patch operations.
365
     * 
366
     * @param instructions
367
     *            the instruction list
368
     * @param idx
369
     *            the index in the instructions
370
     * @param callInst
371
     *            the method call to Unsafe
372
     */
373
    private void patch_arrayBaseOffset( List<WasmInstruction> instructions, int idx, WasmCallInstruction callInst ) {
374
        UnsafeState state = findUnsafeState( instructions, idx );
×
375

376
        // objectFieldOffset() has 2 parameters THIS(Unsafe) and a Class from an array
377
        List<WasmInstruction> paramInstructions = instructions.subList( 0, idx );
×
378
        int from = StackInspector.findInstructionThatPushValue( paramInstructions, 2, callInst.getCodePosition() ).idx;
×
379

380
        StackValue stackValue = StackInspector.findInstructionThatPushValue( paramInstructions, 1, callInst.getCodePosition() );
×
381
        state.typeName = getClassConst( instructions, stackValue );
×
382

383
        nop( instructions, from, idx );
×
384
        // we put the constant value 0 on the stack, we does not need array base offset in WASM
385
        instructions.set( idx, new WasmConstNumberInstruction( 0, callInst.getCodePosition(), callInst.getLineNumber() ) );
×
386
    }
×
387

388
    /**
389
     * Patch method call to Unsafe.arrayIndexScale()
390
     * 
391
     * @param instructions
392
     *            the instruction list
393
     * @param idx
394
     *            the index in the instructions
395
     * @param callInst
396
     *            the method call to Unsafe
397
     */
398
    private void patch_arrayIndexScale( List<WasmInstruction> instructions, int idx, WasmCallInstruction callInst ) {
399
        int from = StackInspector.findInstructionThatPushValue( instructions.subList( 0, idx ), 2, callInst.getCodePosition() ).idx;
×
400

401
        nop( instructions, from, idx );
×
402
        // we put the constant value 1 on the stack because we does not want shift array positions
403
        instructions.set( idx, new WasmConstNumberInstruction( 1, callInst.getCodePosition(), callInst.getLineNumber() ) );
×
404
    }
×
405

406
    /**
407
     * Patch an unsafe function that access a field
408
     * 
409
     * @param instructions
410
     *            the instruction list
411
     * @param idx
412
     *            the index in the instructions
413
     * @param callInst
414
     *            the method call to Unsafe
415
     * @param name
416
     *            the calling function
417
     * @param fieldNameParam
418
     *            the function parameter with the field offset. This must be a long (Java signature "J"). The THIS
419
     *            parameter has the index 0.
420
     */
421
    private void patchFieldFunction( List<WasmInstruction> instructions, int idx, final WasmCallInstruction callInst, FunctionName name, int fieldNameParam ) {
422
        StackValue stackValue = StackInspector.findInstructionThatPushValue( instructions.subList( 0, idx ), fieldNameParam, callInst.getCodePosition() );
×
423
        FunctionName fieldNameWithOffset = ((WasmGlobalInstruction)stackValue.instr).getFieldName();
×
424
        WatCodeSyntheticFunctionName func =
×
425
                        new WatCodeSyntheticFunctionName( fieldNameWithOffset.className, '.' + name.methodName, name.signature, "", (AnyType[])null ) {
×
426
                            @Override
427
                            protected String getCode() {
428
                                UnsafeState state = unsafes.get( fieldNameWithOffset );
×
429
                                if( state == null ) {
×
430
                                    // we are in the scan phase. The static code was not scanned yet.
431
                                    return "";
×
432
                                }
433
                                AnyType[] paramTypes = callInst.getPopValueTypes();
×
434
                                switch( name.methodName ) {
×
435
                                    case "compareAndSwapInt":
436
                                    case "compareAndSwapLong":
437
                                    case "compareAndSwapObject":
438
                                        AnyType type = paramTypes[3];
×
439
                                        if( type.isRefType() ) {
×
440
                                            type = ValueType.ref;
×
441
                                        }
442
                                        return "local.get 0" // THIS
×
443
                                                        + " struct.get " + state.typeName + ' ' + state.fieldName //
444
                                                        + " local.get 2 " // expected
445
                                                        + type + ".eq" //
446
                                                        + " if" //
447
                                                        + "   local.get 0" // THIS
448
                                                        + "   local.get 3" // update
449
                                                        + "   struct.set " + state.typeName + ' ' + state.fieldName //
450
                                                        + "   i32.const 1" //
451
                                                        + "   return" //
452
                                                        + " end" //
453
                                                        + " i32.const 1" //
454
                                                        + " return";
455

456
                                    case "getAndAddInt":
457
                                    case "getAndAddLong":
458
                                        return "local.get 0" // THIS
×
459
                                                        + " local.get 0" // THIS
460
                                                        + " struct.get " + state.typeName + ' ' + state.fieldName //
461
                                                        + " local.tee 3" // temp
462
                                                        + " local.get 2 " // delta
463
                                                        + paramTypes[3] + ".add" //
464
                                                        + " struct.set " + state.typeName + ' ' + state.fieldName //
465
                                                        + " local.get 3" // temp
466
                                                        + " return";
467

468
                                    case "getAndSetInt":
469
                                    case "getAndSetLong":
470
                                    case "getAndSetObject":
471
                                        return "local.get 0" // THIS
×
472
                                                        + " struct.get " + state.typeName + ' ' + state.fieldName //
473
                                                        + " local.get 0" // THIS
474
                                                        + " local.get 2" // newValue
475
                                                        + " struct.set " + state.typeName + ' ' + state.fieldName //
476
                                                        + " return";
477

478
                                    case "putOrderedInt":
479
                                    case "putOrderedLong":
480
                                    case "putOrderedObject":
481
                                        return "local.get 0" // THIS
×
482
                                                        + " local.get 2" // x
483
                                                        + " struct.set " + state.typeName + ' ' + state.fieldName;
484
                                }
485

486
                                throw new RuntimeException( name.signatureName );
×
487
                            }
488
                        };
489
        functions.markAsNeeded( func, false );
×
490
        WasmCallInstruction call = new WasmCallInstruction( func, callInst.getCodePosition(), callInst.getLineNumber(), callInst.getTypeManager(), false );
×
491
        instructions.set( idx, call );
×
492

493
        // a virtual method call has also a DUP of this because we need for virtual method dispatch the parameter 2 times.
494
        for( int i = idx; i >= 0; i-- ) {
×
495
            WasmInstruction instr = instructions.get( i );
×
496
            if( instr.getType() == Type.DupThis && ((DupThis)instr).getValue() == callInst ) {
×
497
                nop( instructions, i, i + 1 );
×
498
                break;
×
499
            }
500
        }
501
    }
×
502

503
    /**
504
     * Patch an unsafe function that access a field
505
     * 
506
     * @param instructions
507
     *            the instruction list
508
     * @param idx
509
     *            the index in the instructions
510
     * @param callInst
511
     *            the method call to Unsafe
512
     */
513
    private void patch_getLongUnaligned( List<WasmInstruction> instructions, int idx, final WasmCallInstruction callInst, FunctionName name ) {
514
        WatCodeSyntheticFunctionName func = new WatCodeSyntheticFunctionName( "", name.methodName, name.signature, "unreachable", (AnyType[])null );
×
515
        functions.markAsNeeded( func, false );
×
516
        WasmCallInstruction call = new WasmCallInstruction( func, callInst.getCodePosition(), callInst.getLineNumber(), callInst.getTypeManager(), false );
×
517
        instructions.set( idx, call );
×
518
    }
×
519

520
    /**
521
     * Patch an unsafe function that access a field
522
     * 
523
     * @param instructions
524
     *            the instruction list
525
     * @param idx
526
     *            the index in the instructions
527
     * @param callInst
528
     *            the method call to Unsafe
529
     */
530
    private void patch_isBigEndian( List<WasmInstruction> instructions, int idx, final WasmCallInstruction callInst ) {
531
//        int from = StackInspector.findInstructionThatPushValue( instructions.subList( 0, idx ), 1, callInst.getCodePosition() ).idx;
532
//
533
//        nop( instructions, from, idx );
534

535
        // on x86 use little endian
536
        instructions.set( idx, new WasmConstNumberInstruction( 0, callInst.getCodePosition(), callInst.getLineNumber() ) );
×
537
    }
×
538

539
    /**
540
     * Patch an unsafe function that access a field
541
     * 
542
     * @param instructions
543
     *            the instruction list
544
     * @param idx
545
     *            the index in the instructions
546
     * @param callInst
547
     *            the method call to Unsafe
548
     */
549
    private void replaceWithConstNumber( List<WasmInstruction> instructions, int idx, final WasmCallInstruction callInst, int paramCount, int number ) {
550
        int from = StackInspector.findInstructionThatPushValue( instructions.subList( 0, idx ), 1, callInst.getCodePosition() ).idx;
×
551

552
        nop( instructions, from, idx );
×
553

554
        // on x86 use little endian
555
        instructions.set( idx, new WasmConstNumberInstruction( number, callInst.getCodePosition(), callInst.getLineNumber() ) );
×
556
    }
×
557

558
    /**
559
     * Patch an unsafe function that access a field
560
     * 
561
     * @param instructions
562
     *            the instruction list
563
     * @param idx
564
     *            the index in the instructions
565
     * @param callInst
566
     *            the method call to Unsafe
567
     */
568
    private void remove( List<WasmInstruction> instructions, int idx, final WasmCallInstruction callInst, int paramCount ) {
569
        int from = StackInspector.findInstructionThatPushValue( instructions.subList( 0, idx ), paramCount, callInst.getCodePosition() ).idx;
×
570

571
        nop( instructions, from, idx + 1 );
×
572
    }
×
573

574
    /**
575
     * Replace the instructions with NOP operations
576
     * 
577
     * @param instructions
578
     *            the instruction list
579
     * @param from
580
     *            starting index
581
     * @param to
582
     *            end index
583
     */
584
    private void nop( List<WasmInstruction> instructions, int from, int to ) {
585
        for( int i = from; i < to; i++ ) {
×
586
            WasmInstruction instr = instructions.get( i );
×
587
            instructions.set( i, new WasmNopInstruction( instr.getCodePosition(), instr.getLineNumber() ) );
×
588
        }
589
    }
×
590

591
    /**
592
     * Hold the state from declaring of Unsafe address
593
     */
594
    static class UnsafeState {
×
595
        String fieldName;
596

597
        String typeName;
598
    }
599
}
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