Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File system concurrency problem using @JsNative #8

Open
NorbertSandor opened this issue Apr 8, 2015 · 1 comment
Open

File system concurrency problem using @JsNative #8

NorbertSandor opened this issue Apr 8, 2015 · 1 comment

Comments

@NorbertSandor
Copy link

There is a problem when multiple methods are marked with @JsNative.
For example:

class C extends JavaScriptObject {
    protected new() {
    }

    @JsNative
    def int a() '''
        this.a();
    '''

    @JsNative
    def int b() '''
        this.b();
    '''
}

results in

public class C extends JavaScriptObject {
  protected C() {
  }

  @JsNative
  public final native int a() {
    C#a()
  }

  @JsNative
  public final native int b() /*-{
        this.b();
    }-*/;
}

Note that the marker code is not replaced in case of method a().

The cause of the problem is that JsNativeProcessor.doGenerateCode() is using MutableFileSystemSupport.setContents() during code generation to modify the generated sources.
setContents()'s javadoc states: Clients should not rely on invocation timing.

Possible solutions:

  • Using an AbstractClassProcessor instead of the current AbstractMethodProcessor to replace all methods of a compilation unit in one turn.
  • Creating a synchronous and locking file system API.

The latter can be emulated in a quick and dirty way by modifying JsNativeProcessor.doGenerateCode() to this:

override doGenerateCode(MethodDeclaration annotatedMethod, extension CodeGenerationContext context) {
    val path = annotatedMethod.declaringType.getTargetPath(context)
    val contents = path.contents.toString
    val markerStart = contents.indexOf(getUniqueMarkerCode(annotatedMethod))
    val startIndex = contents.substring(0, markerStart).lastIndexOf('{')
    val endIndex = contents.substring(markerStart).indexOf('}') + markerStart
    val jsCode = annotatedMethod.body.toString.trimTripleQuotes

    val newContents = contents.substring(0, startIndex) + "/*-{" + jsCode + "}-*/;" +
        contents.substring(endIndex + 1)
    path.contents = newContents
    do {
        Thread.sleep(100);
    } while (path.contents.toString != newContents)
}

Note the last few lines that contain the hack by waiting for the file system operation to finish :)
(This works because the annotated methods of a class are processed by the same processor instance on one thread.)

With this ugly modification the generated code is correct:

public class C extends JavaScriptObject {
  protected C() {
  }

  @JsNative
  public final native int a() /*-{
        this.a();
    }-*/;

  @JsNative
  public final native int b() /*-{
        this.b();
    }-*/;
}
@NorbertSandor
Copy link
Author

Another issue is that I cannot write a working unit test for this problem.
I tried:

class JsNativeTest {

    extension XtendCompilerTester compiler = XtendCompilerTester.newXtendCompilerTester(JsNativeTest)

    @Test def void testSimple() {
        '''
            import «JsNative.name»

            class C /* implements JavaScriptObject */ {
                protected new() {
                }

                @JsNative
                def void a() '«»''
                    this.a();
                '«»''

                @JsNative
                def void b() '«»''
                    this.b();
                '«»''
            }
        '''.assertCompilesTo('''

        ''')
    }
}

but the generated code is

import de.itemis.xtend.auto.gwt.JsNative;

@SuppressWarnings("all")
public class C {
  protected C() {
  }

  @JsNative
  public final native void a() {
    C#a()
  }

  @JsNative
  public final native void b() {
    C#b()
  }
}

It seems that the file system works differently in case of unit tests...

NorbertSandor added a commit to NorbertSandor/auto-gwt that referenced this issue Apr 9, 2015
NorbertSandor added a commit to NorbertSandor/auto-gwt that referenced this issue Apr 9, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant