Module: dfmc-flow-graph Author: Jonathan Bachrach, Keith Playford, and Paul Haahr Synopsis: computation classes -- dylan flow machine program graph nodes Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND define abstract dood-class () slot computation-source-location :: false-or() = parent-source-location(), init-keyword: source-location:; weak slot previous-computation :: false-or() = #f, reinit-expression: #f, init-keyword: previous-computation:; slot next-computation :: false-or() = #f, init-keyword: next-computation:; slot temporary :: false-or() = #f, init-keyword: temporary:; // ONLY NEED THIS IF BACK-END NEEDS TO KNOW VARIABLES IN SCOPE // slot lexical-environment :: false-or() = #f, // /* required- */ init-keyword: lexical-environment:; weak slot environment :: false-or(), reinit-expression: #f, required-init-keyword: environment:; weak slot computation-type = #f, reinit-expression: #f; end dood-class ; // Seal construction over the world. define sealed domain make (subclass()); define sealed domain initialize (); define sealed domain initialize-packed-slots (); // TODO: CORRECTNESS: Why this type-union? define generic computation-value (computation :: type-union(, )) => value; //// operations define generic next-computation (computation :: ) => (next); define generic next-computation-setter (next, computation :: ) => (next); define generic previous-computation (computation :: ) => (previous); define generic previous-computation-setter (previous, computation :: ) => (previous); //// initialization define inline method make-in-environment (env :: , class :: , #rest initargs, #key, #all-keys) let lambda-environment = lambda-environment(env); apply(make, class, environment: lambda-environment, // lexical-environment: env, initargs); end method; define inline method make-with-temporary (env :: , class :: , #rest initargs, #key temporary-class = , #all-keys) => (computation :: , temporary :: false-or()) let lambda-environment = lambda-environment(env); let computation = apply(make, class, environment: lambda-environment, // lexical-environment: env, initargs); let the-temporary = temporary-class & make(temporary-class, generator: computation, environment: lambda-environment); computation.temporary := the-temporary; values(computation, the-temporary) end method; // define method initialize // (computation :: , #key environment, #all-keys) // next-method(); // lambda-environment(lexical-environment(computation)) := environment; // end method; //// tracking define /* inline */ method make (class :: subclass(), #rest initargs, #key, #all-keys) => (object) let c = next-method(); register-used-temporaries(c); c end method; define inline function register-used-temporaries (c :: ) do-used-temporaries(method (t) add-user!(t, c) end, c); end; define class () constant slot temporary-getter :: , required-init-keyword: getter:; constant slot temporary-zetter :: , required-init-keyword: setter:; end class; define sealed domain make (singleton()); define sealed domain initialize (); define inline function do-used-temporaries (fn :: , c :: ) for (accessors :: in c.used-temporary-accessors) let getter = temporary-getter(accessors); let t = getter(c); if (instance?(t, )) for (t in t) fn(t); end; else fn(t); end; end; end; define inline function do-used-value-references (fn :: , c :: ) do-used-temporaries(fn, c) end function; //// //// Computation accessor methods //// define method used-temporary-accessors (c :: ) => (res :: ) #[] end method; define method class-used-temporary-accessors (c :: subclass()) => (res :: ) #[] end method; //// //// classes //// /// NOP define abstract class () end class ; define class () end class ; /// REFERENCE define class () end class; define class () /* constant */ slot referenced-binding :: , required-init-keyword: value:; end class; // define method referenced-binding (c :: ) // local-binding-in-requesting-library(c.%referenced-binding); // end method; define method computation-value (reference :: ) => (cv) reference.referenced-binding.binding-value-slot end method; define class (, ) end class; define class (, ) end class; define class (, ) constant slot referenced-binding :: , required-init-keyword: value:; end class; define class () slot reference-value, required-init-keyword: value:; end class; define class () end class; define /* inline */ method make (class == , #rest initargs, #key value, #all-keys) => (object) if (instance?(value, <&method>)) apply(make, , initargs) else next-method() end if end method; define class () end class; /// TODO: COULD SPLIT OUT COMPUTATION-SIGNATURE-VALUE define graph-class () slot computation-closure-method :: <&method>, required-init-keyword: method:; slot computation-init-closure :: false-or() = #f, init-keyword: init-closure:; temporary slot computation-signature-value = #f, init-keyword: signature:; end graph-class; define leaf packed-slots item-properties (, ) boolean slot computation-no-free-references? = #f; boolean slot closure-has-dynamic-extent? = #f; end packed-slots; define function method-top-level? (m :: <&method>) => (well? :: ) model-has-definition?(m) end function; define function computation-top-level-closure? (c :: ) => (res :: ) method-top-level?(computation-closure-method(c)) end function; define function computation-init-closure? (c :: ) => (res :: ) ~computation-init-closure(c) end function; define method initialize (computation :: , #rest all-keys, #key method: the-method, #all-keys) next-method(); apply(initialize-packed-slots, computation, all-keys); add-user!(the-method, computation); end method; define graph-class () slot computation-closure-method :: <&method>, required-init-keyword: method:; temporary slot computation-closure :: false-or(), required-init-keyword: closure:; end graph-class; /// ASSIGNMENT define abstract graph-class () temporary slot computation-value :: false-or(), required-init-keyword: value:; constant slot %assigned-binding :: , required-init-keyword: binding:; end graph-class; define function assigned-binding (c :: ) let binding = c.%assigned-binding; if (instance?(binding, )) local-binding-in-requesting-library(binding) else binding end end function; define abstract graph-class () end graph-class ; define graph-class () end graph-class ; // Only used in interactive mode... define graph-class () end graph-class ; define graph-class () end graph-class ; define graph-class () temporary slot computation-test-value, init-keyword: test-value:; end graph-class ; /// TYPE REFERENCE define class () constant slot %typed-binding :: , required-init-keyword: binding:; end class; define method typed-binding (c :: ) let binding = c.%typed-binding; if (instance?(binding, )) local-binding-in-requesting-library(binding) else binding end end method; /// TYPE ASSIGNMENT // This is distinct from just to be safe since we're // changing the sense of the assigned-binding slot, defining its // type rather than its value. define abstract graph-class () temporary slot computation-value :: false-or(), required-init-keyword: value:; constant slot %typed-binding :: , required-init-keyword: binding:; end graph-class; define method typed-binding (c :: ) let binding = c.%typed-binding; if (instance?(binding, )) local-binding-in-requesting-library(binding) else binding end end method; define graph-class () end graph-class; // Only used in interactive mode... define graph-class () end graph-class; define abstract graph-class () end graph-class; /// TEMPORARY-TRANSFER define abstract graph-class () temporary slot computation-value :: false-or(), required-init-keyword: value:; end graph-class; define graph-class () end graph-class; define graph-class () temporary slot keyword-default-value-keyword-variable :: false-or(), required-init-keyword: keyword-variable:; constant slot keyword-default-value-specifiers :: , required-init-keyword: specifiers:; end graph-class; // TODO: SPECIFY MAX NUMBER OF PARAMETERS LIMIT define leaf packed-slots item-properties (, ) field slot keyword-default-value-index = 0, field-size: 8, required-init-keyword: index:; end packed-slots; define /* inline */ method initialize (c :: , #rest all-keys, #key, #all-keys) next-method(); apply(initialize-packed-slots, c, all-keys); end method; /// MERGE define abstract graph-class (, ) temporary slot merge-left-value :: false-or(), required-init-keyword: left-value:; temporary slot merge-right-value :: false-or(), required-init-keyword: right-value:; slot merge-left-previous-computation :: false-or() = #f, init-keyword: left-previous-computation:; slot merge-right-previous-computation :: false-or() = #f, init-keyword: right-previous-computation:; end graph-class; define graph-class () end graph-class; define graph-class () end graph-class; define leaf packed-slots item-properties (, ) // FIRST SELF-TAIL CALL? boolean slot loop-merge-initial? = #t; end packed-slots; define constant loop-merge-loop = merge-left-previous-computation; define constant loop-merge-loop-setter = merge-left-previous-computation-setter; define constant loop-merge-call = merge-right-previous-computation; define constant loop-merge-call-setter = merge-right-previous-computation-setter; define constant loop-merge-parameter = merge-left-value; define constant loop-merge-parameter-setter = merge-left-value-setter; define constant loop-merge-argument = merge-right-value; define constant loop-merge-argument-setter = merge-right-value-setter; define /* inline */ method make (class :: subclass(), #rest all-keys, #key loop, call, parameter, argument) => (res :: ) apply(next-method, class, left-value: parameter, right-value: argument, left-previous-computation: loop, right-previous-computation: call, all-keys) end method; define inline method initialize (c :: , #rest all-keys, #key, #all-keys) next-method(); apply(initialize-packed-slots, c, all-keys); end method; define graph-class () end graph-class; //define constant bind-exit-merge-block-return-temporary // = merge-left-value; define constant bind-exit-merge-body-temporary = merge-right-value; /// SLOT-VALUE define abstract graph-class () slot computation-slot-descriptor :: <&slot-descriptor>, required-init-keyword: slot-descriptor:; temporary slot computation-instance :: , required-init-keyword: instance:; end graph-class; define constant $log-max-number-slots = 16; // define constant $max-number-slots = 2 ^ $log-max-number-slots; define packed-slots item-properties (, ) boolean slot computation-guaranteed-initialized? = #f, init-keyword: guaranteed-initialized?:; field slot computation-slot-offset = 0, field-size: $log-max-number-slots, init-keyword: slot-offset:; end packed-slots; define inline method initialize (c :: , #rest all-keys, #key, #all-keys) next-method(); apply(initialize-packed-slots, c, all-keys); end method; define compiler-open generic computation-repeated-byte? (c :: ) => (res :: ); define abstract graph-class () temporary slot computation-index :: , required-init-keyword: index:; end graph-class; define leaf packed-slots item-properties (, ) boolean slot computation-index-tagged? = #f, init-keyword: index-tagged?:; end packed-slots; define graph-class () end graph-class; define graph-class () temporary slot computation-new-value :: false-or(), required-init-keyword: new-value:; end graph-class; define graph-class () end graph-class; define graph-class () temporary slot computation-new-value :: , required-init-keyword: new-value:; end graph-class; /// CALL define constant $compatibility-unchecked = 0; define constant $compatibility-checked-compatible = 1; define constant $compatibility-checked-incompatible = 2; define abstract graph-class () temporary slot arguments :: , required-init-keyword: arguments:; end graph-class; define packed-slots item-properties (, ) field slot compatibility-state = $compatibility-unchecked, field-size: 2; end packed-slots; define inline method initialize (call :: , #rest all-keys, #key, #all-keys) next-method(); apply(initialize-packed-slots, call, all-keys); end method; define graph-class () end graph-class; /// FUNCTION CALL define constant $dispatch-untried = 0; define constant $dispatch-tried = 1; define abstract graph-class () temporary slot function :: false-or(), required-init-keyword: function:; end graph-class; define packed-slots item-properties (, ) field slot dispatch-state = $dispatch-untried, field-size: 1; boolean slot call-congruent? = #f; boolean slot call-iep? = #f; end packed-slots; /// PRIMITIVE CALL define graph-class () slot primitive :: false-or(<&primitive>), required-init-keyword: primitive:; end graph-class; /// SIMPLE CALL -- a direct call to a function, with explicit arguments define thread variable *inlining-depth* = 0; define graph-class () end graph-class; define constant $log-max-inlining-depth = 4; define constant $max-inlining-depth = ash(1, $log-max-inlining-depth) - 1; define leaf packed-slots item-properties (, ) field slot call-inlining-depth = 0, field-size: $log-max-inlining-depth; end packed-slots; /// CONGRUENT CALL define graph-class () end graph-class; define method call-congruent? (c :: ) => (well? :: ) #t end method; /// METHOD CALL define graph-class (, ) temporary slot next-methods :: , required-init-keyword: next-methods:; end graph-class; define /* inline */ method make (call-class == , #rest all-keys, #key next-methods, arguments, #all-keys) => (object) if (next-methods) next-method() else apply(next-method, call-class, next-methods: first(arguments), arguments: copy-sequence(arguments, start: 1), all-keys) end if; end method; define graph-class (, ) temporary slot engine-node :: , required-init-keyword: engine-node:; end graph-class; /// APPLY define graph-class () end graph-class; define graph-class (, ) temporary slot next-methods :: , required-init-keyword: next-methods:; end graph-class; define /* inline */ method make (call-class == , #rest all-keys, #key next-methods, arguments, #all-keys) => (object) if (next-methods) next-method() else apply(next-method, call-class, next-methods: first(arguments), arguments: copy-sequence(arguments, start: 1), all-keys) end end method; define graph-class (, ) temporary slot engine-node :: <&engine-node>, required-init-keyword: engine-node:; end graph-class; /// IF define graph-class () temporary slot test :: , required-init-keyword: test:; slot consequent :: false-or(), required-init-keyword: consequent:; slot alternative :: false-or(), required-init-keyword: alternative:; end graph-class; /// BLOCK define abstract graph-class () temporary slot entry-state :: , required-init-keyword: entry-state:; slot body :: false-or() = #f, init-keyword: body:; end graph-class; /// BIND-EXIT define graph-class () slot %label, init-value: #f; end graph-class; /// UNWIND-PROTECT define graph-class () // (gts,98feb12) temporary slot protected-temporary = #f; slot protected-end :: false-or() = #f; slot cleanups :: false-or() = #f, init-keyword: cleanups:; slot cleanups-end :: false-or() = #f; // to support deletion end graph-class; define method protected-temporary(c :: ) => (t) // let temp = c.protected-end & temporary(previous-computation(c.protected-end)); let temp = c.protected-end & return-temp(c.protected-end); if (temp & temp.used?) temp else #f end if; end method; define function has-cleanups?(c :: ) c.cleanups & (previous-computation(c.cleanups-end) ~== c) end function; define function has-body?(c :: ) ~instance?(c.body, ) end function; /// TERMINATING COMPUTATIONS define abstract graph-class () end graph-class; define graph-class () temporary slot computation-value :: false-or(), required-init-keyword: value:; end graph-class; define graph-class () temporary slot computation-value :: , required-init-keyword: value:; temporary slot entry-state :: , required-init-keyword: entry-state:; end graph-class; define abstract graph-class () temporary slot entry-state :: , required-init-keyword: entry-state:; end graph-class ; define graph-class () // This is a terminating computation, because it terminates execution of // an interpreter thread, but not an , because it doesn't terminate // control flow in the DFM graph -- there is a next-compution, which is // outside of the block. For data flow, that's right. end graph-class ; define graph-class (, ) temporary slot return-temp :: false-or() = #f; // gts,98feb04 end graph-class ; define graph-class (, ) end graph-class ; /// LOOP define graph-class () slot %label, init-value: #f; slot loop-merges :: , required-init-keyword: merges:; slot loop-body :: false-or(), init-value: #f, init-keyword: body:; end graph-class; define graph-class () constant slot ending-loop :: , required-init-keyword: loop:; end graph-class; define function loop-parameters (c :: ) collecting () for (merge in loop-merges(c)) collect(loop-merge-parameter(merge)) end for; end collecting; end function; define function loop-call-arguments (c :: ) collecting () for (merge in loop-call-merges(c)) collect(loop-merge-argument(merge)) end for; end collecting; end function; /// LOOP CALL define graph-class () constant slot loop-call-loop :: , required-init-keyword: loop:; slot loop-call-merges :: = #[], init-keyword: merges:; end graph-class; /// BIND define graph-class () slot bind-return :: ; end graph-class; define method previous-computation-setter (new-value :: false-or(), c :: ) => (new-value) if (new-value) error(" computations may not have previous-computations"); end if; next-method(); end method previous-computation-setter; /// MULTIPLE VALUES define graph-class () temporary slot fixed-values :: , required-init-keyword: values:; temporary slot rest-value :: false-or()= #f, init-keyword: rest-value:; end graph-class ; define abstract graph-class () temporary slot computation-value :: , required-init-keyword: value:; end graph-class ; define inline method initialize (c :: , #rest all-keys, #key, #all-keys) next-method(); apply(initialize-packed-slots, c, all-keys); end method; // TODO: SPECIFY MAX NUMBER OF VALUES LIMIT define packed-slots item-properties (, ) field slot index = 0, field-size: 8; end packed-slots; define graph-class () end graph-class ; define leaf packed-slots item-properties (, ) boolean slot extract-value-index-guaranteed? = #f; end packed-slots; define graph-class () end graph-class ; define graph-class () end graph-class ; define graph-class () end graph-class ; define abstract graph-class () end graph-class ; define inline method initialize (c :: , #rest all-keys, #key, #all-keys) next-method(); apply(initialize-packed-slots, c, all-keys); end method; // TODO: SPECIFY MAX NUMBER OF VALUES LIMIT define leaf packed-slots item-properties (, ) field slot number-of-required-values = 0, field-size: 8, required-init-keyword: number-of-required-values:; end packed-slots; define graph-class () end graph-class ; define graph-class () end graph-class ; /// TYPES define abstract graph-class () end graph-class; define abstract graph-class () temporary slot type :: false-or(), required-init-keyword: type:; end graph-class; define graph-class () end graph-class; // added this to allow back-end's discriminate this case so as to force // emission of these in dylan library for size :: for vectors define graph-class () end graph-class; define graph-class () end graph-class; // keep the original variable name around for meaningful // error messages define graph-class () constant slot lhs-variable-name, required-init-keyword: lhs-variable-name:; end graph-class; define abstract graph-class () temporary slot types :: , required-init-keyword: types:; end graph-class; define graph-class () end graph-class; define graph-class () temporary slot rest-type :: false-or(), required-init-keyword: rest-type:; end graph-class; define abstract graph-class () end graph-class; define abstract graph-class (, ) end graph-class; define graph-class (, ) end graph-class; define graph-class (, ) end graph-class; define graph-class () temporary slot guaranteed-type :: false-or(), init-value: #f, init-keyword: type:; slot static-guaranteed-type :: false-or(<&type>), init-value: #f, init-keyword: static-type:; end graph-class; /// INDIRECT ASSIGNMENT define graph-class () temporary slot computation-value :: false-or(), required-init-keyword: value:; end graph-class ; define graph-class () temporary slot computation-cell :: , required-init-keyword: cell:; end graph-class ; define graph-class () temporary slot computation-cell :: , required-init-keyword: cell:; temporary slot computation-value :: false-or(), required-init-keyword: value:; end graph-class ; /// SOURCE LOCATION PROTOCOL define generic dfm-source-location (c :: ) => (location-or-false); define method dfm-source-location (c :: ) => (location) computation-source-location(c) end method; define compiler-open generic dfm-context-id (c :: type-union(, )) => (context-id-or-false); define inline function do-with-parent-computation (f :: , c :: false-or()) with-parent-source-location (c & computation-source-location(c)) f(); end; end function; define macro with-parent-computation { with-parent-computation (?c:expression) ?:body end } => { do-with-parent-computation(method () ?body end, ?c) } end macro; // eof