зеркало из https://github.com/mozilla/gecko-dev.git
starting to turn the icode StatementNode vector into actual Instructions...
This commit is contained in:
Родитель
878b456f05
Коммит
70055678b6
|
@ -124,6 +124,239 @@ static struct {
|
|||
{"XOR", {otRegister, otRegister, otRegister}},
|
||||
};
|
||||
|
||||
VM::Instruction *InstructionFromNode (StatementNode *node)
|
||||
{
|
||||
using namespace VM;
|
||||
Instruction *i;
|
||||
|
||||
switch (node->icodeID)
|
||||
{
|
||||
case 0:
|
||||
i = new Add (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 1:
|
||||
i = new And (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 2:
|
||||
i = new Bitnot (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 3:
|
||||
i = new Branch (reinterpret_cast<Label*>(node->operand[0].data));
|
||||
break;
|
||||
case 4:
|
||||
i = new BranchFalse (reinterpret_cast<Label*>(node->operand[0].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 5:
|
||||
i = new BranchInitialized (reinterpret_cast<Label*>(node->operand[0].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 6:
|
||||
i = new BranchTrue (reinterpret_cast<Label*>(node->operand[0].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 7:
|
||||
i = new Call (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0), static_cast<ArgumentList>(node->operand[3].data));
|
||||
break;
|
||||
case 8:
|
||||
i = new Cast (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), reinterpret_cast<JSType*>(node->operand[2].data));
|
||||
break;
|
||||
case 9:
|
||||
i = new CompareEQ (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 10:
|
||||
i = new CompareGE (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 11:
|
||||
i = new CompareGT (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 12:
|
||||
i = new CompareIN (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 13:
|
||||
i = new CompareLE (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 14:
|
||||
i = new CompareLT (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 15:
|
||||
i = new CompareNE (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 16:
|
||||
i = new Debugger ();
|
||||
break;
|
||||
case 17:
|
||||
i = new DeleteProp (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), reinterpret_cast<const StringAtom*>(node->operand[2].data));
|
||||
break;
|
||||
case 18:
|
||||
i = new DirectCall (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<JSFunction*>(node->operand[1].data), static_cast<ArgumentList>(node->operand[2].data));
|
||||
break;
|
||||
case 19:
|
||||
i = new Divide (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 20:
|
||||
i = new ElemXcr (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0), static_cast<double>(node->operand[3].data));
|
||||
break;
|
||||
case 21:
|
||||
i = new GenericBinaryOP (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), static_cast<BinaryOperator::BinaryOp>(node->operand[1].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[3].data), 0));
|
||||
break;
|
||||
case 22:
|
||||
i = new GetElement (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 23:
|
||||
i = new GetMethod (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), static_cast<uint32>(node->operand[2].data));
|
||||
break;
|
||||
case 24:
|
||||
i = new GetProp (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), reinterpret_cast<const StringAtom*>(node->operand[2].data));
|
||||
break;
|
||||
case 25:
|
||||
i = new GetSlot (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), static_cast<uint32>(node->operand[2].data));
|
||||
break;
|
||||
case 26:
|
||||
i = new GetStatic (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<JSClass*>(node->operand[1].data), static_cast<uint32>(node->operand[2].data));
|
||||
break;
|
||||
case 27:
|
||||
i = new Instanceof (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 28:
|
||||
i = new Jsr (reinterpret_cast<Label*>(node->operand[0].data));
|
||||
break;
|
||||
case 29:
|
||||
i = new LoadBoolean (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), static_cast<bool>(node->operand[1].data));
|
||||
break;
|
||||
case 30:
|
||||
i = new LoadImmediate (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), static_cast<double>(node->operand[1].data));
|
||||
break;
|
||||
case 31:
|
||||
i = new LoadName (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<const StringAtom*>(node->operand[1].data));
|
||||
break;
|
||||
case 32:
|
||||
i = new LoadString (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<JSString*>(node->operand[1].data));
|
||||
break;
|
||||
case 33:
|
||||
i = new Move (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 34:
|
||||
i = new Multiply (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 35:
|
||||
i = new NameXcr (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<const StringAtom*>(node->operand[1].data), static_cast<double>(node->operand[2].data));
|
||||
break;
|
||||
case 36:
|
||||
i = new Negate (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 37:
|
||||
i = new NewArray (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0));
|
||||
break;
|
||||
case 38:
|
||||
i = new NewClass (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<JSClass*>(node->operand[1].data));
|
||||
break;
|
||||
case 39:
|
||||
i = new NewFunction (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<ICodeModule*>(node->operand[1].data));
|
||||
break;
|
||||
case 40:
|
||||
i = new NewObject (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 41:
|
||||
i = new Nop ();
|
||||
break;
|
||||
case 42:
|
||||
i = new Not (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 43:
|
||||
i = new Or (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 44:
|
||||
i = new Posate (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 45:
|
||||
i = new PropXcr (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), reinterpret_cast<const StringAtom*>(node->operand[2].data), static_cast<double>(node->operand[3].data));
|
||||
break;
|
||||
case 46:
|
||||
i = new Remainder (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 47:
|
||||
i = new Return (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0));
|
||||
break;
|
||||
case 48:
|
||||
i = new ReturnVoid ();
|
||||
break;
|
||||
case 49:
|
||||
i = new Rts ();
|
||||
break;
|
||||
case 50:
|
||||
i = new SaveName (reinterpret_cast<const StringAtom*>(node->operand[0].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 51:
|
||||
i = new SetElement (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 52:
|
||||
i = new SetProp (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<const StringAtom*>(node->operand[1].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 53:
|
||||
i = new SetSlot (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), static_cast<uint32>(node->operand[1].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 54:
|
||||
i = new SetStatic (reinterpret_cast<JSClass*>(node->operand[0].data), static_cast<uint32>(node->operand[1].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 55:
|
||||
i = new Shiftleft (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 56:
|
||||
i = new Shiftright (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 57:
|
||||
i = new SlotXcr (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), static_cast<uint32>(node->operand[2].data), static_cast<double>(node->operand[3].data));
|
||||
break;
|
||||
case 58:
|
||||
i = new StaticXcr (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<JSClass*>(node->operand[1].data), static_cast<uint32>(node->operand[2].data), static_cast<double>(node->operand[3].data));
|
||||
break;
|
||||
case 59:
|
||||
i = new StrictEQ (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 60:
|
||||
i = new StrictNE (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 61:
|
||||
i = new Subtract (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 62:
|
||||
i = new Super (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0));
|
||||
break;
|
||||
case 63:
|
||||
i = new Test (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 64:
|
||||
i = new Throw (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0));
|
||||
break;
|
||||
case 65:
|
||||
i = new Tryin (reinterpret_cast<Label*>(node->operand[0].data), reinterpret_cast<Label*>(node->operand[1].data));
|
||||
break;
|
||||
case 66:
|
||||
i = new Tryout ();
|
||||
break;
|
||||
case 67:
|
||||
i = new Ushiftright (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 68:
|
||||
i = new VarXcr (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), static_cast<double>(node->operand[2].data));
|
||||
break;
|
||||
case 69:
|
||||
i = new Within (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0));
|
||||
break;
|
||||
case 70:
|
||||
i = new Without ();
|
||||
break;
|
||||
case 71:
|
||||
i = new Xor (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED("Unknown icodeID");
|
||||
}
|
||||
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ sub collect {
|
|||
}
|
||||
|
||||
my $opname = $k;
|
||||
my $cname = get_classname ($k);
|
||||
my $cname = jsicodes::get_classname ($k);
|
||||
my $super = $c->{"super"};
|
||||
my $constructor = $super;
|
||||
my @params;
|
||||
|
@ -171,26 +171,6 @@ sub spew {
|
|||
print "#endif\n\n"
|
||||
}
|
||||
|
||||
sub get_classname {
|
||||
# munge an OPCODE_MNEMONIC into a ClassName
|
||||
my ($enum_name) = @_;
|
||||
my @words = split ("_", $enum_name);
|
||||
my $cname = "";
|
||||
my $i = 0;
|
||||
my $word;
|
||||
|
||||
for $word (@words) {
|
||||
if ((length($word) == 2) && ($i != 0)) {
|
||||
$cname .= uc($word);
|
||||
} else {
|
||||
$cname .= uc(substr($word, 0, 1)) . lc(substr($word, 1));
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $cname;
|
||||
}
|
||||
|
||||
sub get_paramlists {
|
||||
# parse the params entry (passed into @types) into various parameter lists
|
||||
# used in the class declaration
|
||||
|
|
|
@ -34,12 +34,20 @@
|
|||
use strict;
|
||||
use jsicodes;
|
||||
|
||||
my $k;
|
||||
my $count = 0;
|
||||
my $tab = " ";
|
||||
|
||||
for $k (sort(keys(%jsicodes::ops))) {
|
||||
$count++;
|
||||
print " {\"$k\", {";
|
||||
my @map = &get_map();
|
||||
my $gen_body = &get_generator();
|
||||
|
||||
print $tab . "static uint icodemap_size = " . ($#map + 1) . "\n\n\n";
|
||||
print join ("\n", @map) . "\n\n\n";
|
||||
print $gen_body . "\n";
|
||||
|
||||
sub get_map {
|
||||
my $k;
|
||||
my @map;
|
||||
for $k (sort(keys(%jsicodes::ops))) {
|
||||
my $map_entry .= $tab . $tab . "{\"$k\", {";
|
||||
my $c = $jsicodes::ops{$k};
|
||||
if ($c->{"params"}) {
|
||||
my @ot;
|
||||
|
@ -77,11 +85,47 @@ for $k (sort(keys(%jsicodes::ops))) {
|
|||
die "unknown parameter type '$p' for icode '$k'.\n";
|
||||
}
|
||||
}
|
||||
print (join (", ", @ot));
|
||||
$map_entry .= join (", ", @ot);
|
||||
} else {
|
||||
print "otNone";
|
||||
$map_entry .= "otNone";
|
||||
}
|
||||
print "}},\n";
|
||||
$map_entry .= "}},";
|
||||
push (@map, $map_entry);
|
||||
}
|
||||
|
||||
return @map;
|
||||
}
|
||||
|
||||
print "\n\nstatic uint icodemap_size = $count\n";
|
||||
sub get_generator {
|
||||
my $k;
|
||||
my $rval = "";
|
||||
my $icode_id = 0;
|
||||
for $k (sort(keys(%jsicodes::ops))) {
|
||||
my $c = $jsicodes::ops{$k};
|
||||
my @args = ();
|
||||
if ($c->{"params"}) {
|
||||
my @params = @{$c->{"params"}};
|
||||
my $arg_num = 0;
|
||||
my $p;
|
||||
for $p (@params) {
|
||||
if ($p eq "TypedRegister") {
|
||||
push (@args, "TypedRegister(static_cast<JSTypes::Register>(node->operand[$arg_num].data), 0)");
|
||||
} elsif ($p =~ /\*$/) {
|
||||
push (@args, "reinterpret_cast<$p>(node->operand[$arg_num].data)");
|
||||
} else {
|
||||
push (@args, "static_cast<$p>(node->operand[$arg_num].data)");
|
||||
}
|
||||
$arg_num++;
|
||||
}
|
||||
}
|
||||
|
||||
$rval .= $tab . $tab . $tab . "case $icode_id:\n";
|
||||
$rval .= $tab . $tab . $tab . $tab .
|
||||
"i = new " . &jsicodes::get_classname($k) . " (" . join (", ", @args) .
|
||||
");\n";
|
||||
$rval .= $tab . $tab . $tab . $tab . "break;\n";
|
||||
$icode_id++;
|
||||
}
|
||||
|
||||
return $rval;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,27 @@ use vars qw(%ops @ISA);
|
|||
require Exporter;
|
||||
@ISA = qw(Exporter);
|
||||
|
||||
sub get_classname {
|
||||
# munge an OPCODE_MNEMONIC into a ClassName
|
||||
my ($enum_name) = @_;
|
||||
my @words = split ("_", $enum_name);
|
||||
my $cname = "";
|
||||
my $i = 0;
|
||||
my $word;
|
||||
|
||||
for $word (@words) {
|
||||
if ((length($word) == 2) && ($i != 0)) {
|
||||
$cname .= uc($word);
|
||||
} else {
|
||||
$cname .= uc(substr($word, 0, 1)) . lc(substr($word, 1));
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $cname;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# fields are:
|
||||
#
|
||||
|
|
|
@ -124,6 +124,239 @@ static struct {
|
|||
{"XOR", {otRegister, otRegister, otRegister}},
|
||||
};
|
||||
|
||||
VM::Instruction *InstructionFromNode (StatementNode *node)
|
||||
{
|
||||
using namespace VM;
|
||||
Instruction *i;
|
||||
|
||||
switch (node->icodeID)
|
||||
{
|
||||
case 0:
|
||||
i = new Add (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 1:
|
||||
i = new And (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 2:
|
||||
i = new Bitnot (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 3:
|
||||
i = new Branch (reinterpret_cast<Label*>(node->operand[0].data));
|
||||
break;
|
||||
case 4:
|
||||
i = new BranchFalse (reinterpret_cast<Label*>(node->operand[0].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 5:
|
||||
i = new BranchInitialized (reinterpret_cast<Label*>(node->operand[0].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 6:
|
||||
i = new BranchTrue (reinterpret_cast<Label*>(node->operand[0].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 7:
|
||||
i = new Call (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0), static_cast<ArgumentList>(node->operand[3].data));
|
||||
break;
|
||||
case 8:
|
||||
i = new Cast (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), reinterpret_cast<JSType*>(node->operand[2].data));
|
||||
break;
|
||||
case 9:
|
||||
i = new CompareEQ (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 10:
|
||||
i = new CompareGE (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 11:
|
||||
i = new CompareGT (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 12:
|
||||
i = new CompareIN (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 13:
|
||||
i = new CompareLE (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 14:
|
||||
i = new CompareLT (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 15:
|
||||
i = new CompareNE (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 16:
|
||||
i = new Debugger ();
|
||||
break;
|
||||
case 17:
|
||||
i = new DeleteProp (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), reinterpret_cast<const StringAtom*>(node->operand[2].data));
|
||||
break;
|
||||
case 18:
|
||||
i = new DirectCall (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<JSFunction*>(node->operand[1].data), static_cast<ArgumentList>(node->operand[2].data));
|
||||
break;
|
||||
case 19:
|
||||
i = new Divide (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 20:
|
||||
i = new ElemXcr (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0), static_cast<double>(node->operand[3].data));
|
||||
break;
|
||||
case 21:
|
||||
i = new GenericBinaryOP (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), static_cast<BinaryOperator::BinaryOp>(node->operand[1].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[3].data), 0));
|
||||
break;
|
||||
case 22:
|
||||
i = new GetElement (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 23:
|
||||
i = new GetMethod (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), static_cast<uint32>(node->operand[2].data));
|
||||
break;
|
||||
case 24:
|
||||
i = new GetProp (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), reinterpret_cast<const StringAtom*>(node->operand[2].data));
|
||||
break;
|
||||
case 25:
|
||||
i = new GetSlot (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), static_cast<uint32>(node->operand[2].data));
|
||||
break;
|
||||
case 26:
|
||||
i = new GetStatic (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<JSClass*>(node->operand[1].data), static_cast<uint32>(node->operand[2].data));
|
||||
break;
|
||||
case 27:
|
||||
i = new Instanceof (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 28:
|
||||
i = new Jsr (reinterpret_cast<Label*>(node->operand[0].data));
|
||||
break;
|
||||
case 29:
|
||||
i = new LoadBoolean (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), static_cast<bool>(node->operand[1].data));
|
||||
break;
|
||||
case 30:
|
||||
i = new LoadImmediate (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), static_cast<double>(node->operand[1].data));
|
||||
break;
|
||||
case 31:
|
||||
i = new LoadName (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<const StringAtom*>(node->operand[1].data));
|
||||
break;
|
||||
case 32:
|
||||
i = new LoadString (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<JSString*>(node->operand[1].data));
|
||||
break;
|
||||
case 33:
|
||||
i = new Move (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 34:
|
||||
i = new Multiply (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 35:
|
||||
i = new NameXcr (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<const StringAtom*>(node->operand[1].data), static_cast<double>(node->operand[2].data));
|
||||
break;
|
||||
case 36:
|
||||
i = new Negate (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 37:
|
||||
i = new NewArray (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0));
|
||||
break;
|
||||
case 38:
|
||||
i = new NewClass (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<JSClass*>(node->operand[1].data));
|
||||
break;
|
||||
case 39:
|
||||
i = new NewFunction (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<ICodeModule*>(node->operand[1].data));
|
||||
break;
|
||||
case 40:
|
||||
i = new NewObject (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 41:
|
||||
i = new Nop ();
|
||||
break;
|
||||
case 42:
|
||||
i = new Not (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 43:
|
||||
i = new Or (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 44:
|
||||
i = new Posate (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 45:
|
||||
i = new PropXcr (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), reinterpret_cast<const StringAtom*>(node->operand[2].data), static_cast<double>(node->operand[3].data));
|
||||
break;
|
||||
case 46:
|
||||
i = new Remainder (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 47:
|
||||
i = new Return (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0));
|
||||
break;
|
||||
case 48:
|
||||
i = new ReturnVoid ();
|
||||
break;
|
||||
case 49:
|
||||
i = new Rts ();
|
||||
break;
|
||||
case 50:
|
||||
i = new SaveName (reinterpret_cast<const StringAtom*>(node->operand[0].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 51:
|
||||
i = new SetElement (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 52:
|
||||
i = new SetProp (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<const StringAtom*>(node->operand[1].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 53:
|
||||
i = new SetSlot (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), static_cast<uint32>(node->operand[1].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 54:
|
||||
i = new SetStatic (reinterpret_cast<JSClass*>(node->operand[0].data), static_cast<uint32>(node->operand[1].data), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 55:
|
||||
i = new Shiftleft (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 56:
|
||||
i = new Shiftright (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 57:
|
||||
i = new SlotXcr (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), static_cast<uint32>(node->operand[2].data), static_cast<double>(node->operand[3].data));
|
||||
break;
|
||||
case 58:
|
||||
i = new StaticXcr (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), reinterpret_cast<JSClass*>(node->operand[1].data), static_cast<uint32>(node->operand[2].data), static_cast<double>(node->operand[3].data));
|
||||
break;
|
||||
case 59:
|
||||
i = new StrictEQ (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 60:
|
||||
i = new StrictNE (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 61:
|
||||
i = new Subtract (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 62:
|
||||
i = new Super (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0));
|
||||
break;
|
||||
case 63:
|
||||
i = new Test (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0));
|
||||
break;
|
||||
case 64:
|
||||
i = new Throw (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0));
|
||||
break;
|
||||
case 65:
|
||||
i = new Tryin (reinterpret_cast<Label*>(node->operand[0].data), reinterpret_cast<Label*>(node->operand[1].data));
|
||||
break;
|
||||
case 66:
|
||||
i = new Tryout ();
|
||||
break;
|
||||
case 67:
|
||||
i = new Ushiftright (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
case 68:
|
||||
i = new VarXcr (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), static_cast<double>(node->operand[2].data));
|
||||
break;
|
||||
case 69:
|
||||
i = new Within (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0));
|
||||
break;
|
||||
case 70:
|
||||
i = new Without ();
|
||||
break;
|
||||
case 71:
|
||||
i = new Xor (TypedRegister(static_cast<JSTypes::Register>(node->operand[0].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[1].data), 0), TypedRegister(static_cast<JSTypes::Register>(node->operand[2].data), 0));
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED("Unknown icodeID");
|
||||
}
|
||||
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ sub collect {
|
|||
}
|
||||
|
||||
my $opname = $k;
|
||||
my $cname = get_classname ($k);
|
||||
my $cname = jsicodes::get_classname ($k);
|
||||
my $super = $c->{"super"};
|
||||
my $constructor = $super;
|
||||
my @params;
|
||||
|
@ -171,26 +171,6 @@ sub spew {
|
|||
print "#endif\n\n"
|
||||
}
|
||||
|
||||
sub get_classname {
|
||||
# munge an OPCODE_MNEMONIC into a ClassName
|
||||
my ($enum_name) = @_;
|
||||
my @words = split ("_", $enum_name);
|
||||
my $cname = "";
|
||||
my $i = 0;
|
||||
my $word;
|
||||
|
||||
for $word (@words) {
|
||||
if ((length($word) == 2) && ($i != 0)) {
|
||||
$cname .= uc($word);
|
||||
} else {
|
||||
$cname .= uc(substr($word, 0, 1)) . lc(substr($word, 1));
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $cname;
|
||||
}
|
||||
|
||||
sub get_paramlists {
|
||||
# parse the params entry (passed into @types) into various parameter lists
|
||||
# used in the class declaration
|
||||
|
|
|
@ -34,12 +34,20 @@
|
|||
use strict;
|
||||
use jsicodes;
|
||||
|
||||
my $k;
|
||||
my $count = 0;
|
||||
my $tab = " ";
|
||||
|
||||
for $k (sort(keys(%jsicodes::ops))) {
|
||||
$count++;
|
||||
print " {\"$k\", {";
|
||||
my @map = &get_map();
|
||||
my $gen_body = &get_generator();
|
||||
|
||||
print $tab . "static uint icodemap_size = " . ($#map + 1) . "\n\n\n";
|
||||
print join ("\n", @map) . "\n\n\n";
|
||||
print $gen_body . "\n";
|
||||
|
||||
sub get_map {
|
||||
my $k;
|
||||
my @map;
|
||||
for $k (sort(keys(%jsicodes::ops))) {
|
||||
my $map_entry .= $tab . $tab . "{\"$k\", {";
|
||||
my $c = $jsicodes::ops{$k};
|
||||
if ($c->{"params"}) {
|
||||
my @ot;
|
||||
|
@ -77,11 +85,47 @@ for $k (sort(keys(%jsicodes::ops))) {
|
|||
die "unknown parameter type '$p' for icode '$k'.\n";
|
||||
}
|
||||
}
|
||||
print (join (", ", @ot));
|
||||
$map_entry .= join (", ", @ot);
|
||||
} else {
|
||||
print "otNone";
|
||||
$map_entry .= "otNone";
|
||||
}
|
||||
print "}},\n";
|
||||
$map_entry .= "}},";
|
||||
push (@map, $map_entry);
|
||||
}
|
||||
|
||||
return @map;
|
||||
}
|
||||
|
||||
print "\n\nstatic uint icodemap_size = $count\n";
|
||||
sub get_generator {
|
||||
my $k;
|
||||
my $rval = "";
|
||||
my $icode_id = 0;
|
||||
for $k (sort(keys(%jsicodes::ops))) {
|
||||
my $c = $jsicodes::ops{$k};
|
||||
my @args = ();
|
||||
if ($c->{"params"}) {
|
||||
my @params = @{$c->{"params"}};
|
||||
my $arg_num = 0;
|
||||
my $p;
|
||||
for $p (@params) {
|
||||
if ($p eq "TypedRegister") {
|
||||
push (@args, "TypedRegister(static_cast<JSTypes::Register>(node->operand[$arg_num].data), 0)");
|
||||
} elsif ($p =~ /\*$/) {
|
||||
push (@args, "reinterpret_cast<$p>(node->operand[$arg_num].data)");
|
||||
} else {
|
||||
push (@args, "static_cast<$p>(node->operand[$arg_num].data)");
|
||||
}
|
||||
$arg_num++;
|
||||
}
|
||||
}
|
||||
|
||||
$rval .= $tab . $tab . $tab . "case $icode_id:\n";
|
||||
$rval .= $tab . $tab . $tab . $tab .
|
||||
"i = new " . &jsicodes::get_classname($k) . " (" . join (", ", @args) .
|
||||
");\n";
|
||||
$rval .= $tab . $tab . $tab . $tab . "break;\n";
|
||||
$icode_id++;
|
||||
}
|
||||
|
||||
return $rval;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,27 @@ use vars qw(%ops @ISA);
|
|||
require Exporter;
|
||||
@ISA = qw(Exporter);
|
||||
|
||||
sub get_classname {
|
||||
# munge an OPCODE_MNEMONIC into a ClassName
|
||||
my ($enum_name) = @_;
|
||||
my @words = split ("_", $enum_name);
|
||||
my $cname = "";
|
||||
my $i = 0;
|
||||
my $word;
|
||||
|
||||
for $word (@words) {
|
||||
if ((length($word) == 2) && ($i != 0)) {
|
||||
$cname .= uc($word);
|
||||
} else {
|
||||
$cname .= uc(substr($word, 0, 1)) . lc(substr($word, 1));
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $cname;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# fields are:
|
||||
#
|
||||
|
|
Загрузка…
Ссылка в новой задаче