Initial commit
[profile/ivi/openjade.git] / style / Insn.cxx
1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
3
4 #include "stylelib.h"
5 #include "VM.h"
6 #include "Insn.h"
7 #include "Interpreter.h"
8 #include "InterpreterMessages.h"
9 #include "ELObjMessageArg.h"
10 #include "Expression.h"
11 #include "macros.h"
12 #include "Insn2.h"
13 #include "SosofoObj.h"
14 #include "Node.h"
15 #include "ELObjPropVal.h"
16 #include <string.h>
17 #include <stddef.h>
18 #include <stdio.h>
19
20 #ifdef DSSSL_NAMESPACE
21 namespace DSSSL_NAMESPACE {
22 #endif
23
24
25 VM::VM(Interpreter &interpreter)
26 : Collector::DynamicRoot(interpreter), interp(&interpreter)
27 {
28   init();
29 }
30
31 VM::VM(EvalContext &context, Interpreter &interpreter)
32 : EvalContext(context), Collector::DynamicRoot(interpreter), interp(&interpreter)
33 {
34   init();
35 }
36
37 void VM::init()
38 {
39   slim = 0;
40   sbase = 0;
41   sp = 0;
42   closure = 0;
43   frame = 0;
44   protectClosure = 0;
45   csp = 0;
46   cslim = 0;
47   csbase = 0;
48   closureLoc.clear();
49 }
50
51 VM::~VM()
52 {
53   delete [] sbase;
54   delete [] csbase;
55 }
56
57 void VM::initStack()
58 {
59   sp = sbase;
60   frame = sbase;
61   csp = csbase;
62   modeStack.resize(0);
63 }
64
65 void VM::growStack(int n)
66 {
67   size_t newSize = sp - sbase;
68   if (n > newSize)
69     newSize += (n + 15) & ~15;
70   else
71     newSize += newSize;
72   ELObj **newStack = new ELObj *[newSize];
73   slim = newStack + newSize;
74   memcpy(newStack, sbase, (sp - sbase)*sizeof(ELObj *));
75   sp = newStack + (sp - sbase);
76   frame = newStack + (frame - sbase);
77   if (sbase)
78     delete [] sbase;
79   sbase = newStack;
80 }
81
82 void VM::trace(Collector &c) const
83 {
84   if (sp) {
85     for (ELObj **p = sbase; p != sp; p++)
86       c.trace(*p);
87   }
88   for (ControlStackEntry *p = csbase; p != csp; p++) {
89     c.trace(p->protectClosure);
90     c.trace(p->continuation);
91   }
92   c.trace(protectClosure);
93 }
94
95 void VM::pushFrame(const Insn *next, int argsPushed)
96 {
97   if (csp >= cslim) {
98     size_t newSize = csbase ? (cslim - csbase)*2 : 8;
99     ControlStackEntry *newBase = new ControlStackEntry[newSize];
100     cslim = newBase + newSize;
101     ControlStackEntry *newP = newBase;
102     for (const ControlStackEntry *oldP = csbase; oldP < csp; oldP++)
103       *newP++ = *oldP;
104     csp = newP;
105     if (csbase)
106       delete [] csbase;
107     csbase = newBase;
108   }
109   csp->closure = closure;
110   csp->protectClosure = protectClosure;
111   csp->next = next;
112   csp->frameSize = sp - frame - argsPushed;
113   csp->closureLoc = closureLoc;
114   csp->continuation = 0;
115   csp++;
116 }
117
118 const Insn *VM::popFrame()
119 {
120   ASSERT(csp > csbase);
121   --csp;
122   if (csp->continuation)
123     csp->continuation->kill();
124   closure = csp->closure;
125   protectClosure = csp->protectClosure;
126   frame = sp - csp->frameSize;
127   closureLoc = csp->closureLoc;
128   return csp->next;
129 }
130
131 void VM::setClosureArgToCC()
132 {
133   ASSERT(nActualArgs == 1);
134   ContinuationObj *cc = (ContinuationObj *)sp[-1];
135   csp[-1].continuation = cc;
136   cc->set(sp - sbase, csp - csbase);
137 }
138
139 ELObj *VM::eval(const Insn *insn, ELObj **display, ELObj *arg)
140 {
141   initStack();
142   if (arg) {
143     needStack(1);
144     *sp++ = arg;
145   }
146   closure = display;
147   protectClosure = 0;
148   closureLoc.clear();
149   // The inner loop.
150   while (insn)
151     insn = insn->execute(*this);
152   ELObj *result;
153   if (sp) {
154     sp--;
155     ASSERT(sp == sbase);
156     ASSERT(csp == csbase);
157     result = *sp;
158     ASSERT(result != 0);
159   }
160   else {
161     if (interp->debugMode())
162       stackTrace();
163     result = interp->makeError();
164   }
165   return result;
166 }
167
168 void VM::stackTrace()
169 {
170   unsigned long count = 0;
171   if (protectClosure) {
172     interp->setNextLocation(closureLoc);
173     interp->message(InterpreterMessages::stackTrace);
174     count++;
175   }
176   ControlStackEntry *lim = csbase;
177   if (csp != csbase && !csbase->protectClosure)
178     lim++;
179   for (ControlStackEntry *p = csp; p != lim; p--) {
180     interp->setNextLocation(p[-1].closureLoc);
181     count++;
182     if (count == 5 && p - lim > 7) {
183       interp->message(InterpreterMessages::stackTraceEllipsis,
184                       NumberMessageArg(p - (lim + 6)));
185       p = lim + 6;
186     }
187     else
188       interp->message(InterpreterMessages::stackTrace);
189   }
190 }
191
192 Insn::~Insn()
193 {
194 }
195
196 bool Insn::isReturn(int &) const
197 {
198   return false;
199 }
200
201 bool Insn::isPopBindings(int &, InsnPtr &) const
202 {
203   return false;
204 }
205
206 const Insn *ErrorInsn::execute(VM &vm) const
207 {
208   vm.sp = 0;
209   return 0;
210 }
211
212 CondFailInsn::CondFailInsn(const Location &loc)
213 : loc_(loc)
214 {
215 }
216
217 const Insn *CondFailInsn::execute(VM &vm) const
218 {
219   vm.interp->setNextLocation(loc_);
220   vm.interp->message(InterpreterMessages::condFail);
221   return ErrorInsn::execute(vm);
222 }
223
224 CaseFailInsn::CaseFailInsn(const Location &loc)
225 : loc_(loc)
226 {
227 }
228
229 const Insn *CaseFailInsn::execute(VM &vm) const
230 {
231   vm.interp->setNextLocation(loc_);
232   vm.interp->message(InterpreterMessages::caseFail, ELObjMessageArg(vm.sp[-1], *vm.interp));
233   return ErrorInsn::execute(vm);
234 }
235
236 ConstantInsn::ConstantInsn(ELObj *obj, InsnPtr next)
237 : value_(obj), next_(next)
238 {
239 }
240
241 const Insn *ConstantInsn::execute(VM &vm) const
242 {
243   vm.needStack(1);
244   *vm.sp++ = value_;
245   return next_.pointer();
246 }
247
248 ResolveQuantitiesInsn::ResolveQuantitiesInsn(const Location &loc, InsnPtr next)
249 : loc_(loc), next_(next)
250 {
251 }
252
253 const Insn *ResolveQuantitiesInsn::execute(VM &vm) const
254 {
255   ELObj *tem = vm.sp[-1]->resolveQuantities(1,
256                                             *vm.interp,
257                                             loc_);
258   ASSERT(tem != 0);
259   if (vm.interp->isError(tem)) {
260     vm.sp = 0;
261     return 0;
262   }
263   vm.sp[-1] = tem;
264   return next_.pointer();
265 }
266
267 TestInsn::TestInsn(InsnPtr consequent, InsnPtr alternative)
268 : consequent_(consequent), alternative_(alternative)
269 {
270 }
271
272 const Insn *TestInsn::execute(VM &vm) const
273 {
274   return (*--vm.sp)->isTrue() ? consequent_.pointer() : alternative_.pointer();
275 }
276
277 OrInsn::OrInsn(InsnPtr nextTest, InsnPtr next)
278 : nextTest_(nextTest), next_(next)
279 {
280 }
281
282 const Insn *OrInsn::execute(VM &vm) const
283 {
284   if (vm.sp[-1]->isTrue())
285     return next_.pointer();
286   --vm.sp;
287   return nextTest_.pointer();
288 }
289
290 AndInsn::AndInsn(InsnPtr nextTest, InsnPtr next)
291 : nextTest_(nextTest), next_(next)
292 {
293 }
294
295 const Insn *AndInsn::execute(VM &vm) const
296 {
297   if (!vm.sp[-1]->isTrue())
298     return next_.pointer();
299   --vm.sp;
300   return nextTest_.pointer();
301 }
302
303 CaseInsn::CaseInsn(ELObj *obj, InsnPtr match, InsnPtr fail)
304 : obj_(obj), match_(match), fail_(fail)
305 {
306 }
307
308 const Insn *CaseInsn::execute(VM &vm) const
309 {
310   if (ELObj::eqv(*vm.sp[-1], *obj_)) {
311     --vm.sp;
312     return match_.pointer();
313   }
314   return fail_.pointer();
315 }
316
317 PopInsn::PopInsn(InsnPtr next)
318 : next_(next)
319 {
320 }
321
322 const Insn *PopInsn::execute(VM &vm) const
323 {
324   --vm.sp;
325   return next_.pointer();
326 }
327
328 ConsInsn::ConsInsn(InsnPtr next)
329 : next_(next)
330 {
331 }
332
333 const Insn *ConsInsn::execute(VM &vm) const
334 {
335   vm.sp[-2] = vm.interp->makePair(vm.sp[-1], vm.sp[-2]);
336   --vm.sp;
337   return next_.pointer();
338 }
339
340 AppendInsn:: AppendInsn(const Location &loc, InsnPtr next)
341 : loc_(loc), next_(next)
342 {
343 }
344
345 const Insn *AppendInsn::execute(VM &vm) const
346 {
347   ELObj *&source = vm.sp[-1];
348   if (!source->isNil()) {
349     PairObj *pair = source->asPair();
350     if (!pair) {
351       vm.interp->setNextLocation(loc_);
352       vm.interp->message(InterpreterMessages::spliceNotList);
353       vm.sp = 0;
354       return 0;
355     }
356     source = pair->cdr();
357     PairObj *tail = vm.interp->makePair(pair->car(), 0);
358     ELObjDynamicRoot head(*vm.interp, tail);
359     while (!source->isNil()) {
360       pair = source->asPair();
361       if (!pair) {
362         vm.interp->setNextLocation(loc_);
363         vm.interp->message(InterpreterMessages::spliceNotList);
364         vm.sp = 0;
365         return 0;
366       }
367       PairObj *newTail = vm.interp->makePair(pair->car(), 0);
368       tail->setCdr(newTail);
369       tail = newTail;
370       source = pair->cdr();
371     }
372     tail->setCdr(vm.sp[-2]);
373     vm.sp[-2] = head;
374   }
375   --vm.sp;
376   return next_.pointer();
377 }
378
379 ApplyBaseInsn::ApplyBaseInsn(int nArgs, const Location &loc)
380 : nArgs_(nArgs), loc_(loc)
381 {
382 }
383
384 ApplyInsn::ApplyInsn(int nArgs, const Location &loc, InsnPtr next)
385 : ApplyBaseInsn(nArgs, loc), next_(next)
386 {
387 }
388
389 TailApplyInsn::TailApplyInsn(int nCallerArgs, int nArgs, const Location &loc)
390 : ApplyBaseInsn(nArgs, loc), nCallerArgs_(nCallerArgs)
391 {
392 }
393
394 // top of stack is operand; next down is last operand and so on
395
396 FunctionObj *ApplyBaseInsn::decodeArgs(VM &vm) const
397 {
398   FunctionObj *func = (*--vm.sp)->asFunction();
399   if (!func) {
400     vm.interp->setNextLocation(loc_);
401     vm.interp->message(InterpreterMessages::callNonFunction,
402                        ELObjMessageArg(*vm.sp, *vm.interp));
403     vm.sp = 0;
404     return 0;
405   }
406   int nReq = func->nRequiredArgs();
407   if (nArgs_ < nReq) {
408     vm.interp->setNextLocation(loc_);
409     vm.interp->message(InterpreterMessages::missingArg);
410     vm.sp = 0;
411     return 0;
412   }
413   if (nArgs_ - nReq > func->nOptionalArgs()) {
414     if (func->nKeyArgs()) {
415       // Keyword args can be specified more than once
416       // so we can only check there are an even number.
417       if ((nArgs_ - nReq - func->nOptionalArgs()) & 1) {
418         vm.interp->setNextLocation(loc_);
419         vm.interp->message(InterpreterMessages::oddKeyArgs);
420         vm.sp -= (nArgs_ - nReq) - func->nOptionalArgs();
421       }
422     }
423     else if (!func->restArg()) {
424       vm.interp->setNextLocation(loc_);
425       vm.interp->message(InterpreterMessages::tooManyArgs);
426       vm.sp -= (nArgs_ - nReq) - func->nOptionalArgs();
427     }
428   }
429   return func;
430 }
431
432 const Insn *ApplyInsn::execute(VM &vm) const
433 {
434   FunctionObj *func = decodeArgs(vm);
435   vm.nActualArgs = nArgs_;
436   if (func)
437     return func->call(vm, loc_, next_.pointer());
438   else
439     return 0;
440 }
441
442 const Insn *TailApplyInsn::execute(VM &vm) const
443 {
444   FunctionObj *func = decodeArgs(vm);
445   vm.nActualArgs = nArgs_;
446   if (func)
447     return func->tailCall(vm, loc_, nCallerArgs_);
448   else
449     return 0;
450 }
451
452 ApplyPrimitiveObj::ApplyPrimitiveObj()
453 : FunctionObj(&signature_)
454 {
455 }
456
457 const Signature ApplyPrimitiveObj::signature_ = { 2, 0, 1 };
458
459 const Insn *ApplyPrimitiveObj::call(VM &vm, const Location &loc,
460                                     const Insn *next)
461 {
462   if (!shuffle(vm, loc))
463     return 0;
464   ApplyInsn insn(vm.nActualArgs, loc, (Insn *)next);
465   return insn.execute(vm);
466 }
467
468 bool ApplyPrimitiveObj::shuffle(VM &vm, const Location &loc)
469 {
470   int nArgs = vm.nActualArgs;
471   ELObj *func = vm.sp[-nArgs];
472   for (int i = nArgs - 2; i > 0; i--)
473     vm.sp[-i - 2] = vm.sp[-i - 1];
474   vm.nActualArgs = nArgs - 2;
475   ELObj *list = *--vm.sp;
476   --vm.sp;
477   while (!list->isNil()) {
478     PairObj *tem = list->asPair();
479     if (!tem) {
480       vm.interp->setNextLocation(loc);
481       vm.interp->message(InterpreterMessages::notAList,
482                          StringMessageArg(vm.interp->makeStringC("apply")),
483                          OrdinalMessageArg(nArgs),
484                          ELObjMessageArg(list, *vm.interp));
485       vm.sp = 0;
486       return 0;
487     }
488     vm.needStack(1);
489     vm.nActualArgs++;
490     *vm.sp++ = tem->car();
491     list = tem->cdr();
492   }
493   vm.needStack(1);
494   *vm.sp++ = func;
495   return 1;
496 }
497
498 const Insn *ApplyPrimitiveObj::tailCall(VM &vm, const Location &loc,
499                                         int nCallerArgs)
500 {
501   if (!shuffle(vm, loc))
502     return 0;
503   TailApplyInsn insn(nCallerArgs, vm.nActualArgs, loc);
504   return insn.execute(vm);
505 }
506
507 PrimitiveCallInsn::PrimitiveCallInsn(int nArgs, PrimitiveObj *prim,
508                                      const Location &loc,
509                                      InsnPtr next)
510 : nArgs_(nArgs), prim_(prim), loc_(loc), next_(next)
511 {
512 }
513
514 const Insn *PrimitiveCallInsn::execute(VM &vm) const
515 {
516   if (nArgs_ == 0)
517     vm.needStack(1);
518   ELObj **argp = vm.sp - nArgs_;
519   *argp = prim_->primitiveCall(nArgs_, argp, vm, *vm.interp, loc_);
520   ASSERT(vm.interp->objectMaybeLive(*argp));
521   vm.sp = argp + 1;
522   if (vm.interp->isError(*argp)) {
523     vm.sp = 0;
524     return 0;
525   }
526   else
527     return next_.pointer();
528 }
529
530 InsnPtr FunctionObj::makeCallInsn(int nArgs, Interpreter &,
531                                   const Location &loc,
532                                   InsnPtr next)
533 {
534   return new FunctionCallInsn(nArgs, this, loc, next);
535 }
536
537 InsnPtr FunctionObj::makeTailCallInsn(int nArgs, Interpreter &,
538                                       const Location &loc, int nCallerArgs)
539 {
540   return new FunctionTailCallInsn(nArgs, this, loc, nCallerArgs);
541 }
542
543 FunctionObj *FunctionObj::asFunction()
544 {
545   return this;
546 }
547
548 void FunctionObj::setArgToCC(VM &)
549 {
550 }
551
552 const Insn *PrimitiveObj::call(VM &vm, const Location &loc,
553                                const Insn *next)
554 {
555   if (vm.nActualArgs == 0)
556     vm.needStack(1);
557   ELObj **argp = vm.sp - vm.nActualArgs;
558   *argp = primitiveCall(vm.nActualArgs, argp, vm, *vm.interp, loc);
559   vm.sp = argp + 1;
560   if (vm.interp->isError(*argp)) {
561     vm.sp = 0;
562     return 0;
563   }
564   else
565     return next;
566 }
567
568 const Insn *PrimitiveObj::tailCall(VM &vm, const Location &loc,
569                                    int nCallerArgs)
570 {
571   ELObj **argp = vm.sp - vm.nActualArgs;
572   ELObj *result = primitiveCall(vm.nActualArgs, argp, vm, *vm.interp, loc);
573   if (vm.interp->isError(result)) {
574     vm.sp = 0;
575     return 0;
576   }
577   else {
578     vm.sp = argp - nCallerArgs;
579     const Insn *next = vm.popFrame();
580     vm.needStack(1);
581     *vm.sp++ = result;
582     return next;
583   }
584 }
585
586 InsnPtr PrimitiveObj::makeCallInsn(int nArgs, Interpreter &interp, const Location &loc,
587                                    InsnPtr next)
588 {
589   return new PrimitiveCallInsn(nArgs, this, loc, next);
590 }
591
592 ELObj *PrimitiveObj::argError(Interpreter &interp,
593                               const Location &loc,
594                               const MessageType3 &msg,
595                               unsigned index,
596                               ELObj *obj) const
597 {
598   NodeListObj *nl = obj->asNodeList();
599   if (!nl || !nl->suppressError()) {
600     interp.setNextLocation(loc);
601     interp.message(msg,
602                    StringMessageArg(ident_->name()),
603                    OrdinalMessageArg(index + 1),
604                    ELObjMessageArg(obj, interp));
605   }
606   return interp.makeError();
607 }
608
609 ELObj *PrimitiveObj::noCurrentNodeError(Interpreter &interp,
610                                         const Location &loc) const
611 {
612   interp.setNextLocation(loc);
613   interp.message(InterpreterMessages::noCurrentNode);
614   return interp.makeError();
615 }
616
617 ClosureInsn::ClosureInsn(const Signature *sig, InsnPtr code, int displayLength,
618                          InsnPtr next)
619 : sig_(sig), code_(code), displayLength_(displayLength), next_(next)
620 {
621 }
622
623 const Insn *ClosureInsn::execute(VM &vm) const
624 {
625   ELObj **display
626     = displayLength_ ? new ELObj *[displayLength_ + 1] : 0;
627   ELObj **tem = vm.sp - displayLength_;
628   for (int i = 0; i < displayLength_; i++)
629     display[i] = tem[i];
630   if (displayLength_ == 0) {
631     vm.needStack(1);
632     tem = vm.sp;
633   }
634   else
635     display[displayLength_] = 0;
636   // Make sure objects in display are still visible on the stack
637   // to the garbage collector.
638   *tem++ = new (*vm.interp) ClosureObj(sig_, code_, display);
639   vm.sp = tem;
640   return next_.pointer();
641 }
642
643 FunctionCallInsn:: FunctionCallInsn(int nArgs, FunctionObj *function,
644                                     const Location &loc, InsnPtr next)
645 : nArgs_(nArgs), function_(function), loc_(loc), next_(next)
646 {
647 }
648
649 const Insn *FunctionCallInsn::execute(VM &vm) const
650 {
651   vm.nActualArgs = nArgs_;
652   return function_->call(vm, loc_, next_.pointer());
653 }
654
655 FunctionTailCallInsn:: FunctionTailCallInsn(int nArgs, FunctionObj *function,
656                                             const Location &loc,
657                                             int nCallerArgs)
658 : nArgs_(nArgs), function_(function), loc_(loc), nCallerArgs_(nCallerArgs)
659 {
660 }
661
662 const Insn *FunctionTailCallInsn::execute(VM &vm) const
663 {
664   vm.nActualArgs = nArgs_;
665   return function_->tailCall(vm, loc_, nCallerArgs_);
666 }
667
668 TestNullInsn::TestNullInsn(int offset, InsnPtr ifNull, InsnPtr ifNotNull)
669 : offset_(offset), ifNull_(ifNull), ifNotNull_(ifNotNull)
670 {
671 }
672      
673 const Insn *TestNullInsn::execute(VM &vm) const
674 {
675   if (vm.sp[offset_] == 0)
676     return ifNull_.pointer();
677   else
678     return ifNotNull_.pointer();
679 }
680
681 VarargsInsn::VarargsInsn(const Signature &sig,
682                          Vector<InsnPtr> &entryPoints,
683                          const Location &loc)
684 : sig_(&sig), loc_(loc)
685 {
686   entryPoints.swap(entryPoints_);
687 }
688
689 const Insn *VarargsInsn::execute(VM &vm) const
690 {
691   int n = vm.nActualArgs - sig_->nRequiredArgs;
692   if ((sig_->restArg || sig_->nKeyArgs)
693       && n > entryPoints_.size() - 2) {
694     // cons up the rest args
695     ELObjDynamicRoot protect(*vm.interp, vm.interp->makeNil());
696     for (int i = n - (entryPoints_.size() - 2); i > 0; i--) {
697       protect = new (*vm.interp) PairObj(vm.sp[-1], protect);
698       --vm.sp;
699     }
700     vm.needStack(sig_->nKeyArgs + sig_->restArg);
701     if (sig_->restArg)
702       *vm.sp++ = protect;
703     if (sig_->nKeyArgs) {
704       for (int i = 0; i < sig_->nKeyArgs; i++)
705         vm.sp[i] = 0;
706       ELObj *tem = protect;
707       for (int i = n - (entryPoints_.size() - 2); i > 0; i -= 2) {
708         KeywordObj *k = ((PairObj *)tem)->car()->asKeyword();
709         tem = ((PairObj *)tem)->cdr();
710         if (k) {
711           for (int j = 0; j < sig_->nKeyArgs; j++)
712             if (sig_->keys[j] == k->identifier()) {
713               if (vm.sp[j] == 0)
714                 vm.sp[j] = ((PairObj *)tem)->car();
715               k = 0;
716               break;
717             }
718           if (k && !sig_->restArg) {
719             vm.interp->setNextLocation(loc_);
720             vm.interp->message(InterpreterMessages::invalidKeyArg,
721                                StringMessageArg(k->identifier()->name()));
722           }
723         }
724         else {
725           vm.interp->setNextLocation(loc_);
726           vm.interp->message(InterpreterMessages::keyArgsNotKey);
727         }
728         tem = ((PairObj *)tem)->cdr();
729       }
730       vm.sp += sig_->nKeyArgs;
731     }
732     return entryPoints_.back().pointer();
733   }
734   return entryPoints_[n].pointer();
735 }
736
737 SetKeyArgInsn::SetKeyArgInsn(int offset, InsnPtr next)
738 : offset_(offset), next_(next)
739 {
740 }
741
742 const Insn *SetKeyArgInsn::execute(VM &vm) const
743 {
744   ELObj *val = *--vm.sp;
745   vm.sp[offset_] = val;
746   return next_.pointer();
747 }
748
749 ClosureObj::ClosureObj(const Signature *sig, InsnPtr code, ELObj **display)
750 : FunctionObj(sig), code_(code), display_(display)
751 {
752   hasSubObjects_ = 1;
753 }
754
755 const Insn *ClosureObj::call(VM &vm, const Location &loc, const Insn *next)
756 {
757   vm.needStack(1);
758   vm.pushFrame(next, vm.nActualArgs);
759   vm.frame = vm.sp - vm.nActualArgs;
760   vm.closure = display_;
761   vm.protectClosure = this;
762   vm.closureLoc = loc;
763   return code_.pointer();
764 }
765
766 const Insn *ClosureObj::tailCall(VM &vm, const Location &loc, int nCallerArgs)
767 {
768   vm.needStack(1);
769   int nArgs = vm.nActualArgs;
770   if (nCallerArgs) {
771     ELObj **oldFrame = vm.sp - nArgs;
772     ELObj **newFrame = oldFrame - nCallerArgs;
773     for (int i = 0; i < nArgs; i++)
774       newFrame[i] = oldFrame[i];
775     vm.frame = newFrame;
776     vm.sp = newFrame + nArgs;
777   }
778   else
779     vm.frame = vm.sp - nArgs;
780   vm.closure = display_;
781   vm.protectClosure = this;
782   vm.closureLoc = loc;
783   return code_.pointer();
784 }
785
786 void ClosureObj::setArgToCC(VM &vm)
787 {
788   vm.setClosureArgToCC();
789 }
790
791 void ClosureObj::traceSubObjects(Collector &c) const
792 {
793   if (display_) {
794     for (ELObj **p = display_; *p; p++)
795       c.trace(*p);
796   }
797 }
798
799 const Signature ContinuationObj::signature_ = { 1, 0, 0 };
800
801 ContinuationObj::ContinuationObj()
802 : FunctionObj(&signature_), controlStackSize_(0)
803 {
804 }
805
806 const Insn *ContinuationObj::call(VM &vm, const Location &loc, const Insn *)
807 {
808   if (!live() || readOnly()) {
809     vm.interp->setNextLocation(loc);
810     vm.interp->message(InterpreterMessages::continuationDead);
811     vm.sp = 0;
812     return 0;
813   }
814   ELObj *result = vm.sp[-1];
815   ASSERT(vm.sp - vm.sbase >= stackSize_);
816   ASSERT(vm.csp - vm.csbase >= controlStackSize_);
817   ASSERT(vm.csbase[controlStackSize_ - 1].continuation == this);
818   while (vm.csp - vm.csbase > controlStackSize_) {
819     vm.csp--;
820     if (vm.csp->continuation)
821       vm.csp->continuation->kill();
822   }
823   vm.sp = vm.sbase + stackSize_;
824   --vm.sp;
825   const Insn *next = vm.popFrame();
826   *vm.sp++ = result;
827   return next;
828 }
829  
830 const Insn *ContinuationObj::tailCall(VM &vm, const Location &loc, int nCallerArgs)
831 {
832   return call(vm, loc, 0);
833 }
834
835 ReturnInsn::ReturnInsn(int totalArgs)
836 : totalArgs_(totalArgs)
837 {
838 }
839
840 bool ReturnInsn::isReturn(int &nArgs) const
841 {
842   nArgs = totalArgs_;
843   return true;
844 }
845
846 const Insn *ReturnInsn::execute(VM &vm) const
847 {
848   ELObj *result = *--vm.sp;
849   vm.sp -= totalArgs_;
850   const Insn *next = vm.popFrame();
851   *vm.sp++ = result;
852   return next;
853 }
854
855 FrameRefInsn::FrameRefInsn(int index, InsnPtr next)
856 : index_(index), next_(next)
857 {
858 }
859
860 const Insn *FrameRefInsn::execute(VM &vm) const
861 {
862   vm.needStack(1);
863   *vm.sp++ = vm.frame[index_];
864   return next_.pointer();
865 }
866
867 StackRefInsn::StackRefInsn(int index, int frameIndex, InsnPtr next)
868 : index_(index), frameIndex_(frameIndex), next_(next)
869 {
870 }
871
872 const Insn *StackRefInsn::execute(VM &vm) const
873 {
874   vm.needStack(1);
875   ASSERT(vm.sp - vm.frame == frameIndex_ - index_);
876   *vm.sp = vm.sp[index_];
877   vm.sp += 1;
878   return next_.pointer();
879 }
880
881 ClosureRefInsn::ClosureRefInsn(int index, InsnPtr next)
882 : index_(index), next_(next)
883 {
884 }
885
886 const Insn *ClosureRefInsn::execute(VM &vm) const
887 {
888   vm.needStack(1);
889   *vm.sp++ = vm.closure[index_];
890   return next_.pointer();
891 }
892
893 TopRefInsn::TopRefInsn(const Identifier *var, InsnPtr next)
894 : var_(var), next_(next)
895 {
896 }
897
898 const Insn *TopRefInsn::execute(VM &vm) const
899 {
900   ELObj *tem = var_->computeValue(1, *vm.interp);
901   if (vm.interp->isError(tem)) {
902     vm.sp = 0;
903     return 0;
904   }
905   else {
906     vm.needStack(1);
907     *vm.sp++ = tem;
908     return next_.pointer();
909   }
910 }
911
912 ClosureSetBoxInsn::ClosureSetBoxInsn(int index, const Location &loc, InsnPtr next)
913 : index_(index), loc_(loc), next_(next)
914 {
915 }
916
917 const Insn *ClosureSetBoxInsn::execute(VM &vm) const
918 {
919   BoxObj *box = vm.closure[index_]->asBox();
920   ASSERT(box != 0);
921   if (box->readOnly()) {
922     vm.interp->setNextLocation(loc_);
923     vm.interp->message(InterpreterMessages::readOnly);
924     vm.sp = 0;
925     return 0;
926   }
927   ELObj *tem = box->value;
928   box->value = vm.sp[-1];
929   vm.sp[-1] = tem;
930   return next_.pointer();
931 }
932
933 StackSetBoxInsn::StackSetBoxInsn(int index, int frameIndex, const Location &loc,
934                                  InsnPtr next)
935 : index_(index), frameIndex_(frameIndex), loc_(loc), next_(next)
936 {
937 }
938
939 const Insn *StackSetBoxInsn::execute(VM &vm) const
940 {
941   ASSERT(vm.sp - vm.frame == frameIndex_ - index_);
942   BoxObj *box = vm.sp[index_]->asBox();
943   ASSERT(box != 0);
944   if (box->readOnly()) {
945     vm.interp->setNextLocation(loc_);
946     vm.interp->message(InterpreterMessages::readOnly);
947     vm.sp = 0;
948     return 0;
949   }
950   ELObj *tem = box->value;
951   box->value = vm.sp[-1];
952   vm.sp[-1] = tem;
953   return next_.pointer();
954 }
955
956 StackSetInsn::StackSetInsn(int index, int frameIndex, InsnPtr next)
957 : index_(index), frameIndex_(frameIndex), next_(next)
958 {
959 }
960
961 const Insn *StackSetInsn::execute(VM &vm) const
962 {
963   ASSERT(vm.sp - vm.frame == frameIndex_ - index_);
964   ELObj *tem = vm.sp[index_];
965   vm.sp[index_] = vm.sp[-1];
966   vm.sp[-1] = tem;
967   return next_.pointer();
968 }
969
970 InsnPtr PopBindingsInsn::make(int n, InsnPtr next)
971 {
972   if (!next.isNull()) {
973     int i;
974     if (next->isReturn(i))
975       return new ReturnInsn(n + i);
976     if (next->isPopBindings(i, next))
977       return new PopBindingsInsn(n + i, next);
978   }
979   return new PopBindingsInsn(n, next);
980 }
981
982 PopBindingsInsn::PopBindingsInsn(int n, InsnPtr next)
983 : n_(n), next_(next)
984 {
985 }
986
987 const Insn *PopBindingsInsn::execute(VM &vm) const
988 {
989   vm.sp -= n_;
990   vm.sp[-1] = vm.sp[n_ - 1];
991   return next_.pointer();
992 }
993
994 bool PopBindingsInsn::isPopBindings(int &n, InsnPtr &next) const
995 {
996   n = n_;
997   next = next_;
998   return true;
999 }
1000
1001 SetBoxInsn::SetBoxInsn(int n, InsnPtr next)
1002 : n_(n), next_(next)
1003 {
1004 }
1005
1006 const Insn *SetBoxInsn::execute(VM &vm) const
1007 {
1008   --vm.sp;
1009   BoxObj *box = vm.sp[-n_]->asBox();
1010   ASSERT(box != 0);
1011   box->value = *vm.sp;
1012   return next_.pointer();
1013 }
1014
1015 SetImmediateInsn::SetImmediateInsn(int n, InsnPtr next)
1016 : n_(n), next_(next)
1017 {
1018 }
1019
1020 const Insn *SetImmediateInsn::execute(VM &vm) const
1021 {
1022   --vm.sp;
1023   vm.sp[-n_] = *vm.sp;
1024   return next_.pointer();
1025 }
1026
1027 CheckInitInsn::CheckInitInsn(const Identifier *ident, const Location &loc, InsnPtr next)
1028 : ident_(ident), loc_(loc), next_(next)
1029 {
1030 }
1031
1032 const Insn *CheckInitInsn::execute(VM &vm) const
1033 {
1034   if (vm.sp[-1] == 0) {
1035     vm.interp->setNextLocation(loc_);
1036     vm.interp->message(InterpreterMessages::uninitializedVariableReference,
1037                        StringMessageArg(ident_->name()));
1038     vm.sp = 0;
1039     return 0;
1040   }
1041   return next_.pointer();
1042 }
1043
1044 UnboxInsn::UnboxInsn(InsnPtr next)
1045 : next_(next)
1046 {
1047 }
1048
1049 const Insn *UnboxInsn::execute(VM &vm) const
1050 {
1051   BoxObj *box = vm.sp[-1]->asBox();
1052   ASSERT(box != 0);
1053   vm.sp[-1] = box->value;
1054   return next_.pointer();
1055 }
1056
1057 BoxInsn::BoxInsn(InsnPtr next)
1058 : next_(next)
1059 {
1060 }
1061
1062 const Insn *BoxInsn::execute(VM &vm) const
1063 {
1064   vm.sp[-1] = new (*vm.interp) BoxObj(vm.sp[-1]);
1065   return next_.pointer();
1066 }
1067
1068 BoxArgInsn::BoxArgInsn(int n, InsnPtr next)
1069 : n_(n), next_(next)
1070 {
1071 }
1072
1073 const Insn *BoxArgInsn::execute(VM &vm) const
1074 {
1075   ELObj *&arg = vm.sp[n_ - vm.nActualArgs];
1076   arg = new (*vm.interp) BoxObj(arg);
1077   return next_.pointer();
1078 }
1079
1080 BoxStackInsn::BoxStackInsn(int n, InsnPtr next)
1081 : n_(n), next_(next)
1082 {
1083 }
1084
1085 const Insn *BoxStackInsn::execute(VM &vm) const
1086 {
1087   vm.sp[n_] = new (*vm.interp) BoxObj(vm.sp[n_]);
1088   return next_.pointer();
1089 }
1090
1091 VectorInsn::VectorInsn(size_t n, InsnPtr next)
1092 : n_(n), next_(next)
1093 {
1094 }
1095
1096 const Insn *VectorInsn::execute(VM &vm) const
1097 {
1098   if (n_ == 0) {
1099     vm.needStack(1);
1100     *vm.sp++ = new (*vm.interp) VectorObj;
1101   }
1102   else {
1103     Vector<ELObj *> v(n_);
1104     ELObj **p = vm.sp;
1105     for (size_t n = n_; n > 0; n--)
1106       v[n - 1] = *--p;
1107     *p = new (*vm.interp) VectorObj(v);
1108     vm.sp = p + 1;
1109   }
1110   return next_.pointer();
1111 }
1112
1113 ListToVectorInsn::ListToVectorInsn(InsnPtr next)
1114 : next_(next)
1115 {
1116 }
1117
1118 const Insn *ListToVectorInsn::execute(VM &vm) const
1119 {
1120   Vector<ELObj *> v;
1121   ELObj *obj = vm.sp[-1];
1122   while (!obj->isNil()) {
1123     PairObj *pair = obj->asPair();
1124     ASSERT(pair != 0);
1125     v.push_back(pair->car());
1126     obj = pair->cdr();
1127   }
1128   vm.sp[-1] = new (*vm.interp) VectorObj(v);
1129   return next_.pointer();
1130 }
1131
1132 const Insn *CheckSosofoInsn::execute(VM &vm) const
1133 {
1134   if (!vm.sp[-1]->asSosofo()) {
1135     vm.sp = 0;
1136     vm.interp->setNextLocation(loc_);
1137     vm.interp->message(InterpreterMessages::sosofoContext);
1138     return 0;
1139   }
1140   return next_.pointer();
1141 }
1142
1143 const Insn *CheckStyleInsn::execute(VM &vm) const
1144 {
1145   if (!vm.sp[-1]->asStyle()) {
1146     vm.sp = 0;
1147     vm.interp->setNextLocation(loc_);
1148     vm.interp->message(InterpreterMessages::styleContext);
1149     return 0;
1150   }
1151   return next_.pointer();
1152 }
1153
1154 const Insn *PushModeInsn::execute(VM &vm) const
1155 {
1156   vm.modeStack.push_back(vm.processingMode);
1157   vm.processingMode = mode_;
1158   return next_.pointer();
1159 }
1160
1161 const Insn *PopModeInsn::execute(VM &vm) const
1162 {
1163   vm.processingMode = vm.modeStack.back();
1164   vm.modeStack.resize(vm.modeStack.size() - 1);
1165   return next_.pointer();
1166 }
1167
1168 MaybeOverrideStyleInsn::MaybeOverrideStyleInsn(InsnPtr next)
1169 : next_(next)
1170 {
1171 }
1172
1173 const Insn *MaybeOverrideStyleInsn::execute(VM &vm) const
1174 {
1175   if (vm.overridingStyle)
1176     vm.sp[-1] = new (*vm.interp) OverriddenStyleObj((BasicStyleObj *)vm.sp[-1],
1177                                                     vm.overridingStyle);
1178   return next_.pointer();
1179 }
1180
1181 VarStyleInsn::VarStyleInsn(const ConstPtr<StyleSpec> &styleSpec, unsigned displayLength,
1182                            bool hasUse, InsnPtr next)
1183 : styleSpec_(styleSpec), displayLength_(displayLength), hasUse_(hasUse), next_(next)
1184 {
1185 }
1186
1187 const Insn *VarStyleInsn::execute(VM &vm) const
1188 {
1189   ELObj **display
1190     = displayLength_ ? new ELObj *[displayLength_ + 1] : 0;
1191   ELObj **tem = vm.sp - displayLength_;
1192   for (int i = 0; i < displayLength_; i++)
1193     display[i] = tem[i];
1194   if (displayLength_ == 0) {
1195     vm.needStack(1);
1196     tem = vm.sp;
1197   }
1198   else
1199     display[displayLength_] = 0;
1200   // Make sure objects in display are still visible on the stack
1201   // to the garbage collector.
1202   StyleObj *use;
1203   if (hasUse_)
1204     use = (StyleObj *)*--tem;
1205   else
1206     use = 0;
1207   *tem++ = new (*vm.interp) VarStyleObj(styleSpec_, use, display, vm.currentNode);
1208   vm.sp = tem;
1209   vm.interp->makeReadOnly(tem[-1]);
1210   return next_.pointer();
1211 }
1212
1213 SetStyleInsn::SetStyleInsn(InsnPtr next)
1214 : next_(next)
1215 {
1216 }
1217
1218 const Insn *SetStyleInsn::execute(VM &vm) const
1219 {
1220   ((FlowObj *)vm.sp[-2])->setStyle((StyleObj *)vm.sp[-1]);
1221   vm.sp--;
1222   return next_.pointer();
1223 }
1224
1225 SosofoAppendInsn::SosofoAppendInsn(size_t n, InsnPtr next)
1226 : n_(n), next_(next)
1227 {
1228 }
1229
1230 const Insn *SosofoAppendInsn::execute(VM &vm) const
1231 {
1232   AppendSosofoObj *obj = new (*vm.interp) AppendSosofoObj;
1233   ELObj **tem = vm.sp - n_;
1234   for (size_t i = 0; i < n_; i++) {
1235     ASSERT(tem[i]->asSosofo() != 0);
1236     obj->append((SosofoObj *)tem[i]);
1237   }
1238   vm.sp -= n_ - 1;
1239   vm.sp[-1] = obj;
1240   return next_.pointer();
1241 }
1242
1243 CopyFlowObjInsn::CopyFlowObjInsn(FlowObj *flowObj, InsnPtr next)
1244 : flowObj_(flowObj), next_(next)
1245 {
1246 }
1247
1248 const Insn *CopyFlowObjInsn::execute(VM &vm) const
1249 {
1250   vm.needStack(1);
1251   *vm.sp++ = flowObj_->copy(*vm.interp);
1252   return next_.pointer();
1253 }
1254
1255 SetNonInheritedCsSosofoInsn
1256 ::SetNonInheritedCsSosofoInsn(InsnPtr code, int displayLength, InsnPtr next)
1257 : code_(code), displayLength_(displayLength), next_(next)
1258 {
1259 }
1260
1261 const Insn *SetNonInheritedCsSosofoInsn::execute(VM &vm) const
1262 {
1263   ELObj **display
1264     = displayLength_ ? new ELObj *[displayLength_ + 1] : 0;
1265   ELObj **tem = vm.sp - displayLength_;
1266   for (int i = 0; i < displayLength_; i++) {
1267     display[i] = tem[i];
1268     ASSERT(display[i] != 0);
1269   }
1270   if (displayLength_)
1271     display[displayLength_] = 0;
1272   // Make sure objects in display are still visible on the stack
1273   // to the garbage collector.
1274   FlowObj *flowObj = (FlowObj *)*--tem;
1275   ASSERT((*tem)->asSosofo() != 0);
1276   *tem++ = new (*vm.interp) SetNonInheritedCsSosofoObj(flowObj, code_, display, vm.currentNode);
1277   vm.sp = tem;
1278   return next_.pointer();
1279 }
1280
1281
1282 SetPseudoNonInheritedCInsn::SetPseudoNonInheritedCInsn(const Identifier *nic, const Location &loc,
1283                                            InsnPtr next)
1284 : nic_(nic), loc_(loc), next_(next)
1285 {
1286 }
1287
1288 const Insn *SetPseudoNonInheritedCInsn::execute(VM &vm) const
1289 {
1290   ASSERT(vm.sp[-2]->asSosofo() != 0);
1291   ((FlowObj *)vm.sp[-2])->setNonInheritedC(nic_, vm.sp[-1], loc_, *vm.interp);
1292   vm.sp--;
1293   return next_.pointer();
1294 }
1295
1296 SetNonInheritedCInsn::SetNonInheritedCInsn(const Identifier *nic, const Location &loc,
1297                                            InsnPtr next)
1298 : SetPseudoNonInheritedCInsn(nic, loc, next)
1299 {
1300 }
1301
1302 const Insn *SetNonInheritedCInsn::execute(VM &vm) const
1303 {
1304   vm.actualDependencies->resize(0);
1305   return SetPseudoNonInheritedCInsn::execute(vm);
1306 }
1307
1308 SetContentInsn::SetContentInsn(const CompoundFlowObj *flowObj, InsnPtr next)
1309 : flowObj_(flowObj), next_(next)
1310 {
1311 }
1312
1313 SetImplicitCharInsn::SetImplicitCharInsn(const Location &loc, InsnPtr next)
1314 : loc_(loc), next_(next)
1315 {
1316 }
1317
1318 const Insn *SetImplicitCharInsn::execute(VM &vm) const
1319 {
1320   ASSERT(vm.sp[-1]->asSosofo() != 0);
1321
1322   if (vm.currentNode) {
1323     ELObjPropertyValue value(*vm.interp, 0);
1324     AccessResult ret = vm.currentNode->property(ComponentName::idChar, *vm.interp, value);
1325     if (ret == accessOK) 
1326       ((FlowObj *)vm.sp[-1])->setImplicitChar(value.obj, loc_, *vm.interp);
1327   }
1328   return next_.pointer();
1329 }
1330
1331 const Insn *SetContentInsn::execute(VM &vm) const
1332 {
1333   CompoundFlowObj *copy = (CompoundFlowObj *)flowObj_->copy(*vm.interp);
1334   copy->setContent((SosofoObj *)vm.sp[-1]);
1335   vm.sp[-1] = copy;
1336   return next_.pointer();
1337 }
1338
1339 SetDefaultContentInsn::SetDefaultContentInsn(const CompoundFlowObj *flowObj, const Location &loc, InsnPtr next)
1340 : flowObj_(flowObj), next_(next), loc_(loc)
1341 {
1342 }
1343
1344 const Insn *SetDefaultContentInsn::execute(VM &vm) const
1345 {
1346   if (!vm.processingMode) {
1347     vm.interp->setNextLocation(loc_);
1348     vm.interp->message(InterpreterMessages::noCurrentProcessingMode);
1349     vm.sp = 0;
1350     return 0;
1351   }
1352   vm.needStack(1);
1353   *vm.sp++ = flowObj_->copy(*vm.interp);
1354   ((CompoundFlowObj *)vm.sp[-1])
1355     ->setContent(new (*vm.interp) ProcessChildrenSosofoObj(vm.processingMode));
1356   return next_.pointer();
1357 }
1358
1359 MakeDefaultContentInsn::MakeDefaultContentInsn(const Location &loc, InsnPtr next)
1360 : next_(next), loc_(loc)
1361 {
1362 }
1363
1364 const Insn *MakeDefaultContentInsn::execute(VM &vm) const
1365 {
1366   if (!vm.processingMode) {
1367     vm.interp->setNextLocation(loc_);
1368     vm.interp->message(InterpreterMessages::noCurrentProcessingMode);
1369     vm.sp = 0;
1370     return 0;
1371   }
1372   vm.needStack(1);
1373   *vm.sp++ = new (*vm.interp) ProcessChildrenSosofoObj(vm.processingMode);
1374   return next_.pointer();
1375 }
1376
1377 LabelSosofoInsn::LabelSosofoInsn(const Location &loc, InsnPtr next)
1378 : loc_(loc), next_(next)
1379 {
1380 }
1381
1382 const Insn *LabelSosofoInsn::execute(VM &vm) const
1383 {
1384   SymbolObj *sym = vm.sp[-1]->asSymbol();
1385   if (!sym) {
1386     vm.interp->setNextLocation(loc_);
1387     vm.interp->message(InterpreterMessages::labelNotASymbol);
1388     vm.sp = 0;
1389     return 0;
1390   }
1391   ASSERT(vm.sp[-2]->asSosofo() != 0);
1392   vm.sp[-2] = new (*vm.interp) LabelSosofoObj(sym, loc_, (SosofoObj *)vm.sp[-2]);
1393   vm.sp--;
1394   return next_.pointer();
1395 }
1396
1397 ContentMapSosofoInsn::ContentMapSosofoInsn(const Location &loc, InsnPtr next)
1398 : loc_(loc), next_(next)
1399 {
1400 }
1401
1402 const Insn *ContentMapSosofoInsn::execute(VM &vm) const
1403 {
1404   ASSERT(vm.sp[-2]->asSosofo() != 0);
1405   vm.sp[-2] = new (*vm.interp) ContentMapSosofoObj(vm.sp[-1], &loc_, (SosofoObj *)vm.sp[-2]);
1406   vm.sp--;
1407   return next_.pointer();
1408 }
1409
1410 BoxObj::BoxObj()
1411 : value(0)
1412 {
1413   hasSubObjects_ = 1;
1414 }
1415
1416 BoxObj::BoxObj(ELObj *obj)
1417 : value(obj)
1418 {
1419   hasSubObjects_ = 1;
1420 }
1421
1422 BoxObj *BoxObj::asBox()
1423 {
1424   return this;
1425 }
1426
1427 void BoxObj::traceSubObjects(Collector &c) const
1428 {
1429   c.trace(value);
1430 }
1431
1432 CallWithCurrentContinuationPrimitiveObj::CallWithCurrentContinuationPrimitiveObj()
1433 : FunctionObj(&signature_)
1434 {
1435 }
1436
1437 const Insn *CallWithCurrentContinuationPrimitiveObj::call(VM &vm, const Location &loc,
1438                                                           const Insn *next)
1439 {
1440   FunctionObj *f = vm.sp[-1]->asFunction();
1441   if (!f) {
1442     vm.interp->setNextLocation(loc);
1443     vm.interp->message(InterpreterMessages::notAProcedure,
1444                        StringMessageArg(Interpreter::makeStringC("call-with-current-continuation")),
1445                        OrdinalMessageArg(1),
1446                        ELObjMessageArg(vm.sp[-1], *vm.interp));
1447     vm.sp = 0;
1448     return 0;
1449   }
1450   ELObjDynamicRoot protect(*vm.interp, f);
1451   vm.sp[-1] = new (*vm.interp) ContinuationObj;
1452   const Insn *insn = f->call(vm, loc, next);
1453   f->setArgToCC(vm);
1454   return insn;
1455 }
1456
1457
1458 const Insn *CallWithCurrentContinuationPrimitiveObj::tailCall(VM &vm, const Location &loc,
1459                                                               int nCallerArgs)
1460 {
1461   FunctionObj *f = vm.sp[-1]->asFunction();
1462   if (!f) {
1463     vm.interp->setNextLocation(loc);
1464     vm.interp->message(InterpreterMessages::notAProcedure,
1465                        StringMessageArg(Interpreter::makeStringC("call-with-current-continuation")),
1466                        OrdinalMessageArg(1),
1467                        ELObjMessageArg(vm.sp[-1], *vm.interp));
1468     vm.sp = 0;
1469     return 0;
1470   }
1471   ELObjDynamicRoot protect(*vm.interp, f);
1472   vm.sp[-1] = new (*vm.interp) ContinuationObj;
1473   const Insn *insn = f->tailCall(vm, loc, nCallerArgs);
1474   f->setArgToCC(vm);
1475   return insn;
1476 }
1477
1478 const Signature CallWithCurrentContinuationPrimitiveObj::signature_ = { 1, 0, 0 };
1479
1480 #ifdef DSSSL_NAMESPACE
1481 }
1482 #endif