Source code of Windows XP (NT5)
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.

301 lines
6.6 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
  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. REGISTER TEMPORARY)]);
  16. use Carp qw(confess);
  17. use strict;
  18. use B qw(class);
  19. # Perl internal constants that I should probably define elsewhere.
  20. sub SVf_IOK () { 0x10000 }
  21. sub SVf_NOK () { 0x20000 }
  22. # Types
  23. sub T_UNKNOWN () { 0 }
  24. sub T_DOUBLE () { 1 }
  25. sub T_INT () { 2 }
  26. # Flags
  27. sub VALID_INT () { 0x01 }
  28. sub VALID_DOUBLE () { 0x02 }
  29. sub VALID_SV () { 0x04 }
  30. sub REGISTER () { 0x08 } # no implicit write-back when calling subs
  31. sub TEMPORARY () { 0x10 } # no implicit write-back needed at all
  32. #
  33. # Callback for runtime code generation
  34. #
  35. my $runtime_callback = sub { confess "set_callback not yet called" };
  36. sub set_callback (&) { $runtime_callback = shift }
  37. sub runtime { &$runtime_callback(@_) }
  38. #
  39. # Methods
  40. #
  41. sub write_back { confess "stack object does not implement write_back" }
  42. sub invalidate { shift->{flags} &= ~(VALID_INT | VALID_DOUBLE) }
  43. sub as_sv {
  44. my $obj = shift;
  45. if (!($obj->{flags} & VALID_SV)) {
  46. $obj->write_back;
  47. $obj->{flags} |= VALID_SV;
  48. }
  49. return $obj->{sv};
  50. }
  51. sub as_int {
  52. my $obj = shift;
  53. if (!($obj->{flags} & VALID_INT)) {
  54. $obj->load_int;
  55. $obj->{flags} |= VALID_INT;
  56. }
  57. return $obj->{iv};
  58. }
  59. sub as_double {
  60. my $obj = shift;
  61. if (!($obj->{flags} & VALID_DOUBLE)) {
  62. $obj->load_double;
  63. $obj->{flags} |= VALID_DOUBLE;
  64. }
  65. return $obj->{nv};
  66. }
  67. sub as_numeric {
  68. my $obj = shift;
  69. return $obj->{type} == T_INT ? $obj->as_int : $obj->as_double;
  70. }
  71. #
  72. # Debugging methods
  73. #
  74. sub peek {
  75. my $obj = shift;
  76. my $type = $obj->{type};
  77. my $flags = $obj->{flags};
  78. my @flags;
  79. if ($type == T_UNKNOWN) {
  80. $type = "T_UNKNOWN";
  81. } elsif ($type == T_INT) {
  82. $type = "T_INT";
  83. } elsif ($type == T_DOUBLE) {
  84. $type = "T_DOUBLE";
  85. } else {
  86. $type = "(illegal type $type)";
  87. }
  88. push(@flags, "VALID_INT") if $flags & VALID_INT;
  89. push(@flags, "VALID_DOUBLE") if $flags & VALID_DOUBLE;
  90. push(@flags, "VALID_SV") if $flags & VALID_SV;
  91. push(@flags, "REGISTER") if $flags & REGISTER;
  92. push(@flags, "TEMPORARY") if $flags & TEMPORARY;
  93. @flags = ("none") unless @flags;
  94. return sprintf("%s type=$type flags=%s sv=$obj->{sv}",
  95. class($obj), join("|", @flags));
  96. }
  97. sub minipeek {
  98. my $obj = shift;
  99. my $type = $obj->{type};
  100. my $flags = $obj->{flags};
  101. if ($type == T_INT || $flags & VALID_INT) {
  102. return $obj->{iv};
  103. } elsif ($type == T_DOUBLE || $flags & VALID_DOUBLE) {
  104. return $obj->{nv};
  105. } else {
  106. return $obj->{sv};
  107. }
  108. }
  109. #
  110. # Caller needs to ensure that set_int, set_double,
  111. # set_numeric and set_sv are only invoked on legal lvalues.
  112. #
  113. sub set_int {
  114. my ($obj, $expr) = @_;
  115. runtime("$obj->{iv} = $expr;");
  116. $obj->{flags} &= ~(VALID_SV | VALID_DOUBLE);
  117. $obj->{flags} |= VALID_INT;
  118. }
  119. sub set_double {
  120. my ($obj, $expr) = @_;
  121. runtime("$obj->{nv} = $expr;");
  122. $obj->{flags} &= ~(VALID_SV | VALID_INT);
  123. $obj->{flags} |= VALID_DOUBLE;
  124. }
  125. sub set_numeric {
  126. my ($obj, $expr) = @_;
  127. if ($obj->{type} == T_INT) {
  128. $obj->set_int($expr);
  129. } else {
  130. $obj->set_double($expr);
  131. }
  132. }
  133. sub set_sv {
  134. my ($obj, $expr) = @_;
  135. runtime("SvSetSV($obj->{sv}, $expr);");
  136. $obj->invalidate;
  137. $obj->{flags} |= VALID_SV;
  138. }
  139. #
  140. # Stackobj::Padsv
  141. #
  142. @B::Stackobj::Padsv::ISA = 'B::Stackobj';
  143. sub B::Stackobj::Padsv::new {
  144. my ($class, $type, $extra_flags, $ix, $iname, $dname) = @_;
  145. bless {
  146. type => $type,
  147. flags => VALID_SV | $extra_flags,
  148. sv => "PL_curpad[$ix]",
  149. iv => "$iname",
  150. nv => "$dname"
  151. }, $class;
  152. }
  153. sub B::Stackobj::Padsv::load_int {
  154. my $obj = shift;
  155. if ($obj->{flags} & VALID_DOUBLE) {
  156. runtime("$obj->{iv} = $obj->{nv};");
  157. } else {
  158. runtime("$obj->{iv} = SvIV($obj->{sv});");
  159. }
  160. $obj->{flags} |= VALID_INT;
  161. }
  162. sub B::Stackobj::Padsv::load_double {
  163. my $obj = shift;
  164. $obj->write_back;
  165. runtime("$obj->{nv} = SvNV($obj->{sv});");
  166. $obj->{flags} |= VALID_DOUBLE;
  167. }
  168. sub B::Stackobj::Padsv::write_back {
  169. my $obj = shift;
  170. my $flags = $obj->{flags};
  171. return if $flags & VALID_SV;
  172. if ($flags & VALID_INT) {
  173. runtime("sv_setiv($obj->{sv}, $obj->{iv});");
  174. } elsif ($flags & VALID_DOUBLE) {
  175. runtime("sv_setnv($obj->{sv}, $obj->{nv});");
  176. } else {
  177. confess "write_back failed for lexical @{[$obj->peek]}\n";
  178. }
  179. $obj->{flags} |= VALID_SV;
  180. }
  181. #
  182. # Stackobj::Const
  183. #
  184. @B::Stackobj::Const::ISA = 'B::Stackobj';
  185. sub B::Stackobj::Const::new {
  186. my ($class, $sv) = @_;
  187. my $obj = bless {
  188. flags => 0,
  189. sv => $sv # holds the SV object until write_back happens
  190. }, $class;
  191. my $svflags = $sv->FLAGS;
  192. if ($svflags & SVf_IOK) {
  193. $obj->{flags} = VALID_INT|VALID_DOUBLE;
  194. $obj->{type} = T_INT;
  195. $obj->{nv} = $obj->{iv} = $sv->IV;
  196. } elsif ($svflags & SVf_NOK) {
  197. $obj->{flags} = VALID_INT|VALID_DOUBLE;
  198. $obj->{type} = T_DOUBLE;
  199. $obj->{iv} = $obj->{nv} = $sv->NV;
  200. } else {
  201. $obj->{type} = T_UNKNOWN;
  202. }
  203. return $obj;
  204. }
  205. sub B::Stackobj::Const::write_back {
  206. my $obj = shift;
  207. return if $obj->{flags} & VALID_SV;
  208. # Save the SV object and replace $obj->{sv} by its C source code name
  209. $obj->{sv} = $obj->{sv}->save;
  210. $obj->{flags} |= VALID_SV|VALID_INT|VALID_DOUBLE;
  211. }
  212. sub B::Stackobj::Const::load_int {
  213. my $obj = shift;
  214. $obj->{iv} = int($obj->{sv}->PV);
  215. $obj->{flags} |= VALID_INT;
  216. }
  217. sub B::Stackobj::Const::load_double {
  218. my $obj = shift;
  219. $obj->{nv} = $obj->{sv}->PV + 0.0;
  220. $obj->{flags} |= VALID_DOUBLE;
  221. }
  222. sub B::Stackobj::Const::invalidate {}
  223. #
  224. # Stackobj::Bool
  225. #
  226. @B::Stackobj::Bool::ISA = 'B::Stackobj';
  227. sub B::Stackobj::Bool::new {
  228. my ($class, $preg) = @_;
  229. my $obj = bless {
  230. type => T_INT,
  231. flags => VALID_INT|VALID_DOUBLE,
  232. iv => $$preg,
  233. nv => $$preg,
  234. preg => $preg # this holds our ref to the pseudo-reg
  235. }, $class;
  236. return $obj;
  237. }
  238. sub B::Stackobj::Bool::write_back {
  239. my $obj = shift;
  240. return if $obj->{flags} & VALID_SV;
  241. $obj->{sv} = "($obj->{iv} ? &PL_sv_yes : &PL_sv_no)";
  242. $obj->{flags} |= VALID_SV;
  243. }
  244. # XXX Might want to handle as_double/set_double/load_double?
  245. sub B::Stackobj::Bool::invalidate {}
  246. 1;
  247. __END__
  248. =head1 NAME
  249. B::Stackobj - Helper module for CC backend
  250. =head1 SYNOPSIS
  251. use B::Stackobj;
  252. =head1 DESCRIPTION
  253. See F<ext/B/README>.
  254. =head1 AUTHOR
  255. Malcolm Beattie, C<[email protected]>
  256. =cut