Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

346 lines
8.3 KiB

  1. # Stackobj.pm
  2. #
  3. # Copyright (c) 1996 Malcolm Beattie
  4. #
  5. # You may distribute under the terms of either the GNU General Public
  6. # License or the Artistic License, as specified in the README file.
  7. #
  8. package B::Stackobj;
  9. use Exporter ();
  10. @ISA = qw(Exporter);
  11. @EXPORT_OK = qw(set_callback T_UNKNOWN T_DOUBLE T_INT VALID_UNSIGNED
  12. VALID_INT VALID_DOUBLE VALID_SV REGISTER TEMPORARY);
  13. %EXPORT_TAGS = (types => [qw(T_UNKNOWN T_DOUBLE T_INT)],
  14. flags => [qw(VALID_INT VALID_DOUBLE VALID_SV
  15. VALID_UNSIGNED REGISTER TEMPORARY)]);
  16. use Carp qw(confess);
  17. use strict;
  18. use B qw(class SVf_IOK SVf_NOK SVf_IVisUV);
  19. # Types
  20. sub T_UNKNOWN () { 0 }
  21. sub T_DOUBLE () { 1 }
  22. sub T_INT () { 2 }
  23. sub T_SPECIAL () { 3 }
  24. # Flags
  25. sub VALID_INT () { 0x01 }
  26. sub VALID_UNSIGNED () { 0x02 }
  27. sub VALID_DOUBLE () { 0x04 }
  28. sub VALID_SV () { 0x08 }
  29. sub REGISTER () { 0x10 } # no implicit write-back when calling subs
  30. sub TEMPORARY () { 0x20 } # no implicit write-back needed at all
  31. sub SAVE_INT () { 0x40 } #if int part needs to be saved at all
  32. sub SAVE_DOUBLE () { 0x80 } #if double part needs to be saved at all
  33. #
  34. # Callback for runtime code generation
  35. #
  36. my $runtime_callback = sub { confess "set_callback not yet called" };
  37. sub set_callback (&) { $runtime_callback = shift }
  38. sub runtime { &$runtime_callback(@_) }
  39. #
  40. # Methods
  41. #
  42. sub write_back { confess "stack object does not implement write_back" }
  43. sub invalidate { shift->{flags} &= ~(VALID_INT |VALID_UNSIGNED | VALID_DOUBLE) }
  44. sub as_sv {
  45. my $obj = shift;
  46. if (!($obj->{flags} & VALID_SV)) {
  47. $obj->write_back;
  48. $obj->{flags} |= VALID_SV;
  49. }
  50. return $obj->{sv};
  51. }
  52. sub as_int {
  53. my $obj = shift;
  54. if (!($obj->{flags} & VALID_INT)) {
  55. $obj->load_int;
  56. $obj->{flags} |= VALID_INT|SAVE_INT;
  57. }
  58. return $obj->{iv};
  59. }
  60. sub as_double {
  61. my $obj = shift;
  62. if (!($obj->{flags} & VALID_DOUBLE)) {
  63. $obj->load_double;
  64. $obj->{flags} |= VALID_DOUBLE|SAVE_DOUBLE;
  65. }
  66. return $obj->{nv};
  67. }
  68. sub as_numeric {
  69. my $obj = shift;
  70. return $obj->{type} == T_INT ? $obj->as_int : $obj->as_double;
  71. }
  72. sub as_bool {
  73. my $obj=shift;
  74. if ($obj->{flags} & VALID_INT ){
  75. return $obj->{iv};
  76. }
  77. if ($obj->{flags} & VALID_DOUBLE ){
  78. return $obj->{nv};
  79. }
  80. return sprintf("(SvTRUE(%s))", $obj->as_sv) ;
  81. }
  82. #
  83. # Debugging methods
  84. #
  85. sub peek {
  86. my $obj = shift;
  87. my $type = $obj->{type};
  88. my $flags = $obj->{flags};
  89. my @flags;
  90. if ($type == T_UNKNOWN) {
  91. $type = "T_UNKNOWN";
  92. } elsif ($type == T_INT) {
  93. $type = "T_INT";
  94. } elsif ($type == T_DOUBLE) {
  95. $type = "T_DOUBLE";
  96. } else {
  97. $type = "(illegal type $type)";
  98. }
  99. push(@flags, "VALID_INT") if $flags & VALID_INT;
  100. push(@flags, "VALID_DOUBLE") if $flags & VALID_DOUBLE;
  101. push(@flags, "VALID_SV") if $flags & VALID_SV;
  102. push(@flags, "REGISTER") if $flags & REGISTER;
  103. push(@flags, "TEMPORARY") if $flags & TEMPORARY;
  104. @flags = ("none") unless @flags;
  105. return sprintf("%s type=$type flags=%s sv=$obj->{sv}",
  106. class($obj), join("|", @flags));
  107. }
  108. sub minipeek {
  109. my $obj = shift;
  110. my $type = $obj->{type};
  111. my $flags = $obj->{flags};
  112. if ($type == T_INT || $flags & VALID_INT) {
  113. return $obj->{iv};
  114. } elsif ($type == T_DOUBLE || $flags & VALID_DOUBLE) {
  115. return $obj->{nv};
  116. } else {
  117. return $obj->{sv};
  118. }
  119. }
  120. #
  121. # Caller needs to ensure that set_int, set_double,
  122. # set_numeric and set_sv are only invoked on legal lvalues.
  123. #
  124. sub set_int {
  125. my ($obj, $expr,$unsigned) = @_;
  126. runtime("$obj->{iv} = $expr;");
  127. $obj->{flags} &= ~(VALID_SV | VALID_DOUBLE);
  128. $obj->{flags} |= VALID_INT|SAVE_INT;
  129. $obj->{flags} |= VALID_UNSIGNED if $unsigned;
  130. }
  131. sub set_double {
  132. my ($obj, $expr) = @_;
  133. runtime("$obj->{nv} = $expr;");
  134. $obj->{flags} &= ~(VALID_SV | VALID_INT);
  135. $obj->{flags} |= VALID_DOUBLE|SAVE_DOUBLE;
  136. }
  137. sub set_numeric {
  138. my ($obj, $expr) = @_;
  139. if ($obj->{type} == T_INT) {
  140. $obj->set_int($expr);
  141. } else {
  142. $obj->set_double($expr);
  143. }
  144. }
  145. sub set_sv {
  146. my ($obj, $expr) = @_;
  147. runtime("SvSetSV($obj->{sv}, $expr);");
  148. $obj->invalidate;
  149. $obj->{flags} |= VALID_SV;
  150. }
  151. #
  152. # Stackobj::Padsv
  153. #
  154. @B::Stackobj::Padsv::ISA = 'B::Stackobj';
  155. sub B::Stackobj::Padsv::new {
  156. my ($class, $type, $extra_flags, $ix, $iname, $dname) = @_;
  157. $extra_flags |= SAVE_INT if $extra_flags & VALID_INT;
  158. $extra_flags |= SAVE_DOUBLE if $extra_flags & VALID_DOUBLE;
  159. bless {
  160. type => $type,
  161. flags => VALID_SV | $extra_flags,
  162. sv => "PL_curpad[$ix]",
  163. iv => "$iname",
  164. nv => "$dname"
  165. }, $class;
  166. }
  167. sub B::Stackobj::Padsv::load_int {
  168. my $obj = shift;
  169. if ($obj->{flags} & VALID_DOUBLE) {
  170. runtime("$obj->{iv} = $obj->{nv};");
  171. } else {
  172. runtime("$obj->{iv} = SvIV($obj->{sv});");
  173. }
  174. $obj->{flags} |= VALID_INT|SAVE_INT;
  175. }
  176. sub B::Stackobj::Padsv::load_double {
  177. my $obj = shift;
  178. $obj->write_back;
  179. runtime("$obj->{nv} = SvNV($obj->{sv});");
  180. $obj->{flags} |= VALID_DOUBLE|SAVE_DOUBLE;
  181. }
  182. sub B::Stackobj::Padsv::save_int {
  183. my $obj = shift;
  184. return $obj->{flags} & SAVE_INT;
  185. }
  186. sub B::Stackobj::Padsv::save_double {
  187. my $obj = shift;
  188. return $obj->{flags} & SAVE_DOUBLE;
  189. }
  190. sub B::Stackobj::Padsv::write_back {
  191. my $obj = shift;
  192. my $flags = $obj->{flags};
  193. return if $flags & VALID_SV;
  194. if ($flags & VALID_INT) {
  195. if ($flags & VALID_UNSIGNED ){
  196. runtime("sv_setuv($obj->{sv}, $obj->{iv});");
  197. }else{
  198. runtime("sv_setiv($obj->{sv}, $obj->{iv});");
  199. }
  200. } elsif ($flags & VALID_DOUBLE) {
  201. runtime("sv_setnv($obj->{sv}, $obj->{nv});");
  202. } else {
  203. confess "write_back failed for lexical @{[$obj->peek]}\n";
  204. }
  205. $obj->{flags} |= VALID_SV;
  206. }
  207. #
  208. # Stackobj::Const
  209. #
  210. @B::Stackobj::Const::ISA = 'B::Stackobj';
  211. sub B::Stackobj::Const::new {
  212. my ($class, $sv) = @_;
  213. my $obj = bless {
  214. flags => 0,
  215. sv => $sv # holds the SV object until write_back happens
  216. }, $class;
  217. if ( ref($sv) eq "B::SPECIAL" ){
  218. $obj->{type}= T_SPECIAL;
  219. }else{
  220. my $svflags = $sv->FLAGS;
  221. if ($svflags & SVf_IOK) {
  222. $obj->{flags} = VALID_INT|VALID_DOUBLE;
  223. $obj->{type} = T_INT;
  224. if ($svflags & SVf_IVisUV){
  225. $obj->{flags} |= VALID_UNSIGNED;
  226. $obj->{nv} = $obj->{iv} = $sv->UVX;
  227. }else{
  228. $obj->{nv} = $obj->{iv} = $sv->IV;
  229. }
  230. } elsif ($svflags & SVf_NOK) {
  231. $obj->{flags} = VALID_INT|VALID_DOUBLE;
  232. $obj->{type} = T_DOUBLE;
  233. $obj->{iv} = $obj->{nv} = $sv->NV;
  234. } else {
  235. $obj->{type} = T_UNKNOWN;
  236. }
  237. }
  238. return $obj;
  239. }
  240. sub B::Stackobj::Const::write_back {
  241. my $obj = shift;
  242. return if $obj->{flags} & VALID_SV;
  243. # Save the SV object and replace $obj->{sv} by its C source code name
  244. $obj->{sv} = $obj->{sv}->save;
  245. $obj->{flags} |= VALID_SV|VALID_INT|VALID_DOUBLE;
  246. }
  247. sub B::Stackobj::Const::load_int {
  248. my $obj = shift;
  249. if (ref($obj->{sv}) eq "B::RV"){
  250. $obj->{iv} = int($obj->{sv}->RV->PV);
  251. }else{
  252. $obj->{iv} = int($obj->{sv}->PV);
  253. }
  254. $obj->{flags} |= VALID_INT;
  255. }
  256. sub B::Stackobj::Const::load_double {
  257. my $obj = shift;
  258. if (ref($obj->{sv}) eq "B::RV"){
  259. $obj->{nv} = $obj->{sv}->RV->PV + 0.0;
  260. }else{
  261. $obj->{nv} = $obj->{sv}->PV + 0.0;
  262. }
  263. $obj->{flags} |= VALID_DOUBLE;
  264. }
  265. sub B::Stackobj::Const::invalidate {}
  266. #
  267. # Stackobj::Bool
  268. #
  269. @B::Stackobj::Bool::ISA = 'B::Stackobj';
  270. sub B::Stackobj::Bool::new {
  271. my ($class, $preg) = @_;
  272. my $obj = bless {
  273. type => T_INT,
  274. flags => VALID_INT|VALID_DOUBLE,
  275. iv => $$preg,
  276. nv => $$preg,
  277. preg => $preg # this holds our ref to the pseudo-reg
  278. }, $class;
  279. return $obj;
  280. }
  281. sub B::Stackobj::Bool::write_back {
  282. my $obj = shift;
  283. return if $obj->{flags} & VALID_SV;
  284. $obj->{sv} = "($obj->{iv} ? &PL_sv_yes : &PL_sv_no)";
  285. $obj->{flags} |= VALID_SV;
  286. }
  287. # XXX Might want to handle as_double/set_double/load_double?
  288. sub B::Stackobj::Bool::invalidate {}
  289. 1;
  290. __END__
  291. =head1 NAME
  292. B::Stackobj - Helper module for CC backend
  293. =head1 SYNOPSIS
  294. use B::Stackobj;
  295. =head1 DESCRIPTION
  296. See F<ext/B/README>.
  297. =head1 AUTHOR
  298. Malcolm Beattie, C<[email protected]>
  299. =cut