_Blog

Post Thumbnail

জাভাস্ক্রিপ্ট ইঞ্জিন - জাভাস্ক্রিপ্ট বিহাইন্ড দা সিন

April 25, 2023 by Shahriar Ahmed Shovon

জাভাস্ক্রিপ্ট বিহাইন্ড দা সিন সিরিজের দ্বিতীয় পর্বে আলোচনা করব জাভাস্ক্রিপ্ট ইঞ্জিন নিয়ে। আলোচনা চলতে চলতে আবিষ্কার করব আমরা কম্পাইলেশনইন্টারপ্রেটেশন এর পার্থক্য বুঝে ফেলেছি এবং সেই সাথে জাস্ট ইন টাইম কম্পাইলেশন নামের নতুন একটা সিস্টেম কে খুঁজে পেয়েছি। তাহলে চলুন শুরু করা যাক

আমরা মোটামুটি অল্পবিস্তর জানি যে জাভাস্ক্রিপ্ট এখন আর কোন স্ক্রিপ্টিং ল্যাঙ্গুয়েজ না যা শুধু ব্রাউজারে চলে বরং এখন জাভাস্ক্রিপ্ট রান টাইম এর কল্যাণে জাভাস্ক্রিপ্ট সম্পুর্ন একটা প্রোগ্রামিং ল্যাঙ্গুয়েজ হয়ে গেছে। যে প্রোগ্রামিং ল্যাঙ্গুয়েজ এখন কোর হার্ডওয়ারের সাথে কাজ করতে পারে। আর এই প্রতিটা জাভাস্ক্রিপ্ট রানটাইম এবং প্রতিটা ব্রাউজারের মধ্যেই আছে জাভাস্ক্রিপ্ট ইঞ্জিন। কিন্তু এই জাভাস্ক্রিপ্ট ইঞ্জিন জিনিসটা কি? কিভাবে কাজ করে?

এই উত্তর জানার আগে চলুন কম্পাইল, ইন্টারপ্রেটেশন আর JIT বা জাস্ট ইন টাইম কম্পাইল টা একটু বুঝে ফেলি।

কম্পাইল

Compile

কম্পাইল বোঝার জন্য উপরের ছবিটা ভালো ভাবে লক্ষ্য করি। এখানে সোর্স কোড হচ্ছে আমরা যে জাভাস্ক্রিপ্ট কোড লিখি সেটা। এরপরে সেই সোর্স কোড পুরোটা আমাদের কম্পাইলার রিড করে এবং কম্পাইল হয়ে মেশিন কোড হয়ে যায় [১] এবং সেই মেশিন কোড টা হয় পোর্টেবল। এবং সেই পোর্টেবল মেশিন কোড ফাইলটা এরপরে এক্সিকিউট হয়ে প্রোগ্রাম রান হয়।

অর্থাৎ এই ফাইল টা আপনি জাভাস্ক্রিপ্ট ছাড়াই দুনিয়ার সব কম্পিউটারেই রান করতে পারবেন। আমরা যেমন কোন সফটওয়ার রান করতে গেলে সেই সফটওয়ার কোন ল্যাঙ্গুয়েজ দিয়ে বানানো সেইটা নিয়ে মাথা ঘামায় না কারণ আমাদের কাছে পোর্টেবল ফাইল আছে যেটা অলরেডি কম্পাইল্ড হয়ে আছে। আর চাইলেই সেই কম্পাইল্ড ফাইল আমরা রান করতে পারি। কিন্তু যদি কম্পাইল্ড না থাকতো তবে যে ল্যাঙ্গুয়েজ দিয়ে বানানো সেই ল্যাঙ্গুয়েজ এর কম্পাইলার নিয়ে এসে সোর্স কোড কম্পাইল করে এরপরে রান করতে হতো। যায় হোক, তো সহজ ভাষায় এটাই হচ্ছে কম্পাইল।

এরপরে অনেকটা একই রকম আমাদের ইন্টারপ্রেটেশন।

ইন্টারপ্রেটেশন

Interpration

উপরের চিত্রটা দেখি। আগের কম্পাইল এর কাজটাও ইন্টারপ্রেটেশনের মতোই তবে আগের বার পুরো সোর্স কোড একবারে রিড হয়ে একবারে কম্পাইল হয়ে সেটা পোর্টেবল ফাইল হয়ে থাকত। যখন খুশি সেটা এক্সিকিউট করা যেত।

আর এখানে সোর্স কোড থেকে একটা করে লাইন রিড হয় এবং সেই লাইন কম্পাইল হয়ে এক্সিকিউট হয়। অর্থাৎ কোন পোর্টেবল ফাইল নেই। যখন আমরা প্রোগ্রাম রান করব বা এক্সিকিউট করব তখন সোর্স কোড কম্পাইল হবে লাইন বাই লাইন এবং এক্সিকিউট বা রান হবে লাইন বাই লাইন। এটাই মূলত ইন্টারপ্রেটেশন। এবং এজন্য ইন্টারপ্রেটেশন অনেক স্লো কারণ প্রত্যেক রান/এক্সিকিউট এর সময় কম্পাইল হতে হয়।

এবং আগের লেখায় বলেছিলাম সোর্স কোড থেকে কম্পাইলার এ যাওয়ার আগে সোর্স কোড গুলো টোকেন হিসেবে পার্স হয়ে AST ( Abstraction Syntax Tree ) ডেটা স্ট্রাকচারে স্টোর হয়। আর এই ধাপেই মূলত সিনট্যাক্স ইরোর গুলো ধরা পরে।

পিওর কম্পাইল ল্যাঙ্গুয়েজ যেমন সি/সি++ এর ক্ষেত্রে যদি কোন সিনট্যাক্স/গ্রামারের ইরোর হয় তাহলে প্রোগ্রাম কম্পাইল না হয়ে স্টপ হয়ে আপনাকে ইরোর দিবে, কম্পাইল আর হবেনা। যদি ১০০ লাইনের কোড হয় আর প্রথমের সব লাইন ঠিক থাকে কিন্তু ৯৭ নাম্বার লাইনে কোন ইরোর থাকে তাহলেও পুরো প্রোগ্রাম ওই একটা লাইনের ইরোরের জন্য স্টপ হয়ে যাবে। এটা কম্পাইলেশন এর ক্ষেত্রে।

অন্যদিকে ইন্টারপ্রেটেড ল্যাঙ্গুয়েজ যেমন জাভাস্ক্রিপ্ট, পাইথন এসব ল্যাঙ্গুয়েজ এ যেহেতু লাইন বাই লাইন রিড করে কম্পাইল করে এবং সেই কম্পাইল্ড লাইন রান হয়ে আবার পরের লাইন রিড হয়ে একই কাজ রিপিট হয় তাই এক লাইনের ভুলের জন্য পুরো প্রোগ্রাম থমকে যায়না। যেমন ৯৭ নাম্বার লাইনে যদি ইরোর থাকে তাহলে প্রথম ৯৬ লাইন ঠিকঠাক রান হবে কিন্তু ৯৭ নাম্বার লাইনে ইরোর দিয়ে ওখানে স্টপ হয়ে যাবে। আপাত দৃষ্টিতে এটা সুবিধা মনে হলেও পারফরম্যান্সে ইফেক্ট পড়ে, যার কারণে পিওর কম্পাইল্ড ল্যাঙ্গুয়েজ ইন্টারপ্রেটেড ল্যাঙ্গুয়েজ থেকে ফাস্ট হয়।

কিন্তু জাভাস্ক্রিপ্ট আগে শুধু ইন্টারপ্রেটেড ল্যাঙ্গুয়েজ থাকলেও এখন একে বলা হয় জাস্ট ইন টাইম কম্পাইল্ড ( JIT ) ল্যাঙ্গুয়েজ। কিন্তু কেন এমন নাম? আর পার্থক্যই বা কিসে?

জাস্ট ইন টাইম কম্পাইল্ড

ওয়েল, JIT কে চিন্তা করা যায় কম্পাইল এবং ইন্টারপ্রেটেশনের মিক্স হিসেবে। নিচের চিত্রটা দেখুন।

JIT

এক্ষেত্রে যখন ই আমরা প্রোগ্রাম রান বা এক্সিকিউট করতে যাবো তখনই সোর্স কোড থেকে পুরো কোড একবারে রিড হয়ে কম্পাইল হয়ে এরপরে রান হবে। কিন্তু কম্পাইল হয়ে কোন পোর্টেবল ফাইল হয়ে থাকবেনা যেটা পরে রান করব। অর্থাৎ প্রতিবার রান হবার সময় একবার করে কম্পাইল হবে।

পিওর কম্পাইল থেকে পার্থক্য হচ্ছে, কম্পাইল হওয়ার পরে কোন পোর্টেবল ফাইল তৈরি হয়ে থাকেনা। আর ইন্টারপ্রেটেড থেকে পার্থক্য হচ্ছে লাইন বাই লাইন কম্পাইল হয়না বরং একবারেই পুরোটা কম্পাইল হয়।

এর সুবিধা হচ্ছে, ইন্টারপ্রেটেড ল্যাঙ্গুয়েজ থেকে এটা অনেকটা ফাস্ট হয়ে থাকে।

তো এই গেল সহজ করে, কম্পাইল, ইন্টারপ্রেটেশন এবং JIT এর বিহাইন্ড দা সিন। যদিও এখানে বোঝানোর সুবিধার্তে আমি খুব বেশিই সহজ সরল করে ব্যাখ্যা করেছি। যেমন সোর্স কোড থেকে কম্পাইল হওয়ার মধ্যে অনেক কমপ্লেক্স কাজ হয় যেগুলো এখানে ব্যাখ্যা করা হয়নি। আগ্রহী হলে অবশ্যই গুগল সার্চ করে জেনে নিবেন, এবং আশা করি আপনি আগ্রহী।

যায় হোক, এটা তো গেল ওভারোল প্রোগ্রাম ল্যাঙ্গুয়েজ হিসেবে কিভাবে কাজ হয়। কিন্তু স্পেশালি জাভাস্ক্রিপ্টের ক্ষেত্রে কিভাবে কাজ হয়? চলুন এবার সেটাই দেখে নেই।

জাভাস্ক্রিপ্ট ইঞ্জিনের মধ্যে JIT

জাভাস্ক্রিপ্ট যখন ব্রাউজারে চলবে বা এক্সিকিউট হবে তখন নিশ্চয় একে মেশিন কোড এ কনভার্ট হতে হবে কারণ কম্পিউটার তো জাভাস্ক্রিপ্ট বুঝবে না, বুঝবে শুধু মেশিন কোড। আর এই জাভাস্ক্রিপ্ট থেকে মেশিন কোড এ কম্পাইল করার কাজটা এবং এক্সিকিউশন এর কাজ করে একটা জাভাস্ক্রিপ্ট ইঞ্জিন। জাভাস্ক্রিপ্ট ইঞ্জিন থাকে আমাদের ব্রাউজারের মধ্যে যেমন ক্রোমিয়াম ব্রাউজারের V8 ইঞ্জিন বা ফায়ারফক্সের Spider Monkey ইঞ্জিন। তবে শুধু এটূকুই না বরং আরো বিস্তর কাজ আছে। আলোচনা সহজ করার সুবিধার্তে বলা।

জাভাস্ক্রিপ্ট ইঞ্জিনে মূলত দুইটা পার্ট আছে, কল স্ট্যাক এবং হিপ। কলস্ট্যাকে জাভাস্ক্রিপ্ট সোর্স কোড রান হয় বা এক্সিকিউট হয় এবং হিপে জাভাস্ক্রিপ্ট অবজেক্ট গুলো মেমোরি হিসেবে স্টোর হয়। চলুন একটু সহজ করে বলি,

জাভাস্ক্রিপ্ট ইঞ্জিনের দুইটা পার্ট মূলত কল স্ট্যাক এবং হিপ। হিপের কাজ সম্পর্কে জানব যখন স্কোপ সম্বন্ধে জানব তখন। আপাতত কল স্ট্যাকের কাজটা ব্যাখ্যা করি। তবে তার আগে নিচের চিত্রটা একটু দেখে নিন

JIT Tree

উপরের চিত্রের সবগুলো স্টেপ সম্পন্ন হয় জাভাস্ক্রিপ্ট ইঞ্জিনের মধ্যে। প্রথমে সোর্স কোড থেকে টোকেন আকারে পার্স হয় এবং AST ডেটা স্ট্রাকচারে স্টোর হয়।

যেমন নিচের এই কোড টুকুর জন্য AST স্ট্রাকচার হবে নিচের স্ক্রিনশটের মতো

1
const myName : "Shahriar Ahmed Shovon";

AST ডেটা স্ট্রাকচার টা দেখতে অনেকটা এরকমঃ

AST Tree

ব্যাখ্যায় যাচ্ছি না, আপনি নিজেই একটু এক্সপ্লোর করলেই বুঝতে পারবেন। ( কোড এর AST/JSON স্ট্রাকচার দেখার জন্য https://astexplorer.net/ )

ওকে, এখন পার্সিং এর পরে কোড হবে কম্পাইল্ড। এবং আগেই বলেছি এই পার্সিং এর সময় ই কিন্তু সিনট্যাক্স ইরোর গুলো ধরা হয়।

যায় হোক, কম্পাইল হওয়ার পরে সঙ্গে সঙ্গে এক্সিকিউট হবে, এবং এক্সিকিউশন হবে ইঞ্জিনের কল স্ট্যাকে। কিভাবে এক্সিকিউট হবে সেটা এর পরের পর্বের আলোচনা। যেহেতু এটা জাস্ট ইন টাইম কম্পাইল তাই কম্পাইল হওয়ার সঙ্গে সঙ্গেই এক্সিকিউট হয়। ( মডার্ন জাভাস্ক্রিপ্ট JIT স্টাইলেই চলে )

এরপরে এক্সিকিউট হয়েই কিন্তু ইঞ্জিনের কাজ শেষ না, বরং আরো এক্সট্রা একটা স্টেপ আছে। সেটা হল অপ্টিমাইজ। কম্পাইল থেকে এক্সিকিউট হবার পরে আমাদের কে রেজাল্ট দেখায় এবং সঙ্গে সঙ্গে ব্যাকগ্রাউন্ডে আবার কম্পাইল শুরু হয়ে যায়। আগের কম্পাইল টা ছিল আমাদের সোর্স কোড কোন অপ্টিমাইজ না করেই র' কোড কম্পাইল করা।

কিন্তু এবারে এক্সিকিউট হওয়ার পরে আমাদের সোর্স কোড বা পার্সড কোড অপ্টিমাইজ হবে এবং অপ্টিমাইজ হবার পরে সেই অপ্টিমাইজড কোড আবার কম্পাইলেশন স্টেপে গিয়ে কম্পাইল হবে। কম্পাইল হওয়া রেজাল্ট এরপরে আমাদের আগের যে এক্সিকিউটেড রেজাল্ট আছে সেটাকে রিপ্লেস করে দিবে। অর্থাৎ আগের আনঅপ্টিমাইজড এক্সিকিউশন কে অপ্টিমাইজড এক্সিকিউশনে রিপ্লেস করবে।

কিন্তু আবার কেন কম্পাইল হল? ওয়েল প্রথমেই অপ্টিমাইজ করে কম্পাইল হতে টাইম লেগে যেত কিন্তু ফাস্ট করার জন্য আনপ্টিমাইজড কোড আগে কম্পাইল হয়ে এক্সিকিউট হয়ে যায় এবং এরপরে আস্তে ধীরে অপ্টিমাইজড এক্সিকিউশন সম্পন্ন হয়। আর এই অপটিমাইজেশন কিন্তু থ্রেডকে ব্লক করেনা, বরং অন্য সেপারেট থ্রেডের মাধ্যমে কাজ করে। এই ব্যাপারে বিস্তারিত জানতে গুগল করুন।

শেষের কথা

এভাবেই মূলত সোর্স কোড থেকে এক্সিকিউশন অব্ধি জাভাস্ক্রিপ্ট তার ইঞ্জিনের মধ্যে কাজ করে। অনেক সাদামাটা করে বোঝানো হয়েছে বাস্তবে আরো অনেক কমপ্লেক্স। নেক্সট পর্বে আমরা জানব জাভাস্ক্রিপ্ট রানটাইম সম্বন্ধে।

রেফারেন্সঃ

[১] কম্পাইল এর কাজ অনেক বিস্তর। এখানে শুধু প্রয়োজনীয় বোঝার অংশটুকু দেয়া হয়েছে। আগ্রহীরা গুগল করে বিস্তারিত জেনে নিতে পারেন।