@@ -439,26 +439,71 @@ bool MethodGenerationContext::InlineAndOr(bool isOr) {
439439 return true ;
440440}
441441
442+ bool MethodGenerationContext::InlineToDo () {
443+ // HACK: We do assume that the receiver on the stack is a integer,
444+ // HACK: similar to the other inlined messages.
445+ // HACK: We don't support anything but integer at the moment.
446+ assert (Bytecode::GetBytecodeLength (BC_PUSH_BLOCK) == 2 );
447+ if (!hasOneLiteralBlockArgument ()) {
448+ return false ;
449+ }
450+
451+ VMMethod* toBeInlined =
452+ static_cast <VMMethod*>(extractBlockMethodAndRemoveBytecode ());
453+
454+ toBeInlined->MergeScopeInto (*this );
455+
456+ const Variable* blockArg = toBeInlined->GetArgument (1 , 0 );
457+ uint8_t iVarIdx = GetInlinedLocalIdx (blockArg);
458+
459+ isCurrentlyInliningABlock = true ;
460+ EmitDupSecond (*this );
461+
462+ size_t loopBeginIdx = OffsetOfNextInstruction ();
463+ size_t jumpOffsetIdxToEnd = EmitJumpIfGreaterWithDummyOffset (*this );
464+
465+ EmitDUP (*this );
466+
467+ EmitPOPLOCAL (*this , iVarIdx, 0 );
468+
469+ toBeInlined->InlineInto (*this , false );
470+
471+ EmitPOP (*this );
472+ EmitINC (*this );
473+
474+ EmitBackwardsJumpOffsetToTarget (loopBeginIdx);
475+
476+ PatchJumpOffsetToPointToNextInstruction (jumpOffsetIdxToEnd);
477+
478+ isCurrentlyInliningABlock = false ;
479+
480+ return true ;
481+ }
482+
442483void MethodGenerationContext::CompleteLexicalScope () {
443484 lexicalScope = new LexicalScope (
444485 outerGenc == nullptr ? nullptr : outerGenc->lexicalScope , arguments,
445486 locals);
446487}
447488
448489void MethodGenerationContext::MergeIntoScope (LexicalScope& scopeToBeInlined) {
449- assert (scopeToBeInlined.GetNumberOfArguments () == 1 );
450- size_t numLocals = scopeToBeInlined.GetNumberOfLocals ();
451- if (numLocals > 0 ) {
452- inlineLocals (scopeToBeInlined);
490+ if (scopeToBeInlined.GetNumberOfArguments () > 1 ) {
491+ inlineAsLocals (scopeToBeInlined.arguments );
492+ }
493+
494+ if (scopeToBeInlined.GetNumberOfLocals () > 0 ) {
495+ inlineAsLocals (scopeToBeInlined.locals );
453496 }
454497}
455498
456- void MethodGenerationContext::inlineLocals (LexicalScope& scopeToBeInlined ) {
457- for (const Variable& local : scopeToBeInlined. locals ) {
458- Variable freshCopy = local .CopyForInlining (this ->locals .size ());
499+ void MethodGenerationContext::inlineAsLocals (vector<Variable>& vars ) {
500+ for (const Variable& var : vars ) {
501+ Variable freshCopy = var .CopyForInlining (this ->locals .size ());
459502 if (freshCopy.IsValid ()) {
503+ assert (!freshCopy.IsArgument ());
504+
460505 // freshCopy can be invalid, because we don't need the $blockSelf
461- std::string qualifiedName = local .MakeQualifiedName ();
506+ std::string qualifiedName = var .MakeQualifiedName ();
462507 assert (!Contains (this ->locals , qualifiedName));
463508 lexicalScope->AddInlinedLocal (freshCopy);
464509 this ->locals .push_back (freshCopy);
0 commit comments