1 Programming Language အသစ္ထြင္ၾကမယ္ (၇) 13th May 2009, 10:06 pm
sHa92
Founder
Function Support (ေနာက္ဆက္တြဲ)
Note: ေရွ႕က Function Support Chapter ဟာေရးရင္းနဲ႔
ရွည္သြားတဲ့အတြက္ ျဖတ္လိုက္ရတာပါ။ တကယ္ေတာ့ function နဲ႔ပတ္သက္ၿပီးနဲနဲ
ေျပာစရာက်န္ပါေသးတယ္။ ဒါေၾကာင့္ ဒီ chapter ကိုဆက္လိုက္ရပါတယ္။
Virtual Function
ေအာက္က C code ကိုၾကည့္ပါ။
address ကိုဒီလိုပဲ pass လုပ္ၿပီး ေခၚလို႔ရတယ္။ ဒါေပမဲ့ ကၽြန္ေတာ္တို႔
Language မွာေခၚလို႔မရေသးဘူး။ ဘာေၾကာင့္လဲဆိုေတာ့ function ရဲ႔ address
ကို operand ေန pass လုပ္ေပးလိုက္လို႔။ ဒီအတြက္ function ရဲ႔ address ကို
stack ေပၚကေန ယူရင္ အေပၚက C code လိုေရးလို႔ရၿပီ။ ရွိၿပီးသား OP_CALL
ကိုမျပင္ေတာ့ဘဲ ဒီအတြက္ op-code အသစ္ထပ္ေရးရေအာင္။ သူ႕ကိုေတာ့
virtual_call လို႔ေခၚပါမယ္။ ဒါမွ static function ကိုေခၚခ်င္ရင္ ပို
efficient ျဖစ္တဲ့ call ကိုသုံးၿပီး dynamic function ေတြအတြက္
virtual_call ကိုသုံးၾကတာေပါ့။ Virtual call op-code အသစ္ကိုသြားေၾကညာပါ။
ၿပီးရင္ virtual call အတြက္ Virtual Machine ရဲ႔ Run() function မွာသြားေရးပါ။
ဘာမွေထြေထြထူးထူးမဟုတ္ပါဘူး။ Call ထဲကအတိုင္းေရးထားပါတယ္။ ဒါေပမဲ့
function address ကို operand 0 ကေနမယူဘဲ stack ေပၚက pop
လုပ္ယူလိုက္ပါတယ္။ ၿပီးရင္ Assembly code table ထဲပို virtual_call အတြက္
entry အသစ္သြားထည့္ပါအုံး။ ဒါမွ assembler က compile လုပ္လို႔ရမွာေလ။
အရင္ chapter က function စမ္းတဲ့ code ကို virtual call သုံးၿပီး ေရးၾကည့္ရေအာင္ပါ။
ဒီ assembly code မွာ function address ကို operand ေနမေပးဘဲ stack
ေပၚကေန pass လုပ္ေပးလိုက္ပါတယ္။ ဒါဆို function address ကိုသိမ္းခ်င္တဲ့
ေနရာမွာသိမ္း၊ ၿပီးရင္ stack ေပၚကို Push လုပ္တင္၊ ၿပီးရင္ virtual call
နဲ႔ေခၚလိုက္ရုံပါဘဲ။
ခုကၽြန္ေတာ္တို႕ language မွာ function ကို static ေကာ dynamic
ေကာေခၚလို႔ရေနပါၿပီ။ Dynamic function ေတြဟာ Object Oriented Programming
ထဲက polymorphism အတြက္လဲ အေရးပါပါတယ္။ ဘာေၾကာင့္လဲဆိုရင္ polymorphism
ဟာလဲ virtual table လို႔ေခၚတဲ့ function pointer ေတြသိမ္းထားတဲ့ table နဲ႔
အလုပ္လုပ္တာပါ။ ဒီလို function pointer ကို dynamically ေခၚတာဟာ၊ ရိုးရိုး
function ကို static ေခၚတာေလာက္ efficient မျဖစ္ဘူးဆိုတာ လက္ေတြ႕
ေတြ႕ၿပီမဟုတ္လား (ကၽြန္ေတာ္တို႔ language မွာဆို push_stack တခုပိုတယ္ေလ)။
ဒါေၾကာင့္ C++ လို programming ေတြမွာ virtual keyword ကို တကယ္လိုအပ္တဲ့
member function ေတြမွာသာေပးသင့္ပါတယ္။ မလိုအပ္ရင္ (polymorphism အရ
overwrite မလုပ္ရင္) static function အေနနဲ႔ေခၚတာဟာ ပိုၿပီး efficient
ျဖစ္ၿပီး ျမန္ေစပါတယ္။
Why Inline Function?
ဒီေနရာမွာ inline function အေၾကာင္းပါဆက္ ေျပာခ်င္ပါတယ္။ Function
တခုကို call လုပ္ရင္ သူ႔ထဲမွာေရးထားတဲ့ code ေတြတင္အလုပ္လုပ္တာ
မဟုတ္ပါဘူး။ call ကိုမေခၚခင္ parameter ေတြနဲ႔ local variable ေတြကို
stack ေပၚကိုတင္ရပါမယ္။ ၿပီးရင္ scope သတ္မွတ္ရပါမယ္။ ဒီအတြက္ scope
offset နဲ႔ scope size ေတြကိုလဲ stack ေပၚသြားသိမ္းရပါမယ္။ processing
လုပ္ရသလို၊ stack size လဲကုန္ပါတယ္။ Return ျပန္ရင္လဲ stack
ေပၚတင္ထားသမွ်ျပန္ pop လုပ္ရပါမယ္။ ဒါ function တခုေခၚဖို႔အတြက္
လုပ္ေဆာင္ခ်က္ေတြပါ။
တကယ္လို႔ function ထဲက code ကနဲနဲေလးဆိုရင္ coding ကို run ရတာထက္
function ေခၚဖို႔ prepare လုပ္ရတာ ပိုေနပါလိမ့္မယ္။ ေပၚ့ေစလိုလို႔
ေၾကာင္ရုပ္ထိုး ေဆးအတြက္ေလး ဆိုတဲ့ စကားပုံလို ျဖစ္ေနပါတယ္ [You must be registered and logged in to see this image.]
ဒီအတြက္ solution ကေတာ့ code ေတြကို function ထဲမထည့္ဘဲ
တိုက္ရိုက္ေရးျခင္းပါ။ C လို High-level language ေတြမွာေတာ့ Inline
Function လုပ္လိုက္ရင္ အဲဒီ function က တကယ့္ function မဟုတ္ေတာ့ဘဲ
compiler က function ထဲက code ေတြကို ေခၚတဲ့ေနရာမွာဘဲ တိုက္ရုိက္ေရးပါတယ္။
ဒီအတြက္ ေစာေစာက ေျပာတဲ့ function ေခၚဖို႔ prepare လုပ္ရတဲ့
အဆင့္ေတြမရွိေတာ့ပါဘူး။ ကၽြန္ေတာ္တို႕ assembly language မွာေတာ့ ဒီလို
luxury မ်ိဳးမရွိတဲ့အတြက္ လူကိုယ္တိုင္ကဘဲ code ေတြကို တိုက္ရိုက္ေရး
ရပါေတာ့မယ္။
Note: ေရွ႕က Function Support Chapter ဟာေရးရင္းနဲ႔
ရွည္သြားတဲ့အတြက္ ျဖတ္လိုက္ရတာပါ။ တကယ္ေတာ့ function နဲ႔ပတ္သက္ၿပီးနဲနဲ
ေျပာစရာက်န္ပါေသးတယ္။ ဒါေၾကာင့္ ဒီ chapter ကိုဆက္လိုက္ရပါတယ္။
Virtual Function
ေအာက္က C code ကိုၾကည့္ပါ။
- Code:
typedef void (*FuncPointer)(int param);
void MyFunc(int param) {
}
FuncPointer foo = MyFunc;
foo( 10 );
address ကိုဒီလိုပဲ pass လုပ္ၿပီး ေခၚလို႔ရတယ္။ ဒါေပမဲ့ ကၽြန္ေတာ္တို႔
Language မွာေခၚလို႔မရေသးဘူး။ ဘာေၾကာင့္လဲဆိုေတာ့ function ရဲ႔ address
ကို operand ေန pass လုပ္ေပးလိုက္လို႔။ ဒီအတြက္ function ရဲ႔ address ကို
stack ေပၚကေန ယူရင္ အေပၚက C code လိုေရးလို႔ရၿပီ။ ရွိၿပီးသား OP_CALL
ကိုမျပင္ေတာ့ဘဲ ဒီအတြက္ op-code အသစ္ထပ္ေရးရေအာင္။ သူ႕ကိုေတာ့
virtual_call လို႔ေခၚပါမယ္။ ဒါမွ static function ကိုေခၚခ်င္ရင္ ပို
efficient ျဖစ္တဲ့ call ကိုသုံးၿပီး dynamic function ေတြအတြက္
virtual_call ကိုသုံးၾကတာေပါ့။ Virtual call op-code အသစ္ကိုသြားေၾကညာပါ။
- Code:
enum OpCode {
OP_TALK,
..........................
..........................
OP_VIRTUAL_CALL,
OP_END
};
ၿပီးရင္ virtual call အတြက္ Virtual Machine ရဲ႔ Run() function မွာသြားေရးပါ။
- Code:
void Run(Program& program) {
while (true)
{
Instruction inst = program.Next();
switch (inst.code)
{
....................
....................
case OP_VIRTUAL_CALL:
{
int FuncAddress = program.PopStack();
program.PushStack( program.GetCurrentInstruction() );
program.SetInstruction( FuncAddress );
break;
}
....................
....................
}
}
}
ဘာမွေထြေထြထူးထူးမဟုတ္ပါဘူး။ Call ထဲကအတိုင္းေရးထားပါတယ္။ ဒါေပမဲ့
function address ကို operand 0 ကေနမယူဘဲ stack ေပၚက pop
လုပ္ယူလိုက္ပါတယ္။ ၿပီးရင္ Assembly code table ထဲပို virtual_call အတြက္
entry အသစ္သြားထည့္ပါအုံး။ ဒါမွ assembler က compile လုပ္လို႔ရမွာေလ။
အရင္ chapter က function စမ္းတဲ့ code ကို virtual call သုံးၿပီး ေရးၾကည့္ရေအာင္ပါ။
- Code:
000 put_stack 10
001 put_stack 5
002 scope 2
003 put_stack 13
004 virtual_call
005 num
006 put_stack 45
007 put_stack 32
008 scope 2
009 put_stack 13
010 virtual_call
011 num
012 end
// function A()
013 get_scope 0
014 get_scope 1
015 add
016 return
ဒီ assembly code မွာ function address ကို operand ေနမေပးဘဲ stack
ေပၚကေန pass လုပ္ေပးလိုက္ပါတယ္။ ဒါဆို function address ကိုသိမ္းခ်င္တဲ့
ေနရာမွာသိမ္း၊ ၿပီးရင္ stack ေပၚကို Push လုပ္တင္၊ ၿပီးရင္ virtual call
နဲ႔ေခၚလိုက္ရုံပါဘဲ။
ခုကၽြန္ေတာ္တို႕ language မွာ function ကို static ေကာ dynamic
ေကာေခၚလို႔ရေနပါၿပီ။ Dynamic function ေတြဟာ Object Oriented Programming
ထဲက polymorphism အတြက္လဲ အေရးပါပါတယ္။ ဘာေၾကာင့္လဲဆိုရင္ polymorphism
ဟာလဲ virtual table လို႔ေခၚတဲ့ function pointer ေတြသိမ္းထားတဲ့ table နဲ႔
အလုပ္လုပ္တာပါ။ ဒီလို function pointer ကို dynamically ေခၚတာဟာ၊ ရိုးရိုး
function ကို static ေခၚတာေလာက္ efficient မျဖစ္ဘူးဆိုတာ လက္ေတြ႕
ေတြ႕ၿပီမဟုတ္လား (ကၽြန္ေတာ္တို႔ language မွာဆို push_stack တခုပိုတယ္ေလ)။
ဒါေၾကာင့္ C++ လို programming ေတြမွာ virtual keyword ကို တကယ္လိုအပ္တဲ့
member function ေတြမွာသာေပးသင့္ပါတယ္။ မလိုအပ္ရင္ (polymorphism အရ
overwrite မလုပ္ရင္) static function အေနနဲ႔ေခၚတာဟာ ပိုၿပီး efficient
ျဖစ္ၿပီး ျမန္ေစပါတယ္။
Why Inline Function?
ဒီေနရာမွာ inline function အေၾကာင္းပါဆက္ ေျပာခ်င္ပါတယ္။ Function
တခုကို call လုပ္ရင္ သူ႔ထဲမွာေရးထားတဲ့ code ေတြတင္အလုပ္လုပ္တာ
မဟုတ္ပါဘူး။ call ကိုမေခၚခင္ parameter ေတြနဲ႔ local variable ေတြကို
stack ေပၚကိုတင္ရပါမယ္။ ၿပီးရင္ scope သတ္မွတ္ရပါမယ္။ ဒီအတြက္ scope
offset နဲ႔ scope size ေတြကိုလဲ stack ေပၚသြားသိမ္းရပါမယ္။ processing
လုပ္ရသလို၊ stack size လဲကုန္ပါတယ္။ Return ျပန္ရင္လဲ stack
ေပၚတင္ထားသမွ်ျပန္ pop လုပ္ရပါမယ္။ ဒါ function တခုေခၚဖို႔အတြက္
လုပ္ေဆာင္ခ်က္ေတြပါ။
တကယ္လို႔ function ထဲက code ကနဲနဲေလးဆိုရင္ coding ကို run ရတာထက္
function ေခၚဖို႔ prepare လုပ္ရတာ ပိုေနပါလိမ့္မယ္။ ေပၚ့ေစလိုလို႔
ေၾကာင္ရုပ္ထိုး ေဆးအတြက္ေလး ဆိုတဲ့ စကားပုံလို ျဖစ္ေနပါတယ္ [You must be registered and logged in to see this image.]
ဒီအတြက္ solution ကေတာ့ code ေတြကို function ထဲမထည့္ဘဲ
တိုက္ရိုက္ေရးျခင္းပါ။ C လို High-level language ေတြမွာေတာ့ Inline
Function လုပ္လိုက္ရင္ အဲဒီ function က တကယ့္ function မဟုတ္ေတာ့ဘဲ
compiler က function ထဲက code ေတြကို ေခၚတဲ့ေနရာမွာဘဲ တိုက္ရုိက္ေရးပါတယ္။
ဒီအတြက္ ေစာေစာက ေျပာတဲ့ function ေခၚဖို႔ prepare လုပ္ရတဲ့
အဆင့္ေတြမရွိေတာ့ပါဘူး။ ကၽြန္ေတာ္တို႕ assembly language မွာေတာ့ ဒီလို
luxury မ်ိဳးမရွိတဲ့အတြက္ လူကိုယ္တိုင္ကဘဲ code ေတြကို တိုက္ရိုက္ေရး
ရပါေတာ့မယ္။