סביבת זמן הריצה

Preview:

DESCRIPTION

סביבת זמן הריצה. כשאת אומרת x , למה את מתכוונת?. מה תדפיס התוכנית הבאה? var x: int; function foo(): int is return x; function bar(): int is var x:int; x = 1; return foo(); procedure main() is x = 0; print bar();. תוצאות אפשריות. התוכנית תדפיס 0 - PowerPoint PPT Presentation

Citation preview

סביבת זמן הריצה

, למה את מתכוונת?xכשאת אומרת

מה תדפיס התוכנית הבאה?

var x: int;

function foo(): int is return x;

function bar(): int is var x:int;

x = 1;

return foo();

procedure main() is x = 0;

print bar();

תוצאות אפשריות

0התוכנית תדפיס C ,פסקל ,C++, Java ורוב השפות

ה"מודרניות"

1התוכנית תדפיס LISP, APL, Perl... ,(לפעמים)

התוכנית תדפיס הודעת שגיאהPHP

מה ההבדל?

Scoping איך מחליטים – לאיזו כתובת בזכרון

מתייחס כל שם

dynamic scopingחריג –

static scoping ההכרזה – המקיפה הקרובה ביותר

main ( )

{

int a = 0 ;

int b = 0 ;

{

int b = 1 ;

{

int a = 2 ;

printf (“%d %d\n”, a, b)

}

{

int b = 3 ;

printf (“%d %d\n”, a, b) ;

}

printf (“%d %d\n”, a, b) ;

}

printf (“%d %d\n”, a, b) ;

}

B0

B1

B3B3

B2

dynamic scopingמימוש

לכל שם יש מחסנית (ריקה בפוטנציה). אפשר לנהלhash table.של שמות

שבו מוגדר משתנה: דחיפה של ההגדרה scopeכניסה ל-למחסנית.

מהמחסנית.pop שבו מוגדר משתנה: scopeיציאה מ-

גישה למשתנה: לפי ראש המחסנית.

האם אפשר לגלות גישות לא חוקיות (למשתנים לא קיימים) בזמן קומפילציה?

מה לגבי בדיקות טיפוסים?

static scopingמימוש

המשתנה אליו מתייחס הקוד ידוע בזמן קומפילציה.

לכן, ידועה גם הכתובת שבה שוכן המשתנה. הקצאת כתובות למשתנים היא חלק מתהליך

הקומפילציה.

אין שגיאות זמן-ריצה של "גישה למשתנה לא קיים".

static scopingמימוש

למשל:

var x: int;

function foo(): int is return x;

function bar(): int is var x:int;

x = 1;

return foo();

procedure main() is x = 0;

print bar();

כתובת שהוקצתה עבורו

שם

432234x(גלובלי)

432238x בתוך) bar(

static scopingמימוש

בדוגמה הבאה?bרק רגע: מה הכתובת של המשתנה

procedure fib(n:int) is var a:int;

var b:int;

if (n ≤ 1) return 0;

a = fib(n – 1);

b = fib(n – 2);

return a + b;

procedure main() is print fib(5);

.dynamic scopingשימו לב לכך שהבעיה לא קיימת במקרה של

גורמים המשפיעים על ארגון הזיכרון ע"י המהדר

האם פרוצדורות יכולות להיות רקורסיביות?

מה קורה לערכים של משתנים מקומיים עם סגירת ההפעלה הנוכחית של הפרוצדורה?

האם פרוצדורות יכולות להתייחס למשתנים לא מקומיים?

איך מועברים פרמטרים?

האם אפשר להעביר פרוצדורות כפרמטרים?

האם אפשר להקצות זיכרון באופן דינאמי? האם יש צורך לשחררו באופן דינאמי?

ארגון הזיכרון

code

static data

stack

heap

גודל זה ידוע בזמן קומפילציה

המחסנית גדלה וקטנה בזמן ריצה. היא activation(מכילה רשומות הפעלה

records(

הקצאת זיכרון בשליטת התוכנית

top of stack →

משתניםגלובליים

הכתובות של משתנים מקומיים

בכל כניסה לפרוצדורה, מוסיפים רשומת הפעלה למחסנית

בכל יציאה, מסירים רשומת הפעלה

משתנים מקומיים הם חלק מרשומת ההפעלה של כל פרוצדורה

S-aכתובת של משתנה מקומי: Sהיא כתובת ראש המחסנית a של המשתנה המקומיהיחסית היא הכתובת !הכתובות היחסיות נקבעות בזמן קומפילציה

fibדוגמה: הפעלה של

… other parts of activation record …

n (addr: S-20)a (addr: S-16)b (addr: S-12)

… other parts of activation record …

… other parts of activation record …

n (addr: S-20)a (addr: S-16)b (addr: S-12)

… other parts of activation record …

… other parts of activation record …

n (addr: S-20)a (addr: S-16)b (addr: S-12)

… other parts of activation record …

פרמטרים הםמשתנים מקומיים.

מה עוד יש ברשומת הפעלה?

returned valueערך מוחזר; לעיתים -- רגיסטר

actual parametersפרמטרים אקטואליים; לעיתים רגיסטרים

optional control linkמצביע לרשומת ההפעלה של הפרוצדורה הקוראת

optional access linkדרוש לפעמים על מנת להתייחס למשתנים לא מקומיים

)display(

saved machine statusמצב המכונה לפני התחלת עבודתה של הפרוצדורה הנוכחית

local dataמשתים מקומיים

temporariesערכי ביניים

מה עוד יש ברשומת הפעלה?

ערך החזרה מהפונקציה – במקרים רבים נשמר ברגיסטר ולא על המחסנית

בשפות תכנות מסוימות, כתלות בסוג ערך לא)struct ישמר ברגיסטר, intהחזרה (

הפרמטרים האקטואליים (ערכי הפרמטרים) מוכנסים למחסנית על-ידי הפונקציה הקוראת

כתובת החזרהמצב המכונה – מכיל בעיקר את

ערכי ביניים – למעשה, משתנים מקומיים שהקומפיילר יצר

מי יוצר את רשומת ההפעלה?

הצד בחלקה על-ידי נוצרתרשומת ההפעלה הקורא

הצד הנקרא... ובחלקה על-ידי

בחלקה על-ידי מוסרת מהזכרוןרשומת ההפעלה הצד הנקרא

הצד הקורא... ובחלקה על-ידי

האם באופן סימטרי? כלומר, האם כל צד מסיר מהזכרון את מה שהוא

יצר?

פרוצדורות בתוך פרוצדורות: פסקל

) מוגדרת כאוסף של שגרות programבפסקל, תוכנית ()procedure ו/או function(

לכל שגרה יכולות להיות תת-שגרות

scopesכל תת-שגרה יכולה לגשת לכל מה שהוגדר ב-המכילים אותה

בשיטת top-downהרעיון: תכנון תוכנה מתבצע stepwise refinement

Niklaus Wirth, “Program Development by Stepwise Refinement”, Communications of the ACM, April 1971.

פרוצדורות בתוך פרוצדורות: פסקל

So, naturalists observe, a flea

Hath smaller fleas that on him prey;

And these have smaller fleas to bite 'em

And so proceed ad infinitium

Jonathan Swift (1667-1745)

פרוצדורות בתוך פרוצדורות: פסקל

program p;

var x: Integer;

procedure a

var y: Integer;procedure b begin…b… end;

function c

var z: Integer;procedure d begin…d… end;

begin…c…end;

begin…a… end;

begin…p… end.

מה הכתובת של משתנהy מתוך הפרוצדורה d?

סדרת קריאות אפשרית:p→a→a→c→b→c→d

פרוצדורות בתוך פרוצדורות: פסקל

ברשומת ההפעלהaccess linksהפתרון:

מכיל מחוון לרשומת ההפעלה access linkכל של רמת הקינון שמעליו

-למשל, הaccess link של d מכיל מחוונים .cלרשומת ההפעלה של

נבנים בזמן ריצהaccess linksה-

שצריך "לטייל" ידוע בזמן linksמספר ה-קומפילציה

פרוצדורות בתוך פרוצדורות: פסקל

a

a

c

b

c

d

y

y

z

z

בעיות מודרניות: תכנות מונחה-עצמים

class A {

virtual void foo() { print “A”; }

}

class B extends A {

virtual void foo() { print “B”; }

}

main() {

A myA = (…) ? new A() : new B();

myA.foo();

} לאיזו כתובת פונה הקריאה הזו?

Dynamic Binding

בשפות "רגילות", הקישור בין קריאה לפונקציה לבין כתובת הפונקציה ידוע בזמן קומפילציה

static binding

בשפות מונחות-עצמים, הקישור (עבור פונקציות .בזמן ריצההמכונות "מתודות וירטואליות") מתבצע

, והוא חלק ממנגנון dynamic bindingמנגנון זה נקרא .פולימורפיזםהמכונה

פולימורפיזם מאפשר למשתנה להיות, בזמן ריצה, שייך לאחד מכמה טיפוסים שונים.

לכל הטיפוסים הללו יש "אב קדמון" משותף, שהואהטיפוס בו הוגדר המשתנה האמור.

למה זה טוב?

class Shape {int x; int y;virtual moveBy(dX, dY) { … };virtual draw();

}

class Square extends Shape {int size;virtual draw() { … }

}

class Circle extends Shape {int radius;virtual draw() { … }

}

function animate(Shape s) {

for (int i = 0 ; i < 10; i++)

s.moveBy(1,1);

s.draw();

}

}

dynamic bindingמימוש

אפשר לחשוב על אובייקט כעל רשומה

הרשומה מכילה שדות עם נתונים בכל רשומה, הערך של שדה מסוים (למשלx או

yנמצא בהיסט קבוע מתחילת הרשומה בזכרון (

האובייקט הוא רשומה המכילה גם מחוונים לפונקציות

בכל אובייקט, המחוון לפונקציה מסוימת נמצאבהיסט קבוע מתחילת האובייקט בזכרון.

dynamic bindingמימוש

אובייקטים בזמן ריצה

קוד (בזכרון בזמן ריצה, כתובות ידועות כבר בזמן קומפילציה)

Shape::moveBy Circle::draw Square::draw

Circle

x : int = 17

y : int = 24

radius : int = 9

moveBy : addr

draw : addr

Square

x : int = 76

y : int = 39

size : int = 23

moveBy : addr

draw : addr

Circle

x : int = 73

y : int = 5

radius : int = 76

moveBy : addr

draw : addr

VMTמימוש מעשי יותר:

המימוש הנאיבי מאוד בזבזני בזכרון כלCircleמכיל את אותה טבלה בדיוק (המון מתודות) הטבלה יכולה להיות ענקית

Virtual Method Tableמימוש יעיל יותר: טבלה אחת המשותפת לכל האובייקטים מכל

סוג כל אובייקט רק מצביע לטבלה הרלוונטית

לטיפוס שלו

מה המחיר?

אופטימיזציות

static ב-dynamic bindingמתי ניתן להחליף binding?

מדוע זה כדאי?

Recommended