2
0

evalContext.ml 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. (*
  2. The Haxe Compiler
  3. Copyright (C) 2005-2019 Haxe Foundation
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  15. *)
  16. open Globals
  17. open EvalValue
  18. open EvalHash
  19. open EvalString
  20. type var_info = {
  21. vi_name : string;
  22. vi_pos : pos;
  23. vi_generated : bool;
  24. }
  25. type scope = {
  26. (* The position of the current scope. *)
  27. pos : pos;
  28. (* The local start offset of the current scope. *)
  29. local_offset : int;
  30. (* The locals declared in the current scope. Maps variable IDs to local slots. *)
  31. locals : (int,int) Hashtbl.t;
  32. (* The name of local variables. Maps local slots to variable names. Only filled in debug mode. *)
  33. local_infos : (int,var_info) Hashtbl.t;
  34. (* The IDs of local variables. Maps variable names to variable IDs. *)
  35. local_ids : (string,int) Hashtbl.t;
  36. }
  37. type env_kind =
  38. | EKLocalFunction of int
  39. | EKMethod of int * int
  40. | EKEntrypoint
  41. (* Compile-time information for environments. This information is static for all
  42. environments of the same kind, e.g. all environments of a specific method. *)
  43. type env_info = {
  44. (* If false, the environment has a this-context. *)
  45. static : bool;
  46. (* Hash of the source file of this environment. *)
  47. pfile : int;
  48. (* Hash of the unique source file of this environment. *)
  49. pfile_unique : int;
  50. (* The environment kind. *)
  51. kind : env_kind;
  52. (* The name of capture variables. Maps local slots to variable names. Only filled in debug mode. *)
  53. capture_infos : (int,var_info) Hashtbl.t;
  54. (* The number of local variables. *)
  55. num_locals : int;
  56. (* The number of capture variables. *)
  57. num_captures : int;
  58. }
  59. (* Per-environment debug information. These values are only modified while debugging. *)
  60. type env_debug = {
  61. (* The timer function to execute when the environment finishes executing *)
  62. timer : unit -> unit;
  63. (* The current scope stack. *)
  64. mutable scopes : scope list;
  65. (* The current line being executed. This in conjunction with `env_info.pfile` is used to find breakpoints. *)
  66. mutable line : int;
  67. (* The current expression being executed *)
  68. mutable debug_expr : string;
  69. (* The current expression position being executed *)
  70. mutable debug_pos : pos;
  71. }
  72. (* An environment in which code is executed. Environments are created whenever a function is called and when
  73. evaluating static inits. *)
  74. type env = {
  75. (* The compile-time information for the current environment *)
  76. env_info : env_info;
  77. (* The debug information for the current environment *)
  78. env_debug : env_debug;
  79. (* The position at which the current environment was left, e.g. by a call. *)
  80. mutable env_leave_pmin : int;
  81. (* The position at which the current environment was left, e.g. by a call. *)
  82. mutable env_leave_pmax : int;
  83. (* The environment's local variables. Indices are determined during compile-time, or can be obtained
  84. through `scope.locals` when debugging. *)
  85. env_locals : value array;
  86. (* The reference to the environment's captured local variables. Indices are determined during compile-time,
  87. or can be obtained through `env_info.capture_infos`. *)
  88. env_captures : value array;
  89. (* Map of extra variables added while debugging. Keys are hashed variable names. *)
  90. mutable env_extra_locals : value IntMap.t;
  91. (* The parent of the current environment, if exists. *)
  92. env_parent : env option;
  93. (** Exeucution stack depth *)
  94. env_stack_depth : int;
  95. env_eval : eval;
  96. }
  97. and eval = {
  98. mutable env : env option;
  99. thread : vthread;
  100. (* The threads current debug state *)
  101. mutable debug_state : debug_state;
  102. (* The currently active breakpoint. Set to a dummy value initially. *)
  103. mutable breakpoint : breakpoint;
  104. (* Map of all types that are currently being caught. Updated by `emit_try`. *)
  105. caught_types : (int,bool) Hashtbl.t;
  106. (* The most recently caught exception. Used by `debug_loop` to avoid getting stuck. *)
  107. mutable caught_exception : value;
  108. (* The value which was last returned. *)
  109. mutable last_return : value option;
  110. (* The debug channel used to synchronize with the debugger. *)
  111. debug_channel : unit Event.channel;
  112. }
  113. and debug_state =
  114. | DbgRunning
  115. | DbgWaiting
  116. | DbgStep
  117. | DbgNext of env * pos
  118. | DbgFinish of env (* parent env *)
  119. and breakpoint_state =
  120. | BPEnabled
  121. | BPDisabled
  122. | BPHit
  123. and breakpoint_column =
  124. | BPAny
  125. | BPColumn of int
  126. and breakpoint = {
  127. bpid : int;
  128. bpfile : int;
  129. bpline : int;
  130. bpcolumn : breakpoint_column;
  131. bpcondition : Ast.expr option;
  132. mutable bpstate : breakpoint_state;
  133. }
  134. type function_breakpoint = {
  135. fbpid : int;
  136. mutable fbpstate : breakpoint_state;
  137. }
  138. type builtins = {
  139. mutable instance_builtins : (int * value) list IntMap.t;
  140. mutable static_builtins : (int * value) list IntMap.t;
  141. constructor_builtins : (int,value list -> value) Hashtbl.t;
  142. empty_constructor_builtins : (int,unit -> value) Hashtbl.t;
  143. }
  144. type debug_scope_info = {
  145. ds_expr : string;
  146. ds_return : value option;
  147. }
  148. type context_reference =
  149. | StackFrame of env
  150. | Scope of scope * env
  151. | CaptureScope of (int,var_info) Hashtbl.t * env
  152. | DebugScope of debug_scope_info * env
  153. | Value of value * env
  154. | Toplevel
  155. | NoSuchReference
  156. class eval_debug_context = object(self)
  157. val lut =
  158. let d = DynArray.create() in
  159. DynArray.add d Toplevel;
  160. d
  161. val mutex = Mutex.create()
  162. method private add reference =
  163. Mutex.lock mutex;
  164. DynArray.add lut reference;
  165. let i = DynArray.length lut - 1 in
  166. Mutex.unlock mutex;
  167. i
  168. method add_stack_frame env =
  169. self#add (StackFrame env)
  170. method add_scope scope env =
  171. self#add (Scope(scope,env))
  172. method add_capture_scope h env =
  173. self#add (CaptureScope(h,env))
  174. method add_value v env =
  175. self#add (Value(v,env))
  176. method add_debug_scope scope env =
  177. self#add (DebugScope(scope,env))
  178. method get id =
  179. try DynArray.get lut id with _ -> NoSuchReference
  180. end
  181. class static_prototypes = object(self)
  182. val mutable prototypes : vprototype IntMap.t = IntMap.empty
  183. val mutable inits : (vprototype * (vprototype -> unit) list) IntMap.t = IntMap.empty
  184. method add proto =
  185. prototypes <- IntMap.add proto.ppath proto prototypes
  186. method remove path =
  187. inits <- IntMap.remove path inits;
  188. prototypes <- IntMap.remove path prototypes
  189. method reset =
  190. IntMap.iter (fun _ (proto, delays) -> List.iter (fun f -> f proto) delays) inits
  191. method add_init proto delays =
  192. inits <- IntMap.add proto.ppath (proto, delays) inits
  193. method get path =
  194. IntMap.find path prototypes
  195. end
  196. type exception_mode =
  197. | CatchAll
  198. | CatchUncaught
  199. | CatchNone
  200. type debug_connection = {
  201. bp_stop : debug -> unit;
  202. exc_stop : debug -> value -> pos -> unit;
  203. send_thread_event : int -> string -> unit;
  204. }
  205. and debug_socket = {
  206. socket : Socket.t;
  207. connection : debug_connection;
  208. }
  209. (* Per-context debug information *)
  210. and debug = {
  211. (* The registered breakpoints *)
  212. breakpoints : (int,(int,breakpoint) Hashtbl.t) Hashtbl.t;
  213. (* The registered function breakpoints *)
  214. function_breakpoints : ((int * int),function_breakpoint) Hashtbl.t;
  215. (* Whether or not debugging is supported. Has various effects on the amount of
  216. data being retained at run-time. *)
  217. mutable support_debugger : bool;
  218. (* The debugger socket *)
  219. mutable debug_socket : debug_socket option;
  220. (* The current exception mode *)
  221. mutable exception_mode : exception_mode;
  222. (* The debug context which manages scopes and variables. *)
  223. mutable debug_context : eval_debug_context;
  224. }
  225. and context = {
  226. ctx_id : int;
  227. is_macro : bool;
  228. detail_times : bool;
  229. builtins : builtins;
  230. debug : debug;
  231. mutable had_error : bool;
  232. mutable curapi : value MacroApi.compiler_api;
  233. mutable type_cache : Type.module_type IntMap.t;
  234. overrides : (Globals.path * string,bool) Hashtbl.t;
  235. (* prototypes *)
  236. mutable array_prototype : vprototype;
  237. mutable string_prototype : vprototype;
  238. mutable vector_prototype : vprototype;
  239. mutable instance_prototypes : vprototype IntMap.t;
  240. mutable static_prototypes : static_prototypes;
  241. mutable constructors : value Lazy.t IntMap.t;
  242. file_keys : Common.file_keys;
  243. get_object_prototype : 'a . context -> (int * 'a) list -> vprototype * (int * 'a) list;
  244. (* eval *)
  245. toplevel : value;
  246. eval : eval;
  247. mutable evals : eval IntMap.t;
  248. mutable exception_stack : (pos * env_kind) list;
  249. max_stack_depth : int;
  250. max_print_depth : int;
  251. print_indentation : string option;
  252. }
  253. module GlobalState = struct
  254. let get_ctx_ref : (unit -> context) ref = ref (fun() -> die "GlobalState.get_ctx_ref called before initialization" __LOC__)
  255. let initialized = ref false
  256. let sid : int ref = ref (-1)
  257. let debug : debug option ref = ref None
  258. let debugger_initialized : bool ref = ref false
  259. let stdlib : builtins option ref = ref None
  260. let macro_lib : (string,value) Hashtbl.t = Hashtbl.create 0
  261. let cleanup ctx =
  262. (* curapi holds a reference to the typing context which we don't want to persist. Let's unset it so the
  263. context can be collected. *)
  264. ctx.curapi <- Obj.magic ""
  265. end
  266. let get_ctx () = (!GlobalState.get_ctx_ref)()
  267. let select ctx =
  268. GlobalState.initialized := true;
  269. GlobalState.get_ctx_ref := (fun() -> ctx)
  270. let s_debug_state = function
  271. | DbgRunning -> "DbgRunning"
  272. | DbgWaiting -> "DbgWaiting"
  273. | DbgStep -> "DbgStep"
  274. | DbgNext _ -> "DbgNext"
  275. | DbgFinish _ -> "DbgFinish"
  276. (* Misc *)
  277. let get_eval ctx =
  278. let id = Thread.id (Thread.self()) in
  279. if id = 0 then
  280. ctx.eval
  281. else
  282. try
  283. IntMap.find id ctx.evals
  284. with Not_found ->
  285. die "Cannot run Haxe code in a non-Haxe thread" __LOC__
  286. let rec kind_name eval kind =
  287. let rec loop kind env = match kind with
  288. | EKMethod(i1,i2) ->
  289. Printf.sprintf "%s.%s" (rev_hash i1) (rev_hash i2)
  290. | EKLocalFunction i ->
  291. begin match env with
  292. | None -> Printf.sprintf "localFunction%i" i
  293. | Some env -> Printf.sprintf "%s.localFunction%i" (loop env.env_info.kind env.env_parent) i
  294. end
  295. | EKEntrypoint ->
  296. begin match env with
  297. | None -> "entrypoint"
  298. | Some env -> rev_hash env.env_info.pfile
  299. end
  300. in
  301. match eval.env with
  302. | None -> "toplevel"
  303. | Some env -> loop kind (Some env)
  304. let call_function f vl = f vl
  305. let object_fields o = match o.oproto with
  306. | OProto proto ->
  307. IntMap.fold (fun key index acc ->
  308. (key,(o.ofields.(index))) :: acc
  309. ) proto.pinstance_names []
  310. | ODictionary d ->
  311. IntMap.fold (fun k v acc -> (k,v) :: acc) d []
  312. let instance_fields i =
  313. IntMap.fold (fun name key acc ->
  314. (name,i.ifields.(key)) :: acc
  315. ) i.iproto.pinstance_names []
  316. let proto_fields proto =
  317. IntMap.fold (fun name key acc ->
  318. (name,proto.pfields.(key)) :: acc
  319. ) proto.pnames []
  320. (* Exceptions *)
  321. exception RunTimeException of value * env list * pos
  322. let call_stack eval =
  323. let rec loop acc env =
  324. let acc = env :: acc in
  325. match env.env_parent with
  326. | Some env -> loop acc env
  327. | _ -> List.rev acc
  328. in
  329. match eval.env with
  330. | None -> []
  331. | Some env -> loop [] env
  332. let throw v p =
  333. let ctx = get_ctx() in
  334. let eval = get_eval ctx in
  335. match eval.env with
  336. | Some env ->
  337. if p <> null_pos then begin
  338. env.env_leave_pmin <- p.pmin;
  339. env.env_leave_pmax <- p.pmax;
  340. end;
  341. raise_notrace (RunTimeException(v,call_stack eval,p))
  342. | None ->
  343. raise_notrace (RunTimeException(v,[],p))
  344. let exc v = throw v null_pos
  345. let exc_string str = exc (vstring (EvalString.create_ascii str))
  346. let exc_string_p str p = throw (vstring (EvalString.create_ascii str)) p
  347. let error_message = exc_string
  348. let flush_core_context f =
  349. let ctx = get_ctx() in
  350. ctx.curapi.MacroApi.flush_context f
  351. (* Environment handling *)
  352. let no_timer = fun () -> ()
  353. let empty_array = [||]
  354. let no_expr = ""
  355. let no_debug = {
  356. timer = no_timer;
  357. scopes = [];
  358. line = 0;
  359. debug_expr = no_expr;
  360. debug_pos = null_pos;
  361. }
  362. let create_env_info static pfile pfile_key kind capture_infos num_locals num_captures =
  363. let info = {
  364. static = static;
  365. kind = kind;
  366. pfile = hash pfile;
  367. pfile_unique = hash (Path.UniqueKey.to_string pfile_key);
  368. capture_infos = capture_infos;
  369. num_locals = num_locals;
  370. num_captures = num_captures;
  371. } in
  372. info
  373. let push_environment ctx info =
  374. let eval = get_eval ctx in
  375. let timer = if ctx.detail_times then
  376. Timer.timer ["macro";"execution";kind_name eval info.kind]
  377. else
  378. no_timer
  379. in
  380. let debug = if ctx.debug.support_debugger || ctx.detail_times then
  381. { no_debug with timer = timer }
  382. else
  383. no_debug
  384. in
  385. let locals = if info.num_locals = 0 then
  386. empty_array
  387. else
  388. Array.make info.num_locals vnull
  389. in
  390. let captures = if info.num_captures = 0 then
  391. empty_array
  392. else
  393. Array.make info.num_captures vnull
  394. in
  395. let stack_depth = match eval.env with
  396. | None -> 1;
  397. | Some env -> env.env_stack_depth + 1
  398. in
  399. let env = {
  400. env_info = info;
  401. env_leave_pmin = 0;
  402. env_leave_pmax = 0;
  403. env_debug = debug;
  404. env_locals = locals;
  405. env_captures = captures;
  406. env_extra_locals = IntMap.empty;
  407. env_parent = eval.env;
  408. env_eval = eval;
  409. env_stack_depth = stack_depth;
  410. } in
  411. eval.env <- Some env;
  412. begin match ctx.debug.debug_socket,env.env_info.kind with
  413. | Some socket,EKMethod(key_type,key_field) ->
  414. begin try
  415. let bp = Hashtbl.find ctx.debug.function_breakpoints (key_type,key_field) in
  416. if bp.fbpstate <> BPEnabled then raise Not_found;
  417. socket.connection.bp_stop ctx.debug;
  418. eval.debug_state <- DbgWaiting;
  419. with Not_found ->
  420. ()
  421. end
  422. | _ ->
  423. ()
  424. end;
  425. env
  426. let pop_environment ctx env =
  427. let eval = env.env_eval in
  428. eval.env <- env.env_parent;
  429. env.env_debug.timer();
  430. ()
  431. (* Prototypes *)
  432. let get_static_prototype_raise ctx path =
  433. ctx.static_prototypes#get path
  434. let get_static_prototype ctx path p =
  435. try get_static_prototype_raise ctx path
  436. with Not_found -> Error.raise_typing_error (Printf.sprintf "[%i] Type not found: %s" ctx.ctx_id (rev_hash path)) p
  437. let get_static_prototype_as_value ctx path p =
  438. (get_static_prototype ctx path p).pvalue
  439. let get_instance_prototype_raise ctx path =
  440. IntMap.find path ctx.instance_prototypes
  441. let get_instance_prototype ctx path p =
  442. try get_instance_prototype_raise ctx path
  443. with Not_found -> Error.raise_typing_error (Printf.sprintf "[%i] Instance prototype not found: %s" ctx.ctx_id (rev_hash path)) p
  444. let get_instance_constructor_raise ctx path =
  445. IntMap.find path ctx.constructors
  446. let get_instance_constructor ctx path p =
  447. try get_instance_constructor_raise ctx path
  448. with Not_found -> Error.raise_typing_error (Printf.sprintf "[%i] Instance constructor not found: %s" ctx.ctx_id (rev_hash path)) p
  449. let get_special_instance_constructor_raise ctx path =
  450. Hashtbl.find (get_ctx()).builtins.constructor_builtins path
  451. let get_proto_field_index_raise proto name =
  452. IntMap.find name proto.pnames
  453. let get_proto_field_index proto name =
  454. try get_proto_field_index_raise proto name
  455. with Not_found -> Error.raise_typing_error (Printf.sprintf "Field index for %s not found on prototype %s" (rev_hash name) (rev_hash proto.ppath)) null_pos
  456. let get_instance_field_index_raise proto name =
  457. IntMap.find name proto.pinstance_names
  458. let get_instance_field_index proto name p =
  459. try get_instance_field_index_raise proto name
  460. with Not_found -> Error.raise_typing_error (Printf.sprintf "Field index for %s not found on prototype %s" (rev_hash name) (rev_hash proto.ppath)) p
  461. let is v path =
  462. if path = key_Dynamic then
  463. v <> vnull
  464. else match v with
  465. | VInt32 _ -> path = key_Int || path = key_Float
  466. | VFloat f -> path = key_Float || (path = key_Int && f = (float_of_int (int_of_float f)) && f <= 2147483647. && f >= -2147483648.)
  467. | VTrue | VFalse -> path = key_Bool
  468. | VPrototype {pkind = PClass _} -> path = key_Class
  469. | VPrototype {pkind = PEnum _} -> path = key_Enum
  470. | VEnumValue ve -> path = key_EnumValue || path = ve.epath
  471. | VString _ -> path = key_String
  472. | VArray _ -> path = key_Array
  473. | VVector _ -> path = key_eval_Vector
  474. | VInstance vi ->
  475. let has_interface path' =
  476. try begin match (get_static_prototype_raise (get_ctx()) path').pkind with
  477. | PClass interfaces -> List.mem path interfaces
  478. | _ -> false
  479. end with Not_found ->
  480. false
  481. in
  482. let rec loop proto =
  483. if path = proto.ppath || has_interface proto.ppath then true
  484. else begin match proto.pparent with
  485. | Some proto -> loop proto
  486. | None -> false
  487. end
  488. in
  489. loop vi.iproto
  490. | _ -> false