[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