Files

291 lines
5.7 KiB
JavaScript

// SPDX-FileCopyrightText: 2019-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Extra from './extra.js';
import Base from './base.js';
const _x86_stret = {
'32': {
returns: 'rdi',
receiver: 'eax',
selector: 'ecx',
args: ['edx', 'ecx', 'r8d', 'r9d']
},
'64': {
returns: 'rdi',
receiver: 'rsi',
selector: 'rdx',
args: ['rcx', 'r8', 'r9', 'r10']
}
};
const _x86 = {
'32': {
receiver: 'eax',
selector: 'ecx',
returns: 'eax',
args: ['edx', 'ecx', 'r8d', 'r9d']
},
'64': {
receiver: 'rdi',
selector: 'rsi',
returns: 'rax',
args: [
['edx', 'rdx'],
['ecx', 'rcx'],
['r8d', 'r8'],
['r9d', 'r9']
]
}
};
const _ppc = {
receiver: 'r3',
selector: 'r4',
returns: 'r3',
args: ['r5', 'r6', 'r7', 'r8']
};
const _ppc_stret = {
returns: 'r3',
receiver: 'r4',
selector: 'r5',
args: ['r6', 'r7', 'r8', 'r9']
};
const _arm = {
'16': {
receiver: 'r0',
selector: 'r1',
returns: 'r0',
args: ['r2', 'r3', 'r4', 'r5']
},
'32': {
receiver: 'r0',
selector: 'r1',
returns: 'r0',
args: ['r2', 'r3', 'r4', 'r5']
},
'64': {
receiver: 'x0',
selector: 'x1',
returns: 'x0',
args: ['x2', 'x3', 'x4', 'x5']
}
};
const _arm_stret = {
'16': {
receiver: 'r1',
selector: 'r2',
returns: 'r0',
args: ['r3', 'r4', 'r5', 'r6']
},
'32': {
receiver: 'r1',
selector: 'r2',
returns: 'r0',
args: ['r3', 'r4', 'r5', 'r6']
}
};
const _object_c_registers = {
'x86': {
'32': ['rdi', 'rsi', 'rdx', 'rcx', 'r8', 'r9'],
'64': ['edi', 'esi', 'edx', 'ecx', 'r8d', 'r9d'],
},
'ppc': {
'32': ['r3', 'r4', 'r5', 'r6', 'r7', 'r8'],
'64': ['r3', 'r4', 'r5', 'r6', 'r7', 'r8'],
},
'arm': {
'16': ['r0', 'r1', 'r2', 'r3', 'r4', 'r5'],
'32': ['r0', 'r1', 'r2', 'r3', 'r4', 'r5'],
'64': ['x0', 'x1', 'x2', 'x3', 'x4', 'x5'],
}
};
const _object_c_class_methods = {
objc_msgSend: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSend_fpret: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSend_noarg: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSendSuper: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSendSuper2: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSend_stret: {
'x86': _x86_stret,
'ppc': {
'32': _ppc_stret,
'64': _ppc_stret
},
'arm': _arm_stret
},
objc_msgSendSuper_stret: {
'x86': _x86_stret,
'ppc': {
'32': _ppc_stret,
'64': _ppc_stret
},
'arm': _arm_stret
},
objc_msgSendSuper2_stret: {
'x86': _x86_stret,
'ppc': {
'32': _ppc_stret,
'64': _ppc_stret
},
'arm': _arm_stret
},
/* fixup */
objc_msgSend_fixup: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSend_fpret_fixup: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSendSuper2_fixup: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSend_stret_fixup: {
'x86': _x86_stret,
'ppc': {
'32': _ppc_stret,
'64': _ppc_stret
},
'arm': _arm_stret
},
objc_msgSendSuper2_stret_fixup: {
'x86': _x86_stret,
'ppc': {
'32': _ppc_stret,
'64': _ppc_stret
},
'arm': _arm_stret
}
};
const _object_c_block_methods = {
objc_autoreleasePoolPush: function(instr, context, instructions) {
if (!context.object_c.autorelease) {
context.object_c.autorelease = [instr];
} else {
context.object_c.autorelease.push(instr);
}
instr.customflow = '@' + Global().printer.theme.flow('autoreleasepool');
return Base.nop();
},
objc_autoreleasePoolPop: function(instr, context, instructions) {
context.object_c.autorelease.pop().jump = instr.location;
return Base.nop();
},
objc_retainAutoreleasedReturnValue: function() {
return Base.nop();
},
objc_release: function() {
var arch = Global().evars.arch;
var bits = Global().evars.archbits.toString();
return Base.objc_call(_object_c_registers[arch][bits][0], 'release');
},
objc_retain: function() {
var arch = Global().evars.arch;
var bits = Global().evars.archbits.toString();
return Base.objc_call(_object_c_registers[arch][bits][0], 'retain');
},
};
export default {
arguments: function(callname) {
callname = Extra.replace.call(callname);
var arch = Global().evars.arch;
var bits = Global().evars.archbits.toString();
return _object_c_class_methods[callname][arch][bits].args.slice();
},
returns: function(callname) {
callname = Extra.replace.call(callname);
var arch = Global().evars.arch;
var bits = Global().evars.archbits.toString();
return _object_c_class_methods[callname][arch][bits].returns;
},
receiver: function(callname) {
callname = Extra.replace.call(callname);
var arch = Global().evars.arch;
var bits = Global().evars.archbits.toString();
return _object_c_class_methods[callname][arch][bits].receiver;
},
selector: function(callname) {
callname = Extra.replace.call(callname);
var arch = Global().evars.arch;
var bits = Global().evars.archbits.toString();
return _object_c_class_methods[callname][arch][bits].selector;
},
handle_others: function(callname, instr, context, instructions) {
if (_object_c_block_methods[callname]) {
if (!context.object_c) {
context.object_c = {};
}
return _object_c_block_methods[callname](instr, context, instructions);
}
return null;
},
is_class_method: function(callname) {
callname = Extra.replace.call(callname);
return !!_object_c_class_methods[callname];
},
is: function(callname) {
callname = Extra.replace.call(callname);
return callname.startsWith('objc_') && (
_object_c_block_methods[callname] ||
_object_c_class_methods[callname]
);
}
};