2024 Clojure状态调查!中分享您的想法。

欢迎!请查看关于页面了解更多该网站如何运作的信息。

+3投票
Clojure

嗨,各位 - 我发现带类型提示与不带类型提示的letfn似乎存在一个局部清除问题

(defn- letfn-prim []
  (letfn [(f [coll ^long n]
            )]
    (f (take 3 (range)) 0)))

(defn- letfn-noprim []
  (letfn [(f [coll n]
            )]
    (f (take 3 (range)) 0)))

在实践中,我在f中懒加载地处理coll,并想避免保留头(head)

noprim变体正确地清除了coll参数,而prim版本并没有。

我知道letfn并不完全支持类型提示,但这个似乎不仅是意外的装箱(boxing),而且影响远不止提示的变量。

在这两种情况下,调用者都调用f.invoke(Object)invokeinterface clojure/lang/IFn.invoke:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;),但差异在于f函数。(可争论带类型提示的版本可以直接调用invokePrim,但正如我所言,已知letfn并不完全支持类型提示)

在未提示的情况下,invoke很 trivial

  public java.lang.Object invoke(java.lang.Object, java.lang.Object);
    Code:
       0: aconst_null
       1: areturn

添加更多主体后,它会尽快清除参数。

但在提示的情况下,我们得到这个

  public final java.lang.Object invokePrim(java.lang.Object, long);
    Code:
       0: aconst_null
       1: areturn

  public java.lang.Object invoke(java.lang.Object, java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: aload_2
       3: checkcast     #22                 // class java/lang/Number
       6: invokestatic  #28                 // Method clojure/lang/RT.longCast:(Ljava/lang/Object;)J
       9: invokeinterface #30,  4           // InterfaceMethod clojure/lang/IFn$OLO.invokePrim:(Ljava/lang/Object;J)Ljava/lang/Object;
      14: areturn

invoke像平常一样调用到invokePrim,但它不会在这样做之前清除其局部变量。

(defn- defn-prim [coll ^long n]
  )

与之相比,其字节码中的invoke方法确实清除了对象。

  public static java.lang.Object invokeStatic(java.lang.Object, long);
    Code:
       0: aconst_null
       1: areturn

  public java.lang.Object invoke(java.lang.Object, java.lang.Object);
    Code:
       0: aload_1
       1: aconst_null
       2: astore_1      // <--- local cleared here
       3: aload_2
       4: checkcast     #21                 // class java/lang/Number
       7: invokestatic  #27                 // Method clojure/lang/RT.longCast:(Ljava/lang/Object;)J
      10: invokestatic  #29                 // Method invokeStatic:(Ljava/lang/Object;J)Ljava/lang/Object;
      13: areturn

  public final java.lang.Object invokePrim(java.lang.Object, long);
    Code:
       0: aload_1
       1: aconst_null
       2: astore_1
       3: lload_2
       4: invokestatic  #29                 // Method invokeStatic:(Ljava/lang/Object;J)Ljava/lang/Object;
       7: areturn

祝大家好!

詹姆斯

登录注册以回答此问题。

...