方法调用8——MethodHandle方法调用实现原理

public class PolymorphicSignatureTest {
    public int calculate(int num) {
        return num + 1;
    }

    public double calculate(double num) {
        return num + 1;
    }

    public double calculate(Integer num) {
        return num + 1;
    }

    public static void main(String[] args) throws Throwable{
        MethodType mt = MethodType.methodType(int.class, int.class);
        MethodHandle mh =  MethodHandles.lookup()
                .findVirtual(PolymorphicSignatureTest.class, "calculate", mt)
                .bindTo(new PolymorphicSignatureTest());
        int result1 = (int)mh.invoke(1);
        double resultE = (double)mh.invokeExact(1);
        double result2 = (double)mh.invoke(1);
        double result3 = (double)mh.invoke(Integer.valueOf(1));
        System.out.println(result1);
        System.out.println(result2);
        System.out.println(result3);
    }
}

字节码:

        34: invokevirtual #11                 // Method java/lang/invoke/MethodHandle.invoke:(I)I

        40: invokevirtual #12                 // Method java/lang/invoke/MethodHandle.invokeExact:(I)D

        47: invokevirtual #13                 // Method java/lang/invoke/MethodHandle.invoke:(I)D

        57: invokevirtual #15                 // Method java/lang/invoke/MethodHandle.invoke:(Ljava/lang/Integer;)D

其中符号类型描述符为:

(I)I
(I)D
(I)D
(Ljava/lang/Integer;)D

1 MethodHandle实现

通过新建异常实例来查看栈轨迹:

    public int calculate(int num) {
        new Exception().printStackTrace();
        return num + 1;
    }

启用-XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames虚拟机参数来打印隐藏的栈信息:

-XX:+UnlockDiagnosticVMOptions
-XX:+ShowHiddenFrames

结果:

java.lang.Exception
    at com.enjoy.learn.core.oop.method.PolymorphicSignatureTest.calculate(PolymorphicSignatureTest.java:16)
    at java.lang.invoke.LambdaForm$DMH006/2055281021.invokeVirtual_001_LI_I(LambdaForm$DMH006:1000011)
    at java.lang.invoke.LambdaForm$BMH002/1160460865.reinvoke_002(LambdaForm$BMH002:1000021)
    at java.lang.invoke.LambdaForm$MH012/1421795058.invoke_000_MT(LambdaForm$MH012:1000017)
    at com.enjoy.learn.core.oop.method.PolymorphicSignatureTest.main(PolymorphicSignatureTest.java:35)

添加JVM参数导出class文件:

-Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true

LambdaForm$MH012文件反编译如下:

final class LambdaForm$MH012
{
  @LambdaForm.Hidden
  @LambdaForm.Compiled
  @ForceInline
  static double invoke_000_MT(Object paramObject1, int paramInt, Object paramObject2)
  {
    Object localObject = Invokers.checkGenericType(paramObject1, paramObject2);
    Invokers.checkCustomized(localObject);
    return (localObject = (MethodHandle)localObject).invokeBasic(paramInt);
  }
  
  static void dummy()
  {
    "invoke_000_MT=Lambda(a0:L,a1:I,a2:L)=>{\n    t3:L=Invokers.checkGenericType(a0:L,a2:L);\n    t4:V=Invokers.checkCustomized(t3:L);\n    t5:D=MethodHandle.invokeBasic(t3:L,a1:I);t5:D}";
  }
}

该方法的三个步骤:
step1.Invokers.checkGenericType方法类型检查
step2.Invokers.checkCustomized在MethodHandle执行次数超过一个阈值时进行优化(-Djava.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD,默认为127)
step3.调用MethodHandle的invokeBasic。调用至MethodHandle所持有的的适配器中,同样是LambdaForm

    /**
     * Private method for trusted invocation of a method handle respecting simplified signatures.
     * Type mismatches will not throw {@code WrongMethodTypeException}, but could crash the JVM.
     * <p>
     * The caller signature is restricted to the following basic types:
     * Object, int, long, float, double, and void return.
     * <p>
     * The caller is responsible for maintaining type correctness by ensuring
     * that the each outgoing argument value is a member of the range of the corresponding
     * callee argument type.
     * (The caller should therefore issue appropriate casts and integer narrowing
     * operations on outgoing argument values.)
     * The caller can assume that the incoming result value is part of the range
     * of the callee's return type.
     * @param args the signature-polymorphic parameter list, statically represented using varargs
     * @return the signature-polymorphic result, statically represented using {@code Object}
     */
    /*non-public*/ final native @PolymorphicSignature Object invokeBasic(Object... args) throws Throwable;

LambdaForm$BMH002文件:

final class LambdaForm$BMH002
{
  @LambdaForm.Hidden
  @LambdaForm.Compiled
  @ForceInline
  static double reinvoke_002(Object paramObject, int paramInt)
  {
    Object localObject1 = (paramObject = (BoundMethodHandle.Species_L3)paramObject).argL1;
    Object localObject2 = ((BoundMethodHandle.Species_L3)paramObject).argL0;
    int i = ((MethodHandle)localObject2).invokeBasic(localObject1, paramInt);
    Object localObject3 = ((BoundMethodHandle.Species_L3)paramObject).argL2;
    return ((MethodHandle)localObject3).invokeBasic(i);
  }
  
  static void dummy()
  {
    "BMH.reinvoke_002=Lambda(a0:L/SpeciesData<LLL>,a1:I)=>{\n    t2:L=BoundMethodHandle$Species_L3.argL1(a0:L);\n    t3:L=BoundMethodHandle$Species_L3.argL0(a0:L);\n    t4:I=MethodHandle.invokeBasic(t3:L,t2:L,a1:I);\n    t5:L=BoundMethodHandle$Species_L3.argL2(a0:L);\n    t6:D=MethodHandle.invokeBasic(t5:L,t4:I);t6:D}";
  }
}

LambdaForm$DMH006文件:

final class LambdaForm$DMH006
{
  @LambdaForm.Hidden
  @LambdaForm.Compiled
  @ForceInline
  static int invokeVirtual_001_LI_I(Object paramObject1, Object paramObject2, int paramInt)
  {
    Object localObject = DirectMethodHandle.internalMemberName(paramObject1);
    return MethodHandle.linkToVirtual(paramObject2, paramInt, (MemberName)localObject);
  }
  
  static void dummy()
  {
    "DMH.invokeVirtual_001_LI_I=Lambda(a0:L,a1:L,a2:I)=>{\n    t3:L=DirectMethodHandle.internalMemberName(a0:L);\n    t4:I=MethodHandle.linkToVirtual(a1:L,a2:I,t3:L);t4:I}";
  }
}

2 Invokers.checkGenericType

2.1 invokeExact进行严格匹配检查

invokeExact会确认该invokevirtual指令对应的方法描述符和该MethodHandle类型是否严格匹配,不匹配会抛出异常。

double resultE = (double)mh.invokeExact(1);

会进入如下方法进行检查:

    @ForceInline
    void checkExactType(Object mhObj, Object expectedObj) {
        MethodHandle mh = (MethodHandle) mhObj;
        MethodType expected = (MethodType) expectedObj;
        MethodType actual = mh.type();
        if (actual != expected)
            throw newWrongMethodTypeException(expected, actual);
    }

这里的mhObj就是当前的MethodHandle:




这里的expectedObj就是从实际的参数和返回类型派生符号类型描述符,也就是invokevirtual指令对应的方法描述符:



这里会判断mhObj.type()与expectedObj是否相等,如果不等直接抛出异常newWrongMethodTypeException:
Exception in thread "main" java.lang.invoke.WrongMethodTypeException: expected (int)int but found (int)double
    at java.lang.invoke.Invokers.newWrongMethodTypeException(Invokers.java:298)
    at java.lang.invoke.Invokers.checkExactType(Invokers.java:309)
    at com.enjoy.learn.core.oop.method.PolymorphicSignatureTest.main(PolymorphicSignatureTest.java:33)

1.2.2 invoke自动适配参数类型

(R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)}

double result2 = (double)mh.invoke(1);

进入如下代码:

    /** Static definition of MethodHandle.invokeGeneric checking code.
     * Directly returns the type-adjusted MH to invoke, as follows:
     * {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)}
     */
    /*non-public*/ static
    @ForceInline
    Object checkGenericType(Object mhObj, Object expectedObj) {
        MethodHandle mh = (MethodHandle) mhObj;
        MethodType expected = (MethodType) expectedObj;
        return mh.asType(expected);
        /* Maybe add more paths here.  Possible optimizations:
         * for (R)MH.invoke(a*),
         * let MT0 = TYPEOF(a*:R), MT1 = MH.type
         *
         * if MT0==MT1 or MT1 can be safely called by MT0
         *  => MH.invokeBasic(a*)
         * if MT1 can be safely called by MT0[R := Object]
         *  => MH.invokeBasic(a*) & checkcast(R)
         * if MT1 can be safely called by MT0[* := Object]
         *  => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R)
         * if a big adapter BA can be pulled out of (MT0,MT1)
         *  => BA.invokeBasic(MT0,MH,a*)
         * if a local adapter LA can cached on static CS0 = new GICS(MT0)
         *  => CS0.LA.invokeBasic(MH,a*)
         * else
         *  => MH.asType(MT0).invokeBasic(A*)
         */
    }
    public MethodHandle asType(MethodType newType) {
        // Fast path alternative to a heavyweight {@code asType} call.
        // Return 'this' if the conversion will be a no-op.
        if (newType == type) {
            return this;
        }
        // Return 'this.asTypeCache' if the conversion is already memoized.
        MethodHandle atc = asTypeCached(newType);
        if (atc != null) {
            return atc;
        }
        return asTypeUncached(newType);
    }

asType方法可能会抛出NullPointerException(newType是null引用)或者WrongMethodTypeException(如果类型转换没法进行)。

MethodHandle.asType会返回一个适配器MethodHandle将现有的MethodHandle适配成目标类型newType。
新的适配器MethodHandle调用invoke时:
1)将入参列表进行转换以适配老的MethodHandle的参数列表
2)以转换后的参数列表调用老的MethodHandle
3)将老的MethodHandle的返回值转换为新的适配器MethodHandle的返回类型

3 Invokers.checkCustomized

    /*non-public*/ static
    @ForceInline
    void checkCustomized(Object o) {
        MethodHandle mh = (MethodHandle)o;
        if (mh.form.customized == null) {
            maybeCustomize(mh);
        }
    }

    /*non-public*/ static
    @DontInline
    void maybeCustomize(MethodHandle mh) {
        byte count = mh.customizationCount;
        if (count >= CUSTOMIZE_THRESHOLD) {
            mh.customize();
        } else {
            mh.customizationCount = (byte)(count+1);
        }
    }

CUSTOMIZE_THRESHOLD的值为127。当调用次数超过127时,调用MethodHandle.customize()为该MethodHandle定制一个LambdaForm,并将该MH的(final LambdaForm form)设置为新的LambdaForm。

    /** Craft a LambdaForm customized for this particular MethodHandle */
    /*non-public*/
    void customize() {
        if (form.customized == null) {
            LambdaForm newForm = form.customize(this);
            updateForm(newForm);
        } else {
            assert(form.customized == this);
        }
    }

4.BoundMethodHandle 适配器

4.1 调用栈

LambdaForm$BMH002文件:

final class LambdaForm$BMH002
{
  @LambdaForm.Hidden
  @LambdaForm.Compiled
  @ForceInline
  static double reinvoke_002(Object paramObject, int paramInt)
  {
    Object localObject1 = (paramObject = (BoundMethodHandle.Species_L3)paramObject).argL1;
    Object localObject2 = ((BoundMethodHandle.Species_L3)paramObject).argL0;
    int i = ((MethodHandle)localObject2).invokeBasic(localObject1, paramInt);
    Object localObject3 = ((BoundMethodHandle.Species_L3)paramObject).argL2;
    return ((MethodHandle)localObject3).invokeBasic(i);
  }
  
  static void dummy()
  {
    "BMH.reinvoke_002=Lambda(a0:L/SpeciesData<LLL>,a1:I)=>{\n    t2:L=BoundMethodHandle$Species_L3.argL1(a0:L);\n    t3:L=BoundMethodHandle$Species_L3.argL0(a0:L);\n    t4:I=MethodHandle.invokeBasic(t3:L,t2:L,a1:I);\n    t5:L=BoundMethodHandle$Species_L3.argL2(a0:L);\n    t6:D=MethodHandle.invokeBasic(t5:L,t4:I);t6:D}";
  }
}

4.2 适配器BoundMethodHandle$Species_L3各参数值

BMH的注释:

/**
 * The flavor of method handle which emulates an invoke instruction
 * on a predetermined argument.  The JVM dispatches to the correct method
 * when the handle is created, not when it is invoked.
 *
 * All bound arguments are encapsulated in dedicated species.
 */
/*non-public*/ abstract class BoundMethodHandle extends MethodHandle {

BMH模拟对预先确定参数的调用指令,JVM在创建MH时就已经确定了调度的方法,而不是调用时。所有绑定参数都封装在专用的species中。

如下为BoundMethodHandle$Species_L3文件:

final class BoundMethodHandle$Species_L3
  extends BoundMethodHandle
{
  @Stable
  static BoundMethodHandle.SpeciesData SPECIES_DATA;
  final Object argL0;
  final Object argL1;
  final Object argL2;
  
  private BoundMethodHandle$Species_L3(MethodType paramMethodType, LambdaForm paramLambdaForm, Object paramObject1, Object paramObject2, Object paramObject3)
  {
    super(paramMethodType, paramLambdaForm);
    this.argL0 = paramObject1;
    this.argL1 = paramObject2;
    this.argL2 = paramObject3;
  }
  
  final BoundMethodHandle.SpeciesData speciesData()
  {
    return SPECIES_DATA;
  }
  
  final int fieldCount()
  {
    return 3;
  }
  
  static BoundMethodHandle make(MethodType paramMethodType, LambdaForm paramLambdaForm, Object paramObject1, Object paramObject2, Object paramObject3)
  {
    return new Species_L3(paramMethodType, paramLambdaForm, paramObject1, paramObject2, paramObject3);
  }
  
  final BoundMethodHandle copyWith(MethodType paramMethodType, LambdaForm paramLambdaForm)
  {
    return new Species_L3(paramMethodType, paramLambdaForm, this.argL0, this.argL1, this.argL2);
  }
  
  final BoundMethodHandle copyWithExtendL(MethodType paramMethodType, LambdaForm paramLambdaForm, Object paramObject)
    throws Throwable
  {
    return SPECIES_DATA.extendWith((byte)0).constructor().invokeBasic(paramMethodType, paramLambdaForm, this.argL0, this.argL1, this.argL2, paramObject);
  }
  
  final BoundMethodHandle copyWithExtendI(MethodType paramMethodType, LambdaForm paramLambdaForm, int paramInt)
    throws Throwable
  {
    return SPECIES_DATA.extendWith((byte)1).constructor().invokeBasic(paramMethodType, paramLambdaForm, this.argL0, this.argL1, this.argL2, paramInt);
  }
  
  final BoundMethodHandle copyWithExtendJ(MethodType paramMethodType, LambdaForm paramLambdaForm, long paramLong)
    throws Throwable
  {
    return SPECIES_DATA.extendWith((byte)2).constructor().invokeBasic(paramMethodType, paramLambdaForm, this.argL0, this.argL1, this.argL2, paramLong);
  }
  
  final BoundMethodHandle copyWithExtendF(MethodType paramMethodType, LambdaForm paramLambdaForm, float paramFloat)
    throws Throwable
  {
    return SPECIES_DATA.extendWith((byte)3).constructor().invokeBasic(paramMethodType, paramLambdaForm, this.argL0, this.argL1, this.argL2, paramFloat);
  }
  
  final BoundMethodHandle copyWithExtendD(MethodType paramMethodType, LambdaForm paramLambdaForm, double paramDouble)
    throws Throwable
  {
    return SPECIES_DATA.extendWith((byte)4).constructor().invokeBasic(paramMethodType, paramLambdaForm, this.argL0, this.argL1, this.argL2, paramDouble);
  }
}

调试方法:
在运行到checkGenericType中,在BMH的构造函数处打断点;

    /*non-public*/ BoundMethodHandle(MethodType type, LambdaForm form) {
        super(type, form);
        assert(speciesData() == speciesData(form));
    }

然后获得如下调用栈:




分析这五个参数:
param_1是方法描述符为"(I)D"的MethodType,代表根据实际类型生成的方法描述符。



param_2是LambdaFrom

param_3是之前lookup()生成MH,代表原始的MH:

1)其MemberName member代表对指定类PolymorphicSinatureTest的方法calculate:(I)I的引用
2)其MethodType type就是对方法类型的描述(返回类型int;入参(1-PolymorphicSinatureTest,2-int))
3)其LambdaForm form值如下

DMH.invokeVirtual_001_LI_I=Lambda(a0:L,a1:L,a2:I)=>{
    t3:L=DirectMethodHandle.internalMemberName(a0:L);
    t4:I=MethodHandle.linkToVirtual(a1:L,a2:I,t3:L);t4:I}

param_4是之前传入的入参bindTo(new PolymorphicSignatureTest())



param_5是调用完老的MH后,需要调用该方法进行返回值转换


因此可知BMH的各参数值如下:
MethodType type = "(I)D"的MethodType
LambdaForm form = LambdaForm$BMH002.reinvoke_002
argL0 = 代表原始的MH
argL1 = 之前传入的入参bindTo(new PolymorphicSignatureTest())
argL2 = DMH intToDouble (调用完老的MH后,需要调用该方法进行返回值转换)

4.3 理解 LambdaForm$BMH002.reinvoke_002方法

  static double reinvoke_002(Object paramObject, int paramInt)
  {
    Object localObject1 = (paramObject = (BoundMethodHandle.Species_L3)paramObject).argL1;
    Object localObject2 = ((BoundMethodHandle.Species_L3)paramObject).argL0;
    int i = ((MethodHandle)localObject2).invokeBasic(localObject1, paramInt);
    Object localObject3 = ((BoundMethodHandle.Species_L3)paramObject).argL2;
    return ((MethodHandle)localObject3).invokeBasic(i);
  }

两个入参的含义:
1)paramObject 为上面介绍的适配器BMH
2)paramInt 实际传入的参数值:(double)mh.invoke(1)中的1

Object localObject1 = (paramObject = (BoundMethodHandle.Species_L3)paramObject).argL1;
将入参bindTo(new PolymorphicSignatureTest())赋值给localObject1

Object localObject2 = ((BoundMethodHandle.Species_L3)paramObject).argL0;
将原始MH赋值给localObject2

int i = ((MethodHandle)localObject2).invokeBasic(localObject1, paramInt);
通过原始MH调用invokeBasic(new PolymorphicSignatureTest(), 1)调用实际的方法,获得int类型的返回值i

Object localObject3 = ((BoundMethodHandle.Species_L3)paramObject).argL2;
将DMH intToDouble赋值给localObject3

((MethodHandle)localObject3).invokeBasic(i)
调用DMH intToDouble,将int类型转为double类型并返回

总结:
适配器MethodHandle调用invoke时:
1)将入参列表进行转换以适配老的MethodHandle的参数列表
2)以转换后的参数列表调用老的MethodHandle
3)将老的MethodHandle的返回值转换为新的适配器MethodHandle的返回类型

5.原始DMH.invokeBasic(new PolymorphicSignatureTest(), 1)

根据栈信息该方法会调用:
java.lang.invoke.LambdaForm$DMH006/2055281021.invokeVirtual_001_LI_I(LambdaForm$DMH006:1000011)
该方法本身就是原始DMH的form,请参考上一节的param_3的LambdaForm form值。

final class LambdaForm$DMH006
{
  @LambdaForm.Hidden
  @LambdaForm.Compiled
  @ForceInline
  static int invokeVirtual_001_LI_I(Object paramObject1, Object paramObject2, int paramInt)
  {
    Object localObject = DirectMethodHandle.internalMemberName(paramObject1);
    return MethodHandle.linkToVirtual(paramObject2, paramInt, (MemberName)localObject);
  }
  
  static void dummy()
  {
    "DMH.invokeVirtual_001_LI_I=Lambda(a0:L,a1:L,a2:I)=>{\n    t3:L=DirectMethodHandle.internalMemberName(a0:L);\n    t4:I=MethodHandle.linkToVirtual(a1:L,a2:I,t3:L);t4:I}";
  }
}

根据该方法的含义,可推知invokeVirtual_001_LI_I三个参数的含义:
paramObject1 —— 原始DMH
paramObject2 —— new PolymorphicSignatureTest()
paramInt —— 1

Object localObject = DirectMethodHandle.internalMemberName(paramObject1);
获取原始DMH的member,也即类PolymorphicSinatureTest的方法calculate:(I)I的引用。

    /*non-public*/ static Object internalMemberNameEnsureInit(Object mh) {
        DirectMethodHandle dmh = (DirectMethodHandle)mh;
        dmh.ensureInitialized();
        return dmh.member;
    }

MethodHandle.linkToVirtual(paramObject2, paramInt, (MemberName)localObject);
该方法最后一个参数必须是MemberName类型,也即将参数传入PolymorphicSinatureTest的方法calculate:(I)I,进行调用。

    /**
     * Private method for trusted invocation of a MemberName of kind {@code REF_invokeVirtual}.
     * The caller signature is restricted to basic types as with {@code invokeBasic}.
     * The trailing (not leading) argument must be a MemberName.
     * @param args the signature-polymorphic parameter list, statically represented using varargs
     * @return the signature-polymorphic result, statically represented using {@code Object}
     */
    /*non-public*/ static native @PolymorphicSignature Object linkToVirtual(Object... args) throws Throwable;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容