[Vm-dev] VM Maker: VMMakerJS-bf.4.mcz
commits at source.squeak.org
commits at source.squeak.org
Fri Oct 10 13:45:39 UTC 2014
Bert Freudenberg uploaded a new version of VMMakerJS to project VM Maker:
http://source.squeak.org/VMMaker/VMMakerJS-bf.4.mcz
==================== Summary ====================
Name: VMMakerJS-bf.4
Author: bf
Time: 6 October 2014, 12:13:38.274 am
UUID: 4a371688-d63e-4c10-9157-885c0d229f4e
Ancestors: VMMakerJS-bf.3
More types., fixes.
Generates SoundGenerationPlugin, Matrix2x3Plugin, FloatArrayPlugin now.
=============== Diff against VMMakerJS-bf.3 ===============
Item was changed:
----- Method: JSCodeGenerator>>generateAsFloat:on:indent: (in category 'JS translation') -----
generateAsFloat: msgNode on: aStream indent: level
"Generate the JS code for this message onto the given stream."
- self halt.
- aStream nextPutAll:'((double) '.
self emitJSExpression: msgNode receiver on: aStream.
+ !
- aStream nextPutAll: ' )'.!
Item was changed:
----- Method: JSCodeGenerator>>generateAsInteger:on:indent: (in category 'JS translation') -----
generateAsInteger: msgNode on: aStream indent: level
"Generate the JS code for this message onto the given stream."
+ aStream nextPutAll:'('.
- self halt.
- aStream nextPutAll:'((sqInt)'.
self emitJSExpression: msgNode receiver on: aStream.
+ aStream nextPutAll: '|0)'!
- aStream nextPut: $)!
Item was changed:
----- Method: JSCodeGenerator>>generateCCoercion:on:indent: (in category 'JS translation') -----
generateCCoercion: msgNode on: aStream indent: level
"Generate the JS code for this message onto the given stream."
+ | expr cType |.
- | expr |.
expr := msgNode args first.
+ cType := msgNode args second value.
(expr isSend and: [expr receiver name = 'interpreterProxy' and: [expr selector = #firstIndexableField:]]) ifTrue: [
+ cType := msgNode args second value.
+ self emitJSExpression: expr args first on: aStream.
+ cType = 'unsigned char *' ifTrue: [^aStream nextPutAll: '.bytes'].
+ cType = 'int *' ifTrue: [^aStream nextPutAll: '.wordsAsInt32Array()'].
+ cType = 'float *' ifTrue: [^aStream nextPutAll: '.wordsAsFloat32Array()'].
- | cType |
- cType := msgNode args second.
- cType value = 'unsigned char *' ifTrue: [
- self emitJSExpression: expr args first on: aStream.
- ^aStream nextPutAll: '.bytes'.
- ].
self halt.
] ifFalse: [
+ (#('double' 'float') includes: cType) ifFalse: [self halt].
- self halt.
self emitJSExpression: expr on: aStream.
]
!
Item was changed:
----- Method: JSCodeGenerator>>generateFirstIndexableField:on:indent: (in category 'JS hacks') -----
generateFirstIndexableField: msgNode on: aStream indent: level
| parent cType accessor |
self oneBasedArrays: false.
"HACK: detect cType from parent node"
parent := thisContext sender sender sender.
cType := parent method == (TAssignmentNode>>#emitJSCodeOn:level:generator:)
ifTrue: [self typeOfVariable: parent receiver variable name] ifFalse: [
parent method == (TSendNode>>#emitJSCodeAsFunctionCallOn:level:generator:)
ifTrue: [self typeOfArgument: (parent receiver args indexOf: msgNode) in: parent receiver selector] ifFalse: [
self halt]].
cType ifNotNil: [
cType := cType copyReplaceAll: ' *' with: '* '.
accessor := (cType beginsWith: 'unsigned char*') ifTrue: ['.bytes']
ifFalse: [(cType beginsWith: 'unsigned int*') ifTrue: ['.words']
ifFalse: [(cType beginsWith: 'int*') ifTrue: ['.wordsAsInt32Array()']
ifFalse: [(cType beginsWith: 'char*') ifTrue: ['.bytes']
+ ifFalse: [(cType beginsWith: 'float*') ifTrue: ['.wordsAsFloat32Array()']
+ ifFalse: [self halt: 'need to handle ', cType]]]]].
- ifFalse: [self halt: 'need to handle ', cType]]]].
accessor ifNotNil: [msgNode args first emitJSCodeOn: aStream level: level generator: self.
^aStream nextPutAll: accessor]].
"generic code below, not needed ever hopefully"
aStream nextPutAll: 'interpreterProxy.'.
^ msgNode emitJSCodeAsFunctionCallOn: aStream level: level generator: self!
Item was added:
+ ----- Method: JSCodeGenerator>>generateIntAtPointer:on:indent: (in category 'JS hacks') -----
+ generateIntAtPointer: msgNode on: aStream indent: level
+ msgNode args first asString = 'self cCoerce: argPtr + i to: ''char*'''
+ ifTrue: [^aStream nextPutAll: 'argPtr[i]'].
+ self halt
+
+
+ !
Item was added:
+ ----- Method: JSCodeGenerator>>generateIsFloatObject:on:indent: (in category 'JS hacks') -----
+ generateIsFloatObject: msgNode on: aStream indent: level
+ msgNode args first emitJSCodeOn: aStream level: level generator: self.
+ aStream nextPutAll: '.isFloat'.
+ !
Item was changed:
----- Method: JSCodeGenerator>>initializeCTranslationDictionary (in category 'JS translation') -----
initializeCTranslationDictionary
"Initialize the dictionary mapping message names to actions for C code generation."
| pairs |
translationDict := Dictionary new: 200.
pairs := #(
#& #generateAnd:on:indent:
#| #generateOr:on:indent:
#and: #generateSequentialAnd:on:indent:
#or: #generateSequentialOr:on:indent:
#not #generateNot:on:indent:
#+ #generatePlus:on:indent:
#- #generateMinus:on:indent:
#negated #generateNegated:on:indent:
#* #generateTimes:on:indent:
#/ #generateDivide:on:indent:
#// #generateDivide:on:indent:
#\\ #generateModulo:on:indent:
#<< #generateShiftLeft:on:indent:
#>> #generateShiftRight:on:indent:
#min: #generateMin:on:indent:
#max: #generateMax:on:indent:
#between:and: #generateBetweenAnd:on:indent:
#bitAnd: #generateBitAnd:on:indent:
#bitOr: #generateBitOr:on:indent:
#bitXor: #generateBitXor:on:indent:
#bitShift: #generateBitShift:on:indent:
#signedBitShift: #generateSignedBitShift:on:indent:
#bitInvert32 #generateBitInvert32:on:indent:
#bitClear: #generateBitClear:on:indent:
#< #generateLessThan:on:indent:
#<= #generateLessThanOrEqual:on:indent:
#= #generateEqual:on:indent:
#> #generateGreaterThan:on:indent:
#>= #generateGreaterThanOrEqual:on:indent:
#~= #generateNotEqual:on:indent:
#== #generateEqual:on:indent:
#~~ #generateNotEqual:on:indent:
#isNil #generateIsNil:on:indent:
#notNil #generateNotNil:on:indent:
#whileTrue: #generateWhileTrue:on:indent:
#whileFalse: #generateWhileFalse:on:indent:
#whileTrue #generateDoWhileTrue:on:indent:
#whileFalse #generateDoWhileFalse:on:indent:
#to:do: #generateToDo:on:indent:
#to:by:do: #generateToByDo:on:indent:
#repeat #generateRepeat:on:indent:
#ifTrue: #generateIfTrue:on:indent:
#ifFalse: #generateIfFalse:on:indent:
#ifTrue:ifFalse: #generateIfTrueIfFalse:on:indent:
#ifFalse:ifTrue: #generateIfFalseIfTrue:on:indent:
#at: #generateAt:on:indent:
#at:put: #generateAtPut:on:indent:
#basicAt: #generateAt:on:indent:
#basicAt:put: #generateAtPut:on:indent:
#integerValueOf: #generateIntegerValueOf:on:indent:
#integerObjectOf: #generateIntegerObjectOf:on:indent:
#isIntegerObject: #generateIsIntegerObject:on:indent:
#cCode: #generateInlineCCode:on:indent:
#cCode:inSmalltalk: #generateInlineCCode:on:indent:
#cPreprocessorDirective: #generateInlineCPreprocessorDirective:on:indent:
#preprocessorExpression: #generateInlineCppDirective:on:indent:
#isDefined:inSmalltalk:comment:ifTrue: #generateInlineCppIfDef:on:indent:
#isDefined:inSmalltalk:comment:ifTrue:ifFalse: #generateInlineCppIfDefElse:on:indent:
#isDefinedTrueExpression:inSmalltalk:comment:ifTrue:ifFalse: #generateInlineCppIfElse:on:indent:
#cCoerce:to: #generateCCoercion:on:indent:
#cCoerceSimple:to: #generateCCoercion:on:indent:
#addressOf: #generateAddressOf:on:indent:
#signedIntFromLong #generateSignedIntFromLong:on:indent:
#signedIntToLong #generateSignedIntToLong:on:indent:
#signedIntFromShort #generateSignedIntFromShort:on:indent:
#signedIntToShort #generateSignedIntToShort:on:indent:
#preIncrement #generatePreIncrement:on:indent:
#preDecrement #generatePreDecrement:on:indent:
#inline: #generateInlineDirective:on:indent:
#asFloat #generateAsFloat:on:indent:
#asInteger #generateAsInteger:on:indent:
#asUnsignedInteger #generateAsUnsignedInteger:on:indent:
#asSymbol #generateAsSymbol:on:indent:
#anyMask: #generateBitAnd:on:indent:
#raisedTo: #generateRaisedTo:on:indent:
#touch: #generateTouch:on:indent:
#bytesPerWord #generateBytesPerWord:on:indent:
#baseHeaderSize #generateBaseHeaderSize:on:indent:
#sharedCodeNamed:inCase: #generateSharedCodeDirective:on:indent:
#perform: #generatePerform:on:indent:
#perform:with: #generatePerform:on:indent:
#perform:with:with: #generatePerform:on:indent:
#perform:with:with:with: #generatePerform:on:indent:
#perform:with:with:with:with: #generatePerform:on:indent:
#perform:with:with:with:with:with: #generatePerform:on:indent:
#shouldNotImplement #generateSmalltalkMetaError:on:indent:
#shouldBeImplemented #generateSmalltalkMetaError:on:indent:
"optimized interpreterProxy calls"
#firstIndexableField: #generateFirstIndexableField:on:indent:
#slotSizeOf: #generateSlotSizeOf:on:indent:
+ #stSizeOf: #generateSlotSizeOf:on:indent:
#byteSizeOfBytes: #generateByteSizeOf:on:indent:
#byteSizeOf: #generateByteSizeOf:on:indent:
#fetchClassOf: #generateFetchClassOf:on:indent:
#superclassOf: #generateSuperclassOf:on:indent:
#instanceSizeOf: #generateInstanceSizeOf:on:indent:
#is:KindOf: #generateIsKindOf:on:indent:
+ #isFloatObject: #generateIsFloatObject:on:indent:
#cDigitCopyFrom:to:len: #generateCDigitCopy:on:indent:
#sizeOfSTArrayFromCPrimitive: #generateSizeOfSTArrayFromCPrimitive:on:indent:
#asciiValue #generateIdentityUnary:on:indent:
#primitiveFail #generateInterpreterProxyCall:on:indent:
+ #intAtPointer: #generateIntAtPointer:on:indent:
).
1 to: pairs size by: 2 do: [:i |
translationDict at: (pairs at: i) put: (pairs at: i + 1)].
pairs := #(
#ifTrue: #generateIfTrueAsArgument:on:indent:
#ifFalse: #generateIfFalseAsArgument:on:indent:
#ifTrue:ifFalse: #generateIfTrueIfFalseAsArgument:on:indent:
#ifFalse:ifTrue: #generateIfFalseIfTrueAsArgument:on:indent:
#cCode: #generateInlineCCodeAsArgument:on:indent:
#cCode:inSmalltalk: #generateInlineCCodeAsArgument:on:indent:
).
asArgumentTranslationDict := Dictionary new: 8.
1 to: pairs size by: 2 do: [:i |
asArgumentTranslationDict at: (pairs at: i) put: (pairs at: i + 1)].
cCodeTranslationDict := Dictionary new: 8.
pairs := #(
'fprintf(stderr, "\n%s: %s", moduleName, s)' 'console.log(moduleName + ": " + s)'
'interpreterProxy->majorVersion() == VM_PROXY_MAJOR' 'interpreterProxy.majorVersion() == VM_PROXY_MAJOR'
'interpreterProxy->minorVersion() >= VM_PROXY_MINOR' 'interpreterProxy.minorVersion() >= VM_PROXY_MINOR'
+ 'sqrt(result)' 'Math.sqrt(result)'
+ 'sqrt(len)' 'Math.sqrt(len)'
).
1 to: pairs size by: 2 do: [:i |
cCodeTranslationDict at: (pairs at: i) put: (pairs at: i + 1)].
!
Item was added:
+ ----- Method: JSCodeGenerator>>isBuiltinSelector: (in category 'utilities') -----
+ isBuiltinSelector: sel
+ "Answer true if the given selector is one of the builtin selectors."
+
+ ^(self isKernelSelector: sel) or: [translationDict includesKey: sel]!
Item was added:
+ ----- Method: JSCodeGenerator>>isKernelSelector: (in category 'utilities') -----
+ isKernelSelector: sel
+ "Answer true if the given selector is one of the kernel selectors that are implemented as macros."
+
+ ^(#(error:
+ oopAt: oopAt:put: oopAtPointer: oopAtPointer:put:
+ byteAt: byteAt:put: byteAtPointer: byteAtPointer:put:
+ shortAt: shortAt:put: shortAtPointer: shortAtPointer:put:
+ intAt: intAt:put: intAtPointer: intAtPointer:put:
+ longAt: longAt:put: longAtPointer: longAtPointer:put:
+ longLongAt: longLongAt:put: longLongAtPointer: longLongAtPointer:put:
+ fetchFloatAt:into: storeFloatAt:from:
+ fetchFloatAtPointer:into: storeFloatAtPointer:from:
+ fetchSingleFloatAt:into: storeSingleFloatAt:from:
+ fetchSingleFloatAtPointer:into: storeSingleFloatAtPointer:from:
+ pointerForOop: oopForPointer:
+ cCoerce:to: cCoerceSimple:to:)
+ includes: sel)!
Item was changed:
----- Method: JSMethod>>argConversionExprFor:stackIndex: (in category 'primitive compilation') -----
argConversionExprFor: varName stackIndex: stackIndex
"Return the parse tree for an expression that fetches and converts the
primitive argument at the given stack offset."
| exprList decl stmtList |
oneBasedArrays ifNil: [oneBasedArrays := Set new]. "only non-nil in a primitive method"
exprList := OrderedCollection new.
(declarations includesKey: varName) ifTrue:[
decl := declarations at: varName.
(decl includes: $*) ifTrue:["array"
(decl includesSubString: 'char') ifTrue:[
exprList add: varName , ' := ', self vmNameString, ' stackBytes: ',stackIndex printString] ifFalse: [
+ (decl beginsWith: 'unsigned int') ifTrue:[
+ exprList add: varName , ' := ', self vmNameString, ' stackWords: ',stackIndex printString] ifFalse: [
(decl beginsWith: 'unsigned short') ifTrue:[
exprList add: varName , ' := ', self vmNameString, ' stackUint16Array: ',stackIndex printString] ifFalse: [
+ (decl beginsWith: 'short int') ifTrue:[
+ exprList add: varName , ' := ', self vmNameString, ' stackInt16Array: ',stackIndex printString] ifFalse: [
(decl beginsWith: 'int') ifTrue:[
exprList add: varName , ' := ', self vmNameString, ' stackInt32Array: ',stackIndex printString]
+ ifFalse: [self halt]]]]].
- ifFalse: [self halt]]].
self beOneBasedArray: varName.
] ifFalse:["must be a double"
(decl findString: 'double' startingAt: 1) = 0 ifTrue: [
self error: 'unsupported type declaration in a primitive method'
].
exprList add: varName , ' := ', self vmNameString, ' stackFloatValue: ' , stackIndex printString.
]
] ifFalse: ["undeclared variables are taken to be integer"
exprList add: varName , ' := ', self vmNameString, ' stackIntegerValue: ' , stackIndex printString
].
stmtList := OrderedCollection new.
exprList do: [:e | stmtList addAll: (self statementsFor: e varName: varName)].
^ stmtList!
Item was changed:
----- Method: JSMethod>>instVarGetExprFor:offset: (in category 'primitive compilation') -----
instVarGetExprFor: varName offset: instIndex
"Return the parse tree for an expression that fetches and converts the value of the instance variable at the given offset."
| exprList decl stmtList |
exprList := OrderedCollection new.
(declarations includesKey: varName) ifTrue: [
decl := declarations at: varName.
+ (decl includes: $*) ifTrue: ["array"
+ (decl includesSubString: 'char') ifTrue:[
+ exprList add: varName , ' := ', self vmNameString, ' fetchBytes: ', instIndex printString, ' ofObject: rcvr'] ifFalse: [
+ (decl includesSubString: 'unsigned int') ifTrue:[
+ exprList add: varName , ' := ', self vmNameString, ' fetchWords: ', instIndex printString, ' ofObject: rcvr'] ifFalse: [
+ (decl beginsWith: 'unsigned short') ifTrue:[
+ exprList add: varName , ' := ', self vmNameString, ' fetchUint16Array: ', instIndex printString, ' ofObject: rcvr'] ifFalse: [
+ (decl beginsWith: 'short int') ifTrue:[
+ exprList add: varName , ' := ', self vmNameString, ' fetchInt16Array: ', instIndex printString, ' ofObject: rcvr'] ifFalse: [
+ (decl beginsWith: 'int') ifTrue:[
+ exprList add: varName , ' := ', self vmNameString, ' fetchInt32Array: ', instIndex printString, ' ofObject: rcvr']
+ ifFalse: [self halt]]]]].
+ self beOneBasedArray: varName.
- (decl includes: $*) ifTrue: [ "array"
- exprList add:
- (varName, ' := ', self vmNameString, ' fetchArray: ', instIndex printString, ' ofObject: rcvr').
- exprList add: (varName, ' := ', varName, ' - 1').
] ifFalse: [ "must be a double"
((decl findString: 'double' startingAt: 1) = 0)
ifTrue: [ self error: 'unsupported type declaration in a primitive method' ].
exprList add:
(varName, ' := ', self vmNameString, ' fetchFloat: ', instIndex printString, ' ofObject: rcvr').
].
] ifFalse: [ "undeclared variables are taken to be integer"
exprList add:
(varName, ' := ', self vmNameString, ' fetchInteger: ', instIndex printString, ' ofObject: rcvr').
].
stmtList := OrderedCollection new.
exprList do: [:e | stmtList addAll: (self statementsFor: e varName: varName)].
^ stmtList
!
Item was changed:
----- Method: JSMethod>>prepareMethodIn: (in category 'transformations') -----
prepareMethodIn: aCodeGen
+ "Record sends of builtin operators, map sends of the special selector dispatchOn:in:
+ with case statement nodes, and map sends of caseOf:[otherwise:] to switch statements.
+ As a hack also update the types of variables introduced to implement cascades correctly.
+ This has to be done at the same time as this is done, so why not piggy back here?"
+ extraVariableNumber ifNotNil:
+ [declarations keysAndValuesDo:
+ [:varName :decl|
+ decl isBlock ifTrue:
+ [self assert: ((varName beginsWith: 'cascade') and: [varName last isDigit]).
+ locals add: varName.
+ self declarationAt: varName
+ put: (decl value: self value: aCodeGen), ' ', varName]]].
+ aCodeGen
+ pushScope: declarations
+ while:"N.B. nodesWithParentsDo: is bottom-up, hence replacement is destructive and conserved."
+ [parseTree nodesWithParentsDo:
+ [:node :parent|
+ node isSend ifTrue:
+ [(aCodeGen isBuiltinSelector: node selector)
+ ifTrue:
+ [node isBuiltinOperator: true.
+ "If a to:by:do:'s limit has side-effects, declare the limit variable, otherwise delete it from the args"
+ (node selector = #to:by:do:
+ and: [node args size = 4]) ifTrue:
+ [| limitExpr |
+ limitExpr := node args first.
+ (limitExpr anySatisfy:
+ [:subNode|
+ subNode isSend
+ and: [(aCodeGen isBuiltinSelector: subNode selector) not
+ and: [(subNode isStructSendIn: aCodeGen) not]]])
+ ifTrue: [ | limitVar |
+ limitVar := node args last name.
+ "n.b. Two loops in the same method may share the same variable
+ for loop limit, so add the variable declaration only if not already
+ declared by a previous loop. Assumes that the name of the loop
+ limit variable (e.g. 'iLimiT') is unlikely to have been used as an actual
+ instance variable elsewhere."
+ (locals includes: limitVar) ifFalse: [locals add: limitVar]]
+ ifFalse:
+ [node arguments: node args allButLast]]]
+ ifFalse:
+ [(CaseStatements includes: node selector) ifTrue:
+ [parent replaceNodesIn: (Dictionary newFromPairs: { node. self buildCaseStmt: node})].
+ (#(caseOf: #caseOf:otherwise:) includes: node selector) ifTrue:
+ [parent replaceNodesIn: (Dictionary newFromPairs: { node. self buildSwitchStmt: node parent: parent })]]]]]!
- "Record sends of builtin operators and replace sends of the special selector dispatchOn:in: with case statement nodes."
- "Note: Only replaces top-level sends of dispatchOn:in:. Case statements must be top-level statements; they cannot appear in expressions."
-
- | stmts stmt |
- parseTree nodesDo: [ :node |
- node isSend ifTrue: [
- "record sends of builtin operators"
- (aCodeGen builtin: node selector) ifTrue: [ node isBuiltinOperator: true ].
- ].
- node isStmtList ifTrue: [
- "replace dispatchOn:in: with case statement node"
- stmts := node statements.
- 1 to: stmts size do: [ :i |
- stmt := stmts at: i.
- (stmt isSend and: [CaseStatements includes: stmt selector]) ifTrue: [
- stmts at: i put: (self buildCaseStmt: stmt).
- ].
- ].
- ].
- ].!
More information about the Vm-dev
mailing list