VM Maker: VMMaker.oscog-eem.1833.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

VM Maker: VMMaker.oscog-eem.1833.mcz

commits-2
 
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.1833.mcz

==================== Summary ====================

Name: VMMaker.oscog-eem.1833
Author: eem
Time: 22 April 2016, 11:15:44.990146 am
UUID: 04364d67-49f1-4615-87e7-942001d37706
Ancestors: VMMaker.oscog-eem.1832

The year Ada Lovelace was introduced to Charles Babbage by Mary Somerville.

Revise slightly the declaration of the integer type testing macros for internal plugins.  Arrange that plugins not using the API are generated as previously.  Arrange that external plugins make no assumptions about tag assignments.  Fix the speeling of the proxy dereference generator.

Fix primAlienReplace to use positiveMachineIntegerValueOf: instead of positive32BitValueOf:.

=============== Diff against VMMaker.oscog-eem.1832 ===============

Item was changed:
  ----- Method: IA32ABIPlugin>>primAlienReplace (in category 'primitives-accessing') -----
  primAlienReplace
  "Copy some number of bytes from some source object starting at the index
+ into the receiver destination object from startIndex to stopIndex.  The  source
+ and destination may be Aliens or byte-indexable objects.  The primitive wll have
+ either of the following signatures:
- into the receiver destination object  from startIndex to stopIndex .  The  source
- and destination may be Aliens or byte-indexable objects.  The primitive wll have either
- of the following signatures:
  <Alien | indexableByteSubclass | indexableWordSubclass>
  primReplaceFrom: start <Integer>
  to: stop <Integer>
  with: replacement <Alien | indexableByteSubclass | indexableWordSubclass | Integer>
  startingAt: repStart <Integer> ^<self>
  <primitive: 'primitiveAlienReplace' error: errorCode module: 'IA32ABI'>
  <Anywhere>
  primReplaceIn: dest <Alien | indexableByteSubclass | indexableWordSubclass>
  from: start <Integer>
  to: stop <Integer>
  with: replacement <Alien | indexableByteSubclass | indexableWordSubclass | Integer>
  startingAt: repStart <Integer> ^<self>
  <primitive: 'primitiveAlienReplace' error: errorCode module: 'IA32ABI'>
  "
  | array start stop repl replStart dest src totalLength count |
  <export: true>
  array := interpreterProxy stackValue: 4.
  start := interpreterProxy stackIntegerValue: 3.
  stop := interpreterProxy stackIntegerValue: 2.
  repl := interpreterProxy stackValue: 1.
  replStart := interpreterProxy stackIntegerValue: 0.
 
  (interpreterProxy failed
  or: [(interpreterProxy isWordsOrBytes: array) not]) ifTrue:
  [^interpreterProxy primitiveFailFor: PrimErrBadArgument].
 
  (self isAlien: array)
  ifTrue:
  [totalLength := self sizeField: array.
  dest := (self startOfData: array withSize: totalLength) + start - 1.
  totalLength = 0 "no bounds checks for zero-sized (pointer) Aliens"
  ifTrue: [totalLength := stop]
  ifFalse: [totalLength := totalLength abs]]
  ifFalse:
  [totalLength := interpreterProxy byteSizeOf: array.
  dest := (self startOfByteData: array) + start - 1].
+ (start >= 1 and: [start - 1 <= stop and: [stop <= totalLength]]) ifFalse:
+ [^interpreterProxy primitiveFailFor: PrimErrBadIndex].
- (start >= 1 and: [start - 1 <= stop and: [stop <= totalLength]])
- ifFalse: [^interpreterProxy primitiveFailFor: PrimErrBadIndex].
 
+ (interpreterProxy isKindOfInteger: repl)
- (interpreterProxy isIntegerObject: repl)
  ifTrue:
+ [src := (interpreterProxy positiveMachineIntegerValueOf: repl) + replStart - 1.
+ interpreterProxy failed ifTrue:
+ [^interpreterProxy primitiveFailFor: PrimErrBadArgument]]
- [(interpreterProxy integerValueOf: repl) <= 0 ifTrue:
- [^interpreterProxy primitiveFailFor: PrimErrBadArgument].
- src := (interpreterProxy integerValueOf: repl) + replStart - 1]
  ifFalse:
+ [(self isAlien: repl)
- [(interpreterProxy isLargePositiveIntegerObject: repl)
  ifTrue:
+ [totalLength := self sizeField: repl.
+ src := (self startOfData: repl withSize: totalLength) + replStart - 1.
+ totalLength = 0 "no bounds checks for zero-sized (pointer) Aliens"
+ ifTrue: [totalLength := stop - start + replStart]
+ ifFalse: [totalLength := totalLength abs]]
- [src := (interpreterProxy positive32BitValueOf: repl) + replStart - 1.
- interpreterProxy failed ifTrue:
- [^interpreterProxy primitiveFailFor: PrimErrBadArgument]]
  ifFalse:
+ [(interpreterProxy isWordsOrBytes: repl) ifFalse:
+ [^interpreterProxy primitiveFailFor: PrimErrBadArgument].
+ totalLength := interpreterProxy byteSizeOf: repl.
+ src := (self startOfByteData: repl) + replStart - 1].
+ (replStart >= 1 and: [stop - start + replStart <= totalLength]) ifFalse:
+ [^interpreterProxy primitiveFailFor: PrimErrBadIndex]].
- [(self isAlien: repl)
- ifTrue:
- [totalLength := self sizeField: repl.
- src := (self startOfData: repl withSize: totalLength) + replStart - 1.
- totalLength = 0 "no bounds checks for zero-sized (pointer) Aliens"
- ifTrue: [totalLength := stop - start + replStart]
- ifFalse: [totalLength := totalLength abs]]
- ifFalse:
- [(interpreterProxy isWordsOrBytes: repl) ifFalse:
- [^interpreterProxy primitiveFailFor: PrimErrBadArgument].
- totalLength := interpreterProxy byteSizeOf: repl.
- src := (self startOfByteData: repl) + replStart - 1].
- (replStart >= 1 and: [stop - start + replStart <= totalLength]) ifFalse:
- [^interpreterProxy primitiveFailFor: PrimErrBadIndex]]].
 
  (interpreterProxy isOopImmutable: array) ifTrue:
  [^interpreterProxy primitiveFailFor: PrimErrNoModification].
 
  count := stop - start + 1.
+ self mem: dest asVoidPointer mo: src asVoidPointer ve: count.
- self cCode: 'memmove((void *)dest,(void *)src,count)'
- inSmalltalk:
- [count := count + src + dest. "squash unused var compiler warnings"
- self error: 'not implemented'].
 
  interpreterProxy pop: interpreterProxy methodArgumentCount!

Item was removed:
- ----- Method: VMPluginCodeGenerator>>generateInterpreterProxyFunctionDeference:on:indent: (in category 'C translation') -----
- generateInterpreterProxyFunctionDeference: aNode on: aStream indent: anInteger
- | pluginsToClone |
- (pluginsToClone := self pluginFunctionsToClone) isEmpty ifTrue:
- [^self].
- aStream cr; nextPutAll: '#if !!defined(SQUEAK_BUILTIN_PLUGIN)'; cr.
- pluginsToClone do:
- [:s| | cs |
- cs := self cFunctionNameFor: s.
- self withOptionalVerbiageFor: s
- on: aStream
- do: [aStream tab: anInteger; nextPutAll: cs; nextPutAll: ' = interpreterProxy->'; nextPutAll: cs; nextPut: $;; cr]
- ifOptionalDo: [aStream
- nextPutAll: '# if !!defined('; nextPutAll: cs; nextPut: $);
- crtab: anInteger; nextPutAll: cs; nextPutAll: ' = 0;';
- cr; nextPutAll: '# endif'; cr]].
- aStream nextPutAll: '#endif /* !!defined(SQUEAK_BUILTIN_PLUGIN) */'.!

Item was added:
+ ----- Method: VMPluginCodeGenerator>>generateInterpreterProxyFunctionDereference:on:indent: (in category 'C translation') -----
+ generateInterpreterProxyFunctionDereference: aNode on: aStream indent: anInteger
+ | pluginsToClone |
+ pluginsToClone := self pluginFunctionsToClone copyWithoutAll: self selectorsThatAreGeneratedAsMacros.
+ pluginsToClone isEmpty ifTrue:
+ [^self].
+ aStream cr; nextPutAll: '#if !!defined(SQUEAK_BUILTIN_PLUGIN)'; cr.
+ pluginsToClone do:
+ [:s| | cs |
+ cs := self cFunctionNameFor: s.
+ self withOptionalVerbiageFor: s
+ on: aStream
+ do: [aStream tab: anInteger; nextPutAll: cs; nextPutAll: ' = interpreterProxy->'; nextPutAll: cs; nextPut: $;; cr]
+ ifOptionalDo: [aStream
+ nextPutAll: '# if !!defined('; nextPutAll: cs; nextPut: $);
+ crtab: anInteger; nextPutAll: cs; nextPutAll: ' = 0;';
+ cr; nextPutAll: '# endif'; cr]].
+ aStream nextPutAll: '#endif /* !!defined(SQUEAK_BUILTIN_PLUGIN) */'.!

Item was changed:
  ----- Method: VMPluginCodeGenerator>>initializeCTranslationDictionary (in category 'public') -----
  initializeCTranslationDictionary
  "Initialize the dictionary mapping message names to actions for C code generation."
 
  super initializeCTranslationDictionary.
  translationDict
  at: #expandDereferenceInterpreterProxyFunctionTable
+ put: #generateInterpreterProxyFunctionDereference:on:indent:;
- put: #generateInterpreterProxyFunctionDeference:on:indent:;
  at: #remapOop:in:
  put: #generateRemapOopIn:on:indent:!

Item was changed:
  ----- Method: VMPluginCodeGenerator>>pluginFunctionsToClone (in category 'public') -----
  pluginFunctionsToClone
  "Answer those of the used plugin functions to clone as a sorted collection.
  Exclude those that are static to sqVirtualMachine.c and hence always need
+ to be called through interpreterProxy."
- to be called through interpreterProxy.
- Also exclude those that are generated as macros rather than function call."
 
  ^((pluginFunctionsUsed
  reject: [:selector| self noteUsedPluginFunction: selector])
+ select: [:selector| InterpreterProxy includesSelector: selector])
- select: [:selector| (InterpreterProxy includesSelector: selector) and: [(self selectorsThatAreGeneratedAsMacros includes: selector) not]])
  asSortedCollection!

Item was changed:
  ----- Method: VMPluginCodeGenerator>>preDeclareInterpreterProxyOn: (in category 'C code generator') -----
  preDeclareInterpreterProxyOn: aStream
  "Put the necessary #defines needed before interpreterProxy.  Basically
  internal plugins use the VM's interpreterProxy variable and external plugins
  use their own.  Override to keep local copies of all functions in external
  prims, and link directly in internal plugins."
  "| pcc |
  pcc := self new.
  (InterpreterProxy selectors reject: [:s| #(initialize private) includes: (InterpreterProxy whichCategoryIncludesSelector: s)]) do:
  [:s| pcc noteUsedPluginFunction: s].
  pcc preDeclareInterpreterProxyOn: Transcript.
  Transcript flush"
  | pluginFuncs interpreterClass objectMemoryClass |
  self notePluginFunctionsUsedByMacros.
- self preDeclareMacrosForFastClassCheckingOn: aStream.
  (pluginFuncs := self pluginFunctionsToClone) isEmpty ifTrue:
  [^super preDeclareInterpreterProxyOn: aStream].
+ (pluginFuncs includesAnyOf: self selectorsThatAreGeneratedAsMacros) ifTrue:
+ [self preDeclareMacrosForFastClassCheckingOn: aStream].
+ pluginFuncs := pluginFuncs copyWithoutAll: self selectorsThatAreGeneratedAsMacros.
+ pluginFuncs isEmpty ifTrue:
+ [^self].
-
  aStream cr; nextPutAll: '#if !!defined(SQUEAK_BUILTIN_PLUGIN)'; cr.
  interpreterClass := self referenceInterpreterClass.
  objectMemoryClass := self referenceObjectMemoryClass.
  pluginFuncs := pluginFuncs collect:
  [:selector| | reference actual |
  reference := self compileToTMethodSelector: selector
  in: ((interpreterClass whichClassIncludesSelector: selector) ifNil:
  [(objectMemoryClass whichClassIncludesSelector: selector) ifNil:
  [InterpreterProxy]]).
  actual := self compileToTMethodSelector: selector in: InterpreterProxy.
  (reference returnType ~= actual returnType
  or: [(1 to: reference args size) anySatisfy:
  [:i| (reference typeFor: (reference args at: i) in: self)
   ~= (actual typeFor: (actual args at: i) in: self)]]) ifTrue:
  [self logger
  nextPutAll: 'warning, signature of InterpreterProxy>>';
  nextPutAll: selector;
  nextPutAll: ' does not match reference implementation.';
  cr].
  actual].
  pluginFuncs do:
  [:tMethod|
  tMethod recordDeclarationsIn: self.
  tMethod returnType ifNil:
  [tMethod inferReturnTypeIn: self]].
  pluginFuncs do:
  [:tMethod| | functionName |
  functionName := self cFunctionNameFor: tMethod selector.
  aStream nextPutAll:
  ((String streamContents:
  [:s|
  tMethod
  static: true;
  emitCFunctionPrototype: s generator: self])
  copyReplaceAll: functionName
  with: '(*', functionName, ')'
  tokenish: [:ch| ch = $_ or: [ch isAlphaNumeric]])].
  aStream nextPutAll: '#else /* !!defined(SQUEAK_BUILTIN_PLUGIN) */'; cr.
  pluginFuncs do:
  [:tMethod|
+ self withGuardAgainstDefinitionOf: tMethod selector on: aStream do:
+ [self withOptionalVerbiageFor: tMethod selector
+ on: aStream
+ do: [tMethod static: false; export: false; emitCFunctionPrototype: aStream generator: self]
+ ifOptionalDo:
+ [aStream nextPutAll: '# define '.
+ (TSendNode new
+ setSelector: tMethod selector
+ receiver: (TVariableNode new setName: 'interpreterProxy')
+ arguments: (tMethod args collect: [:a| TVariableNode new setName: a]))
+ emitCCodeAsArgumentOn: aStream
+ level: 0
+ generator: self.
+ aStream nextPutAll: ' 0'; cr]]].
+ aStream nextPutAll: 'extern'; cr; nextPutAll: '#endif'; cr!
- self withOptionalVerbiageFor: tMethod selector
- on: aStream
- do: [tMethod static: false; export: false; emitCFunctionPrototype: aStream generator: self]
- ifOptionalDo:
- [aStream nextPutAll: '# define '.
- (TSendNode new
- setSelector: tMethod selector
- receiver: (TVariableNode new setName: 'interpreterProxy')
- arguments: (tMethod args collect: [:a| TVariableNode new setName: a]))
- emitCCodeAsArgumentOn: aStream
- level: 0
- generator: self.
- aStream nextPutAll: ' 0'; cr]].
- aStream nextPutAll: 'extern'; cr; nextPutAll: '#endif'; cr.!

Item was changed:
  ----- Method: VMPluginCodeGenerator>>preDeclareMacrosForFastClassCheckingOn: (in category 'C code generator') -----
  preDeclareMacrosForFastClassCheckingOn: aStream
+ "These macros can be used to check for various cases of Integer types.
+ Since they can be defined based on existing API, this is a good trade off:
+ - avoid extending the interpreterProxy API unnecessarily
+ - provide fast type checking"
- "These macros can be used to check for various case of Integer type.
- Since they can be defined based on existing API, this is a good trade off:
- - avoid extending the interpreterProxy API like mad
- - provide fast type checking"
 
+ "Speed-up generated code for internal plugins by using macros and fixed class indices to define this well known functionality."
+ #( '#if defined(SQUEAK_BUILTIN_PLUGIN)' cr
- "Fast-up generated code by using a macro for this well known function unconditionnally"
- #( '#define isIntegerObject(oop) (oop & 1)' cr
- '#if SPURVM && defined(SQUEAK_BUILTIN_PLUGIN)'
 
+ '# define isIntegerObject(oop) ((oop) & 1)' cr
+
+ '# if SPURVM'
- "Compact class index are hardcoded because there is no guarantee that the pool values at generation time are that of SPUR..
- Make sure they are in sync with SpurMemoryManager class>>initializeCompactClassIndices"
  'extern sqInt classIndexOf(sqInt);'
+ "Compact class indices are hardcoded here because there is no guarantee that the pool values at generation time
+ are that of SPUR.. Make sure they are in sync with SpurMemoryManager class>>initializeCompactClassIndices"
+ '# define LargeNegativeIntegerClassIndex 32'
+ '# define LargePositiveIntegerClassIndex 33'
+ '# if BytesPerOop == 4'
+ '#  define isImmediate(oop) ((oop) & 3)'
+ '# else'
+ '#  define isImmediate(oop) ((oop) & 7)'
+ '# endif'
+ '# define isKindOfInteger(oop) (isImmediate(oop) ? isIntegerObject(oop) : (unsigned)(classIndexOf(oop) - LargeNegativeIntegerClassIndex) <= 1)'
+ '# define isLargeIntegerObject(oop) (!!isImmediate(oop) && (unsigned)(classIndexOf(oop) - LargeNegativeIntegerClassIndex) <= 1)'
+ '# define isLargeNegativeIntegerObject(oop) (!!isImmediate(oop) && classIndexOf(oop) == LargeNegativeIntegerClassIndex)'
+ '# define isLargePositiveIntegerObject(oop) (!!isImmediate(oop) && classIndexOf(oop) == LargePositiveIntegerClassIndex)'
+ '# endif /* SPURVM */'
+ '#endif /* defined(SQUEAK_BUILTIN_PLUGIN) */' cr
- '# define LargeNegativeIntegerClassIndex 32'
- '# define LargePositiveIntegerClassIndex 33'
- '# define isKindOfInteger(oop) (isImmediate(oop) ? isIntegerObject(oop) : (unsigned)(classIndexOf(oop) - LargeNegativeIntegerClassIndex) <= 1)'
- '# define isLargeIntegerObject(oop) (!!isImmediate(oop) && (unsigned)(classIndexOf(oop) - LargeNegativeIntegerClassIndex) <= 1)'
- '# define isLargeNegativeIntegerObject(oop) (!!isImmediate(oop) && classIndexOf(oop) == LargeNegativeIntegerClassIndex)'
- '# define isLargePositiveIntegerObject(oop) (!!isImmediate(oop) && classIndexOf(oop) == LargePositiveIntegerClassIndex)'
 
+ "If the functionality has not been defined via macros, define default versions using existing plugin API"
+ '#if !!defined(isKindOfInteger)'
- '#else /* defined(SQUEAK_BUILTIN_PLUGIN) && defined(SPURVM) */'
-
  '# define isLargeNegativeIntegerObject(oop) (fetchClassOf(oop) == classLargeNegativeInteger())'
  '# define isLargePositiveIntegerObject(oop) (fetchClassOf(oop) == classLargePositiveInteger())'
  '# define isLargeIntegerObject(oop) (isLargeNegativeIntegerObject(oop) || isLargePositiveIntegerObject(oop))'
  '# define isKindOfInteger(oop) (isIntegerObject(oop) || isLargeNegativeIntegerObject(oop) || isLargePositiveIntegerObject(oop))'
+ '#endif' cr) do:
-
- '#endif /* defined(SQUEAK_BUILTIN_PLUGIN) && defined(SPURVM) */' cr) do:
  [:element|
  aStream cr.
+ element ~~ #cr ifTrue: [aStream nextPutAll: element]]!
- element ~~ #cr ifTrue: [aStream cr; nextPutAll: element]]!

Item was changed:
  ----- Method: VMPluginCodeGenerator>>selectorsThatAreGeneratedAsMacros (in category 'public') -----
  selectorsThatAreGeneratedAsMacros
  "Answer a list of selectors that are generated as a C macro rather than as an interpreterProxy function call."
 
+ ^#(isKindOfInteger: isLargeIntegerObject: isLargeNegativeIntegerObject: isLargePositiveIntegerObject:)!
- ^#(isKindOfInteger: isIntegerObject: isLargeIntegerObject: isLargeNegativeIntegerObject: isLargePositiveIntegerObject:)!

Item was added:
+ ----- Method: VMPluginCodeGenerator>>selectorsThatMayBeGeneratedAsMacros (in category 'public') -----
+ selectorsThatMayBeGeneratedAsMacros
+ "Answer a list of selectors that maybe generated as a C macro rather than as an interpreterProxy function call."
+
+ ^self selectorsThatAreGeneratedAsMacros, #(isIntegerObject: isImmediate:)!

Item was added:
+ ----- Method: VMPluginCodeGenerator>>withGuardAgainstDefinitionOf:on:do: (in category 'C translation') -----
+ withGuardAgainstDefinitionOf: selector on: aStream do: aBlock
+ "Evaluate aBlock, surrounded by a define if selector is defined as a macro (i.e. by preDeclareInterpreterProxyOn:"
+ (self selectorsThatMayBeGeneratedAsMacros includes: selector) ifFalse:
+ [^aBlock value].
+ aStream nextPutAll: '#if !!defined('; nextPutAll: (self cFunctionNameFor: selector); nextPut: $); cr.
+ aBlock value.
+ aStream nextPutAll: '#endif'; cr!

Reply | Threaded
Open this post in threaded view
|

Re: VM Maker: VMMaker.oscog-eem.1833.mcz

David T. Lewis
 
I love these commit notices. Ohm, Lovelace, Babbage... :-)

Dave

>
> Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
> http://source.squeak.org/VMMaker/VMMaker.oscog-eem.1833.mcz
>
> ==================== Summary ====================
>
> Name: VMMaker.oscog-eem.1833
> Author: eem
> Time: 22 April 2016, 11:15:44.990146 am
> UUID: 04364d67-49f1-4615-87e7-942001d37706
> Ancestors: VMMaker.oscog-eem.1832
>
> The year Ada Lovelace was introduced to Charles Babbage by Mary
> Somerville.
>


Reply | Threaded
Open this post in threaded view
|

re: VM Maker: VMMaker.oscog-eem.1833.mcz

Craig Latta
 

> I love these commit notices. Ohm, Lovelace, Babbage... :-)

     Speeling... :)


-C

--
Craig Latta
Black Page Digital
Amsterdam
[hidden email]
+31   6 2757 7177 (SMS ok)
+ 1 415  287 3547 (no SMS)

Reply | Threaded
Open this post in threaded view
|

Re: VM Maker: VMMaker.oscog-eem.1833.mcz

Eliot Miranda-2
In reply to this post by David T. Lewis
 


On Fri, Apr 22, 2016 at 12:19 PM, David T. Lewis <[hidden email]> wrote:

I love these commit notices. Ohm, Lovelace, Babbage... :-)

anything to distract from the quality of the code ;-)

I've wanted to include in commit notices choice extracts from Wikipedia years corresponding to the version number but I always forget.  In recent months I've missed 1492, 1776, 1789.  When Clément was here I told him of my daft idea and he remembered.  So now I'm getting it under my fingers :-)

 

Dave

>
> Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
> http://source.squeak.org/VMMaker/VMMaker.oscog-eem.1833.mcz
>
> ==================== Summary ====================
>
> Name: VMMaker.oscog-eem.1833
> Author: eem
> Time: 22 April 2016, 11:15:44.990146 am
> UUID: 04364d67-49f1-4615-87e7-942001d37706
> Ancestors: VMMaker.oscog-eem.1832
>
> The year Ada Lovelace was introduced to Charles Babbage by Mary
> Somerville.
>





--
_,,,^..^,,,_
best, Eliot
Reply | Threaded
Open this post in threaded view
|

Re: VM Maker: VMMaker.oscog-eem.1833.mcz

johnmci
 
Should be bot that 

Sent from my iPhone

On Apr 22, 2016, at 5:12 PM, Eliot Miranda <[hidden email]> wrote:



On Fri, Apr 22, 2016 at 12:19 PM, David T. Lewis <[hidden email]> wrote:

I love these commit notices. Ohm, Lovelace, Babbage... :-)

anything to distract from the quality of the code ;-)

I've wanted to include in commit notices choice extracts from Wikipedia years corresponding to the version number but I always forget.  In recent months I've missed 1492, 1776, 1789.  When Clément was here I told him of my daft idea and he remembered.  So now I'm getting it under my fingers :-)

 

Dave

>
> Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
> http://source.squeak.org/VMMaker/VMMaker.oscog-eem.1833.mcz
>
> ==================== Summary ====================
>
> Name: VMMaker.oscog-eem.1833
> Author: eem
> Time: 22 April 2016, 11:15:44.990146 am
> UUID: 04364d67-49f1-4615-87e7-942001d37706
> Ancestors: VMMaker.oscog-eem.1832
>
> The year Ada Lovelace was introduced to Charles Babbage by Mary
> Somerville.
>





--
_,,,^..^,,,_
best, Eliot

smime.p7s (6K) Download Attachment