# Licensed to the .NET Foundation under one or more agreements. # The .NET Foundation licenses this file to you under the MIT license. # See the LICENSE file in the project root for more information. # # GENREFOPS.PL # # PERL script used to generate the numbering of the reference opcodes # #use strict 'vars'; #use strict 'subs'; #use strict 'refs'; my $ret = 0; my %oneByte; my %twoByte; my %controlFlow; my @singleByteArg; my %stackbehav; my %opcodetype; my %operandtype; my %opcodes; my $popstate; my $pushstate; $ctrlflowcount = 0; $count = 0; my @lowercaseAlphabet = ('a'..'z','0'..'9'); my %upcaseAlphabet = (); foreach $letter (@lowercaseAlphabet) { $j = $letter; $j=~tr/a-z/A-Z/; $upcaseAlphabet{$letter}=$j; } open (OPCODE, "opcode.def") or die "Couldn't open opcode.def: $!\n"; open (OUTPUT, ">OpCodes.cs") or die "Couldn't open OpCodes.cs: $!\n"; open (FCOUTPUT, ">FlowControl.cs") or die "Couldn't open FlowControl.cs: $!\n"; open (SOUTPUT, ">StackBehaviour.cs") or die "Couldn't open StackBehaviour.cs: $!\n"; open (OCOUTPUT, ">OpCodeType.cs") or die "Couldn't open OpCodeType.cs: $!\n"; open (OPOUTPUT, ">OperandType.cs") or die "Couldn't open OprandType.cs: $!\n"; print OUTPUT "/*============================================================\n"; print OUTPUT "**\n"; print OUTPUT "**Class: OpCodes\n"; print OUTPUT "**\n"; print OUTPUT "**Purpose: Exposes all of the il instructions supported by the runtime.\n"; print OUTPUT "**\n"; print OUTPUT "**Licensed to the .NET Foundation under one or more agreements.\n"; print OUTPUT "**The .NET Foundation licenses this file to you under the MIT license.\n"; print OUTPUT "**See the LICENSE file in the project root for more information.\n"; print OUTPUT "**\n"; print OUTPUT "** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND!\n"; print OUTPUT "** See clr\src\inc\opcodegen.pl for more information.**\n"; print OUTPUT "============================================================*/\n"; print OUTPUT "namespace System.Reflection.Emit {\n\n"; print OUTPUT "using System;\n\n";; print OUTPUT "public class OpCodes {\n\n";; print OUTPUT "/// \n"; print OUTPUT "/// \n"; print OUTPUT "/// The IL instruction opcodes supported by the\n"; print OUTPUT "/// runtime. The IL Instruction Specification describes each\n"; print OUTPUT "/// Opcode.\n"; print OUTPUT "/// \n"; print OUTPUT "/// \n"; print OUTPUT "/// \n"; print OUTPUT "\n"; print OUTPUT "\tprivate OpCodes() { \n\t}\n\n"; print FCOUTPUT "/*============================================================\n"; print FCOUTPUT "**\n"; print FCOUTPUT "**Class: FlowControl\n"; print FCOUTPUT "**\n"; print FCOUTPUT "**Purpose: Exposes FlowControl Attribute of IL .\n"; print FCOUTPUT "**\n"; print FCOUTPUT "**Licensed to the .NET Foundation under one or more agreements.\n"; print FCOUTPUT "**The .NET Foundation licenses this file to you under the MIT license.\n"; print FCOUTPUT "**See the LICENSE file in the project root for more information.\n"; print FCOUTPUT "**\n"; print FCOUTPUT "** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND!\n"; print FCOUTPUT "** See clr\src\inc\opcodegen.pl for more information.**\n"; print FCOUTPUT "============================================================*/\n"; print FCOUTPUT "namespace System.Reflection.Emit {\n\n"; print FCOUTPUT "using System;\n\n"; print FCOUTPUT "public enum FlowControl\n{\n\n"; print SOUTPUT "/*============================================================\n"; print SOUTPUT "**\n"; print SOUTPUT "**Class: StackBehaviour\n"; print SOUTPUT "**\n"; print SOUTPUT "**Purpose: Exposes StackBehaviour Attribute of IL .\n"; print SOUTPUT "**\n"; print SOUTPUT "**Licensed to the .NET Foundation under one or more agreements.\n"; print SOUTPUT "**The .NET Foundation licenses this file to you under the MIT license.\n"; print SOUTPUT "**See the LICENSE file in the project root for more information.\n"; print SOUTPUT "**\n"; print SOUTPUT "** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND!\n"; print SOUTPUT "** See clr\src\inc\opcodegen.pl for more information.**\n"; print SOUTPUT "============================================================*/\n"; print SOUTPUT "namespace System.Reflection.Emit {\n\n"; print SOUTPUT "using System;\n\n"; print SOUTPUT "public enum StackBehaviour\n{\n\n"; print OCOUTPUT "/*============================================================\n"; print OCOUTPUT "**\n"; print OCOUTPUT "**Class: OpCodeType\n"; print OCOUTPUT "**\n"; print OCOUTPUT "**Purpose: Exposes OpCodeType Attribute of IL .\n"; print OCOUTPUT "**\n"; print OCOUTPUT "**Licensed to the .NET Foundation under one or more agreements.\n"; print OCOUTPUT "**The .NET Foundation licenses this file to you under the MIT license.\n"; print OCOUTPUT "**See the LICENSE file in the project root for more information.\n"; print OCOUTPUT "**\n"; print OCOUTPUT "** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND!\n"; print OCOUTPUT "** See clr\src\inc\opcodegen.pl for more information.**\n"; print OCOUTPUT "============================================================*/\n"; print OCOUTPUT "namespace System.Reflection.Emit {\n\n"; print OCOUTPUT "using System;\n\n"; print OCOUTPUT "public enum OpCodeType\n{\n\n"; print OPOUTPUT "/*============================================================\n"; print OPOUTPUT "**\n"; print OPOUTPUT "**Class: OperandType\n"; print OPOUTPUT "**\n"; print OPOUTPUT "**Purpose: Exposes OperandType Attribute of IL .\n"; print OPOUTPUT "**\n"; print OPOUTPUT "**Licensed to the .NET Foundation under one or more agreements.\n"; print OPOUTPUT "**The .NET Foundation licenses this file to you under the MIT license.\n"; print OPOUTPUT "**See the LICENSE file in the project root for more information.\n"; print OPOUTPUT "**\n"; print OPOUTPUT "** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND!\n"; print OPOUTPUT "** See clr\src\inc\opcodegen.pl for more information.**\n"; print OPOUTPUT "============================================================*/\n"; print OPOUTPUT "namespace System.Reflection.Emit {\n\n"; print OPOUTPUT "using System;\n\n"; print OPOUTPUT "public enum OperandType\n{\n\n"; while () { # Process only OPDEF(....) lines if (/OPDEF\(\s*/) { chop; # Strip off trailing CR s/^OPDEF\(\s*//; # Strip off "OP(" s/\)$//; # Strip off ")" at end s/,\s*/,/g; # Remove whitespace # Split the line up into its basic parts ($enumname, $stringname, $pop, $push, $operand, $type, $size, $s1, $s2, $ctrl) = split(/,/); $s1 =~ s/0x//; $s1 = hex($s1); $s2 =~ s/0x//; $s2 = hex($s2); if ($size == 0) { next; } next if ($enumname =~ /UNUSED/); #Remove the prefix $enumname=~s/CEE_//g; #Convert name to our casing convention $enumname=~tr/A-Z/a-z/; $enumname=~s/^(.)/\u$1/g; $enumname=~s/_(.)/_\u$1/g; #Convert pop to our casing convention $pop=~tr/A-Z/a-z/; $pop=~s/^(.)/\u$1/g; $pop=~s/_(.)/_\u$1/g; #Convert push to our casing convention $push=~tr/A-Z/a-z/; $push=~s/^(.)/\u$1/g; $push=~s/_(.)/_\u$1/g; #Convert operand to our casing convention #$operand=~tr/A-Z/a-z/; #$operand=~s/^(.)/\u$1/g; #$operand=~s/_(.)/_\u$1/g; #Remove the I prefix on type $type=~s/I//g; #Convert Type to our casing convention $type=~tr/A-Z/a-z/; $type=~s/^(.)/\u$1/g; $type=~s/_(.)/_\u$1/g; #Convert ctrl to our casing convention $ctrl=~tr/A-Z/a-z/; $ctrl=~s/^(.)/\u$1/g; $ctrl=~s/_(.)/_\u$1/g; # Make a list of the flow Control type # Make a list of the opcodes and there values if ($opcodes{$enumname}) { } else { if ($size == 1) { $opcodes{$enumname} = $s2; } else { $opcodes{$enumname} = ($s2 + 256 * $s1); } } #Make a list of the instructions which only take one-byte arguments if ($enumname =~ /^.*_S$/) { #but exclude the deprecated expressions (sometimes spelled "depricated") if (!($enumname=~/^Depr.cated.*/)) { my $caseStatement = sprintf("\t\tcase %-20s: \n", $enumname); push(@singleByteArg, $caseStatement); } } #make a list of the control Flow Types if ($controlFlow{$ctrl}) { #printf("DUPE Control Flow\n"); } else { $controlFlow{$ctrl} = $ctrlflowcount; $ctrlflowcount++; } $ctrlflowcount = 0; #make a list of the control Flow Types $pop=~s/\+/_/g; if ($stackbehav{$pop}) { #printf("DUPE Control Flow\n"); } else { $stackbehav{$pop} = $ctrlflowcount; $ctrlflowcount++; } #make a list of the control Flow Types $push=~s/\+/_/g; if ($stackbehav{$push}) { #printf("DUPE Control Flow\n"); } else { $stackbehav{$push} = $ctrlflowcount; $ctrlflowcount++; } #make a list of operand types if ($operandtype{$operand}) { #printf("DUPE Control Flow\n"); } else { $operandtype{$operand} = $ctrlflowcount; $ctrlflowcount++; } #make a list of opcode types if ($opcodetype{$type}) { #printf("DUPE Control Flow\n"); } else { $opcodetype{$type} = $ctrlflowcount; $ctrlflowcount++; } print "$enumname\n"; print "$stringname\n"; if ($stringname eq "arglist") { print "This is arglist----------\n"; } my $line = sprintf("\tpublic static readonly OpCode %-20s = ", $enumname); if ($size == 1) { $line .= sprintf("new OpCode(%s, StackBehaviour.%s, StackBehaviour.%s, OperandType.%s, OpCodeType.%s, %u, (byte)0x%x, (byte)0x%x, FlowControl.%s, " , $stringname, $pop, $push, $operand, $type, $size, $s1, $s2, $ctrl); if ($ctrl eq "Return" || $ctrl eq "Branch" || $ctrl eq "Throw" || $stringname eq "\"jmp\"" || $stringname eq "\"jmpi\"") { $line .= sprintf("true, "); } else { $line .= sprintf("false, "); } $popstate = 0; if($pop eq "Pop0" || $pop eq "Varpop") { $popstate = 0; } elsif ($pop eq "Pop1" || $pop eq "Popi" || $pop eq "Popref") { $popstate = $popstate -1; } elsif ($pop eq "Pop1_pop1" || $pop eq "Popi_pop1" || $pop eq "Popi_popi" || $pop eq "Popi_popi8" || $pop eq "Popi_popr4" || $pop eq "Popi_popr8" || $pop eq "Popref_pop1" || $pop eq "Popref_popi") { $popstate = $popstate -2; } elsif ($pop eq "Popi_popi_popi" || $pop eq "Popref_popi_popi" || $pop eq "Popref_popi_popi8" || $pop eq "Popref_popi_popr4" || $pop eq "Popref_popi_popr8" || $pop eq "Popref_popi_popref") { $popstate = $popstate -3; } if ($push eq "Push1" || $push eq "Pushi" ||$push eq "Pushi8" ||$push eq "Pushr4" ||$push eq "Pushr8" ||$push eq "Pushref") { $popstate = $popstate + 1; } elsif($push eq "Push1_push1") { $popstate = $popstate + 2; } $line .= sprintf(" $popstate"); $line .= sprintf(");\n\n"); if ($oneByte{$s2}) { printf("Error opcode 0x%x already defined!\n", $s2); print " Old = $oneByte{$s2}"; print " New = $line"; $ret = -1; } $oneByte{$s2} = $line; } elsif ($size == 2) { if ($twoByte{$s2}) { printf("Error opcode 0x%x%x already defined!\n", $s1, $s2); print " Old = $oneByte{$s2}"; print " New = $line"; $ret = -1; } $line .= sprintf("new OpCode(%s, StackBehaviour.%s, StackBehaviour.%s, OperandType.%s, OpCodeType.%s, %u, (byte)0x%x, (byte)0x%x, FlowControl.%s, " , $stringname, $pop, $push, $operand, $type, $size, $s1, $s2, $ctrl); if ($ctrl eq "Return" || $ctrl eq "Branch" || $ctrl eq "Throw" || $stringname eq "\"jmp\"" || $stringname eq "\"jmpi\"") { $line .= sprintf("true, "); } else { $line .= sprintf("false, "); } $popstate = 0; if($pop eq "Pop0" || $pop eq "Varpop") { $popstate = 0; } elsif($pop eq "Pop1" || $pop eq "Popi" || $pop eq "Popref") { $popstate = $popstate -1; } elsif ($pop eq "Pop1_pop1" || $pop eq "Popi_pop1" || $pop eq "Popi_popi" || $pop eq "Popi_popi8" || $pop eq "Popi_popr4" || $pop eq "Popi_popr8" || $pop eq "Popref_pop1" || $pop eq "Popref_popi") { $popstate = $popstate -2; } elsif ($pop eq "Popi_popi_popi" || $pop eq "Popref_popi_popi" || $pop eq "Popref_popi_popi8" || $pop eq "Popref_popi_popr4" || $pop eq "Popref_popi_popr8" || $pop eq "Popref_popi_popref") { $popstate = $popstate -3; } if ($push eq "Push1" || $push eq "Pushi" ||$push eq "Pushi8" ||$push eq "Pushr4" ||$push eq "Pushr8" ||$push eq "Pushref") { $popstate = $popstate + 1; } elsif($push eq "Push1_push1") { $popstate = $popstate + 2; } $line .= sprintf(" $popstate"); $line .= sprintf(");\n\n"); $twoByte{$s2 + 256 * $s1} = $line; } else { $line .= "\n"; push(@deprecated, $line); } $count++; } } #Write out the Flow Control class $ctrlflowcount = 0; foreach $key (sort {$a cmp $b} keys (%controlFlow)) { print FCOUTPUT "\t$key"; print FCOUTPUT "\t= $ctrlflowcount,\n"; $ctrlflowcount++; } #end the flowcontrol class print FCOUTPUT "}\n}"; #Write out the StackBehaviour class $ctrlflowcount = 0; foreach $key (sort {$a cmp $b} keys (%stackbehav)) { print SOUTPUT "\t$key"; print SOUTPUT "\t= $ctrlflowcount,\n"; $ctrlflowcount++; } #end the StackBehaviour class print SOUTPUT "}\n}"; $ctrlflowcount = 0; foreach $key (sort {$a cmp $b} keys (%opcodetype)) { print OCOUTPUT "\t$key"; print OCOUTPUT "\t= $ctrlflowcount,\n"; $ctrlflowcount++; } #end the OpCodeTYpe class print OCOUTPUT "}\n}"; $ctrlflowcount = 0; foreach $key (sort {$a cmp $b} keys (%operandtype)) { print OPOUTPUT "\t$key"; print OPOUTPUT "\t= $ctrlflowcount,\n"; $ctrlflowcount++; } #end the OperandType class print OPOUTPUT "}\n}"; my $opcode; my $lastOp = -1; foreach $opcode (sort {$a <=> $b} keys(%oneByte)) { printf("***** GAP %d instrs ****\n", $opcode - $lastOp) if ($lastOp + 1 != $opcode && $lastOp > 0); print OUTPUT $oneByte{$opcode}; $lastOp = $opcode; } $lastOp = -1; foreach $opcode (sort {$a <=> $b} keys(%twoByte)) { printf("***** GAP %d instrs ****\n", $opcode - $lastOp) if ($lastOp + 1 != $opcode && $lastOp > 0); print OUTPUT $twoByte{$opcode}; $lastOp = $opcode; } print OUTPUT "\n\n\tpublic static bool TakesSingleByteArgument(OpCode inst)\n\t{\n"; print OUTPUT"\t\tswitch(inst.m_operand)\n\t\t{\n"; print OUTPUT "\t\t\tcase OperandType.ShortInlineBrTarget :\n"; print OUTPUT "\t\t\tcase OperandType.ShortInlineI :\n"; print OUTPUT "\t\t\tcase OperandType.ShortInlineVar :\n"; print OUTPUT "\t\t\treturn true;\n"; print OUTPUT "\t\t};\n"; print OUTPUT "\t\treturn false;\n"; print OUTPUT "\t}\n"; print OUTPUT "}\n}"; exit($ret);