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

i-net-software / JWebAssembly / 529

pending completion
529

push

travis-ci-com

Horcrux7
fix Unsafe for array elements

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

5925 of 6780 relevant lines covered (87.39%)

0.87 hits per line

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

88.35
/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java
1
/*
2
   Copyright 2018 - 2022 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;
18

19
import java.io.IOException;
20
import java.util.List;
21
import java.util.Objects;
22

23
import javax.annotation.Nonnull;
24
import javax.annotation.Nullable;
25

26
import de.inetsoftware.jwebassembly.WasmException;
27
import de.inetsoftware.jwebassembly.javascript.JavaScriptSyntheticFunctionName;
28
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
29
import de.inetsoftware.jwebassembly.wasm.AnyType;
30
import de.inetsoftware.jwebassembly.wasm.NamedStorageType;
31
import de.inetsoftware.jwebassembly.wasm.StructOperator;
32
import de.inetsoftware.jwebassembly.wasm.ValueType;
33

34
/**
35
 * WasmInstruction for struct operation. A struct is like a Java class without methods.
36
 * 
37
 * @author Volker Berlin
38
 *
39
 */
40
class WasmStructInstruction extends WasmInstruction {
1✔
41

42
    @Nonnull
43
    private final StructOperator   op;
44

45
    private       StructType       type;
46

47
    private final NamedStorageType fieldName;
48

49
    private SyntheticFunctionName functionName;
50

51
    private final WasmOptions     options;
52

53
    /**
54
     * Create an instance of numeric operation.
55
     * 
56
     * @param op
57
     *            the struct operation
58
     * @param typeName
59
     *            the type name of the parameters
60
     * @param fieldName
61
     *            the name of field if needed for the operation
62
     * @param javaCodePos
63
     *            the code position/offset in the Java method
64
     * @param lineNumber
65
     *            the line number in the Java source code
66
     * @param types
67
     *            the type manager
68
     */
69
    WasmStructInstruction( @Nonnull StructOperator op, @Nonnull String typeName, @Nullable NamedStorageType fieldName, int javaCodePos, int lineNumber, TypeManager types ) {
70
        this( op, types.valueOf( typeName ), fieldName, javaCodePos, lineNumber, types );
1✔
71
    }
1✔
72

73
    /**
74
     * Create an instance of numeric operation.
75
     * 
76
     * @param op
77
     *            the struct operation
78
     * @param type
79
     *            the type of the parameters
80
     * @param fieldName
81
     *            the name of field if needed for the operation
82
     * @param javaCodePos
83
     *            the code position/offset in the Java method
84
     * @param lineNumber
85
     *            the line number in the Java source code
86
     * @param types
87
     *            the type manager
88
     */
89
    WasmStructInstruction( @Nonnull StructOperator op, @Nonnull StructType type, @Nullable NamedStorageType fieldName, int javaCodePos, int lineNumber, TypeManager types ) {
90
        super( javaCodePos, lineNumber );
1✔
91
        this.op = op;
1✔
92
        this.type = type;
1✔
93
        this.fieldName = fieldName;
1✔
94
        if( type != null && fieldName != null ) {
1✔
95
            type.useFieldName( fieldName );
1✔
96
        }
97
        this.options = types.options;
1✔
98
    }
1✔
99

100
    /**
101
     * Create the synthetic polyfill function of this instruction for nonGC mode.
102
     * 
103
     * @return the function or null if not needed
104
     */
105
    SyntheticFunctionName createNonGcFunction() {
106
        switch( op ) {
1✔
107
            case NEW:
108
            case NEW_DEFAULT:
109
                functionName = new JavaScriptSyntheticFunctionName( "NonGC", "new_" + type.getName().replace( '/', '_' ), () -> {
1✔
110
                    // create the default values of a new type
111
                    StringBuilder js = new StringBuilder("() => Object.seal({");
1✔
112
                    List<NamedStorageType> list = type.getFields();
1✔
113
                    for( int i = 0; i < list.size(); i++ ) {
1✔
114
                        if( i > 0 ) {
1✔
115
                            js.append( ',' );
1✔
116
                        }
117
                        js.append( i ).append( ':' );
1✔
118
                        NamedStorageType storageType = list.get( i );
1✔
119
                        if( TypeManager.FIELD_VTABLE == storageType.getName() ) {
1✔
120
                            js.append( type.getVTable() );
1✔
121
                        } else {
122
                            AnyType fieldType = storageType.getType();
1✔
123
                            if( fieldType == ValueType.i64 ) {
1✔
124
                                js.append( "0n" );
1✔
125
                            } else if( fieldType instanceof ValueType && fieldType != ValueType.externref ) {
1✔
126
                                js.append( '0' );
1✔
127
                            } else {
128
                                js.append( "null" );
1✔
129
                            }
130
                        }
131
                    }
132
                    js.append( "})" );
1✔
133
                    return js.toString();
1✔
134
                }, null, type );
135
                break;
1✔
136
            case SET:
137
                AnyType fieldType = fieldName.getType();
1✔
138
                functionName = new JavaScriptSyntheticFunctionName( "NonGC", "set_" + validJsName( fieldType ), () -> "(a,v,i) => a[i]=v", ValueType.externref, fieldType, ValueType.i32, null, null );
1✔
139
                break;
1✔
140
            case GET:
141
                fieldType = fieldName.getType();
1✔
142
                functionName = new JavaScriptSyntheticFunctionName( "NonGC", "get_" + validJsName( fieldType ), () -> "(a,i) => a[i]", ValueType.externref, ValueType.i32, null, fieldType );
1✔
143
                break;
1✔
144
            case INSTANCEOF:
145
                functionName = options.getInstanceOf();
1✔
146
                break;
1✔
147
            case CAST:
148
                functionName = options.getCast();
1✔
149
                break;
1✔
150
            default:
151
        }
152
        return functionName;
1✔
153
    }
154

155
    /**
156
     * Get a valid JavaScript name.
157
     * @param type the type
158
     * @return the identifier that is valid 
159
     */
160
    private static String validJsName( AnyType type ) {
161
        return type instanceof StructType ? "anyref" : type.toString();
1✔
162
    }
163

164
    /**
165
     * Get the StructOperator
166
     * 
167
     * @return the operator
168
     */
169
    StructOperator getOperator() {
170
        return op;
1✔
171
    }
172

173
    /**
174
     * Get the struct type of this instruction.
175
     * 
176
     * @return the type
177
     */
178
    StructType getStructType() {
179
        return type;
1✔
180
    }
181

182
    /**
183
     * Set a new type for NULL const. 
184
     * @param type the type
185
     */
186
    void setStructType( @Nonnull StructType type ) {
187
        this.type = Objects.requireNonNull( type );
1✔
188
    }
1✔
189

190
    /**
191
     * {@inheritDoc}
192
     */
193
    @Override
194
    Type getType() {
195
        return Type.Struct;
1✔
196
    }
197

198
    /**
199
     * {@inheritDoc}
200
     */
201
    @Override
202
    public void writeTo( @Nonnull ModuleWriter writer ) throws IOException {
203
        String comment = null;
1✔
204
        int idx = -1;
1✔
205
        switch( op ) {
1✔
206
            case GET:
207
            case SET:
208
                // The fieldName of the struct operation does not contain the class name in which the field was declared. It contains the class name of the variable. This can be the class or a subclass.
209
                List<NamedStorageType> fields = type.getFields();
1✔
210
                boolean classNameMatched = type.getName().equals( fieldName.geClassName() );
1✔
211
                for( int i = fields.size()-1; i >= 0; i-- ) {
1✔
212
                    NamedStorageType field = fields.get( i );
1✔
213
                    if( !classNameMatched && field.geClassName().equals( fieldName.geClassName() ) ) {
1✔
214
                        classNameMatched = true;
1✔
215
                    }
216
                    if( classNameMatched && field.getName().equals( fieldName.getName() ) ) {
1✔
217
                        idx = i;
1✔
218
                        break;
1✔
219
                    }
220
                }
221
                if( !classNameMatched ) {
1✔
222
                    // special case, the type self does not add a needed field, that we search in all fields
223
                    for( int i = fields.size()-1; i >= 0; i-- ) {
1✔
224
                        NamedStorageType field = fields.get( i );
1✔
225
                        if( field.getName().equals( fieldName.getName() ) ) {
1✔
226
                            idx = i;
1✔
227
                            break;
1✔
228
                        }
229
                    }
230
                }
231
                comment = fieldName.getName();
1✔
232
                assert idx >=0;
1✔
233
                break;
234
            case INSTANCEOF:
235
            case CAST:
236
                idx = type.getClassIndex();
1✔
237
                break;
1✔
238
            default:
239
        }
240
        if( functionName != null ) { // nonGC
1✔
241
            if( idx >= 0 ) {
1✔
242
                writer.writeConst( idx, ValueType.i32 );
1✔
243
            }
244
            writer.writeFunctionCall( functionName, comment );
1✔
245
            if( op == StructOperator.CAST && options.useGC() ) {
1✔
246
                writer.writeStructOperator( StructOperator.RTT_CANON, type, null, -1 );
1✔
247
                writer.writeStructOperator( op, type, null, -1 );
1✔
248
            }
249
        } else {
250
            writer.writeStructOperator( op, type, fieldName, idx );
1✔
251
        }
252
    }
1✔
253

254
    /**
255
     * {@inheritDoc}
256
     */
257
    @Override
258
    AnyType getPushValueType() {
259
        switch( op ) {
1✔
260
            case NULL:
261
                return options.useGC() ? ValueType.eqref : ValueType.externref;
1✔
262
            case NEW:
263
            case NEW_DEFAULT:
264
            case CAST:
265
            case NEW_WITH_RTT:
266
                return type;
1✔
267
            case GET:
268
                return fieldName.getType();
1✔
269
            case SET:
270
                return null;
1✔
271
            case INSTANCEOF:
272
                return ValueType.i32; // a boolean value
1✔
273
            case RTT_CANON:
274
                return ValueType.i32; // rtt type
×
275
            default:
276
                throw new WasmException( "Unknown array operation: " + op, -1 );
×
277
        }
278
    }
279

280
    /**
281
     * {@inheritDoc}
282
     */
283
    @Override
284
    int getPopCount() {
285
        switch( op ) {
1✔
286
            case GET:
287
            case INSTANCEOF:
288
            case CAST:
289
            case NEW_WITH_RTT:
290
                return 1;
1✔
291
            case SET:
292
                return 2;
1✔
293
            case NEW:
294
            case NEW_DEFAULT:
295
            case NULL:
296
            case RTT_CANON:
297
                return 0;
1✔
298
            default:
299
                throw new WasmException( "Unknown array operation: " + op, -1 );
×
300
        }
301
    }
302

303
    /**
304
     * {@inheritDoc}
305
     */
306
    @Override
307
    AnyType[] getPopValueTypes() {
308
        switch( op ) {
1✔
309
            case GET:
310
                return new AnyType[] { type };
×
311
            case INSTANCEOF:
312
            case CAST:
313
                return new AnyType[] { options.types.valueOf( "java/lang/Object" ) };
×
314
            case NEW_WITH_RTT:
315
                return new AnyType[] { ValueType.i32 };// rtt type
×
316
            case SET:
317
                return new AnyType[] { type, fieldName.getType() };
1✔
318
            case NEW:
319
            case NEW_DEFAULT:
320
            case NULL:
321
            case RTT_CANON:
322
                return null;
×
323
            default:
324
                throw new WasmException( "Unknown array operation: " + op, -1 );
×
325
        }
326
    }
327

328
    /**
329
     * Only used for debugging
330
     */
331
    @Override
332
    public String toString() {
333
        switch( op ) {
×
334
            case GET:
335
                return "struct.get " + fieldName.getName();
×
336
            case SET:
337
                return "struct.set " + fieldName.getName();
×
338
        }
339
        return super.toString();
×
340
    }
341
}
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