1 / 28

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

סביבת זמן הריצה. כשאת אומרת 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

tahir
Download Presentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

  2. כשאת אומרת 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();

  3. תוצאות אפשריות • התוכנית תדפיס 0 • C, פסקל, C++, Java ורוב השפות ה"מודרניות" • התוכנית תדפיס 1 • LISP, APL, Perl (לפעמים), ... • התוכנית תדפיס הודעת שגיאה • PHP

  4. מה ההבדל? 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) ; } • Scoping – איך מחליטים לאיזו כתובת בזכרון מתייחס כל שם • dynamic scoping – חריג • static scoping – ההכרזה המקיפה הקרובה ביותר B2 B0 B1 B3 B3

  5. מימוש dynamic scoping • לכל שם יש מחסנית (ריקה בפוטנציה). • אפשר לנהל hash table של שמות. • כניסה ל-scope שבו מוגדר משתנה: דחיפה של ההגדרה למחסנית. • יציאה מ-scope שבו מוגדר משתנה: pop מהמחסנית. • גישה למשתנה: לפי ראש המחסנית. • האם אפשר לגלות גישות לא חוקיות (למשתנים לא קיימים) בזמן קומפילציה? • מה לגבי בדיקות טיפוסים?

  6. מימוש static scoping • המשתנה אליו מתייחס הקוד ידוע בזמן קומפילציה. • לכן, ידועה גם הכתובת שבה שוכן המשתנה. • הקצאת כתובות למשתנים היא חלק מתהליך הקומפילציה. • אין שגיאות זמן-ריצה של "גישה למשתנה לא קיים".

  7. מימוש 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();

  8. מימוש 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.

  9. גורמים המשפיעים על ארגון הזיכרון ע"י המהדר • האם פרוצדורות יכולות להיות רקורסיביות? • מה קורה לערכים של משתנים מקומיים עם סגירת ההפעלה הנוכחית של הפרוצדורה? • האם פרוצדורות יכולות להתייחס למשתנים לא מקומיים? • איך מועברים פרמטרים? • האם אפשר להעביר פרוצדורות כפרמטרים? • האם אפשר להקצות זיכרון באופן דינאמי? האם יש צורך לשחררו באופן דינאמי?

  10. ארגון הזיכרון משתנים גלובליים גודל זה ידוע בזמן קומפילציה המחסנית גדלה וקטנה בזמן ריצה. היא מכילה רשומות הפעלה (activation records) top of stack → הקצאת זיכרון בשליטת התוכנית

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

  12. דוגמה: הפעלה של 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 …

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

  14. מה עוד יש ברשומת הפעלה? • ערך החזרה מהפונקציה – במקרים רבים נשמר ברגיסטר ולא על המחסנית • בשפות תכנות מסוימות, כתלות בסוג ערך החזרה (int ישמר ברגיסטר, struct לא) • הפרמטרים האקטואליים (ערכי הפרמטרים) מוכנסים למחסנית על-ידי הפונקציה הקוראת • מצב המכונה – מכיל בעיקר את כתובת החזרה • ערכי ביניים – למעשה, משתנים מקומיים שהקומפיילר יצר

  15. מי יוצר את רשומת ההפעלה? • רשומת ההפעלה נוצרת בחלקה על-ידי הצד הקורא • ... ובחלקה על-ידי הצד הנקרא • רשומת ההפעלה מוסרת מהזכרון בחלקה על-ידי הצד הנקרא • ... ובחלקה על-ידי הצד הקורא • האם באופן סימטרי? • כלומר, האם כל צד מסיר מהזכרון את מה שהוא יצר?

  16. פרוצדורות בתוך פרוצדורות: פסקל • בפסקל, תוכנית (program) מוגדרת כאוסף של שגרות (procedure ו/או function) • לכל שגרה יכולות להיות תת-שגרות • כל תת-שגרה יכולה לגשת לכל מה שהוגדר ב-scopes המכילים אותה • הרעיון: תכנון תוכנה מתבצע top-down בשיטת stepwise refinement Niklaus Wirth, “Program Development by Stepwise Refinement”, Communications of the ACM, April 1971.

  17. פרוצדורות בתוך פרוצדורות: פסקל 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)

  18. פרוצדורות בתוך פרוצדורות: פסקל סדרת קריאות אפשרית: p→a→a→c→b→c→d 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?

  19. פרוצדורות בתוך פרוצדורות: פסקל • הפתרון: access links ברשומת ההפעלה • כל access link מכיל מחוון לרשומת ההפעלה של רמת הקינון שמעליו • למשל, ה-access link של d מכיל מחוונים לרשומת ההפעלה של c. • ה-access links נבנים בזמן ריצה • מספר ה-links שצריך "לטייל" ידוע בזמן קומפילציה

  20. פרוצדורות בתוך פרוצדורות: פסקל a y a y c z b c z d

  21. בעיות מודרניות: תכנות מונחה-עצמים 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(); } לאיזו כתובת פונה הקריאה הזו?

  22. Dynamic Binding • בשפות "רגילות", הקישור בין קריאה לפונקציה לבין כתובת הפונקציה ידוע בזמן קומפילציה • static binding • בשפות מונחות-עצמים, הקישור (עבור פונקציות המכונות "מתודות וירטואליות") מתבצע בזמן ריצה. • מנגנון זה נקרא dynamic binding, והוא חלק ממנגנון המכונה פולימורפיזם. • פולימורפיזם מאפשר למשתנה להיות, בזמן ריצה, שייך לאחד מכמה טיפוסים שונים. • לכל הטיפוסים הללו יש "אב קדמון" משותף, שהוא הטיפוס בו הוגדר המשתנה האמור.

  23. למה זה טוב? 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(); } }

  24. מימוש dynamic binding • אפשר לחשוב על אובייקט כעל רשומה • הרשומה מכילה שדות עם נתונים • בכל רשומה, הערך של שדה מסוים (למשל x או y) נמצא בהיסט קבוע מתחילת הרשומה בזכרון • האובייקט הוא רשומה המכילה גם מחוונים לפונקציות • בכל אובייקט, המחוון לפונקציה מסוימת נמצא בהיסט קבוע מתחילת האובייקט בזכרון.

  25. מימוש dynamic binding • אובייקטים בזמן ריצה • קוד (בזכרון בזמן ריצה, כתובות ידועות כבר בזמן קומפילציה) Shape::moveBy Circle::draw Square::draw

  26. מימוש מעשי יותר: VMT • המימוש הנאיבי מאוד בזבזני בזכרון • כל Circle מכיל את אותה טבלה בדיוק • הטבלה יכולה להיות ענקית (המון מתודות) • מימוש יעיל יותר: Virtual Method Table • טבלה אחת המשותפת לכל האובייקטים מכל סוג • כל אובייקט רק מצביע לטבלה הרלוונטית לטיפוס שלו • מה המחיר?

  27. מימוש dynamic binding על-ידי VMT • אובייקטים בזמן ריצה • קוד (בזכרון בזמן ריצה, כתובות ידועות כבר בזמן קומפילציה) Shape::moveBy Circle::draw Square::draw

  28. אופטימיזציות • מתי ניתן להחליף dynamic binding ב-static binding? • מדוע זה כדאי?

More Related