saveStacks.ml 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. open Globals
  2. open SafeCom
  3. open Type
  4. open Error
  5. open ExceptionFunctions
  6. open Exceptions
  7. (**
  8. Inserts `haxe.NativeStackTrace.saveStack(e)` in non-haxe.Exception catches.
  9. *)
  10. let insert_save_stacks ectx scom =
  11. let native_stack_trace_cls = ectx.haxe_native_stack_trace in
  12. let rec contains_insertion_points e =
  13. match e.eexpr with
  14. | TTry (e, catches) ->
  15. List.exists (fun (v, _) -> Meta.has Meta.NeedsExceptionStack v.v_meta) catches
  16. || contains_insertion_points e
  17. || List.exists (fun (_, e) -> contains_insertion_points e) catches
  18. | _ ->
  19. check_expr contains_insertion_points e
  20. in
  21. let save_exception_stack catch_var =
  22. let method_field =
  23. try PMap.find "saveStack" native_stack_trace_cls.cl_statics
  24. with Not_found -> raise_typing_error ("haxe.NativeStackTrace has no field saveStack") null_pos
  25. in
  26. let return_type =
  27. match follow method_field.cf_type with
  28. | TFun(_,t) -> t
  29. | _ -> raise_typing_error ("haxe.NativeStackTrace." ^ method_field.cf_name ^ " is not a function and cannot be called") null_pos
  30. in
  31. let catch_local = mk (TLocal catch_var) catch_var.v_type catch_var.v_pos in
  32. begin
  33. add_dependency scom.curclass.cl_module native_stack_trace_cls.cl_module MDepFromTyping;
  34. make_static_call scom native_stack_trace_cls method_field [catch_local] return_type catch_var.v_pos
  35. end
  36. in
  37. let rec run e =
  38. match e.eexpr with
  39. | TTry (e1, catches) ->
  40. let e1 = map_expr run e1 in
  41. let catches =
  42. List.map (fun ((v, body) as catch) ->
  43. if Meta.has Meta.NeedsExceptionStack v.v_meta then
  44. let exprs =
  45. match body.eexpr with
  46. | TBlock exprs ->
  47. save_exception_stack v :: exprs
  48. | _ ->
  49. [save_exception_stack v; body]
  50. in
  51. (v, { body with eexpr = TBlock exprs })
  52. else
  53. catch
  54. ) catches
  55. in
  56. { e with eexpr = TTry (e1, catches) }
  57. | _ ->
  58. map_expr run e
  59. in
  60. (fun e ->
  61. if contains_insertion_points e then run e
  62. else e
  63. )
  64. (**
  65. Adds `this.__shiftStack()` calls to constructors of classes which extend `haxe.Exception`
  66. *)
  67. let patch_constructors ectx =
  68. match ectx.haxe_exception_type with
  69. (* Add only if `__shiftStack` method exists *)
  70. | TInst(cls,_) when PMap.mem "__shiftStack" cls.cl_fields ->
  71. (fun mt ->
  72. match mt with
  73. | TClassDecl cls when not (has_class_flag cls CExtern) && cls.cl_path <> haxe_exception_type_path && is_haxe_exception_class cls ->
  74. let shift_stack p =
  75. let t = type_of_module_type mt in
  76. let this = { eexpr = TConst(TThis); etype = t; epos = p } in
  77. let faccess =
  78. try quick_field t "__shiftStack"
  79. with Not_found -> raise_typing_error "haxe.Exception has no field __shiftStack" p
  80. in
  81. match faccess with
  82. | FInstance (_,_,cf) ->
  83. let efield = { eexpr = TField(this,faccess); etype = cf.cf_type; epos = p } in
  84. let rt =
  85. match follow cf.cf_type with
  86. | TFun(_,t) -> t
  87. | _ ->
  88. raise_typing_error "haxe.Exception.__shiftStack is not a function and cannot be called" cf.cf_name_pos
  89. in
  90. make_call ectx.scom efield [] rt p
  91. | _ -> raise_typing_error "haxe.Exception.__shiftStack is expected to be an instance method" p
  92. in
  93. (* TypeloadFunction.add_constructor tctx cls true cls.cl_name_pos; *) (* TODO: why? *)
  94. Option.may (fun cf -> ignore(follow cf.cf_type)) cls.cl_constructor;
  95. (match cls.cl_constructor with
  96. | Some ({ cf_expr = Some e_ctor } as ctor) ->
  97. let rec add e =
  98. match e.eexpr with
  99. | TFunction _ -> e
  100. | TReturn _ -> mk (TBlock [shift_stack e.epos; e]) e.etype e.epos
  101. | _ -> map_expr add e
  102. in
  103. (ctor.cf_expr <- match e_ctor.eexpr with
  104. | TFunction fn ->
  105. Some { e_ctor with
  106. eexpr = TFunction { fn with
  107. tf_expr = mk (TBlock [add fn.tf_expr; shift_stack fn.tf_expr.epos]) ectx.scom.basic.tvoid fn.tf_expr.epos
  108. }
  109. }
  110. | _ -> die "" __LOC__
  111. )
  112. | None ->
  113. raise_typing_error "Could not patch constructor on this function because there isn't one" cls.cl_name_pos
  114. | _ -> ()
  115. )
  116. | _ -> ()
  117. )
  118. | _ -> (fun _ -> ())
  119. let patch_constructors ectx scom =
  120. match ectx with
  121. | Some ctx ->
  122. patch_constructors {ctx with scom = scom}
  123. | None ->
  124. (fun _ -> ())