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

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

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

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

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

Name: VMMaker.oscog-eem.2908
Author: eem
Time: 22 December 2020, 6:11:26.000244 pm
UUID: fddf1a4f-c585-45ab-8a74-442230cd3dbd
Ancestors: VMMaker.oscog-eem.2907

StackInterpreter:
Provide a selective event printing facility for primGetNextEvent:. Add vm parameter 12 (also potentially settable via a command line argument) to provide a mask of event types to print.

Slang:
Upgrade the f:printf: transformation to allow specifying stderr as the stream. Upgrade literal array declararions to allow more than one (mangle the target variable name).

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

Item was changed:
  ----- Method: Array>>coerceTo:sim: (in category '*VMMaker-interpreter simulator') -----
  coerceTo: cTypeString sim: interpreterSimulator
+ ^CLiteralArray on: self!
-
- ^ self!

Item was changed:
  VMClass subclass: #InterpreterPrimitives
+ instanceVariableNames: 'objectMemory messageSelector argumentCount newMethod primFailCode osErrorCode exceptionPC inFFIFlags profileMethod profileProcess profileSemaphore nextProfileTick preemptionYields newFinalization sHEAFn ffiExceptionResponse eventTraceMask'
- instanceVariableNames: 'objectMemory messageSelector argumentCount newMethod primFailCode osErrorCode exceptionPC inFFIFlags profileMethod profileProcess profileSemaphore nextProfileTick preemptionYields newFinalization sHEAFn ffiExceptionResponse'
  classVariableNames: 'CrossedX EndOfRun MillisecondClockMask'
  poolDictionaries: 'VMBasicConstants VMBytecodeConstants VMMethodCacheConstants VMObjectIndices VMSqueakClassIndices VMStackFrameOffsets'
  category: 'VMMaker-Interpreter'!
 
  !InterpreterPrimitives commentStamp: 'eem 8/24/2018 11:05' prior: 0!
  InterpreterPrimitives implements most of the VM's core primitives.  It is the root of the interpreter hierarchy so as to share the core primitives amongst the varioius interpreters.
 
  Instance Variables
  argumentCount <Integer>
  ffiExceptionResponse <Integer>
  inFFIFlags <Integer>
  messageSelector <Integer>
  newMethod <Integer>
  nextProfileTick <Integer>
  objectMemory <ObjectMemory> (simulation only)
  preemptionYields <Boolean>
  primFailCode <Integer>
  osErrorCode <Integer>
  profileMethod <Integer>
  profileProcess <Integer>
  profileSemaphore <Integer>
  secHasEnvironmentAccess <Integer>
 
  argumentCount
  - the number of arguments of the current message
 
  ffiExceptionResponse
  - controls system response to exceptions during FFI calls.  See primitiveFailForFFIException:at:
 
  inFFIFlags
  - flags recording currently only whether the system is in an FFI call
 
  messageSelector
  - the oop of the selector of the current message
 
  newMethod
  - the oop of the result of looking up the current message
 
  nextProfileTick
  - the millisecond clock value of the next profile tick (if profiling is in effect)
 
  objectMemory
  - the memory manager and garbage collector that manages the heap
 
  preemptionYields
  - a boolean controlling the process primitives.  If true (old, incorrect, blue-book semantics) a preempted process is sent to the back of its run-queue.  If false, a process preempted by a higher-priority process is put back at the head of its run queue, hence preserving cooperative scheduling within priorities.
 
  primFailCode
  - primitive success/failure flag, 0 for success, otherwise the reason code for failure
 
  osErrorCode
  - a 64-bit value settable by external primitives conveying arbitrary error codes from the operating system and/or system libraries
 
  profileMethod
  - the oop of the method at the time nextProfileTick was reached
 
  profileProcess
  - the oop of the activeProcess at the time nextProfileTick was reached
 
  profileSemaphore
  - the oop of the semaphore to signal when nextProfileTick is reached
 
  secHasEnvironmentAccess
  - the function to call to check if access to the envronment should be granted to primitiveGetenv
  !

Item was changed:
  ----- Method: InterpreterPrimitives>>initialize (in category 'initialization') -----
  initialize
  "Here we can initialize the variables C initializes to zero.  #initialize methods do /not/ get translated."
+ argumentCount := primFailCode := nextProfileTick := osErrorCode := exceptionPC := inFFIFlags := ffiExceptionResponse := eventTraceMask := 0.
- argumentCount := primFailCode := nextProfileTick := osErrorCode := exceptionPC := inFFIFlags := ffiExceptionResponse := 0.
  newFinalization := false!

Item was changed:
  ----- Method: InterpreterPrimitives>>primitiveGetNextEvent (in category 'I/O primitives') -----
  primitiveGetNextEvent
  "Primitive. Return the next input event from the VM event queue."
  | evtBuf arg value eventTypeIs |
  <var: #evtBuf declareC:'sqIntptr_t evtBuf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }'>
  self cCode: [] inSmalltalk: [evtBuf := objectMemory newInputEventAccessorOfSize: 8].
  arg := self stackTop.
  ((objectMemory isArray: arg) and:[(objectMemory slotSizeOf: arg) = 8]) ifFalse:
  [^self primitiveFailFor: PrimErrBadArgument].
 
  self ioGetNextEvent: (self cCoerce: evtBuf to: 'sqInputEvent*').
  self successful ifFalse:
  [^nil].
 
+ (eventTraceMask ~= 0
+ and: [eventTraceMask anyMask: (1 bitShift: (evtBuf at: 0))]) ifTrue:
+ [self traceInputEvent: evtBuf].
+
  "Event type"
  eventTypeIs := evtBuf at: 0.
  self storeInteger: 0 ofObject: arg withValue: (evtBuf at: 0).
  self successful ifFalse:
  [^nil].
 
  eventTypeIs = 6
  ifTrue: "Event is Complex, assume evtBuf is populated correctly and return"
  [1 to: 7 do: [:i |
  value := evtBuf at: i.
  self storePointer: i ofObject: arg withValue: value]]
  ifFalse:
  ["Event time stamp"
  self storeInteger: 1 ofObject: arg withValue: ((evtBuf at: 1) bitAnd: MillisecondClockMask).
  self successful ifFalse:
  [^nil].
 
  "Event arguments"
  2 to: 7 do:[:i|
  value := evtBuf at: i.
  (objectMemory isIntegerValue: value)
  ifTrue:[self storeInteger: i ofObject: arg withValue: value]
  ifFalse:
  [value := self positiveMachineIntegerFor: value.
  objectMemory storePointer: i ofObject: arg withValue: value]]].
 
  self successful ifTrue: [self pop: 1]!

Item was added:
+ ----- Method: InterpreterPrimitives>>traceInputEvent: (in category 'I/O primitive support') -----
+ traceInputEvent: evtBuf
+ <var: #evtBuf declareC: 'sqIntptr_t evtBuf[8]'>
+ | eventTypeNames |
+ eventTypeNames := self
+ cCoerce: #('None' 'Mouse' 'Keyboard' 'DragDropFiles' 'Menu' 'Window' 'Complex' 'MouseWheel' 'Plugin')
+ to: #'char **'.
+ 'Event%s/%d @ %u\t\t%d/%x %d/%x\n\t%d/%x %d/%x\t %d/%x %p\n'
+ f: #stderr
+ printf: { ((evtBuf at: 0) between: 0 and: 8)
+ ifTrue: [eventTypeNames at: (evtBuf at: 0)]
+ ifFalse: ['?'].
+ evtBuf at: 0.
+ evtBuf at: 1. "timestamp"
+ evtBuf at: 2. evtBuf at: 2. evtBuf at: 3. evtBuf at: 3.
+ evtBuf at: 4. evtBuf at: 4. evtBuf at: 5. evtBuf at: 5.
+ evtBuf at: 6. evtBuf at: 6.
+ evtBuf at: 7 } "windowIndex"!

Item was changed:
  ----- Method: StackInterpreter class>>mustBeGlobal: (in category 'translation') -----
  mustBeGlobal: var
  "Answer if a variable must be global and exported.  Used for inst vars that are accessed from VM support code,
  and for variables that are initialized to some value (e.g. primitiveDoMixedArithmetic)."
 
  ^(super mustBeGlobal: var)
    or: [(self objectMemoryClass mustBeGlobal: var)
    or: [(#('interpreterProxy' 'interpreterVersion' 'inIOProcessEvents' 'sendWheelEvents'
+ 'deferDisplayUpdates' 'eventTraceMask' 'extraVMMemory'
- 'deferDisplayUpdates' 'extraVMMemory'
  'showSurfaceFn' 'displayBits' 'displayWidth' 'displayHeight' 'displayDepth'
  'desiredNumStackPages' 'desiredEdenBytes'
  'primitiveDoMixedArithmetic'
  'breakLookupClassTag' 'breakSelector' 'breakSelectorLength' 'sendTrace' 'checkAllocFiller' 'checkedPluginName'
  "'reenterInterpreter'" 'suppressHeartbeatFlag' 'ffiExceptionResponse'
  'debugCallbackInvokes' 'debugCallbackPath' 'debugCallbackReturns') includes: var)
    or: [ "This allows slow machines to define bytecodeSetSelector as 0
  to avoid the interpretation overhead."
  MULTIPLEBYTECODESETS not and: [var = 'bytecodeSetSelector']]]]!

Item was changed:
  ----- Method: StackInterpreterPrimitives>>primitiveAllVMParameters: (in category 'system control primitives') -----
(excessive size, no diff calculated)

Item was changed:
  ----- Method: StackInterpreterPrimitives>>primitiveGetVMParameter: (in category 'system control primitives') -----
  primitiveGetVMParameter: arg
  "See primitiveVMParameter method comment.
  N.B. written as a returning case to avoid branch limits in the V3 bytecode set."
  arg caseOf: {
  [1]  -> [^self positiveMachineIntegerFor: objectMemory oldSpaceSize].
  [2]  -> [^objectMemory integerObjectOf: objectMemory newSpaceSize].
  [3]  -> [^self positiveMachineIntegerFor: objectMemory totalMemorySize].
  [6]  -> [^objectMemory integerObjectOf: objectMemory tenuringThreshold].
  [7]  -> [^objectMemory integerObjectOf: objectMemory statFullGCs].
  [8]  -> [^objectMemory integerObjectOf: objectMemory statFullGCUsecs + 500 // 1000].
  [9]  -> [^objectMemory integerObjectOf: (objectMemory hasSpurMemoryManagerAPI
  ifTrue: [objectMemory statScavenges]
  ifFalse: [objectMemory statIncrGCs])].
  [10] -> [^objectMemory integerObjectOf: (objectMemory hasSpurMemoryManagerAPI
  ifTrue: [objectMemory statScavengeGCUsecs]
  ifFalse: [objectMemory statIncrGCUsecs]) + 500 // 1000].
  [11] -> [^objectMemory integerObjectOf: objectMemory statTenures].
+ [12] -> [^objectMemory integerObjectOf: eventTraceMask].
- [12] -> [^ConstZero]. "Was JITTER VM info"
  [13] -> [^self getVMTickerStartUSecs].
  [14] -> [^self getVMTickerCount].
  [15] -> [^self getVMTickeeCallCount].
  [16] -> [^self positive64BitIntegerFor: statIdleUsecs].
  [17] -> [^(SistaVM and: [self isCog])
  ifTrue: [objectMemory floatObjectOf: self getCogCodeZoneThreshold]
  ifFalse: [ConstZero]].
  [18] -> [^objectMemory hasSpurMemoryManagerAPI
  ifTrue: [objectMemory integerObjectOf: objectMemory statCompactionUsecs + 500 // 1000]
  ifFalse: [ConstZero]].
  [19] -> [^objectMemory hasSpurMemoryManagerAPI
  ifTrue: [objectMemory integerObjectOf: objectMemory scavengeThresholdAsExtent]
  ifFalse: [ConstZero]].
  [20] -> [^objectMemory positive64BitIntegerFor: self ioUTCStartMicroseconds].
  [21] -> [^objectMemory integerObjectOf: objectMemory rootTableCount].
  [22] -> [^objectMemory integerObjectOf: objectMemory statRootTableOverflows].
  [23] -> [^objectMemory integerObjectOf: extraVMMemory].
  [24] -> [^objectMemory integerObjectOf: objectMemory shrinkThreshold].
  [25] -> [^objectMemory integerObjectOf: objectMemory growHeadroom].
  [26] -> [^objectMemory integerObjectOf: self ioHeartbeatMilliseconds].
  [27] -> [^objectMemory integerObjectOf: objectMemory statMarkCount].
  [28] -> [^objectMemory integerObjectOf: objectMemory statSweepCount].
  [29] -> [^objectMemory integerObjectOf: objectMemory statMkFwdCount].
  [30] -> [^objectMemory integerObjectOf: objectMemory statCompMoveCount].
  [31] -> [^objectMemory integerObjectOf: objectMemory statGrowMemory].
  [32] -> [^objectMemory integerObjectOf: objectMemory statShrinkMemory].
  [33] -> [^objectMemory integerObjectOf: objectMemory statRootTableCount].
  [34] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:"was statAllocationCount"
  [objectMemory positive64BitIntegerFor: objectMemory currentAllocatedBytes]].
  [35] -> [^objectMemory integerObjectOf: objectMemory statSurvivorCount].
  [36] -> [^objectMemory integerObjectOf: (self microsecondsToMilliseconds: objectMemory statGCEndUsecs)].
  [37] -> [^objectMemory integerObjectOf: objectMemory statSpecialMarkCount].
  [38] -> [^objectMemory integerObjectOf: objectMemory statIGCDeltaUsecs + 500 // 1000].
  [39] -> [^objectMemory integerObjectOf: statPendingFinalizationSignals].
  [40] -> [^objectMemory integerObjectOf: objectMemory wordSize].
  [41] -> [^objectMemory integerObjectOf: self imageFormatVersion].
  [42] -> [^objectMemory integerObjectOf: numStackPages].
  [43] -> [^objectMemory integerObjectOf: desiredNumStackPages].
  [44] -> [^objectMemory integerObjectOf: objectMemory edenBytes].
  [45] -> [^objectMemory integerObjectOf: desiredEdenBytes].
  [46] -> [^self getCogCodeSize].
  [47] -> [^self getDesiredCogCodeSize].
  [48] -> [^self getImageHeaderFlagsParameter].
  [49] -> [^objectMemory integerObjectOf: self ioGetMaxExtSemTableSize].
  [52] -> [^objectMemory integerObjectOf: objectMemory rootTableCapacity].
  [53] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:
  [objectMemory integerObjectOf: objectMemory numSegments]].
  [54] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:
  [objectMemory integerObjectOf: objectMemory freeSize]].
  [55] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:
  [objectMemory floatObjectOf: objectMemory getHeapGrowthToSizeGCRatio]].
  [56] -> [^self positive64BitIntegerFor: statProcessSwitch].
  [57] -> [^self positive64BitIntegerFor: statIOProcessEvents].
  [58] -> [^self positive64BitIntegerFor: statForceInterruptCheck].
  [59] -> [^self positive64BitIntegerFor: statCheckForEvents].
  [60] -> [^self positive64BitIntegerFor: statStackOverflow].
  [61] -> [^self positive64BitIntegerFor: statStackPageDivorce].
  [62] -> [^self getCodeCompactionCount].
  [63] -> [^self getCodeCompactionMSecs].
  [64] -> [^self getCogMethodCount].
  [65] -> [^self getCogVMFeatureFlags].
  [66] -> [^objectMemory integerObjectOf: self stackPageByteSize].
  [67] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:
  [self positiveMachineIntegerFor: objectMemory maxOldSpaceSize]].
  [68] -> [^objectMemory floatObjectOf: stackPages statAverageLivePagesWhenMapping].
  [69] -> [^objectMemory integerObjectOf: stackPages statMaxPageCountWhenMapping].
  [70] -> [^objectMemory integerObjectOf: self vmProxyMajorVersion].
  [71] -> [^objectMemory integerObjectOf: self vmProxyMinorVersion].
  [72] -> [^objectMemory integerObjectOf: objectMemory statMarkUsecs + 500 // 1000].
  [73] -> [^objectMemory integerObjectOf: objectMemory statSweepUsecs + 500 // 1000].
  [74] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:
  [objectMemory integerObjectOf: objectMemory statMaxAllocSegmentTime + 500 // 1000]].
  [75] -> [^objectMemory booleanObjectOf: self primitiveDoMixedArithmetic] }
  otherwise: [^nil]!

Item was changed:
  ----- Method: StackInterpreterPrimitives>>primitiveSetVMParameter:arg: (in category 'system control primitives') -----
  primitiveSetVMParameter: index arg: argOop
  "See primitiveVMParameter method comment"
  | arg result |
 
  "argOop read & checks; in most cases this is an integer parameter. Handle the exceptions."
  index
  caseOf: {
  [17] -> [((objectMemory isFloatInstance: argOop)
  or: [objectMemory isIntegerObject: argOop]) ifFalse:
  [primFailCode := PrimErrBadArgument]].
  [55] -> [((objectMemory isFloatInstance: argOop)
  or: [objectMemory isIntegerObject: argOop]) ifFalse:
  [primFailCode := PrimErrBadArgument]].
  [68] -> [((objectMemory isFloatInstance: argOop)
  or: [objectMemory isIntegerObject: argOop]) ifFalse:
  [primFailCode := PrimErrBadArgument]].
  [67] -> [arg := self positiveMachineIntegerValueOf: argOop].
  [75] -> [arg := objectMemory booleanValueOf: argOop] }
  otherwise: [arg := objectMemory integerValueOf: argOop].
  self failed ifTrue:
  [^self primitiveFailFor: PrimErrBadArgument].
 
  "assume failure, then set success for handled indices"
  self primitiveFailFor: PrimErrBadArgument.
  index caseOf: {
  [5] -> [objectMemory hasSpurMemoryManagerAPI ifFalse:
  ["Was:
  result := allocationsBetweenGCs.
  allocationsBetweenGCs := arg."
  "Ignore for now, because old images won't start up otherwise.
  See 45 for eden size setting."
  result := objectMemory nilObject.
  self initPrimCall]].
  [6] -> [result := objectMemory integerObjectOf: objectMemory tenuringThreshold.
  primFailCode := objectMemory tenuringThreshold: arg].
+ [12] -> [result := objectMemory integerObjectOf: eventTraceMask.
+ eventTraceMask := arg.
+ self initPrimCall].
  [11] -> [arg >= 0 ifTrue:
  [result := objectMemory integerObjectOf: objectMemory statTenures.
  objectMemory statTenures: arg.
  self initPrimCall]].
  [17] -> [(SistaVM and: [self isCog]) ifTrue:
  [result := objectMemory floatObjectOf: self getCogCodeZoneThreshold.
  primFailCode := self setCogCodeZoneThreshold: (self noInlineLoadFloatOrIntFrom: argOop)]].
  [23] -> [result := objectMemory integerObjectOf: extraVMMemory.
  extraVMMemory := arg.
  self initPrimCall].
  [24] -> [arg > 0 ifTrue:
  [result := objectMemory integerObjectOf: objectMemory shrinkThreshold.
  objectMemory shrinkThreshold: arg.
  self initPrimCall]].
  [25] -> [arg > 0 ifTrue:
  [result := objectMemory integerObjectOf: objectMemory growHeadroom.
  objectMemory growHeadroom: arg.
  self initPrimCall]].
  [26] -> [arg >= 0 ifTrue: "0 turns off the heartbeat"
  [result := objectMemory integerObjectOf: self ioHeartbeatMilliseconds.
  self ioSetHeartbeatMilliseconds: arg.
  self initPrimCall]].
  [34] -> [(objectMemory hasSpurMemoryManagerAPI "was statAllocationCount; now statAllocatedBytes"
   and: [arg >= 0]) ifTrue:
  [result := objectMemory positive64BitIntegerFor: objectMemory currentAllocatedBytes.
  objectMemory setCurrentAllocatedBytesTo: arg.
  self initPrimCall]].
  [43] -> [(arg between: 0 and: 65535) ifTrue:
  [result := objectMemory integerObjectOf: desiredNumStackPages.
  desiredNumStackPages := arg.
  self initPrimCall]].
  [45] -> [arg >= 0 ifTrue:
  [result := objectMemory integerObjectOf: desiredEdenBytes.
  desiredEdenBytes := arg.
  self initPrimCall]].
  [47] -> [(self isCog
   and: [arg between: 0 and: self maxCogCodeSize]) ifTrue:
  [result := objectMemory integerObjectOf: self getDesiredCogCodeSize.
  self setDesiredCogCodeSize: arg.
  self initPrimCall]].
  [48] -> [arg >= 0 ifTrue:
  [| oldPrimitiveDoMixedArithmetic |
  oldPrimitiveDoMixedArithmetic := primitiveDoMixedArithmetic.
  result := self getImageHeaderFlagsParameter.
  self initPrimCall. "i.e. setImageHeaderFlags: can fail"
  self setImageHeaderFlags: arg.
  (primFailCode = 0
   and: [oldPrimitiveDoMixedArithmetic ~= primitiveDoMixedArithmetic]) ifTrue:
  [self flushMethodCache.
  self flushMethodsWithMachineCodePrimitivesAndContinueAnswering: result
  "NOT REACHED (in CoInterpreter)"]]].
  [49] -> [(arg between: 0 and: 65535) ifTrue:
  [result := objectMemory integerObjectOf: self ioGetMaxExtSemTableSize.
  self initPrimCall. "i.e. ioSetMaxExtSemTableSize: is allowed to fail"
  self setMaxExtSemSizeTo: arg]].
  [55] -> [objectMemory hasSpurMemoryManagerAPI ifTrue:
  [result := objectMemory floatObjectOf: objectMemory getHeapGrowthToSizeGCRatio.
  primFailCode := objectMemory setHeapGrowthToSizeGCRatio: (self noInlineLoadFloatOrIntFrom: argOop)]].
  [67] -> [(arg >= 0
   and: [objectMemory hasSpurMemoryManagerAPI]) ifTrue:
  [result := self positiveMachineIntegerFor: objectMemory maxOldSpaceSize.
  primFailCode := objectMemory setMaxOldSpaceSize: arg]].
  [68] -> [result := objectMemory floatObjectOf: stackPages statAverageLivePagesWhenMapping.
  self initPrimCall. "i.e. statAverageLivePagesWhenMapping: is allowed to fail"
  stackPages statAverageLivePagesWhenMapping: (self noInlineLoadFloatOrIntFrom: argOop)].
  [69] -> [arg >= 0 ifTrue:
  [result := objectMemory integerObjectOf: stackPages statMaxPageCountWhenMapping.
  stackPages statMaxPageCountWhenMapping: arg.
  self initPrimCall]].
  [74] -> [(arg >= 0
   and: [objectMemory hasSpurMemoryManagerAPI]) ifTrue:
  [result := objectMemory integerObjectOf: objectMemory statMaxAllocSegmentTime + 500 // 1000.
  stackPages statMaxAllocSegmentTime: arg. "usually 0"
  self initPrimCall]].
  [75] -> [| mustFlush |
  result := objectMemory booleanObjectOf: self primitiveDoMixedArithmetic.
  self initPrimCall.
  mustFlush := primitiveDoMixedArithmetic ~= arg.
  primitiveDoMixedArithmetic := arg.
  mustFlush ifTrue:
  [self flushMethodCache.
  self flushMethodsWithMachineCodePrimitivesAndContinueAnswering: result
  "NOT REACHED (in CoInterpreter)"]] }
  otherwise: [].
 
  self successful
  ifTrue: [self methodReturnValue: result]  "return old value"
  ifFalse: [self primitiveFailFor: PrimErrInappropriate] "attempting to write a read-only or non-existent parameter"!

Item was changed:
  ----- Method: TAssignmentNode>>emitLiteralArrayDeclarationOn:level:generator: (in category 'C code generation') -----
  emitLiteralArrayDeclarationOn: aStream level: level generator: aCCodeGen
+ | type literalName |
- | type |
  type := expression args last value.
  self assert: type last = $*.
+ literalName := variable name, 'Initializer'.
  aStream
  crtab: level;
  nextPutAll: '{ static ';
  nextPutAll: (aCCodeGen
+ arrayInitializerCalled: literalName
- arrayInitializerCalled: 'aLiteralArray'
  for: expression args first value
  sizeString: nil
  type: type allButLast) withBlanksTrimmed;
  nextPut: $;;
  crtab: level + 1;
  nextPutAll: variable name;
+ nextPutAll: ' = ';
+ nextPutAll: literalName;
+ nextPut: $; ;
- nextPutAll: ' = aLiteralArray;';
  crtab: level;
  nextPut: $};
  cr!

Item was changed:
  ----- Method: TMethod>>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.
  Declare limit variables for to:[by:]do: loops with limits that potentially have side-effects.
  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 ifStaticallyResolvedPolymorphicReceiverThenUpdateSelectorIn: node.
  (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: ifTrue:
  [self ensureToByDoLoopLimitIsSafeAndEfficient: node in: aCodeGen]]
  ifFalse:
  [(CaseStatements includes: node selector) ifTrue:
  [parent replaceNodesIn: (Dictionary newFromPairs: { node. self buildCaseStmt: node in: aCodeGen})].
  (#(caseOf: #caseOf:otherwise:) includes: node selector) ifTrue:
  [parent replaceNodesIn: (Dictionary newFromPairs: { node. self buildSwitchStmt: node parent: parent })].
  (#(printf: f:printf:) includes: node selector) ifTrue:
+ [self transformPrintf: node]]]]]!
- [| map |
- map := Dictionary new.
- node nodesDo:
- [:subNode|
- (subNode isConstant and: [subNode value isString and: [subNode value includes: $%]]) ifTrue:
- [map at: subNode put: subNode asPrintfFormatStringNode].
- node replaceNodesIn: map]]]]]]!

Item was added:
+ ----- Method: TMethod>>transformPrintf: (in category 'transformations') -----
+ transformPrintf: sendNode
+ "Handle forms of f:printf: & printf:. f:printf: is either
+ logFile f: formatLiteral printf: args
+ or
+ formatLiteral f: streamName printf: args
+ printf is
+ formatLiteral printf: args"
+ | map |
+ (sendNode receiver isConstant
+ and: [sendNode receiver value isString]) ifTrue:
+ [| format |
+   format := sendNode receiver asPrintfFormatStringNode.
+ sendNode selector first == $f ifTrue: "fprintf et al..."
+ [sendNode receiver: (TVariableNode new setName: 'self').
+ sendNode arguments: {sendNode args first. format}, sendNode args allButFirst.
+ ^sendNode].
+ sendNode receiver: format.
+ ^sendNode].
+ map := Dictionary new.
+ sendNode nodesDo:
+ [:subNode|
+ (subNode isConstant and: [subNode value isString and: [subNode value includes: $%]]) ifTrue:
+ [map at: subNode put: subNode asPrintfFormatStringNode]].
+ sendNode replaceNodesIn: map.
+ ^sendNode!