1 /* optimizer.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2005-2009 */
2 
3 /*
4 
5 Copyright (c) 2005-2009 Made to Order Software Corp.
6 
7 Permission is hereby granted, free of charge, to any
8 person obtaining a copy of this software and
9 associated documentation files (the "Software"), to
10 deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom
14 the Software is furnished to do so, subject to the
15 following conditions:
16 
17 The above copyright notice and this permission notice
18 shall be included in all copies or substantial
19 portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
23 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31 
32 */
33 
34 #define	NEED_ISINF
35 #include	"optimizer.h"
36 
37 
38 
39 namespace sswf
40 {
41 namespace as
42 {
43 
44 
45 /**********************************************************************/
46 /**********************************************************************/
47 /***  OPTIMIZER CREATOR  **********************************************/
48 /**********************************************************************/
49 /**********************************************************************/
50 
CreateOptimizer(void)51 Optimizer *Optimizer::CreateOptimizer(void)
52 {
53 	return new IntOptimizer();
54 }
55 
56 
Version(void)57 const char *Optimizer::Version(void)
58 {
59 	return TO_STR(SSWF_VERSION);
60 }
61 
62 
63 /**********************************************************************/
64 /**********************************************************************/
65 /***  INTERNAL OPTIMIZER  *********************************************/
66 /**********************************************************************/
67 /**********************************************************************/
68 
IntOptimizer(void)69 IntOptimizer::IntOptimizer(void)
70 {
71 	f_error_stream = &f_default_error_stream;
72 	f_options = 0;
73 	f_label = 0;
74 	f_errcnt = 0;
75 }
76 
77 
~IntOptimizer()78 IntOptimizer::~IntOptimizer()
79 {
80 }
81 
82 
SetErrorStream(ErrorStream & error_stream)83 void IntOptimizer::SetErrorStream(ErrorStream& error_stream)
84 {
85 	f_error_stream = &error_stream;
86 }
87 
88 
SetOptions(Options & options)89 void IntOptimizer::SetOptions(Options& options)
90 {
91 	f_options = &options;
92 }
93 
94 
95 
96 
97 /**********************************************************************/
98 /**********************************************************************/
99 /***  OPTIMIZE  *******************************************************/
100 /**********************************************************************/
101 /**********************************************************************/
102 
Optimize(NodePtr & node)103 int IntOptimizer::Optimize(NodePtr& node)
104 {
105 	f_errcnt = 0;
106 
107 	Run(node);
108 
109 	return f_errcnt;
110 }
111 
112 
113 
Label(String & label)114 void IntOptimizer::Label(String& label)
115 {
116 	char	buf[256];
117 
118 	snprintf(buf, sizeof(buf), "__optimizer__%d", f_label);
119 	f_label++;
120 	label = buf;
121 }
122 
GetLastLabel(void) const123 int IntOptimizer::GetLastLabel(void) const
124 {
125 	return f_label;
126 }
127 
SetFirstLabel(int label)128 void IntOptimizer::SetFirstLabel(int label)
129 {
130 	f_label = label;
131 }
132 
133 
134 
Run(NodePtr & node)135 void IntOptimizer::Run(NodePtr& node)
136 {
137 	int		idx, max;
138 
139 	// accept empty nodes, just ignore them
140 	if(!node.HasNode()) {
141 		return;
142 	}
143 
144 	// we need to optimize the child most nodes first
145 	max = node.GetChildCount();
146 	for(idx = 0; idx < max; ++idx) {
147 		NodePtr& child = node.GetChild(idx);
148 		if(child.HasNode()) {
149 			Run(child);
150 
151 			Data& data = child.GetData();
152 			if(data.f_type == NODE_UNKNOWN) {
153 				node.DeleteChild(idx);
154 				idx--;
155 				max--;
156 			}
157 		}
158 	}
159 
160 	Data& data = node.GetData();
161 	switch(data.f_type) {
162 	case NODE_DIRECTIVE_LIST:
163 		DirectiveList(node);
164 		break;
165 
166 	case NODE_IF:
167 		If(node);
168 		break;
169 
170 	case NODE_WHILE:
171 		While(node);
172 		break;
173 
174 	case NODE_DO:
175 		Do(node);
176 		break;
177 
178 	case NODE_ASSIGNMENT:
179 		Assignment(node);
180 		break;
181 
182 	case NODE_ASSIGNMENT_ADD:
183 	case NODE_ASSIGNMENT_SUBTRACT:
184 		AssignmentAdd(node);
185 		break;
186 
187 	case NODE_ASSIGNMENT_MULTIPLY:
188 		AssignmentMultiply(node);
189 		break;
190 
191 	case NODE_ASSIGNMENT_DIVIDE:
192 		AssignmentDivide(node);
193 		break;
194 
195 	case NODE_ASSIGNMENT_MODULO:
196 		AssignmentModulo(node);
197 		break;
198 
199 	case NODE_BITWISE_NOT:
200 		BitwiseNot(node);
201 		break;
202 
203 	case NODE_LOGICAL_NOT:
204 		LogicalNot(node);
205 		break;
206 
207 	case NODE_DECREMENT:
208 		Decrement(node);
209 		break;
210 
211 	case NODE_INCREMENT:
212 		Increment(node);
213 		break;
214 
215 	case NODE_POWER:
216 		Power(node);
217 		break;
218 
219 	case NODE_MULTIPLY:
220 		Multiply(node);
221 		break;
222 
223 	case NODE_DIVIDE:
224 		Divide(node);
225 		break;
226 
227 	case NODE_MODULO:
228 		Modulo(node);
229 		break;
230 
231 	case NODE_ADD:
232 		Add(node);
233 		break;
234 
235 	case NODE_SUBTRACT:
236 		Subtract(node);
237 		break;
238 
239 	case NODE_SHIFT_LEFT:
240 		ShiftLeft(node);
241 		break;
242 
243 	case NODE_SHIFT_RIGHT:
244 		ShiftRight(node);
245 		break;
246 
247 	case NODE_SHIFT_RIGHT_UNSIGNED:
248 		ShiftRightUnsigned(node);
249 		break;
250 
251 	case NODE_ROTATE_LEFT:
252 		RotateLeft(node);
253 		break;
254 
255 	case NODE_ROTATE_RIGHT:
256 		RotateRight(node);
257 		break;
258 
259 	case NODE_LESS:
260 		Less(node);
261 		break;
262 
263 	case NODE_LESS_EQUAL:
264 		LessEqual(node);
265 		break;
266 
267 	case NODE_GREATER:
268 		Greater(node);
269 		break;
270 
271 	case NODE_GREATER_EQUAL:
272 		GreaterEqual(node);
273 		break;
274 
275 	case NODE_EQUAL:
276 		Equality(node, false, false);
277 		break;
278 
279 	case NODE_STRICTLY_EQUAL:
280 		Equality(node, true, false);
281 		break;
282 
283 	case NODE_NOT_EQUAL:
284 		Equality(node, false, true);
285 		break;
286 
287 	case NODE_STRICTLY_NOT_EQUAL:
288 		Equality(node, true, true);
289 		break;
290 
291 	case NODE_BITWISE_AND:
292 		BitwiseAnd(node);
293 		break;
294 
295 	case NODE_BITWISE_XOR:
296 		BitwiseXOr(node);
297 		break;
298 
299 	case NODE_BITWISE_OR:
300 		BitwiseOr(node);
301 		break;
302 
303 	case NODE_LOGICAL_AND:
304 		LogicalAnd(node);
305 		break;
306 
307 	case NODE_LOGICAL_XOR:
308 		LogicalXOr(node);
309 		break;
310 
311 	case NODE_LOGICAL_OR:
312 		LogicalOr(node);
313 		break;
314 
315 	case NODE_MAXIMUM:
316 		Maximum(node);
317 		break;
318 
319 	case NODE_MINIMUM:
320 		Minimum(node);
321 		break;
322 
323 	case NODE_CONDITIONAL:
324 		Conditional(node);
325 		break;
326 
327 	default:
328 		break;
329 
330 	}
331 }
332 
333 
334 
DirectiveList(NodePtr & list)335 void IntOptimizer::DirectiveList(NodePtr& list)
336 {
337 	int max = list.GetChildCount();
338 	for(int idx = 0; idx < max; ++idx) {
339 		NodePtr& child = list.GetChild(idx);
340 		Data& data = child.GetData();
341 		if(data.f_type == NODE_IDENTIFIER) {
342 			NodePtr& instance = child.GetLink(NodePtr::LINK_INSTANCE);
343 			if(instance.HasNode()) {
344 				list.DeleteChild(idx);
345 				--idx;
346 				--max;
347 			}
348 		}
349 	}
350 }
351 
352 
If(NodePtr & if_node)353 void IntOptimizer::If(NodePtr& if_node)
354 {
355 	int max = if_node.GetChildCount();
356 	if(max != 2 && max != 3) {
357 		return;
358 	}
359 
360 	NodePtr& condition = if_node.GetChild(0);
361 	Data& data = condition.GetData();
362 	if(data.ToBoolean()) {
363 		if(data.f_type == NODE_TRUE) {
364 			NodePtr then = if_node.GetChild(1);
365 			if_node.DeleteChild(1);
366 			if_node.ReplaceWith(then);
367 		}
368 		else if(max == 3) {
369 			NodePtr else_node = if_node.GetChild(2);
370 			if_node.DeleteChild(2);
371 			if_node.ReplaceWith(else_node);
372 		}
373 		else {
374 			// we want to delete the if_node, it serves
375 			// no purpose! (another function is in charge
376 			// of deleting; we just mark the node as unknown)
377 			Data& data = if_node.GetData();
378 			data.f_type = NODE_UNKNOWN;
379 		}
380 	}
381 }
382 
383 
While(NodePtr & while_node)384 void IntOptimizer::While(NodePtr& while_node)
385 {
386 	int max = while_node.GetChildCount();
387 	if(max != 2) {
388 		return;
389 	}
390 
391 // TODO:
392 //
393 // if we detect something such as:
394 //
395 //	cnt = 3
396 //	while(cnt > 0) {
397 //		...
398 //	}
399 //
400 // we can reduce to:
401 //
402 //	cnt = 3;
403 //	do {
404 //		...
405 //	} while(cnt > 0);
406 //
407 // since the first time cnt > 0 will always be true.
408 //
409 
410 	NodePtr& condition = while_node.GetChild(0);
411 	Data& data = condition.GetData();
412 	if(data.ToBoolean()) {
413 		if(data.f_type == NODE_TRUE) {
414 			// TODO:
415 			// Whenever we detect a forever loop we
416 			// need to check whether it includes some
417 			// break. If there isn't a break, we should
418 			// err about it. It is likely a bad one!
419 			// [except if the function returns Never]
420 			//
421 			// create a forever loop
422 			NodePtr forever;
423 			forever.CreateNode(NODE_DIRECTIVE_LIST);
424 			forever.CopyInputInfo(while_node);
425 
426 			NodePtr label;
427 			label.CreateNode(NODE_LABEL);
428 			label.CopyInputInfo(while_node);
429 			Data& label_data = label.GetData();
430 			Label(label_data.f_str);
431 			forever.AddChild(label);
432 
433 			NodePtr list = while_node.GetChild(1);
434 			while_node.DeleteChild(1);
435 			forever.AddChild(list);
436 
437 			NodePtr goto_label;
438 			goto_label.CreateNode(NODE_GOTO);
439 			goto_label.CopyInputInfo(while_node);
440 			Data& goto_data = goto_label.GetData();
441 			goto_data.f_str = label_data.f_str;
442 			forever.AddChild(goto_label);
443 
444 			while_node.ReplaceWith(forever);
445 		}
446 		else {
447 			// we want to delete the when_node, it serves
448 			// not purpose! (another function is in charge
449 			// of deleting; we just mark the node as unknown)
450 			Data& data = while_node.GetData();
451 			data.f_type = NODE_UNKNOWN;
452 		}
453 	}
454 }
455 
456 
Do(NodePtr & do_node)457 void IntOptimizer::Do(NodePtr& do_node)
458 {
459 	int max = do_node.GetChildCount();
460 	if(max != 2) {
461 		return;
462 	}
463 
464 	NodePtr& condition = do_node.GetChild(1);
465 	Data& data = condition.GetData();
466 	if(data.ToBoolean()) {
467 		if(data.f_type == NODE_TRUE) {
468 			// TODO:
469 			// Whenever we detect a forever loop we
470 			// need to check whether it includes some
471 			// break. If there isn't a break, we should
472 			// err about it. It is likely a bad one!
473 			// [except if the function returns Never]
474 			//
475 			// create a forever loop
476 			NodePtr forever;
477 			forever.CreateNode(NODE_DIRECTIVE_LIST);
478 			forever.CopyInputInfo(do_node);
479 
480 			NodePtr label;
481 			label.CreateNode(NODE_LABEL);
482 			label.CopyInputInfo(do_node);
483 			Data& label_data = label.GetData();
484 			Label(label_data.f_str);
485 			forever.AddChild(label);
486 
487 			NodePtr list = do_node.GetChild(0);
488 			do_node.DeleteChild(0);
489 			forever.AddChild(list);
490 
491 			NodePtr goto_label;
492 			goto_label.CreateNode(NODE_GOTO);
493 			goto_label.CopyInputInfo(do_node);
494 			Data& goto_data = goto_label.GetData();
495 			goto_data.f_str = label_data.f_str;
496 			forever.AddChild(goto_label);
497 
498 			do_node.ReplaceWith(forever);
499 		}
500 		else {
501 			// in this case, we simply run the
502 			// directives once
503 			NodePtr list = do_node.GetChild(0);
504 			do_node.DeleteChild(0);
505 			do_node.ReplaceWith(do_node.GetChild(0));
506 		}
507 	}
508 }
509 
510 
Assignment(NodePtr & assignment)511 void IntOptimizer::Assignment(NodePtr& assignment)
512 {
513 	if(assignment.GetChildCount() != 2) {
514 		return;
515 	}
516 
517 	NodePtr left = assignment.GetChild(0);
518 	NodePtr& right = assignment.GetChild(1);
519 
520 	Data& ldata = left.GetData();
521 	Data& rdata = right.GetData();
522 
523 	if(ldata.f_type == NODE_IDENTIFIER
524 	&& rdata.f_type == NODE_IDENTIFIER
525 	&& ldata.f_str == rdata.f_str) {
526 		// TODO: fix the parenting whenever we copy a
527 		//	 node in another! What we really need
528 		//	 is a recurcive function which reparents
529 		//	 all the children once in a while...
530 		assignment.DeleteChild(0);
531 		assignment.ReplaceWith(left);
532 		// The following is valid ONLY if the offset is up to date
533 		//assignment.GetParent().SetChild(assignment.GetOffset(), left);
534 	}
535 }
536 
537 
AssignmentAdd(NodePtr & assignment)538 void IntOptimizer::AssignmentAdd(NodePtr& assignment)
539 {
540 	// a += 0 -> a
541 	// a -= 0 -> a
542 	if(assignment.GetChildCount() != 2) {
543 		return;
544 	}
545 
546 	NodePtr& right = assignment.GetChild(1);
547 	Data& data = right.GetData();
548 	if(data.f_type == NODE_INT64) {
549 		if(data.f_int.Get() == 0) {
550 			NodePtr left = assignment.GetChild(0);
551 			assignment.DeleteChild(0);
552 			assignment.ReplaceWith(left);
553 		}
554 	}
555 	else if(data.f_type == NODE_FLOAT64) {
556 		if(data.f_float.Get() == 0) {
557 			NodePtr left = assignment.GetChild(0);
558 			assignment.DeleteChild(0);
559 			assignment.ReplaceWith(left);
560 		}
561 	}
562 }
563 
564 
AssignmentMultiply(NodePtr & assignment)565 void IntOptimizer::AssignmentMultiply(NodePtr& assignment)
566 {
567 	// a *= 0 -> 0
568 	// a *= 1 -> a
569 	if(assignment.GetChildCount() != 2) {
570 		return;
571 	}
572 
573 	NodePtr right = assignment.GetChild(1);
574 	Data& data = right.GetData();
575 	if(data.f_type == NODE_INT64) {
576 		if(data.f_int.Get() == 0) {
577 			assignment.DeleteChild(1);
578 			assignment.ReplaceWith(right);
579 		}
580 		else if(data.f_int.Get() == 1) {
581 			NodePtr left = assignment.GetChild(0);
582 			assignment.DeleteChild(0);
583 			assignment.ReplaceWith(left);
584 		}
585 	}
586 	else if(data.f_type == NODE_FLOAT64) {
587 		if(data.f_float.Get() == 0.0) {
588 			assignment.DeleteChild(1);
589 			assignment.ReplaceWith(right);
590 		}
591 		else if(data.f_float.Get() == 1.0) {
592 			NodePtr left = assignment.GetChild(0);
593 			assignment.DeleteChild(0);
594 			assignment.ReplaceWith(left);
595 		}
596 	}
597 }
598 
599 
AssignmentDivide(NodePtr & assignment)600 void IntOptimizer::AssignmentDivide(NodePtr& assignment)
601 {
602 	// a /= 1 -> a
603 	// a /= 0 -> ERROR
604 	if(assignment.GetChildCount() != 2) {
605 		return;
606 	}
607 
608 	NodePtr& right = assignment.GetChild(1);
609 	Data& data = right.GetData();
610 	if(data.f_type == NODE_INT64) {
611 		if(data.f_int.Get() == 0) {
612 			f_error_stream->ErrMsg(AS_ERR_DIVIDE_BY_ZERO, right, "dividing by zero is illegal");
613 			f_errcnt++;
614 		}
615 		else if(data.f_int.Get() == 1) {
616 			NodePtr left = assignment.GetChild(0);
617 			assignment.DeleteChild(0);
618 			assignment.ReplaceWith(left);
619 		}
620 	}
621 	else if(data.f_type == NODE_FLOAT64) {
622 		if(data.f_float.Get() == 0.0) {
623 			f_error_stream->ErrMsg(AS_ERR_DIVIDE_BY_ZERO, right, "dividing by zero is illegal");
624 			f_errcnt++;
625 		}
626 		else if(data.f_float.Get() == 1.0) {
627 			NodePtr left = assignment.GetChild(0);
628 			assignment.DeleteChild(0);
629 			assignment.ReplaceWith(left);
630 		}
631 	}
632 }
633 
634 
AssignmentModulo(NodePtr & assignment)635 void IntOptimizer::AssignmentModulo(NodePtr& assignment)
636 {
637 	// a %= 1 -> a
638 	// a %= 0 -> ERROR
639 	if(assignment.GetChildCount() != 2) {
640 		return;
641 	}
642 
643 	NodePtr& right = assignment.GetChild(1);
644 	Data& data = right.GetData();
645 	if(data.f_type == NODE_INT64) {
646 		if(data.f_int.Get() == 0) {
647 			f_error_stream->ErrMsg(AS_ERR_DIVIDE_BY_ZERO, right, "modulo by zero is illegal");
648 			f_errcnt++;
649 		}
650 	}
651 	else if(data.f_type == NODE_FLOAT64) {
652 		if(data.f_float.Get() == 0.0) {
653 			f_error_stream->ErrMsg(AS_ERR_DIVIDE_BY_ZERO, right, "modulo by zero is illegal");
654 			f_errcnt++;
655 		}
656 	}
657 }
658 
659 
660 
661 // TODO: all arithmetic operations need to be checked for overflows...
662 //	 toBoolean(NaN) == false
663 
BitwiseNot(NodePtr & bitwise_not)664 void IntOptimizer::BitwiseNot(NodePtr& bitwise_not)
665 {
666 	if(bitwise_not.GetChildCount() != 1) {
667 		return;
668 	}
669 	Data& result = bitwise_not.GetData();
670 
671 	NodePtr child = bitwise_not.GetChild(0);
672 	Data data = child.GetData();
673 	if(data.ToNumber()) {
674 		result.f_type = data.f_type;
675 		if(data.f_type == NODE_INT64) {
676 			result.f_int.Set(~data.f_int.Get());
677 		}
678 		else {
679 			// ECMAScript version 4 says we can do this with floats!
680 			result.f_float.Set(~((int64_t) data.f_float.Get() & 0x0FFFFFFFF));
681 		}
682 	}
683 	else {
684 		// We assume that the expression was already
685 		// compiled and thus identifiers which were
686 		// constants have been replaced already.
687 		return;
688 	}
689 
690 // we don't need our child anymore
691 	bitwise_not.DeleteChild(0);
692 }
693 
694 
LogicalNot(NodePtr & logical_not)695 void IntOptimizer::LogicalNot(NodePtr& logical_not)
696 {
697 	if(logical_not.GetChildCount() != 1) {
698 		return;
699 	}
700 	Data& result = logical_not.GetData();
701 
702 	NodePtr child = logical_not.GetChild(0);
703 	Data data = child.GetData();
704 	if(data.ToBoolean()) {
705 		if(data.f_type == NODE_TRUE) {
706 			result.f_type = NODE_FALSE;
707 		}
708 		else {
709 			result.f_type = NODE_TRUE;
710 		}
711 	}
712 	else {
713 		if(data.f_type == NODE_LOGICAL_NOT) {
714 			// Reduce !!expr to expr
715 			// TODO:
716 			// we lose the convertion of boolean...
717 			// we may want to reconsider this optimization!
718 			NodePtr expr = child.GetChild(0);
719 			child.DeleteChild(0);
720 			logical_not.ReplaceWith(expr);
721 		}
722 		// We assume that the expression was already
723 		// compiled and thus identifiers which were
724 		// constants have been replaced already.
725 		return;
726 	}
727 
728 // we don't need our child anymore
729 	logical_not.DeleteChild(0);
730 }
731 
732 
Decrement(NodePtr & decrement)733 void IntOptimizer::Decrement(NodePtr& decrement)
734 {
735 	if(decrement.GetChildCount() != 1) {
736 		return;
737 	}
738 	Data& result = decrement.GetData();
739 
740 	NodePtr child = decrement.GetChild(0);
741 	Data data = child.GetData();
742 	if(data.ToNumber()) {
743 		if(data.f_type == NODE_INT64) {
744 			result.f_int.Set(data.f_int.Get() - 1);
745 		}
746 		else {
747 			result.f_float.Set(data.f_float.Get() - 1.0);
748 		}
749 	}
750 	else {
751 		// We assume that the expression was already
752 		// compiled and thus identifiers which were
753 		// constants have been replaced already.
754 		return;
755 	}
756 
757 	result.f_type = data.f_type;
758 
759 // we don't need our child anymore
760 	decrement.DeleteChild(0);
761 }
762 
763 
Increment(NodePtr & increment)764 void IntOptimizer::Increment(NodePtr& increment)
765 {
766 	if(increment.GetChildCount() != 1) {
767 		return;
768 	}
769 	Data& result = increment.GetData();
770 
771 	NodePtr child = increment.GetChild(0);
772 	Data data = child.GetData();
773 	if(data.ToNumber()) {
774 		if(data.f_type == NODE_INT64) {
775 			result.f_int.Set(data.f_int.Get() + 1);
776 		}
777 		else {
778 			result.f_float.Set(data.f_float.Get() + 1.0);
779 		}
780 	}
781 	else {
782 		// We assume that the expression was already
783 		// compiled and thus identifiers which were
784 		// constants have been replaced already.
785 		return;
786 	}
787 
788 	result.f_type = data.f_type;
789 
790 // we don't need our child anymore
791 	increment.DeleteChild(0);
792 }
793 
794 
Power(NodePtr & power)795 void IntOptimizer::Power(NodePtr& power)
796 {
797 	if(power.GetChildCount() != 2) {
798 		return;
799 	}
800 
801 	// in case we reduce, we may use this
802 	Data& power_data = power.GetData();
803 
804 	NodePtr lchild = power.GetChild(0);
805 	Data left = lchild.GetData();
806 
807 	NodePtr rchild = power.GetChild(1);
808 	Data right = rchild.GetData();
809 
810 	if(!right.ToNumber()) {
811 		// Reduce the following
812 		//	0 ** b = 0 (we can't garantee that b <> 0, we can't do it)
813 		//	1 ** b = 1
814 		if(!left.ToNumber()) {
815 			return;
816 		}
817 		if(left.f_type == NODE_INT64) {
818 			if(left.f_int.Get() == 1) {
819 				if(rchild.HasSideEffects()) {
820 					power.DeleteChild(0);
821 					power.DeleteChild(1);
822 					power.AddChild(rchild);
823 					power.AddChild(lchild);
824 					power_data.f_type = NODE_LIST;
825 				}
826 				else {
827 					power.DeleteChild(0);
828 					power.ReplaceWith(lchild);
829 				}
830 				return;
831 			}
832 		}
833 		else {
834 			if(left.f_float.Get() == 1.0) {
835 				if(rchild.HasSideEffects()) {
836 					power.DeleteChild(0);
837 					power.DeleteChild(1);
838 					power.AddChild(rchild);
839 					power.AddChild(lchild);
840 					power_data.f_type = NODE_LIST;
841 				}
842 				else {
843 					power.DeleteChild(0);
844 					power.ReplaceWith(lchild);
845 				}
846 				return;
847 			}
848 		}
849 		return;
850 	}
851 
852 	//
853 	// Reduce the following if possible
854 	//	a ** 0 = 1
855 	//	a ** 1 = a
856 	//	a ** 2 = a * a (we don't do this one because 'a' can be a
857 	//			complex expression which we don't want
858 	//			to duplicate)
859 	//
860 	if(right.f_type == NODE_INT64) {
861 		if(right.f_int.Get() == 0) {
862 			Data& right = rchild.GetData();
863 			right.f_int.Set(1LL);
864 			// the result is always 1
865 			if(lchild.HasSideEffects()) {
866 				power_data.f_type = NODE_LIST;
867 				return;
868 			}
869 			power.DeleteChild(1);
870 			power.ReplaceWith(rchild);
871 			return;
872 		}
873 		else if(right.f_int.Get() == 1) {
874 			power.DeleteChild(0);
875 			power.ReplaceWith(lchild);
876 			return;
877 		}
878 	}
879 	else {
880 		if(right.f_float.Get() == 0.0) {
881 			Data& right = rchild.GetData();
882 			right.f_float.Set(1.0);
883 			// the result is always 1
884 			if(lchild.HasSideEffects()) {
885 				power_data.f_type = NODE_LIST;
886 				return;
887 			}
888 			power.DeleteChild(1);
889 			power.ReplaceWith(rchild);
890 			return;
891 		}
892 		else if(right.f_float.Get() == 1.0) {
893 			power.DeleteChild(0);
894 			power.ReplaceWith(lchild);
895 			return;
896 		}
897 	}
898 
899 	if(!left.ToNumber()) {
900 		return;
901 	}
902 
903 	Data& result = power.GetData();
904 
905 	if(left.f_type == NODE_INT64) {
906 		if(right.f_type == NODE_INT64) {
907 			result.f_type = NODE_INT64;
908 			result.f_int.Set((int64_t) pow((double) left.f_int.Get(), (double) right.f_int.Get()));
909 		}
910 		else {
911 			result.f_type = NODE_FLOAT64;
912 			result.f_float.Set(pow((double) left.f_int.Get(), right.f_float.Get()));
913 		}
914 	}
915 	else {
916 		result.f_type = NODE_FLOAT64;
917 		if(right.f_type == NODE_INT64) {
918 			result.f_float.Set(pow(left.f_float.Get(), (double) right.f_int.Get()));
919 		}
920 		else {
921 			result.f_float.Set(pow(left.f_float.Get(), right.f_float.Get()));
922 		}
923 	}
924 
925 // we don't need any of these children anymore
926 	power.DeleteChild(1);
927 	power.DeleteChild(0);
928 }
929 
930 
931 
Multiply(NodePtr & multiply)932 void IntOptimizer::Multiply(NodePtr& multiply)
933 {
934 	int64_t		itotal;
935 	double		ftotal;
936 	node_t		type;
937 	int		idx, max;
938 	bool		constant;
939 	NodePtr		zero;
940 
941 	// Reduce
942 	//	a * 0 = 0
943 	//	a * 1 = a
944 
945 	// NOTE: we should also be able to optimize -1 to a simple
946 	//	 negate; this is not very useful for Flash though
947 	//	 since it doesn't even have a negate (we need to
948 	//	 use 0 - expr anyway)
949 
950 	constant = true;
951 	max = multiply.GetChildCount();
952 	for(idx = 0; idx < max && max > 1; ++idx) {
953 		NodePtr& child = multiply.GetChild(idx);
954 		Data data = child.GetData();
955 		if(data.ToNumber()) {
956 			if(data.f_type == NODE_INT64) {
957 				if(data.f_int.Get() == 0) {
958 					// anything else won't matter
959 					// (except function calls with
960 					// side effects)
961 					if(!zero.HasNode()) {
962 						zero = child;
963 					}
964 				}
965 				else if(data.f_int.Get() == 1) {
966 					// ignore this child
967 					multiply.DeleteChild(idx);
968 					--idx;
969 					--max;
970 				}
971 			}
972 			else {
973 				if(data.f_float.Get() == 0.0) {
974 					// anything else won't matter
975 					// (except function calls with
976 					// side effects)
977 					zero = child;
978 				}
979 				else if(data.f_float.Get() == 1.0) {
980 					// ignore this child
981 					multiply.DeleteChild(idx);
982 					--idx;
983 					--max;
984 				}
985 			}
986 		}
987 		else {
988 			constant = false;
989 		}
990 	}
991 
992 	if(zero.HasNode() && max > 1) {
993 		max = multiply.GetChildCount();
994 		for(idx = 0; idx < max; ++idx) {
995 			NodePtr& child = multiply.GetChild(idx);
996 			if(!child.HasSideEffects()
997 			&& !child.SameAs(zero)) {
998 				multiply.DeleteChild(idx);
999 				--idx;
1000 				--max;
1001 			}
1002 		}
1003 	}
1004 
1005 	if(max == 1) {
1006 		// Ha! We deleted many 1's or everything but one
1007 		// zero; remove the multiplication and just leave
1008 		// the other member or the zero
1009 		NodePtr expr = multiply.GetChild(0);
1010 		multiply.DeleteChild(0);
1011 		multiply.ReplaceWith(expr);
1012 		return;
1013 	}
1014 
1015 	if(!constant) {
1016 		return;
1017 	}
1018 
1019 	type = NODE_INT64;
1020 	itotal = 1;
1021 	ftotal = 1.0;
1022 	for(idx = 0; idx < max; ++idx) {
1023 		NodePtr child = multiply.GetChild(idx);
1024 		Data data = child.GetData();
1025 		if(data.ToNumber()) {
1026 			if(data.f_type == NODE_INT64) {
1027 				if(type == NODE_FLOAT64) {
1028 					ftotal *= data.f_int.Get();
1029 				}
1030 				else {
1031 					itotal *= data.f_int.Get();
1032 				}
1033 			}
1034 			else {
1035 				if(type == NODE_INT64) {
1036 					type = NODE_FLOAT64;
1037 					ftotal = itotal * data.f_float.Get();
1038 				}
1039 				else {
1040 					ftotal *= data.f_float.Get();
1041 				}
1042 			}
1043 		}
1044 		else {
1045 			// we should not come here!
1046 			AS_ASSERT(0);
1047 			// We assume that the expression was already
1048 			// compiled and thus identifiers which were
1049 			// constants have been replaced already.
1050 			return;
1051 		}
1052 	}
1053 
1054 // if we reach here, we can change the node type
1055 // to NODE_INT64 or NODE_FLOAT64
1056 	Data& data = multiply.GetData();
1057 	data.f_type = type;
1058 	if(type == NODE_INT64) {
1059 		data.f_int.Set(itotal);
1060 	}
1061 	else {
1062 		data.f_float.Set(ftotal);
1063 	}
1064 
1065 // we don't need any of these children anymore
1066 	while(max > 0) {
1067 		--max;
1068 		multiply.DeleteChild(max);
1069 	}
1070 }
1071 
1072 
Divide(NodePtr & divide)1073 void IntOptimizer::Divide(NodePtr& divide)
1074 {
1075 	int64_t		itotal, idiv;
1076 	double		ftotal, fdiv;
1077 	node_t		type;
1078 	int		idx, max;
1079 	bool		div0, constant;
1080 
1081 	// Reduce
1082 	//	a / 1 = a
1083 	// Error
1084 	//	a / 0
1085 
1086 	type = NODE_UNKNOWN;
1087 	itotal = 0;
1088 	ftotal = 0.0;
1089 	constant = true;
1090 	max = divide.GetChildCount();
1091 	for(idx = 0; idx < max; ++idx) {
1092 		div0 = false;
1093 		NodePtr& child = divide.GetChild(idx);
1094 		Data data = child.GetData();
1095 		if(data.ToNumber()) {
1096 			if(data.f_type == NODE_INT64) {
1097 				idiv = data.f_int.Get();
1098 				if(idx > 0 && idiv == 1) {
1099 					divide.DeleteChild(idx);
1100 					--idx;
1101 					--max;
1102 				}
1103 				else if(type == NODE_UNKNOWN) {
1104 					type = NODE_INT64;
1105 					itotal = idiv;
1106 				}
1107 				else {
1108 					div0 = idiv == 0;
1109 					if(!div0) {
1110 						if(type == NODE_FLOAT64) {
1111 							ftotal /= idiv;
1112 						}
1113 						else {
1114 							itotal /= idiv;
1115 						}
1116 					}
1117 				}
1118 			}
1119 			else {
1120 				fdiv = data.f_float.Get();
1121 				if(idx > 0 && fdiv == 1.0) {
1122 					divide.DeleteChild(idx);
1123 					--idx;
1124 					--max;
1125 				}
1126 				else if(type == NODE_UNKNOWN) {
1127 					type = NODE_FLOAT64;
1128 					ftotal = fdiv;
1129 				}
1130 				else {
1131 					div0 = fdiv == 0.0;
1132 					if(!div0) {
1133 						if(type == NODE_INT64) {
1134 							type = NODE_FLOAT64;
1135 							ftotal = itotal / fdiv;
1136 						}
1137 						else {
1138 							ftotal /= fdiv;
1139 						}
1140 					}
1141 				}
1142 			}
1143 		}
1144 		else {
1145 			// We assume that the expression was already
1146 			// compiled and thus identifiers which were
1147 			// constants have been replaced already.
1148 			constant = false;
1149 		}
1150 		if(div0) {
1151 			f_error_stream->ErrMsg(AS_ERR_DIVIDE_BY_ZERO, divide, "dividing by zero is illegal");
1152 			f_errcnt++;
1153 		}
1154 	}
1155 
1156 	if(max == 1) {
1157 		NodePtr expr = divide.GetChild(0);
1158 		divide.DeleteChild(0);
1159 		divide.ReplaceWith(expr);
1160 		return;
1161 	}
1162 
1163 	if(!constant) {
1164 		return;
1165 	}
1166 
1167 // if we reach here, we can change the node type
1168 // to NODE_INT64 or NODE_FLOAT64
1169 	Data& data = divide.GetData();
1170 	data.f_type = type;
1171 	if(type == NODE_INT64) {
1172 		data.f_int.Set(itotal);
1173 	}
1174 	else {
1175 		data.f_float.Set(ftotal);
1176 	}
1177 
1178 // we don't need any of these children anymore
1179 	while(max > 0) {
1180 		--max;
1181 		divide.DeleteChild(max);
1182 	}
1183 }
1184 
1185 
Modulo(NodePtr & modulo)1186 void IntOptimizer::Modulo(NodePtr& modulo)
1187 {
1188 	int64_t		itotal, idiv;
1189 	double		ftotal, fdiv;
1190 	node_t		type;
1191 	int		idx, max;
1192 	bool		div0, constant;
1193 
1194 	// Error
1195 	//	a % 0
1196 
1197 	type = NODE_UNKNOWN;
1198 	itotal = 0;
1199 	ftotal = 0.0;
1200 	constant = true;
1201 	max = modulo.GetChildCount();
1202 	for(idx = 0; idx < max; ++idx) {
1203 		div0 = false;
1204 		NodePtr& child = modulo.GetChild(idx);
1205 		Data data = child.GetData();
1206 		if(data.ToNumber()) {
1207 			if(data.f_type == NODE_INT64) {
1208 				idiv = data.f_int.Get();
1209 				if(type == NODE_UNKNOWN) {
1210 					type = NODE_INT64;
1211 					itotal = idiv;
1212 				}
1213 				else {
1214 					div0 = idiv == 0;
1215 					if(!div0) {
1216 						if(type == NODE_FLOAT64) {
1217 							ftotal = fmod(ftotal, idiv);
1218 						}
1219 						else {
1220 							itotal %= idiv;
1221 						}
1222 					}
1223 				}
1224 			}
1225 			else {
1226 				fdiv = data.f_float.Get();
1227 				if(type == NODE_UNKNOWN) {
1228 					type = NODE_FLOAT64;
1229 					ftotal = fdiv;
1230 				}
1231 				else {
1232 					div0 = fdiv != 0;
1233 					if(!div0) {
1234 						if(type == NODE_INT64) {
1235 							type = NODE_FLOAT64;
1236 							ftotal = fmod(itotal, fdiv);
1237 						}
1238 						else {
1239 							ftotal = fmod(ftotal, fdiv);
1240 						}
1241 					}
1242 				}
1243 			}
1244 		}
1245 		else {
1246 			// We assume that the expression was already
1247 			// compiled and thus identifiers which were
1248 			// constants have been replaced already.
1249 			constant = false;
1250 		}
1251 		if(div0) {
1252 			f_error_stream->ErrMsg(AS_ERR_DIVIDE_BY_ZERO, modulo, "dividing by zero is illegal");
1253 			f_errcnt++;
1254 		}
1255 	}
1256 
1257 	if(!constant) {
1258 		return;
1259 	}
1260 
1261 // if we reach here, we can change the node type
1262 // to NODE_INT64 or NODE_FLOAT64
1263 	Data& data = modulo.GetData();
1264 	data.f_type = type;
1265 	if(type == NODE_INT64) {
1266 		data.f_int.Set(itotal);
1267 	}
1268 	else {
1269 		data.f_float.Set(ftotal);
1270 	}
1271 
1272 // we don't need any of these children anymore
1273 	while(max > 0) {
1274 		--max;
1275 		modulo.DeleteChild(max);
1276 	}
1277 }
1278 
1279 
Add(NodePtr & add)1280 void IntOptimizer::Add(NodePtr& add)
1281 {
1282 	int64_t		itotal;
1283 	double		ftotal;
1284 	node_t		type;
1285 	int		idx, max;
1286 	bool		constant;
1287 
1288 	// Reduce:
1289 	//	a + 0 = a
1290 	//	0 + a = a
1291 
1292 	constant = true;
1293 	type = NODE_INT64;
1294 	itotal = 0;
1295 	ftotal = 0.0;
1296 	max = add.GetChildCount();
1297 	for(idx = 0; idx < max; ++idx) {
1298 		NodePtr child = add.GetChild(idx);
1299 		Data data = child.GetData();
1300 		if(data.ToNumber()) {
1301 			if(data.f_type == NODE_INT64) {
1302 				if(data.f_int.Get() == 0) {
1303 					add.DeleteChild(idx);
1304 					--idx;
1305 					--max;
1306 				}
1307 				else if(type == NODE_FLOAT64) {
1308 					ftotal += data.f_int.Get();
1309 				}
1310 				else {
1311 					itotal += data.f_int.Get();
1312 				}
1313 			}
1314 			else {
1315 				// special case where we still want
1316 				// to force the value to a floating
1317 				// point value! (1 + 0.0 -> 1.0)
1318 				if(type == NODE_INT64) {
1319 					type = NODE_FLOAT64;
1320 					ftotal = itotal + data.f_float.Get();
1321 				}
1322 				else {
1323 					ftotal += data.f_float.Get();
1324 				}
1325 				if(data.f_float.Get() == 0.0) {
1326 					add.DeleteChild(idx);
1327 					--idx;
1328 					--max;
1329 				}
1330 			}
1331 		}
1332 		else {
1333 			// We assume that the expression was already
1334 			// compiled and thus identifiers which were
1335 			// constants have been replaced already.
1336 			constant = false;
1337 		}
1338 	}
1339 
1340 	// max is 1 when the user used positive or added zero
1341 	if(max == 1) {
1342 		NodePtr expr = add.GetChild(0);
1343 		add.DeleteChild(0);
1344 		add.ReplaceWith(expr);
1345 		return;
1346 	}
1347 
1348 	if(!constant) {
1349 		return;
1350 	}
1351 
1352 // if we reach here, we can change the node type
1353 // to NODE_INT64 or NODE_FLOAT64
1354 	Data& data = add.GetData();
1355 	data.f_type = type;
1356 	if(type == NODE_INT64) {
1357 		data.f_int.Set(itotal);
1358 	}
1359 	else {
1360 		data.f_float.Set(ftotal);
1361 	}
1362 
1363 // we don't need any of these children anymore
1364 	while(max > 0) {
1365 		--max;
1366 		add.DeleteChild(max);
1367 	}
1368 }
1369 
1370 
Subtract(NodePtr & subtract)1371 void IntOptimizer::Subtract(NodePtr& subtract)
1372 {
1373 	int64_t		itotal;
1374 	double		ftotal;
1375 	node_t		type;
1376 	int		idx, max, start_max;
1377 	bool		constant;
1378 
1379 	// Reduce:
1380 	//	a - 0 = a
1381 
1382 	type = NODE_UNKNOWN;
1383 	itotal = 0;
1384 	ftotal = 0.0;
1385 	constant = true;
1386 	start_max = max = subtract.GetChildCount();
1387 	for(idx = 0; idx < max; ++idx) {
1388 		NodePtr& child = subtract.GetChild(idx);
1389 		Data data = child.GetData();
1390 		if(data.ToNumber()) {
1391 			if(data.f_type == NODE_INT64) {
1392 				if(idx != 0 && data.f_int.Get() == 0) {
1393 					subtract.DeleteChild(idx);
1394 					--idx;
1395 					--max;
1396 				}
1397 				else if(type == NODE_UNKNOWN) {
1398 					type = NODE_INT64;
1399 					itotal = data.f_int.Get();
1400 				}
1401 				else if(type == NODE_FLOAT64) {
1402 					ftotal -= data.f_int.Get();
1403 				}
1404 				else {
1405 					itotal -= data.f_int.Get();
1406 				}
1407 			}
1408 			else {
1409 				if(idx != 0 && data.f_int.Get() == 0) {
1410 					subtract.DeleteChild(idx);
1411 					--idx;
1412 					--max;
1413 				}
1414 				else if(type == NODE_UNKNOWN) {
1415 					type = NODE_FLOAT64;
1416 					ftotal = data.f_float.Get();
1417 				}
1418 				else if(type == NODE_INT64) {
1419 					type = NODE_FLOAT64;
1420 					ftotal = itotal - data.f_float.Get();
1421 				}
1422 				else {
1423 					ftotal -= data.f_float.Get();
1424 				}
1425 			}
1426 		}
1427 		else {
1428 			// We assume that the expression was already
1429 			// compiled and thus identifiers which were
1430 			// constants have been replaced already.
1431 			constant = false;
1432 		}
1433 	}
1434 
1435 // cancellation of the operation? (i.e. a - 0)
1436 	if(start_max > 1 && max == 1) {
1437 		NodePtr expr = subtract.GetChild(0);
1438 		subtract.DeleteChild(0);
1439 		subtract.ReplaceWith(expr);
1440 		return;
1441 	}
1442 
1443 	if(!constant) {
1444 		return;
1445 	}
1446 
1447 // subtraction or negation?
1448 	if(max == 1) {
1449 		if(type == NODE_INT64) {
1450 			itotal = -itotal;
1451 		}
1452 		else {
1453 			ftotal = -ftotal;
1454 		}
1455 	}
1456 
1457 // if we reach here, we can change the node type
1458 // to NODE_INT64 or NODE_FLOAT64
1459 	Data& data = subtract.GetData();
1460 	data.f_type = type;
1461 	if(type == NODE_INT64) {
1462 		data.f_int.Set(itotal);
1463 	}
1464 	else {
1465 		data.f_float.Set(ftotal);
1466 	}
1467 
1468 // we don't need any of these children anymore
1469 	while(max > 0) {
1470 		--max;
1471 		subtract.DeleteChild(max);
1472 	}
1473 }
1474 
1475 
1476 
ShiftLeft(NodePtr & shift_left)1477 void IntOptimizer::ShiftLeft(NodePtr& shift_left)
1478 {
1479 	int64_t		itotal;
1480 	node_t		type;
1481 	int		idx, max;
1482 
1483 	type = NODE_UNKNOWN;
1484 	itotal = 0;
1485 	max = shift_left.GetChildCount();
1486 	for(idx = 0; idx < max; ++idx) {
1487 		NodePtr child = shift_left.GetChild(idx);
1488 		Data data = child.GetData();
1489 		if(data.ToNumber()) {
1490 			if(data.f_type == NODE_INT64) {
1491 				if(type == NODE_UNKNOWN) {
1492 					itotal = data.f_int.Get();
1493 				}
1494 				else {
1495 					itotal <<= data.f_int.Get() & 0x3F;
1496 				}
1497 				type = NODE_INT64;
1498 			}
1499 			else {
1500 				if(type == NODE_UNKNOWN) {
1501 					itotal = (int32_t) data.f_float.Get();
1502 				}
1503 				else {
1504 					itotal <<= (int32_t) data.f_float.Get() & 0x1F;
1505 				}
1506 				type = NODE_FLOAT64;
1507 			}
1508 		}
1509 		else {
1510 			// We assume that the expression was already
1511 			// compiled and thus identifiers which were
1512 			// constants have been replaced already.
1513 			return;
1514 		}
1515 	}
1516 
1517 // if we reach here, we can change the node type
1518 // to NODE_INT64 or NODE_FLOAT64
1519 	Data& data = shift_left.GetData();
1520 	data.f_type = type;
1521 	if(type == NODE_INT64) {
1522 		data.f_int.Set(itotal);
1523 	}
1524 	else {
1525 		data.f_float.Set(itotal);
1526 	}
1527 
1528 // we don't need any of these children anymore
1529 	while(max > 0) {
1530 		--max;
1531 		shift_left.DeleteChild(max);
1532 	}
1533 }
1534 
1535 
ShiftRight(NodePtr & shift_right)1536 void IntOptimizer::ShiftRight(NodePtr& shift_right)
1537 {
1538 	int64_t		itotal;
1539 	node_t		type;
1540 	int		idx, max;
1541 
1542 	type = NODE_UNKNOWN;
1543 	itotal = 0;
1544 	max = shift_right.GetChildCount();
1545 	for(idx = 0; idx < max; ++idx) {
1546 		NodePtr child = shift_right.GetChild(idx);
1547 		Data data = child.GetData();
1548 		if(data.ToNumber()) {
1549 			if(data.f_type == NODE_INT64) {
1550 				if(type == NODE_UNKNOWN) {
1551 					itotal = data.f_int.Get();
1552 				}
1553 				else {
1554 					itotal >>= data.f_int.Get() & 0x3F;
1555 				}
1556 				type = NODE_INT64;
1557 			}
1558 			else {
1559 				if(type == NODE_UNKNOWN) {
1560 					itotal = (int32_t) data.f_float.Get();
1561 				}
1562 				else {
1563 					itotal >>= (int32_t) data.f_float.Get() & 0x1F;
1564 				}
1565 				type = NODE_FLOAT64;
1566 			}
1567 		}
1568 		else {
1569 			// We assume that the expression was already
1570 			// compiled and thus identifiers which were
1571 			// constants have been replaced already.
1572 			return;
1573 		}
1574 	}
1575 
1576 // if we reach here, we can change the node type
1577 // to NODE_INT64 or NODE_FLOAT64
1578 	Data& data = shift_right.GetData();
1579 	data.f_type = type;
1580 	if(type == NODE_INT64) {
1581 		data.f_int.Set(itotal);
1582 	}
1583 	else {
1584 		data.f_float.Set(itotal);
1585 	}
1586 
1587 // we don't need any of these children anymore
1588 	while(max > 0) {
1589 		--max;
1590 		shift_right.DeleteChild(max);
1591 	}
1592 }
1593 
1594 
1595 
ShiftRightUnsigned(NodePtr & shift_right_unsigned)1596 void IntOptimizer::ShiftRightUnsigned(NodePtr& shift_right_unsigned)
1597 {
1598 	uint64_t	itotal;
1599 	node_t		type;
1600 	int		idx, max;
1601 
1602 	type = NODE_UNKNOWN;
1603 	itotal = 0;
1604 	max = shift_right_unsigned.GetChildCount();
1605 	for(idx = 0; idx < max; ++idx) {
1606 		NodePtr child = shift_right_unsigned.GetChild(idx);
1607 		Data data = child.GetData();
1608 		if(data.ToNumber()) {
1609 			if(data.f_type == NODE_INT64) {
1610 				if(type == NODE_UNKNOWN) {
1611 					itotal = data.f_int.Get();
1612 				}
1613 				else {
1614 					itotal >>= data.f_int.Get() & 0x3F;
1615 				}
1616 				type = NODE_INT64;
1617 			}
1618 			else {
1619 				if(type == NODE_UNKNOWN) {
1620 					itotal = (int32_t) data.f_float.Get();
1621 				}
1622 				else {
1623 					itotal >>= (int32_t) data.f_float.Get() & 0x1F;
1624 				}
1625 				type = NODE_FLOAT64;
1626 			}
1627 		}
1628 		else {
1629 			// We assume that the expression was already
1630 			// compiled and thus identifiers which were
1631 			// constants have been replaced already.
1632 			return;
1633 		}
1634 	}
1635 
1636 // if we reach here, we can change the node type
1637 // to NODE_INT64 or NODE_FLOAT64
1638 	Data& data = shift_right_unsigned.GetData();
1639 	data.f_type = type;
1640 	if(type == NODE_INT64) {
1641 		data.f_int.Set(itotal);
1642 	}
1643 	else {
1644 		data.f_float.Set(itotal);
1645 	}
1646 
1647 // we don't need any of these children anymore
1648 	while(max > 0) {
1649 		--max;
1650 		shift_right_unsigned.DeleteChild(max);
1651 	}
1652 }
1653 
1654 
RotateLeft(NodePtr & rotate_left)1655 void IntOptimizer::RotateLeft(NodePtr& rotate_left)
1656 {
1657 	uint64_t	itotal;
1658 	node_t		type;
1659 	int		idx, max, count;
1660 
1661 	type = NODE_UNKNOWN;
1662 	itotal = 0;
1663 	max = rotate_left.GetChildCount();
1664 	for(idx = 0; idx < max; ++idx) {
1665 		NodePtr child = rotate_left.GetChild(idx);
1666 		Data data = child.GetData();
1667 		if(data.ToNumber()) {
1668 			if(data.f_type == NODE_INT64) {
1669 				if(type == NODE_UNKNOWN) {
1670 					itotal = data.f_int.Get();
1671 				}
1672 				else {
1673 					count = data.f_int.Get() & 0x3F;
1674 					if(count != 0) {
1675 						itotal = (itotal << count) | (itotal >> (64 - count));
1676 					}
1677 				}
1678 				type = NODE_INT64;
1679 			}
1680 			else {
1681 				if(type == NODE_UNKNOWN) {
1682 					itotal = (int32_t) data.f_float.Get();
1683 				}
1684 				else {
1685 					count = (int32_t) data.f_float.Get() & 0x1F;
1686 					if(count != 0) {
1687 						itotal = ((itotal << count) | (itotal >> (64 - count)));
1688 					}
1689 				}
1690 				type = NODE_FLOAT64;
1691 			}
1692 		}
1693 		else {
1694 			// We assume that the expression was already
1695 			// compiled and thus identifiers which were
1696 			// constants have been replaced already.
1697 			return;
1698 		}
1699 	}
1700 
1701 // if we reach here, we can change the node type
1702 // to NODE_INT64 or NODE_FLOAT64
1703 	Data& data = rotate_left.GetData();
1704 	data.f_type = type;
1705 	if(type == NODE_INT64) {
1706 		data.f_int.Set(itotal);
1707 	}
1708 	else {
1709 		data.f_float.Set(itotal);
1710 	}
1711 
1712 // we don't need any of these children anymore
1713 	while(max > 0) {
1714 		--max;
1715 		rotate_left.DeleteChild(max);
1716 	}
1717 }
1718 
1719 
1720 
RotateRight(NodePtr & rotate_right)1721 void IntOptimizer::RotateRight(NodePtr& rotate_right)
1722 {
1723 	uint64_t	itotal;
1724 	node_t		type;
1725 	int		idx, max, count;
1726 
1727 	type = NODE_UNKNOWN;
1728 	itotal = 0;
1729 	max = rotate_right.GetChildCount();
1730 	for(idx = 0; idx < max; ++idx) {
1731 		NodePtr child = rotate_right.GetChild(idx);
1732 		Data data = child.GetData();
1733 		if(data.ToNumber()) {
1734 			if(data.f_type == NODE_INT64) {
1735 				if(type == NODE_UNKNOWN) {
1736 					itotal = data.f_int.Get();
1737 				}
1738 				else {
1739 					count = data.f_int.Get() & 0x3F;
1740 					if(count != 0) {
1741 						itotal = (itotal >> count) | (itotal << (64 - count));
1742 					}
1743 				}
1744 				type = NODE_INT64;
1745 			}
1746 			else {
1747 				if(type == NODE_UNKNOWN) {
1748 					itotal = (int32_t) data.f_float.Get();
1749 				}
1750 				else {
1751 					count = (int32_t) data.f_float.Get() & 0x1F;
1752 					if(count != 0) {
1753 						itotal = ((itotal >> count) | (itotal << (64 - count)));
1754 					}
1755 				}
1756 				type = NODE_FLOAT64;
1757 			}
1758 		}
1759 		else {
1760 			// We assume that the expression was already
1761 			// compiled and thus identifiers which were
1762 			// constants have been replaced already.
1763 			return;
1764 		}
1765 	}
1766 
1767 // if we reach here, we can change the node type
1768 // to NODE_INT64 or NODE_FLOAT64
1769 	Data& data = rotate_right.GetData();
1770 	data.f_type = type;
1771 	if(type == NODE_INT64) {
1772 		data.f_int.Set(itotal);
1773 	}
1774 	else {
1775 		data.f_float.Set(itotal);
1776 	}
1777 
1778 // we don't need any of these children anymore
1779 	while(max > 0) {
1780 		--max;
1781 		rotate_right.DeleteChild(max);
1782 	}
1783 }
1784 
1785 
1786 
1787 // returns:
1788 //	 0 - equal
1789 //	-1 - left < right
1790 //	 1 - left > right
1791 //	 2 - unordered (left or right is a NaN)
1792 //	-2 - error (can't compare)
Compare(NodePtr & relational)1793 int IntOptimizer::Compare(NodePtr& relational)
1794 {
1795 	if(relational.GetChildCount() != 2) {
1796 		return -2;
1797 	}
1798 
1799 	NodePtr child = relational.GetChild(0);
1800 	Data left = child.GetData();
1801 
1802 	child = relational.GetChild(1);
1803 	Data right = child.GetData();
1804 
1805 	if(left.f_type == NODE_STRING
1806 	&& right.f_type == NODE_STRING) {
1807 		return left.f_str.Compare(right.f_str);
1808 	}
1809 
1810 	if(!left.ToNumber()) {
1811 		return -2;
1812 	}
1813 	if(!right.ToNumber()) {
1814 		return -2;
1815 	}
1816 
1817 	if(left.f_type == NODE_INT64) {
1818 		if(right.f_type == NODE_INT64) {
1819 			int64_t r = left.f_int.Get() - right.f_int.Get();
1820 			if(r == 0) {
1821 				return 0;
1822 			}
1823 			return r < 0 ? -1 : 1;
1824 		}
1825 		else {
1826 			if(isnan(right.f_float.Get())) {
1827 				return 2;
1828 			}
1829 			int inf = isinf(right.f_float.Get());
1830 			if(inf != 0) {
1831 				return -inf;
1832 			}
1833 			double r = left.f_int.Get() - right.f_float.Get();
1834 			if(r == 0.0) {
1835 				return 0;
1836 			}
1837 			return r < 0.0 ? -1 : 1;
1838 		}
1839 	}
1840 	else {
1841 		if(isnan(left.f_float.Get())) {
1842 			return 2;
1843 		}
1844 		if(right.f_type == NODE_INT64) {
1845 			int inf = isinf(left.f_float.Get());
1846 			if(inf != 0) {
1847 				return inf;
1848 			}
1849 			double r = left.f_float.Get() - right.f_int.Get();
1850 			if(r == 0.0) {
1851 				return 0;
1852 			}
1853 			return r < 0.0 ? -1 : 1;
1854 		}
1855 		else {
1856 			if(isnan(right.f_float.Get())) {
1857 				return 2;
1858 			}
1859 			int linf = isinf(left.f_float.Get());
1860 			int rinf = isinf(right.f_float.Get());
1861 			if(linf != 0 || rinf != 0) {
1862 				if(linf == rinf) {
1863 					return 0;
1864 				}
1865 				return linf < rinf ? -1 : 1;
1866 			}
1867 			double r = left.f_float.Get() - right.f_float.Get();
1868 			if(r == 0.0) {
1869 				return 0;
1870 			}
1871 			return r < 0.0 ? -1 : 1;
1872 		}
1873 	}
1874 }
1875 
1876 
1877 
Less(NodePtr & less)1878 void IntOptimizer::Less(NodePtr& less)
1879 {
1880 	long r = Compare(less);
1881 	if(r == -2) {
1882 		return;
1883 	}
1884 
1885 	if(r == 2) {
1886 		// ???
1887 		return;
1888 	}
1889 
1890 	Data& result = less.GetData();
1891 	result.f_type = r < 0 ? NODE_TRUE : NODE_FALSE;
1892 
1893 	less.DeleteChild(1);
1894 	less.DeleteChild(0);
1895 }
1896 
1897 
LessEqual(NodePtr & less_equal)1898 void IntOptimizer::LessEqual(NodePtr& less_equal)
1899 {
1900 	long r = Compare(less_equal);
1901 	if(r == -2) {
1902 		return;
1903 	}
1904 
1905 	if(r == 2) {
1906 		// ???
1907 		return;
1908 	}
1909 
1910 	Data& result = less_equal.GetData();
1911 	result.f_type = r <= 0 ? NODE_TRUE : NODE_FALSE;
1912 
1913 	less_equal.DeleteChild(1);
1914 	less_equal.DeleteChild(0);
1915 }
1916 
1917 
Greater(NodePtr & greater)1918 void IntOptimizer::Greater(NodePtr& greater)
1919 {
1920 	long r = Compare(greater);
1921 	if(r == -2) {
1922 		return;
1923 	}
1924 
1925 	if(r == 2) {
1926 		// ???
1927 		return;
1928 	}
1929 
1930 	Data& result = greater.GetData();
1931 	result.f_type = r > 0 ? NODE_TRUE : NODE_FALSE;
1932 
1933 	greater.DeleteChild(1);
1934 	greater.DeleteChild(0);
1935 }
1936 
1937 
GreaterEqual(NodePtr & greater_equal)1938 void IntOptimizer::GreaterEqual(NodePtr& greater_equal)
1939 {
1940 	long r = Compare(greater_equal);
1941 	if(r == -2) {
1942 		return;
1943 	}
1944 
1945 	if(r == 2) {
1946 		// ???
1947 		return;
1948 	}
1949 
1950 	Data& result = greater_equal.GetData();
1951 	result.f_type = r >= 0 ? NODE_TRUE : NODE_FALSE;
1952 
1953 	greater_equal.DeleteChild(1);
1954 	greater_equal.DeleteChild(0);
1955 }
1956 
1957 
Equality(NodePtr & equality,bool strict,bool logical_not)1958 void IntOptimizer::Equality(NodePtr& equality, bool strict, bool logical_not)
1959 {
1960 	if(equality.GetChildCount() != 2) {
1961 		return;
1962 	}
1963 
1964 	bool result = false;
1965 
1966 	NodePtr child = equality.GetChild(0);
1967 	Data left = child.GetData();
1968 
1969 	child = equality.GetChild(1);
1970 	Data right = child.GetData();
1971 
1972 	if(strict) {		// ===
1973 		if((left.f_type  == NODE_TRUE || left.f_type  == NODE_FALSE)
1974 		&& (right.f_type == NODE_TRUE || right.f_type == NODE_FALSE)) {
1975 			result = left.f_type == right.f_type;
1976 		}
1977 		else if(left.f_type == NODE_INT64 && right.f_type == NODE_INT64) {
1978 			result = left.f_int.Get() == right.f_int.Get();
1979 		}
1980 		else if(left.f_type == NODE_FLOAT64 && right.f_type == NODE_FLOAT64) {
1981 			result = left.f_float.Get() == right.f_float.Get();
1982 		}
1983 		else if(left.f_type == NODE_INT64 && right.f_type == NODE_FLOAT64) {
1984 			result = left.f_int.Get() == right.f_float.Get();
1985 		}
1986 		else if(left.f_type == NODE_FLOAT64 && right.f_type == NODE_INT64) {
1987 			result = left.f_float.Get() == right.f_int.Get();
1988 		}
1989 		else if(left.f_type == NODE_STRING && right.f_type == NODE_STRING) {
1990 			result = left.f_str == right.f_str;
1991 		}
1992 		else if((left.f_type == NODE_UNDEFINED && right.f_type == NODE_UNDEFINED)
1993 		     || (left.f_type == NODE_NULL && right.f_type == NODE_NULL)) {
1994 			result = true;
1995 		}
1996 		else if((left.f_type == NODE_NULL && right.f_type == NODE_UNDEFINED)
1997 		     || (left.f_type == NODE_UNDEFINED && right.f_type == NODE_NULL)) {
1998 			result = false;
1999 		}
2000 		else if((left.f_type  == NODE_IDENTIFIER || left.f_type  == NODE_VIDENTIFIER)
2001 		     && (right.f_type == NODE_IDENTIFIER || right.f_type == NODE_VIDENTIFIER)) {
2002 			// special case of  a === a
2003 			if(left.f_str != right.f_str) {
2004 				// If not the same, we can't know what the result
2005 				// is at compile time.
2006 				return;
2007 			}
2008 			result = true;
2009 		}
2010 		else {
2011 			switch(left.f_type) {
2012 			case NODE_INT64:
2013 			case NODE_FLOAT64:
2014 			case NODE_STRING:
2015 			case NODE_NULL:
2016 			case NODE_UNDEFINED:
2017 			case NODE_TRUE:
2018 			case NODE_FALSE:
2019 				break;
2020 
2021 			default:
2022 				// undefined at compile time
2023 				return;
2024 
2025 			}
2026 			switch(right.f_type) {
2027 			case NODE_INT64:
2028 			case NODE_FLOAT64:
2029 			case NODE_STRING:
2030 			case NODE_NULL:
2031 			case NODE_UNDEFINED:
2032 			case NODE_TRUE:
2033 			case NODE_FALSE:
2034 				break;
2035 
2036 			default:
2037 				// undefined at compile time
2038 				return;
2039 
2040 			}
2041 			// any one of these mix is always false in strict mode
2042 			result = false;
2043 		}
2044 	}
2045 	else {			// ==
2046 		switch(left.f_type) {
2047 		case NODE_UNDEFINED:
2048 		case NODE_NULL:
2049 			switch(right.f_type) {
2050 			case NODE_UNDEFINED:
2051 			case NODE_NULL:
2052 				result = true;
2053 				break;
2054 
2055 			case NODE_INT64:
2056 			case NODE_FLOAT64:
2057 			case NODE_STRING:
2058 			case NODE_TRUE:
2059 			case NODE_FALSE:
2060 				result = false;
2061 				break;
2062 
2063 			default:
2064 				// undefined at compile time
2065 				return;
2066 
2067 			}
2068 			break;
2069 
2070 		case NODE_TRUE:
2071 			switch(right.f_type) {
2072 			case NODE_TRUE:
2073 				result = true;
2074 				break;
2075 
2076 			case NODE_FALSE:
2077 			case NODE_STRING:
2078 			case NODE_NULL:
2079 			case NODE_UNDEFINED:
2080 				result = false;
2081 				break;
2082 
2083 			default:
2084 				if(!right.ToNumber()) {
2085 					// undefined at compile time
2086 					return;
2087 				}
2088 				if(right.f_type == NODE_INT64) {
2089 					result = right.f_int.Get() == 1;
2090 				}
2091 				else {
2092 					result = right.f_float.Get() == 1.0;
2093 				}
2094 				break;
2095 
2096 			}
2097 			break;
2098 
2099 		case NODE_FALSE:
2100 			switch(right.f_type) {
2101 			case NODE_TRUE:
2102 			case NODE_STRING:
2103 			case NODE_NULL:
2104 			case NODE_UNDEFINED:
2105 				result = false;
2106 				break;
2107 
2108 			case NODE_FALSE:
2109 				result = true;
2110 				break;
2111 
2112 			default:
2113 				if(!right.ToNumber()) {
2114 					// undefined at compile time
2115 					return;
2116 				}
2117 				if(right.f_type == NODE_INT64) {
2118 					result = right.f_int.Get() == 0;
2119 				}
2120 				else {
2121 					result = right.f_float.Get() == 0.0;
2122 				}
2123 				break;
2124 
2125 			}
2126 			break;
2127 
2128 		case NODE_INT64:
2129 			switch(right.f_type) {
2130 			case NODE_INT64:
2131 				result = left.f_int.Get() == right.f_int.Get();
2132 				break;
2133 
2134 			case NODE_FLOAT64:
2135 				result = left.f_int.Get() == right.f_float.Get();
2136 				break;
2137 
2138 			case NODE_TRUE:
2139 				result = left.f_int.Get() == 1;
2140 				break;
2141 
2142 			case NODE_FALSE:
2143 				result = left.f_int.Get() == 0;
2144 				break;
2145 
2146 			//case NODE_STRING: ...
2147 
2148 			case NODE_NULL:
2149 			case NODE_UNDEFINED:
2150 				result = false;
2151 				break;
2152 
2153 			default:
2154 				return;
2155 
2156 			}
2157 			break;
2158 
2159 		case NODE_FLOAT64:
2160 			switch(right.f_type) {
2161 			case NODE_FLOAT64:
2162 				result = left.f_float.Get() == right.f_float.Get();
2163 				break;
2164 
2165 			case NODE_INT64:
2166 				result = left.f_float.Get() == right.f_int.Get();
2167 				break;
2168 
2169 			case NODE_TRUE:
2170 				result = left.f_float.Get() == 1.0;
2171 				break;
2172 
2173 			case NODE_FALSE:
2174 				result = left.f_float.Get() == 0.0;
2175 				break;
2176 
2177 			//case NODE_STRING: ...
2178 
2179 			case NODE_NULL:
2180 			case NODE_UNDEFINED:
2181 				result = false;
2182 				break;
2183 
2184 			default:
2185 				return;
2186 
2187 			}
2188 			break;
2189 
2190 		case NODE_STRING:
2191 			switch(right.f_type) {
2192 			case NODE_STRING:
2193 				result = left.f_str == right.f_str;
2194 				break;
2195 
2196 			case NODE_NULL:
2197 			case NODE_UNDEFINED:
2198 				result = false;
2199 				break;
2200 
2201 			//case NODE_INT64: ...
2202 			//case NODE_FLOAT64: ...
2203 
2204 			default:
2205 				return;
2206 
2207 			}
2208 			break;
2209 
2210 		case NODE_IDENTIFIER:
2211 		case NODE_VIDENTIFIER:
2212 			if((right.f_type != NODE_IDENTIFIER && right.f_type != NODE_VIDENTIFIER)
2213 			|| left.f_str != right.f_str) {
2214 				return;
2215 			}
2216 			// special case of  a == a
2217 			result = true;
2218 			break;
2219 
2220 		default:
2221 			// undefined at compile time
2222 			return;
2223 
2224 		}
2225 	}
2226 
2227 // if we reach here, we can change the node type
2228 // to NODE_INT64 or NODE_FLOAT64
2229 	Data& data = equality.GetData();
2230 	data.f_type = result ^ logical_not ? NODE_TRUE : NODE_FALSE;
2231 
2232 // we don't need any of these children anymore
2233 	equality.DeleteChild(1);
2234 	equality.DeleteChild(0);
2235 }
2236 
2237 
2238 
BitwiseAnd(NodePtr & bitwise_and)2239 void IntOptimizer::BitwiseAnd(NodePtr& bitwise_and)
2240 {
2241 	int64_t		itotal;
2242 	double		ftotal;
2243 	node_t		type;
2244 	int		idx, max;
2245 	String		result;
2246 
2247 	type = NODE_INT64;
2248 	itotal = -1;
2249 	ftotal = -1.0;
2250 	max = bitwise_and.GetChildCount();
2251 	for(idx = 0; idx < max; ++idx) {
2252 		NodePtr child = bitwise_and.GetChild(idx);
2253 		Data data = child.GetData();
2254 		if(data.f_type == NODE_STRING || type == NODE_STRING) {
2255 			if(type != NODE_STRING && idx != 0) {
2256 				Data value;
2257 				value.f_type = type;
2258 				if(type == NODE_INT64) {
2259 					value.f_int.Set(itotal);
2260 				}
2261 				else {
2262 					value.f_float.Set(ftotal);
2263 				}
2264 				value.ToString();
2265 				result = value.f_str;
2266 			}
2267 			if(!data.ToString()) {
2268 				return;
2269 			}
2270 			type = NODE_STRING;
2271 			result += data.f_str;
2272 		}
2273 		else if(data.ToNumber()) {
2274 			if(data.f_type == NODE_INT64) {
2275 				if(type == NODE_INT64) {
2276 					itotal &= data.f_int.Get();
2277 				}
2278 				else {
2279 					ftotal = (int32_t) ftotal & (int32_t) data.f_int.Get();
2280 					type = NODE_FLOAT64;
2281 				}
2282 			}
2283 			else {
2284 				if(type == NODE_INT64) {
2285 					type = NODE_FLOAT64;
2286 					ftotal = (int32_t) itotal & (int32_t) data.f_float.Get();
2287 				}
2288 				else {
2289 					ftotal = (int32_t) ftotal & (int32_t) data.f_float.Get();
2290 				}
2291 			}
2292 		}
2293 		else {
2294 			// We assume that the expression was already
2295 			// compiled and thus identifiers which were
2296 			// constants have been replaced already.
2297 			return;
2298 		}
2299 	}
2300 
2301 // if we reach here, we can change the node type
2302 // to NODE_INT64 or NODE_FLOAT64
2303 	Data& data = bitwise_and.GetData();
2304 	data.f_type = type;
2305 	if(type == NODE_STRING) {
2306 		data.f_str = result;
2307 	}
2308 	else if(type == NODE_INT64) {
2309 		data.f_int.Set(itotal);
2310 	}
2311 	else {
2312 		data.f_float.Set(ftotal);
2313 	}
2314 
2315 // we don't need any of these children anymore
2316 	while(max > 0) {
2317 		--max;
2318 		bitwise_and.DeleteChild(max);
2319 	}
2320 }
2321 
2322 
2323 
BitwiseXOr(NodePtr & bitwise_xor)2324 void IntOptimizer::BitwiseXOr(NodePtr& bitwise_xor)
2325 {
2326 	int64_t		itotal;
2327 	double		ftotal;
2328 	node_t		type;
2329 	int		idx, max;
2330 
2331 	type = NODE_INT64;
2332 	itotal = 0;
2333 	ftotal = 0.0;
2334 	max = bitwise_xor.GetChildCount();
2335 	for(idx = 0; idx < max; ++idx) {
2336 		NodePtr child = bitwise_xor.GetChild(idx);
2337 		Data data = child.GetData();
2338 		if(data.ToNumber()) {
2339 			if(data.f_type == NODE_INT64) {
2340 				if(type == NODE_INT64) {
2341 					itotal ^= data.f_int.Get();
2342 				}
2343 				else {
2344 					ftotal = (int32_t) ftotal ^ (int32_t) data.f_int.Get();
2345 				}
2346 			}
2347 			else {
2348 				if(type == NODE_INT64) {
2349 					ftotal = (int32_t) itotal ^ (int32_t) data.f_float.Get();
2350 				}
2351 				else {
2352 					ftotal = (int32_t) ftotal ^ (int32_t) data.f_float.Get();
2353 				}
2354 			}
2355 		}
2356 		else {
2357 			// We assume that the expression was already
2358 			// compiled and thus identifiers which were
2359 			// constants have been replaced already.
2360 			return;
2361 		}
2362 	}
2363 
2364 // if we reach here, we can change the node type
2365 // to NODE_INT64 or NODE_FLOAT64
2366 	Data& data = bitwise_xor.GetData();
2367 	data.f_type = type;
2368 	if(type == NODE_INT64) {
2369 		data.f_int.Set(itotal);
2370 	}
2371 	else {
2372 		data.f_float.Set(ftotal);
2373 	}
2374 
2375 // we don't need any of these children anymore
2376 	while(max > 0) {
2377 		--max;
2378 		bitwise_xor.DeleteChild(max);
2379 	}
2380 }
2381 
2382 
2383 
BitwiseOr(NodePtr & bitwise_or)2384 void IntOptimizer::BitwiseOr(NodePtr& bitwise_or)
2385 {
2386 	int64_t		itotal;
2387 	double		ftotal;
2388 	node_t		type;
2389 	int		idx, max;
2390 
2391 	type = NODE_INT64;
2392 	itotal = 0;
2393 	ftotal = 0.0;
2394 	max = bitwise_or.GetChildCount();
2395 	for(idx = 0; idx < max; ++idx) {
2396 		NodePtr child = bitwise_or.GetChild(idx);
2397 		Data data = child.GetData();
2398 		if(data.ToNumber()) {
2399 			if(data.f_type == NODE_INT64) {
2400 				if(type == NODE_INT64) {
2401 					itotal |= data.f_int.Get();
2402 				}
2403 				else {
2404 					ftotal = (int32_t) ftotal | (int32_t) data.f_int.Get();
2405 				}
2406 			}
2407 			else {
2408 				if(type == NODE_INT64) {
2409 					ftotal = (int32_t) itotal | (int32_t) data.f_float.Get();
2410 				}
2411 				else {
2412 					ftotal = (int32_t) ftotal | (int32_t) data.f_float.Get();
2413 				}
2414 			}
2415 		}
2416 		else {
2417 			// We assume that the expression was already
2418 			// compiled and thus identifiers which were
2419 			// constants have been replaced already.
2420 			return;
2421 		}
2422 	}
2423 
2424 // if we reach here, we can change the node type
2425 // to NODE_INT64 or NODE_FLOAT64
2426 	Data& data = bitwise_or.GetData();
2427 	data.f_type = type;
2428 	if(type == NODE_INT64) {
2429 		data.f_int.Set(itotal);
2430 	}
2431 	else {
2432 		data.f_float.Set(ftotal);
2433 	}
2434 
2435 // we don't need any of these children anymore
2436 	while(max > 0) {
2437 		--max;
2438 		bitwise_or.DeleteChild(max);
2439 	}
2440 }
2441 
2442 
2443 
LogicalAnd(NodePtr & logical_and)2444 void IntOptimizer::LogicalAnd(NodePtr& logical_and)
2445 {
2446 	node_t		type;
2447 	int		idx, max;
2448 
2449 	type = NODE_TRUE;
2450 	max = logical_and.GetChildCount();
2451 	for(idx = 0; idx < max; ++idx) {
2452 		NodePtr child = logical_and.GetChild(idx);
2453 		Data data = child.GetData();
2454 		if(data.ToBoolean()) {
2455 			if(data.f_type == NODE_FALSE) {
2456 				// stop testing as soon as it is known to be false
2457 				type = NODE_FALSE;
2458 				break;
2459 			}
2460 		}
2461 		else {
2462 			// We assume that the expression was already
2463 			// compiled and thus identifiers which were
2464 			// constants have been replaced already.
2465 			return;
2466 		}
2467 	}
2468 
2469 // if we reach here, we can change the node type
2470 // to NODE_INT64 or NODE_FLOAT64
2471 	Data& data = logical_and.GetData();
2472 	data.f_type = type;
2473 
2474 // we don't need any of these children anymore
2475 	while(max > 0) {
2476 		--max;
2477 		logical_and.DeleteChild(max);
2478 	}
2479 }
2480 
2481 
2482 
LogicalXOr(NodePtr & logical_xor)2483 void IntOptimizer::LogicalXOr(NodePtr& logical_xor)
2484 {
2485 	node_t		type;
2486 	int		idx, max;
2487 
2488 	type = NODE_FALSE;
2489 	max = logical_xor.GetChildCount();
2490 	for(idx = 0; idx < max; ++idx) {
2491 		NodePtr child = logical_xor.GetChild(idx);
2492 		Data data = child.GetData();
2493 		if(data.ToBoolean()) {
2494 			if(data.f_type == NODE_TRUE) {
2495 				type = type == NODE_TRUE ? NODE_FALSE : NODE_TRUE;
2496 			}
2497 		}
2498 		else {
2499 			// We assume that the expression was already
2500 			// compiled and thus identifiers which were
2501 			// constants have been replaced already.
2502 			return;
2503 		}
2504 	}
2505 
2506 // if we reach here, we can change the node type
2507 // to NODE_INT64 or NODE_FLOAT64
2508 	Data& data = logical_xor.GetData();
2509 	data.f_type = type;
2510 
2511 // we don't need any of these children anymore
2512 	while(max > 0) {
2513 		--max;
2514 		logical_xor.DeleteChild(max);
2515 	}
2516 }
2517 
2518 
2519 
LogicalOr(NodePtr & logical_or)2520 void IntOptimizer::LogicalOr(NodePtr& logical_or)
2521 {
2522 	node_t		type;
2523 	int		idx, max;
2524 
2525 	type = NODE_FALSE;
2526 	max = logical_or.GetChildCount();
2527 	for(idx = 0; idx < max; ++idx) {
2528 		NodePtr child = logical_or.GetChild(idx);
2529 		Data data = child.GetData();
2530 		if(data.ToBoolean()) {
2531 			if(data.f_type == NODE_TRUE) {
2532 				type = NODE_TRUE;
2533 				break;
2534 			}
2535 		}
2536 		else {
2537 			// We assume that the expression was already
2538 			// compiled and thus identifiers which were
2539 			// constants have been replaced already.
2540 			return;
2541 		}
2542 	}
2543 
2544 // if we reach here, we can change the node type
2545 // to NODE_INT64 or NODE_FLOAT64
2546 	Data& data = logical_or.GetData();
2547 	data.f_type = type;
2548 
2549 // we don't need any of these children anymore
2550 	while(max > 0) {
2551 		--max;
2552 		logical_or.DeleteChild(max);
2553 	}
2554 }
2555 
2556 
2557 
Minimum(NodePtr & minimum)2558 void IntOptimizer::Minimum(NodePtr& minimum)
2559 {
2560 	int r = Compare(minimum);
2561 	if(r == -2 || r == 2) {
2562 		return;
2563 	}
2564 
2565 	if(r <= 0) {
2566 		// in this case we want to keep the left node
2567 		minimum = minimum.GetChild(0);
2568 	}
2569 	else {
2570 		minimum = minimum.GetChild(1);
2571 	}
2572 }
2573 
2574 
2575 
Maximum(NodePtr & maximum)2576 void IntOptimizer::Maximum(NodePtr& maximum)
2577 {
2578 	int r = Compare(maximum);
2579 	if(r == -2 || r == 2) {
2580 		return;
2581 	}
2582 
2583 	if(r >= 0) {
2584 		// in this case we want to keep the left node
2585 		maximum = maximum.GetChild(0);
2586 	}
2587 	else {
2588 		maximum = maximum.GetChild(1);
2589 	}
2590 }
2591 
2592 
2593 
Conditional(NodePtr & conditional)2594 void IntOptimizer::Conditional(NodePtr& conditional)
2595 {
2596 	if(conditional.GetChildCount() != 3) {
2597 		return;
2598 	}
2599 
2600 	NodePtr child = conditional.GetChild(0);
2601 	Data data = child.GetData();
2602 	if(!data.ToBoolean()) {
2603 		return;
2604 	}
2605 
2606 	if(data.f_type == NODE_TRUE) {
2607 		NodePtr expr = conditional.GetChild(1);
2608 		conditional.DeleteChild(1);
2609 		conditional.ReplaceWith(expr);
2610 	}
2611 	else {
2612 		NodePtr expr = conditional.GetChild(2);
2613 		conditional.DeleteChild(2);
2614 		conditional.ReplaceWith(expr);
2615 	}
2616 }
2617 
2618 
2619 
2620 
2621 
2622 };	// namespace as
2623 };	// namespace sswf
2624