[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash ChangeLog server/vm/AbcHandlers.cpp serve...
From: |
Chad Musick |
Subject: |
[Gnash-commit] gnash ChangeLog server/vm/AbcHandlers.cpp serve... |
Date: |
Mon, 08 Oct 2007 06:55:11 +0000 |
CVSROOT: /sources/gnash
Module name: gnash
Changes by: Chad Musick <cmusick> 07/10/08 06:55:11
Modified files:
. : ChangeLog
server/vm : AbcHandlers.cpp Machine.h CodeStream.h
SafeStack.h
Log message:
More work on the AS3 interpreter and supporting classes.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.4565&r2=1.4566
http://cvs.savannah.gnu.org/viewcvs/gnash/server/vm/AbcHandlers.cpp?cvsroot=gnash&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/gnash/server/vm/Machine.h?cvsroot=gnash&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/gnash/server/vm/CodeStream.h?cvsroot=gnash&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/gnash/server/vm/SafeStack.h?cvsroot=gnash&r1=1.1&r2=1.2
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.4565
retrieving revision 1.4566
diff -u -b -r1.4565 -r1.4566
--- ChangeLog 8 Oct 2007 06:33:53 -0000 1.4565
+++ ChangeLog 8 Oct 2007 06:55:11 -0000 1.4566
@@ -1,3 +1,14 @@
+2007-10-08 Chad Musick <address@hidden>
+
+ * server/vm/AbcHandlers.cpp: More work on the AS3 interpreter --
+ function calls and such.
+ * server/vm/Machine.h: Remove Stack (moved to SafeStack.h), remove
+ CodeStream (moved to CodeStream.h), remove FunctionEntry (becomes
+ State internal class).
+ * server/vm/CodeStream.h: Add reInitialize method to allow empty
+ construction.
+ * server/vm/SafeStack.h: Add method to reset stack to a certains state.
+
2007-10-08 Sandro Santilli <address@hidden>
* testsuite/misc-ming.all/ming_utils.c: have totals() and friend also
Index: server/vm/AbcHandlers.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/vm/AbcHandlers.cpp,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- server/vm/AbcHandlers.cpp 5 Oct 2007 17:48:16 -0000 1.4
+++ server/vm/AbcHandlers.cpp 8 Oct 2007 06:55:11 -0000 1.5
@@ -16,13 +16,134 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
+#include <boost/logic/tribool.hpp>
+
+#define ENSURE_NUMBER(vte)
\
+{
\
+ as_value &a = vte; /* Don't call vte multiple times */
\
+ if (vte.is_object())
\
+ {
\
+ asBinding *b = a.to_object()->getBinding(NSV::PROP_VALUE_OF);
\
+ if (b)
\
+ {
\
+ mStream->seekTo(mOpStart);
\
+ mStack.push(vte);
\
+ pushCall(1, &vte, b);
\
+ break;
\
+ }
\
+ }
\
+}
/* end of ENSURE_NUMBER */
+
+#define ENSURE_OBJECT(vte, backup)
\
+{
\
+ if (!vte.is_object())
\
+ throw ASMalformedError();
\
+}
/* end of ENSURE_OBJECT */
+
+#define ENSURE_STRING(vte, backup)
\
+{
\
+ as_value &a = vte; /* Don't call vte multiple times */
\
+ if (a.is_object())
\
+ {
\
+ asBinding *b = a.to_object()->getBinding(NSV::PROP_TO_STRING);
\
+ if (b)
\
+ {
\
+ mStream->seekTo(mOpStart);
\
+ mStack.push(vte);
\
+ pushCall(1, &vte, b);
\
+ break;
\
+ }
\
+ }
\
+}
/* end of ENSURE_STRING */
+
+#define ABSTRACT_COMPARE(store, rv1, rv2, truth_of_undefined)
\
+{
\
+ as_value &a = rv1; /* Don't call rv1 multiple times */
\
+ as_value &b = rv2; /* Don't call rv2 multiple times */
\
+ if (a.ptype() == PTYPE_STRING && b.ptype() == PTYPE_STRING)
\
+ {
\
+ ENSURE_STRING(a);
\
+ ENSURE_STRING(b);
\
+ std::string &str_a = a.to_string();
\
+ std::string &str_b = b.to_string();
\
+ store = a < b;
\
+ }
\
+ else
\
+ {
\
+ ENSURE_NUMBER(a);
\
+ ENSURE_NUMBER(b);
\
+ if (a.is_nan() || b.is_nan())
\
+ store = truth_of_undefined;
\
+ else if (a.is_positive_infinity())
\
+ store = false;
\
+ else if (b.is_positive_infinity())
\
+ store = true;
\
+ else if (b.is_negative_infinity())
\
+ store = false;
\
+ else if (a.is_negative_infinity())
\
+ store = true;
\
+ else
\
+ store = a.to_number() < b.to_number();
\
+ }
\
+}
/* end of ABSTRACT_COMPARE */
+
+#define ABSTRACT_EQUALITY(store, ev1, ev2, strictness_on)
\
+{
\
+ as_value &a = ev1; /* Don't call ev1 multiple times */
\
+ as_value &b = ev2; /* Don't call ev2 multiple times */
\
+ if (a.is_object() && b.is_object())
\
+ store = a.to_object() == b.to_object();
\
+ else if (a.is_object() || b.is_object())
\
+ store = false;
\
+ else if (a.ptype() != b.ptype())
\
+ {
\
+ if (!strictness_on && (a.is_undefined() || b.is_undefined()) &&
\
+ (a.is_null() || b.is_null())
\
+ store = true;
\
+ else
\
+ store = false;
\
+ }
\
+ else if (a.is_number())
\
+ {
\
+ if (a.is_nan() || b.is_nan())
\
+ store = false;
\
+ else if (a.is_positive_infinity() && b.is_positive_infinity())
\
+ store = true;
\
+ else if (a.is_negative_infinity() && b.is_negative_infinity())
\
+ store = true;
\
+ else
\
+ store = a.to_number() == b.to_number();
\
+ }
\
+ else if (a.is_bool() && b.is_bool())
\
+ store = a.to_bool() == b.to_bool();
\
+}
/* end of ABSTRACT_EQUALITY */
+
+#define JUMPIF(jtruth)
\
+{
\
+ int32t jumpOffset = mStream->read_S24();
\
+ if (jtruth)
\
+ mStream->seekBy(jumpOffset);
\
+ break;
\
+}
/* end of JUMPIF */
+
void
-ActionMachine::execute_as3()
+ActionMachine::execute()
{
for ( ; ; )
{
- switch ((opcode = mStream.read_as3op())) // Assignment intentional
+
+ if (mStream->isAS3())
{
+ switch ((opcode = mStream->read_as3op())) // Assignment intentional
+ {
+ default:
+ throw ASException();
+ case 0:
+ {
+// This is not actually an opcode -- it occurs when the stream is
+// empty. We may need to return from a function, or we may be done.
+ break;
+ }
/// 0x01 ABC_ACTION_BKPT
/// Do: Enter the debugger if one has been invoked.
/// This is a no-op. Enable it if desired.
@@ -59,7 +180,7 @@
case SWF::ABC_ACTION_GETSUPER:
{
// Get the name.
- asName a = mStream.read_V32();
+ asName a = mStream->read_V32();
// Finish it, if necessary.
mStack.drop(completeName(a));
// Get the target object.
@@ -84,7 +205,7 @@
case SWF::ABC_ACTION_SETSUPER:
{
// Get and finish the name.
- asName a = mStream.read_V32();
+ asName a = mStream->read_V32();
as_value vobj = mStack.pop(); // The value
mStack.drop(completeName(a));
@@ -104,7 +225,7 @@
/// default XML namespace.
case SWF::ABC_ACTION_DXNS:
{
- uint32_t soffset = mStream.read_V32();
+ uint32_t soffset = mStream->read_V32();
std::string& uri = pool_string(soffset);
mDefaultXMLNamespace = mCH->anonNamespace(mST.find(uri));
break;
@@ -117,6 +238,7 @@
/// Do: Same as ABC_ACTION_DXNS, but the uri is in the stack, not the stream.
case SWF::ABC_ACTION_DXNSLATE:
{
+ ENSURE_STRING(mStack.top(0));
const std::string& uri = mStack.top(0).to_string();
mDefaultXMLNamespace = mCH->anonNamespace(mST.find(uri));
mStack.drop(1);
@@ -129,7 +251,7 @@
/// Equivalent: ACTION_DELETE
case SWF::ABC_ACTION_KILL:
{
- uint32_t regNum = mStream.read_V32();
+ uint32_t regNum = mStream->read_V32();
mFrame.value(regnum).set_undefined();
break;
}
@@ -149,9 +271,10 @@
/// Do: If !(a < b) move by jump in stream, as ABC_ACTION_JUMP does.
case SWF::ABC_ACTION_IFNLT:
{
- bool truth = mStack.top(1).less_than(mStack.top(0));
+ bool truth;
+ ABSTRACT_COMPARE(truth, mStack.top(1), mStack.top(0), false);
mStack.drop(2);
- jumpIf(!truth);
+ JUMPIF(!truth); // truth is: a < b
break;
}
/// 0x0D ABC_ACTION_IFNLE
@@ -164,9 +287,10 @@
/// Do: If !(a <= b) move by jump in stream, as ABC_ACTION_JUMP does.
case SWF::ABC_ACTION_IFNLE:
{
- bool truth = mStack.top(1).less_equal(mStack.top(0));
+ bool truth;
+ ABSTRACT_COMPARE(truth, mStack.top(0), mStack.top(1), true);
mStack.drop(2);
- jumpIf(!truth);
+ JUMPIF(truth); // truth is: b < a
break;
}
/// 0x0E ABC_ACTION_IFNGT
@@ -179,9 +303,10 @@
/// Do: If !(a > b) move by jump in stream, as ABC_ACTION_JUMP does.
case SWF::ABC_ACTION_IFNGT:
{
- bool truth = mStack.top(1).greater_than(mStack.top(0));
+ bool truth;
+ ABSTRACT_COMPARE(truth, mStack.top(0), mStack.top(1), false);
mStack.drop(2);
- jumpIf(!truth);
+ JUMPIF(!truth); // truth is: b < a
break;
}
/// 0x0F ABC_ACTION_IFNGE
@@ -194,9 +319,10 @@
/// Do: If !(a >= b) move by jump in stream, as ABC_ACTION_JUMP does.
case SWF::ABC_ACTION_IFNGE:
{
- bool truth = mStack.top(1).greater_equal(mStack.top(0));
+ bool truth;
+ ABSTRACT_COMPARE(truth, mStack.top(1), mStack.top(0), true);
mStack.drop(2);
- jumpIf(!truth);
+ JUMPIF(truth); // truth is: a < b
break;
}
/// 0x10 ABC_ACTION_JUMP
@@ -205,7 +331,7 @@
/// Equivalent: ACTION_BRANCHALWAYS
case SWF::ABC_ACTION_JUMP:
{
- jumpIf(true);
+ JUMPIF(true);
break;
}
/// 0x11 ABC_ACTION_IFTRUE
@@ -220,7 +346,7 @@
{
bool truth = mStack.top(0).to_bool();
mStack.drop(1);
- jumpIf(truth);
+ JUMPIF(truth);
break;
}
/// 0x12 ABC_ACTION_IFFALSE
@@ -234,7 +360,7 @@
{
bool truth = mStack.top(0).to_bool();
mStack.drop(1);
- jumpIf(!truth);
+ JUMPIF(!truth);
break;
}
/// 0x13 ABC_ACTION_IFEQ
@@ -247,9 +373,10 @@
/// Do: If a == b (weakly), move by jump in stream, as ABC_ACTION_JUMP does.
case SWF::ABC_ACTION_IFEQ:
{
- bool truth = mStack.top(1).weak_equals(mStack.top(0));
+ bool truth;
+ ABSTRACT_EQUALITY(truth, mStack.top(1), mStack.top(0), false);
mStack.drop(2);
- jumpIf(truth);
+ JUMPIF(truth);
break;
}
/// 0x14 ABC_ACTION_IFNE
@@ -262,9 +389,10 @@
/// Do: If a != b (weakly), move by jump in stream, as ABC_ACTION_JUMP does.
case SWF::ABC_ACTION_IFNE:
{
- bool truth = mStack.top(1).weak_nequals(mStack.top(0));
+ bool truth;
+ ABSTRACT_EQUALITY(truth, mStack.top(1), mStack.top(0), false);
mStack.drop(2);
- jumpIf(truth);
+ JUMPIF(!truth);
break;
}
/// 0x15 ABC_ACTION_IFLT
@@ -277,9 +405,10 @@
/// Do: If a < b move by jump in stream, as ABC_ACTION_JUMP does.
case SWF::ABC_ACTION_IFLT:
{
- bool truth = mStack.top(1).less_than(mStack.top(0));
+ bool truth;
+ ABSTRACT_COMPARE(truth, mStack.top(1), mStack.top(0), false);
mStack.drop(2);
- jumpIf(truth);
+ JUMPIF(truth); // truth is: a < b
break;
}
/// 0x16 ABC_ACTION_IFLE
@@ -292,9 +421,10 @@
/// Do: If a <= b move by jump in stream, as ABC_ACTION_JUMP does.
case SWF::ABC_ACTION_IFLE:
{
- bool truth = mStack.top(1).less_equal(mStack.top(0));
+ bool truth;
+ ABSTRACT_COMPARE(truth, mStack.top(0), mStack.top(1), true);
mStack.drop(2);
- jumpIf(truth);
+ JUMPIF(!truth); // truth is: b < a
break;
}
/// 0x17 ABC_ACTION_IFGT
@@ -307,9 +437,11 @@
/// Do: If a > b move by jump in stream, as ABC_ACTION_JUMP does.
case SWF::ABC_ACTION_IFGT:
{
- bool truth = mStack.top(1).greater_than(mStack.top(0));
+ bool truth;
+ // If b < a, then a > b, with undefined as false
+ ABSTRACT_COMPARE(truth, mStack.top(0), mStack.top(1), false);
mStack.drop(2);
- jumpIf(truth);
+ JUMPIF(truth); // truth is: b < a
break;
}
/// 0x18 ABC_ACTION_IFGE
@@ -322,9 +454,10 @@
/// Do: If a >= b move by jump in stream, as ABC_ACTION_JUMP does.
case SWF::ABC_ACTION_IFGE:
{
- bool truth = mStack.top(1).greater_equal(mStack.top(0));
+ bool truth;
+ ABSTRACT_COMPARE(truth, mStack.top(0), mStack.top(1), true);
mStack.drop(2);
- jumpIf(truth);
+ JUMPIF(!truth); // truth is: a < b
break;
}
/// 0x19 ABC_ACTION_IFSTRICTEQ
@@ -337,9 +470,10 @@
/// Do: If a == b (strictly), move by jump in stream, as ABC_ACTION_JUMP
case SWF::ABC_ACTION_IFSTRICTEQ:
{
- bool truth = mStack.top(1).strict_equals(mStack.top(0));
+ bool truth;
+ ABSTRACT_EQUALITY(truth, mStack.top(1), mStack.top(0), true);
mStack.drop(2);
- jumpIf(truth);
+ JUMPIF(truth);
break;
}
/// 0x1A ABC_ACTION_IFSTRICTNE
@@ -352,9 +486,10 @@
/// Do: If a != b (strongly), move by jump in stream, as ABC_ACTION_JUMP
case SWF::ABC_ACTION_IFSTRICTNE:
{
- bool truth = mStack.top(1).strict_nequals(mStack.top(0));
+ bool truth;
+ ABSTRACT_EQUALITY(truth, mStack.top(1), mStack.top(0), true);
mStack.drop(2);
- jumpIf(truth);
+ JUMPIF(!truth);
break;
}
/// 0x18 ABC_ACTION_LOOKUPSWITCH
@@ -368,24 +503,27 @@
/// Otherwise, move by cases[index] - 1 from stream position on op entry.
case SWF::ABC_ACTION_LOOKUPSWITCH:
{
- AbcHandlers::stream_position npos = mStream.tell();
- uint32_t index = mStack.top(0).to_number<uint32_t>();
+ AbcHandlers::stream_position npos = mStream->tell();
+ if (!mStack.top(0).is_number())
+ throw ASMalformedError();
+
+ uint32_t index = mStack.top(0).to_int();
mStack.drop(1);
- mStream.seekBy(3); // Skip the intial offset.
- uint32_t cases = mStream.read_V32();
+ mStream->seekBy(3); // Skip the intial offset.
+ uint32_t cases = mStream->read_V32();
// Read from our original position and use it to skip if the
case
// is out of range.
if (index > cases)
{
- mStream.seekTo(npos);
- mStream.seekTo(npos + mStream.read_S24());
+ mStream->seekTo(npos);
+ mStream->seekTo(npos + mStream->read_S24());
}
else
{
- mStream.seekTo(npos + 3 * (index + 1));
- uint_32t newpos = mStream.read_S24();
- mStream.seekTo(npos - 1 + newpos);
+ mStream->seekTo(npos + 3 * (index + 1));
+ uint_32t newpos = mStream->read_S24();
+ mStream->seekTo(npos - 1 + newpos);
}
break;
}
@@ -398,9 +536,9 @@
/// a base, in which case leave that alone.
case SWF::ABC_ACTION_PUSHWITH:
{
- asScope = mStack.top(0).to_scope();
+ asScope a = mStack.top(0).to_scope();
mStack.drop(1);
- pushScope(asScope);
+ mScopeStack.push(a);
// If there wasn't a base scope, then this becomes it.
if (!mBaseScope)
mBaseScope = mCurrentScope;
@@ -413,7 +551,7 @@
{
if (mCurrentScope == mBaseScope)
mBaseScope = NULL;
- popScope();
+ mScopeStack.pop();
break;
}
/// 0x1E ABC_ACTION_NEXTNAME
@@ -424,8 +562,10 @@
/// name -- the key name of the property at index in obj
case SWF::ABC_ACTION_NEXTNAME:
{
+ ENSURE_NUMBER(mStack.top(0));
+ ENSURE_OBJECT(mStack.top(1));
as_object *obj = mStack.top(1).to_object();
- uint32_t index = mStack.top(0).to_number<uint32_t>();
+ uint32_t index = mStack.top(0).to_uint();
mStack.drop(1);
asBinding *b = obj->binding_at_index(index);
if (next)
@@ -444,8 +584,10 @@
/// Otherwise, make next_index 0.
case SWF::ABC_ACTION_HASNEXT:
{
+ ENSURE_NUMBER(mStack.top(0));
+ ENSURE_OBJECT(mStack.top(1));
as_object *obj = mStack.top(1).to_object();
- uint32_t index = mStack.top(0).to_number<uint32_t>();
+ uint32_t index = mStack.top(0).to_uint();
mStack.drop(1);
asBinding *next = obj->binding_after_index(index);
if (next)
@@ -480,14 +622,16 @@
/// value -- the value of the key value pair in obj at index.
case SWF::ABC_ACTION_NEXTVALUE:
{
+ ENSURE_NUMBER(mStack.top(0));
+ ENSURE_OBJECT(mStack.top(1));
as_object *obj = mStack.top(1).to_object();
- uint32_t index = mStack.top(0).to_number<uint32_t>();
- mStack.drop(1);
+ uint32_t index = mStack.top(0).to_uint();
asBinding *b = obj->binding_at_index(index);
- if (next)
- mStack.top(0) = b->getValue();
- else
+ mStack.drop(1);
+ if (!next)
mStack.top(0).set_undefined();
+ else // The top of the stack is obj, as it should be.
+ pushCall(1, &mStack.top(0), b);
break;
}
/// 0x24 ABC_ACTION_PUSHBYTE
@@ -496,7 +640,7 @@
/// byte -- as a raw byte
case SWF::ABC_ACTION_PUSHBYTE:
{
- int8_t *b = mStream.read_s8();
+ int8_t *b = mStream->read_s8();
mStack.grow(1);
mStack.top(0) = b;
break;
@@ -507,7 +651,7 @@
/// value -- as a raw integer
case SWF::ABC_ACTION_PUSHSHORT:
{
- signed short s = static_cast<signed short>(mStream.read_V32());
+ signed short s = static_cast<signed short>(mStream->read_V32());
mStack.grow(1);
mStack.top(0) = s;
break;
@@ -582,7 +726,7 @@
case SWF::ABC_ACTION_PUSHSTRING:
{
mStack.grow(1);
- mStack.top(0) = pool_string(mStream.read_V32());
+ mStack.top(0) = pool_string(mStream->read_V32());
break;
}
/// 0x2D ABC_ACTION_PUSHINT
@@ -592,7 +736,7 @@
case SWF::ABC_ACTION_PUSHINT:
{
mStack.grow(1);
- mStack.top(0) = pool_int(mStream.read_V32());
+ mStack.top(0) = pool_int(mStream->read_V32());
break;
}
/// 0x2E ABC_ACTION_PUSHUINT
@@ -602,7 +746,7 @@
case SWF::ABC_ACTION_PUSHUINT:
{
mStack.grow(1);
- mStack.top(0) = pool_uint(mStream.read_V32());
+ mStack.top(0) = pool_uint(mStream->read_V32());
break;
}
/// 0x2F ABC_ACTION_PUSHDOUBLE
@@ -612,7 +756,7 @@
case SWF::ABC_ACTION_PUSHDOUBLE:
{
mStack.grow(1);
- mStack.top(0) = pool_double(mStream.read_V32());
+ mStack.top(0) = pool_double(mStream->read_V32());
break;
}
/// 0x30 ABC_ACTION_PUSHSCOPE
@@ -634,7 +778,7 @@
/// ns -- Namespace object from namespace_pool[index]
case SWF::ABC_ACTION_PUSHNAMESPACE:
{
- asNamespace *ns = pool_namespace(mStream.read_V32());
+ asNamespace *ns = pool_namespace(mStream->read_V32());
mStack.grow(1);
mStack.top(0) = *ns;
break;
@@ -649,21 +793,25 @@
/// Change at indexloc to index (as object) of the next value.
case ABC_ACTION_HASNEXT2:
{
- int32_t oindex = mStream.read_V32();
- int32_t iindex = mStream.read_V32();
- as_object *obj = mFrame.value(oindex).to_object();
- int32_t index = mFrame.value(iindex).to_number<int32_t>();
+ int32_t oindex = mStream->read_V32();
+ int32_t iindex = mStream->read_V32();
+ as_value &objv = mFrame.value(oindex);
+ as_value &indexv = mFrame.value(iindex);
+ ENSURE_OBJECT(objv);
+ ENSURE_NUMBER(indexv);
+ as_object *obj = objv.to_object();
+ int32_t index = indexv.to_int();
asBinding *next = obj->next_after_index(index);
mStack.grow(1);
if (next)
{
- mStack.top(0) = true;
+ mStack.top(0).set_bool(true);
mFrame.value(oindex) = next->getOwner();
mFrame.value(iindex) = next->getName();
}
else
{
- mStack.top(0) = false;
+ mStack.top(0).set_bool(false);
mFrame.value(oindex).set_null();
mFrame.value(iindex) = 0;
}
@@ -674,12 +822,12 @@
/// Stack Out:
/// func -- the function object
/// Do: Information about function is in the pool at index. Construct the
-/// function from this information, current scope, and base of the scope.
+/// function from this information and bind the current scope.
case SWF::ABC_ACTION_NEWFUNCTION:
{
mStack.grow(1);
- asMethod *m = pool_method(mStream.read_V32());
- mStack.top(0) = m->construct(mCurrentScope, mBaseScope);
+ asMethod *m = pool_method(mStream->read_V32());
+ mStack.top(0) = m->construct(mCurrentScope);
break;
}
/// 0x41 ABC_ACTION_CALL
@@ -692,11 +840,12 @@
/// value -- the value returned by obj->func(arg1, ...., argN)
case SWF::ABC_ACTION_CALL:
{
- uint32_t argc = mStream.read_V32();
+ uint32_t argc = mStream->read_V32();
as_function *f = mStack.top(argc + 1).to_function();
- as_object *obj = mStack.top(argc).to_object();
- mStack.top(argc + 1) = f.call(obj, mStack);
- mStack.drop(argc + 1);
+ // argc + 1 will be dropped, and mStack.top(argc + 1)
+ // will be the top of the stack, so that is where the
+ // return value should go. (Currently it is the func)
+ pushCall(argc + 1, &mStack.top(argc + 1), asBinding(f));
break;
}
/// 0x42 ABC_ACTION_CONSTRUCT
@@ -708,10 +857,9 @@
/// value -- obj after it has been constructed as obj(arg1, ..., argN)
case SWF::ABC_ACTION_CONSTRUCT:
{
- uint32_t argc = mStream.read_V32();
+ uint32_t argc = mStream->read_V32();
as_function *f = mStack.top(argc).to_function();
- mStack.top(argc) = f.construct(mStack);
- mStack.drop(argc);
+ pushCall(argc, &mStack.top(argc), asBinding(f));
break;
}
/// 0x43 ABC_ACTION_CALLMETHOD
@@ -723,11 +871,18 @@
/// value -- the value returned by obj::'method_id'(arg1, ..., argN)
case SWF::ABC_ACTION_CALLMETHOD:
{
- uint32_t dispatch_id = mStream.read_V32() - 1;
- uint32_t argc = mStream.read_V32();
+ uint32_t dispatch_id = mStream->read_V32() - 1;
+ uint32_t argc = mStream->read_V32();
+ ENSURE_OBJECT(mStack.top(argc));
as_object *obj = mStack.top(argc).to_object();
- mStack.top(argc) = obj.call_dispatch(dispatch_id);
+ asBinding *b = obj.find_at_index(dispatch_id);
+ if (!b)
+ {
mStack.drop(argc);
+ mStack.top(0).set_undefined();
+ break;
+ }
+ pushCall(argc + 1, &mStack.top(argc), b);
break;
}
/// 0x44 ABC_ACTION_CALLSTATIC
@@ -739,10 +894,9 @@
/// value -- the value returned by obj->ABC::'method_id'(arg1, ..., argN)
case SWF::ABC_ACTION_CALLSTATIC:
{
- asMethod *m = pool_method(mStream.read_V32());
- uint32_t argc = mStream.read_V32();
- mStack.top(argc) = m->call_static(mStack.top(argc),
mStack.top(argc - 1));
- mStack.drop(argc);
+ asMethod *m = pool_method(mStream->read_V32());
+ uint32_t argc = mStream->read_V32();
+ pushCall(argc + 1, &mStack.top(argc), asBinding(m));
break;
}
/// 0x45 ABC_ACTION_CALLSUPER
@@ -759,12 +913,16 @@
case SWF::ABC_ACTION_CALLSUPER:
case SWF::ABC_ACTION_CALLSUPERVOID:
{
- asName a = mStream.read_V32();
- mStack.drop(completeName(a));
-
- mStack.top(argc) = mStack.top(argc).get_named_super(a)
- .call_function(mStack.top(argc - 1));
- mStack.drop(opcode == SWF::ABC_ACTION_CALL_SUPER ? argc : argc
+ 1);
+ asName a = mStream->read_V32();
+ uint32_t argc = mStream->read_V32();
+ int dropsize = completeName(a);
+ ENSURE_OBJECT(mStack.top(argc + dropsize));
+ mStack.drop(dropsize);
+ asBinding *b = mStack.top(argc).to_object().get_named_super(a);
+ if (opcode == SWF::ABC_ACTION_CALLSUPER)
+ pushCall(argc + 1, &mStack.top(argc), b);
+ else
+ pushCall(argc + 1, &mIgnoreReturn, b);
break;
}
/// 0x46 ABC_ACTION_CALLPROPERTY
@@ -785,23 +943,34 @@
case SWF::ABC_ACTION_CALLPROPVOID:
{
bool lex_only = (opcode == SWF::ABC_ACTION_CALLPROPLEX);
- asName a = mStream.read_V32();
- uint32_t argc = mStream.read_V32();
+ asName a = mStream->read_V32();
+ uint32_t argc = mStream->read_V32();
int shift = completeName(a, argc);
+ ENSURE_OBJECT(mStack.top(shift + argc));
// Ugly setup. Any name stuff is between the args and the
object.
- as_object *obj = mStack.top(argc + shift).to_object();
- mStack.top(shift + argc) = obj->call_property(a,
mStack.top(argc));
- mStack.drop(shift + argc);
+ if (shift)
+ {
+ uint32_t i = argc;
+ while (i--)
+ mStack.top(i + shift) = mStack.top(i);
+ mStack.drop(shift);
+ }
+ asBinding *b =
mStack.top(argc).to_object()->getPropertyBinding(a);
+ b->setLexOnly(lex_only);
if (opcode == SWF::ABC_ACTION_CALLPROPVOID)
- mStack.drop(1);
+ pushCall(argc + 1, &mIgnoreReturn, b);
+ else
+ pushCall(argc + 1, &mStack.top(argc), b);
break;
}
/// 0x47 ABC_ACTION_RETURNVOID
/// Do: Return an undefined object up the callstack.
case SWF::ABC_ACTION_RETURNVOID:
{
- mReturnStack.grow(1);
- mReturnStack.top(0).set_undefined();
+ // Slot the return.
+ *mGlobalReturn = as_value();
+ // And restore the previous state.
+ restoreState();
break;
}
/// 0x48 ABC_ACTION_RETURNVALUE
@@ -812,7 +981,10 @@
/// Do: Return value up the callstack.
case SWF::ABC_ACTION_RETURNVALUE:
{
- mReturnStack.push(mStack.pop());
+ // Slot the return.
+ *mGlobalReturn = mStack.top(0);
+ // And restore the previous state.
+ restoreState();
break;
}
/// 0x49 ABC_ACTION_CONSTRUCTSUPER
@@ -822,13 +994,13 @@
/// arg1 ... argN -- the arg_count arguments
/// Stack Out:
/// .
-///
case SWF::ABC_ACTION_CONSTRUCTSUPER:
{
- uint32_t argc = mStream.read_V32();
+ uint32_t argc = mStream->read_V32();
+ ENSURE_OBJECT(mStack.top(argc));
as_object *obj = mStack.top(argc).to_object();
- obj->super_construct(mStack.top(argc - 1));
- mStack.drop(argc + 1);
+ asBinding *b = obj->getSuperConstructor();
+ pushCall(argc + 1, &mIgnoreReturn, b);
break;
}
/// 0x4A ABC_ACTION_CONSTRUCTPROP
@@ -842,12 +1014,21 @@
/// 'name_offset'(arg1, ..., argN)
case SWF::ABC_ACTION_CONSTRUCTPROP:
{
- asName a = mStream.read_V32();
- uint32_t argc = mStream.read_V32();
+ asName a = mStream->read_V32();
+ uint32_t argc = mStream->read_V32();
int shift = completeName(a, argc);
- as_object *obj = mStack.top(argc + shift).to_object();
- mStack.top(argc + shift) = obj->construct_property(a,
mStack.top(argc));
- mStack.drop(argc + shift);
+ ENSURE_OBJECT(mStack.top(argc + shift));
+ // We have to move the stack if there was a shift.
+ if (shift)
+ {
+ uint32_t i = argc;
+ while (i--)
+ mStack.top(i + shift) = mStack.top(i);
+ mStack.drop(shift);
+ }
+ as_object *obj = mStack.top(argc).to_object();
+ asBinding *b = obj->getPropertyConstructor(a);
+ pushCall(argc + 1, &mStack.top(0), b);
break;
}
/// 0x55 ABC_ACTION_NEWOBJECT
@@ -866,7 +1047,7 @@
case SWF::ABC_ACTION_NEWOBJECT:
{
as_object *obj = mCH->newOfType(NSV::CLASS_OBJECT);
- uint32_t argc = mStream.read_V32();
+ uint32_t argc = mStream->read_V32();
int i = argc;
while (i--)
{
@@ -888,10 +1069,13 @@
/// array -- an array { value_1, value_2, ..., value_n }
case SWF::ABC_ACTION_NEWARRAY:
{
- uint32_t asize = mStream.read_V32();
+ uint32_t asize = mStream->read_V32();
as_object *obj = mCH->newOfType(NSV::CLASS_ARRAY);
as_array *array = dynamic_cast<as_array*> (obj);
- array->load(mStack.top(asize - 1));
+ array->resize(asize);
+ uint32_t i = asize;
+ while (i--)
+ array->set_indexed(i, mStack.value(i));
mStack.drop(asize - 1);
mStack.top(0) = array;
break;
@@ -914,7 +1098,7 @@
/// NB: This depends on scope and scope base (to determine lifetime(?))
case SWF::ABC_ACTION_NEWCLASS:
{
- uint32_t cid = mStream.read_V32();
+ uint32_t cid = mStream->read_V32();
mStack.top(0) = mCH->newOfId(cid, mStack.top(0));
break;
}
@@ -955,7 +1139,7 @@
case SWF::ABC_ACTION_FINDPROPSTRICT:
case SWF::ABC_ACTION_FINDPROPERTY:
{
- asName a = mStream.read_V32();
+ asName a = mStream->read_V32();
mStack.drop(completeName(a));
as_value v = findProperty(a);
if ((opcode == SWF::ABC_ACTION_FINDPROPSTRICT) &&
v.is_undefined())
@@ -968,7 +1152,7 @@
/// def -- The definition of the name at name_id.
case SWF::ABC_ACTION_FINDDEF:
{
- asName a = mStream.read_V32();
+ asName a = mStream->read_V32();
// TODO
break;
}
@@ -979,7 +1163,7 @@
/// + 0x66 (ABC_ACTION_GETPROPERTY)
case SWF::ABC_ACTION_GETLEX
{
- asName a = mStream.read_V32();
+ asName a = mStream->read_V32();
as_value v = findProperty(a);
if (v.is_undefined())
throw ASReferenceException();
@@ -1004,7 +1188,7 @@
/// key/value is set in the dictionary obj instead.
case SWF::ABC_ACTION_SETPROPERTY:
{
- asName a = mStream.read_V32();
+ asName a = mStream->read_V32();
as_value &v = mStack.pop();
if (!a.isRuntime())
{
@@ -1036,7 +1220,7 @@
case SWF::ABC_ACTION_GETLOCAL:
{
mStack.grow(1);
- mStack.top(0) = mFrame.value(mStream.read_V32());
+ mStack.top(0) = mFrame.value(mStream->read_V32());
break;
}
/// 0x63 ABC_ACTION_SETLOCAL
@@ -1048,7 +1232,7 @@
/// .
case SWF::ABC_ACTION_SETLOCAL:
{
- mFrame.value(mStream.read_V32()) = mStack.top(0);
+ mFrame.value(mStream->read_V32()) = mStack.top(0);
mStack.drop(1);
break;
}
@@ -1067,7 +1251,7 @@
/// scope -- The scope object at depth
case SWF::ABC_ACTION_GETSCOPEOBJECT
{
- uint8_t depth = mStream.read_u8();
+ uint8_t depth = mStream->read_u8();
mStack.grow(1);
mStack.top(0) = mScopeStack(depth);
break;
@@ -1084,7 +1268,7 @@
/// NB: See 0x61 (ABC_ACTION_SETPROPETY) for the decision of ns/key.
case SWF::ABC_ACTION_GETPROPERTY:
{
- asName a = mStream.read_V32();
+ asName a = mStream->read_V32();
if (!a.isRuntime())
{
mStack.top(0) = mStack.top(0).getProperty(a, v);
@@ -1117,7 +1301,7 @@
/// Set obj::(resolve)'name_id' to value, set bindings from the context.
case SWF::ABC_ACTION_INITPROPERTY:
{
- asName a = mStream.read_V32();
+ asName a = mStream->read_V32();
as_value& v = mStack.pop();
mStack.drop(completeName(a));
mStack.pop().to_object().setProperty(a, v, true); // true for
init
@@ -1132,7 +1316,7 @@
/// truth -- True if property was deleted or did not exist, else False.
case SWF::ABC_ACTION_DELETEPROPERTY:
{
- asName a = mStream.read_V32();
+ asName a = mStream->read_V32();
mStack.drop(completeName(a));
mStack.top(0) = mStack.top(0).deleteProperty(a);
break;
@@ -1145,7 +1329,7 @@
/// slot -- obj.slots[slot_index]
case SWF::ABC_ACTION_GETSLOT
{
- uint32_t sindex = mStream.read_V32();
+ uint32_t sindex = mStream->read_V32();
if (!sindex)
throw ASException();
--sindex;
@@ -1162,7 +1346,7 @@
/// Do: obj.slots[slot_index] = value
case SWF::ABC_ACTION_SETSLOT:
{
- uint32_t sindex = mStream.read_V32();
+ uint32_t sindex = mStream->read_V32();
if (!sindex)
throw ASException();
--sindex;
@@ -1179,7 +1363,7 @@
/// NB: Deprecated
case SWF::ABC_ACTION_GETGLOBALSLOT:
{
- uint32_t sindex = mStream.read_V32();
+ uint32_t sindex = mStream->read_V32();
if (!sindex)
throw ASException();
--sindex;
@@ -1197,7 +1381,7 @@
/// NB: Deprecated
case SWF::ABC_ACTION_SETGLOBALSLOT:
{
- uint32_t sindex = mStream.read_V32();
+ uint32_t sindex = mStream->read_V32();
if (!sindex)
throw ASException();
--sindex;
@@ -1316,7 +1500,7 @@
/// coerced_obj -- The object as the desired (resolve)'name_index' type.
case SWF::ABC_ACTION_COERCE:
{
- asName a = mStream.read_V32();
+ asName a = mStream->read_V32();
mStack.drop(completeName(a));
mStack.top(0) = mStack.top(0).coerce(a);
break;
@@ -1353,7 +1537,7 @@
/// cobj -- obj if obj is of type (resolve)'name_index', otherwise Null
case SWF::ABC_ACTION_ASTYPE:
{
- asName a = mStream.read_V32();
+ asName a = mStream->read_V32();
mStack.drop(completeName(a));
if (!mStack.top(0).conforms_to(a)
mStack.top(0).set_null();
@@ -1410,7 +1594,7 @@
/// Frame: Load i from frame_addr and increment it.
case SWF::ABC_ACTION_INCLOCAL:
{
- uint32_t foff = mStream.read_V32();
+ uint32_t foff = mStream->read_V32();
mFrame.value(foff) = mFrame.value(foff).to_number() + 1;
break;
}
@@ -1429,7 +1613,7 @@
/// Frame: Load i from frame_addr and decrement it.
case SWF::ABC_ACTION_DECLOCAL:
{
- uint32_t foff = mStream.read_V32();
+ uint32_t foff = mStream->read_V32();
mFrame.value(foff) = mFrame.value(foff).to_number() - 1;
break;
}
@@ -1695,7 +1879,7 @@
/// truth -- Truth of "obj is of the type given in (resolve)'name_id'"
case SWF::ABC_ACTION_ISTYPE:
{
- asName a = mStream.read_V32();
+ asName a = mStream->read_V32();
mStack.drop(completeName(a));
mStack.top(0).set_bool(mStack.top(0).conforms_to(a));
}
@@ -1744,7 +1928,7 @@
/// See: 0x92 (ABC_ACTION_INCLOCAL), but forces types to int, not double
case SWF::ABC_ACTION_INCLOCAL_I:
{
- uint32_t foff = mStream.read_V32();
+ uint32_t foff = mStream->read_V32();
mFrame.value(foff) = mFrame.value(foff).to_number<int>() + 1;
break;
}
@@ -1752,7 +1936,7 @@
/// See: 0x94 (ABC_ACTION_DECLOCAL), but forces types to int, not double
case SWF::ABC_ACTION_DECLOCAL_I:
{
- uint32_t foff = mStream.read_V32();
+ uint32_t foff = mStream->read_V32();
mFrame.value(foff) = mFrame.value(foff).to_number<int>() - 1;
break;
}
@@ -1827,7 +2011,7 @@
/// Do: skip ahead 7 bytes in stream
case SWF::ABC_ACTION_DEBUG:
{
- seekBy(7);
+ mStream->seekBy(7);
break;
}
/// 0xF0 ABC_ACTION_DEBUGLINE
@@ -1835,7 +2019,7 @@
/// Do: Nothing, but line_number is for the debugger if wanted.
case SWF::ABC_ACTION_DEBUGLINE:
{
- mStream.skip_V32();
+ mStream->skip_V32();
break;
}
/// 0xF1 ABC_ACTION_DEBUGFILE
@@ -1843,7 +2027,7 @@
/// Do: Nothing. 'name_offset' into string pool is the file name if wanted.
case SWF::ABC_ACTION_DEBUGFILE:
{
- mStream.skip_V32();
+ mStream->skip_V32();
break;
}
/// 0xF2 ABC_ACTION_BKPTLINE
@@ -1851,11 +2035,17 @@
/// Do: Enter debugger if present, line_number is the line number in source.
case SWF::ABC_ACTION_BKPTLINE:
{
- mStream.skip_V32();
+ mStream->skip_V32();
break;
}
} // end of switch statement
-
+ } // end of AS3 conditional
+ else // beginning of !AS3 (this code is AS2)
+ {
+ switch (opcode)
+ {
+ } // end of switch statement
+ } // end of AS2 conditional (!AS3)
} // end of main loop
} // end of execute function
@@ -1866,7 +2056,7 @@
if (!instance.is_object())
throw ASTypeError();
- asBinding *pBinding = pDefinition->findMember(name);
+ asBinding *pBinding = pDefinition->findMember(name, instance);
if (pBinding->isWriteOnly())
throw ASReferenceError();
@@ -1878,9 +2068,9 @@
// This is a getter, so we need to execute it. Even those
// written in C++ get called like this, with pushCall handling.
- // 1 parameter (the source), 1 value expected back.
+ // And push the instance ('this')
mStack.push(instance);
- pushCall(1, 1, pBinding->getGetter());
+ pushCall(1, &mStack.top(0), pBinding->getGetter());
}
void
@@ -1890,7 +2080,8 @@
if (!instance.is_object())
throw ReferenceError();
- asBinding *pBinding = pDefinition->findMember(name);
+ asBinding *pBinding = pDefinition->findMember(name, instance);
+
if (pBinding->isReadOnly())
throw ASReferenceError();
@@ -1903,7 +2094,7 @@
// Two parameters -- the target object, the value to set.
mStack.push(instance);
mStack.push(newvalue);
- pushCall(2, 0, pBinding->getSetter());
+ pushCall(2, &mStack.top(1), pBinding->getSetter());
}
int
@@ -1952,3 +2143,90 @@
return NULL;
}
+void
+ActionMachine::pushCall(unsigned int stack_in, as_value *return_slot,
+ asBinding *pBind)
+{
+ switch (pBind->mType)
+ {
+ default:
+ case asBinding::T_ACCESS:
+ case asBinding::T_CLASS:
+ throw ASException();
+ return;
+ case asBinding::T_VALUE:
+ return_slot = pBind->getValue()->getCurrentValue();
+ return;
+ case asBinding::T_METHOD:
+ break;
+ }
+
+ asMethod *m = pBind->getMethod();
+
+ if (!(m->isNative() || m->hasBody())
+ throw ASException();
+
+ // Here is where the SafeStack shines:
+ // We set the stack the way it should be on return.
+ // If the return slot is the deepest parameter, leave room for it.
+ if (stack_in && (return_slot == &mStack.top(stack_in - 1)))
+ mStack.drop(stack_in - 1);
+ else // The return slot is somewhere else.
+ mStack.drop(stack_in);
+ // We save that state.
+ saveState();
+ // We make the stack appear empty.
+ mStack.fixDownstop();
+ // We grow to reclaim the parameters. Since this is a SafeStack, they
+ // were not lost.
+ mStack.grow(stack_in);
+
+ // Native functions have to be called now.
+ if (m->isNative())
+ {
+ return_slot = m->CallNative(mStack, mGlobalScope);
+ restoreState();
+ return;
+ }
+
+ // The scope stack should be fixed for non-native calls.
+ mScopeStack.fixDownstop();
+ mScopeStack.push(m->getActivation());
+ mCurrentScope = mScopeStack.top(0);
+
+ // We set the stream and return as given in the method and call.
+ mStream = m->getCode();
+ mGlobalReturn = return_slot;
+
+ // When control goes to the main loop of the interpreter, it will
+ // automatically start executing the method.
+}
+
+void
+ActionMachine::restoreState()
+{
+ State &s = mStateStack.top(0);
+ mStack.setAllSizes(s.mStackTotalSize, s.mStackDepth);
+ mScopeStack.setAllSizes(s.mScopeTotalSize, s.mScopeStackDepth);
+ mStream = s.mStream;
+ mDefaultXMLNamespace = s.mDefaultXMLNamespace;
+ mCurrentScope = s.mCurrentScope;
+ mGlobalReturn = s.mGlobalReturn;
+ mStateStack.drop(1);
+}
+
+void
+ActionMachine::saveState()
+{
+ mStateStack.grow(1);
+ State &s = mStateStack.top(0);
+ s.mStackDepth = mStack.getDownstop();
+ s.mStackTotalSize = mStack.getTotalSize();
+ s.mScopeStackDepth = mScopeStack.getDownstop();
+ s.mScopeTotalSize = mScopeStack.getTotalSize();
+ s.mStream = mStream;
+ s.mDefaultXMLNamespace = mDefaultXMLNamespace;
+ s.mCurrentScope = mCurrentScope;
+ s.mGlobalReturn = mGlobalReturn;
+}
+
Index: server/vm/Machine.h
===================================================================
RCS file: /sources/gnash/gnash/server/vm/Machine.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- server/vm/Machine.h 5 Oct 2007 17:48:16 -0000 1.2
+++ server/vm/Machine.h 8 Oct 2007 06:55:11 -0000 1.3
@@ -19,118 +19,11 @@
#include <vector>
+#include "SafeStack.h"
#include "as_value.h"
namespace gnash {
-class ASException
-{
-};
-
-class StackException : public ASException
-{
-};
-
-template <class T>
-class Stack
-{
-public:
- T& top(unsigned int i)
- {
- if (i >= mDownstop)
- throw StackException();
- unsigned int offset = mEnd - i;
- return mData[offset >> mChunkShift][offset & mChunkMod];
- }
-
- T& value(unsigned int i)
- {
- if (i >= mDownstop)
- throw StackException();
- unsigned int offset = mEnd - mDownstop + i;
- return mData[offset >> mChunkShift][offset & mChunkMod];
- }
-
- void drop(unsigned int i)
- { if (i >= mDownstop) throw StackException(); mDownstop -= i; mEnd -=
i; }
-
- void push(const T& t)
- { grow(1); top(0) = t; }
-
- void grow(unsigned int i)
- {
- if (((mEnd + i) >> mChunkShift) > mData.size())
- {
- if (i > (1 << mChunkShift))
- throw StackException();
- mData.push_back(new data_vector(1 << mChunkShift));
- mData.back()->resize(1 << mChunkShift);
- }
- mDownstop += i;
- mEnd += i;
- }
-
- unsigned int getDownstop() const
- { return mDownstop; }
-
- unsigned int fixDownstop()
- { unsigned int ret = mDownstop; mDownstop = 0; return ret; }
-
- void setDownstop(unsigned int i)
- { if (mDownstop > mEnd) throw StackException(); mDownstop = i; }
-
- Stack() : mData(), mDownstop(1), mEnd(1)
- { /**/ }
-
- ~Stack()
- {
- stack_type::iterator i = mData.begin();
- for ( ; i != mData.end(); ++i)
- {
- delete (*i);
- }
- }
-
-private:
- typedef std::vector<T> data_vector;
- typedef std::vector<data_vector *> stack_type;
- stack_type mData;
- unsigned int mDownstop;
- unsigned int mEnd;
-
- // If mChunkMod is not a power of 2 less 1, it will not work properly.
- static const unsigned int mChunkShift = 6;
- static const unsigned int mChunkMod = (1 << mChunkShift) - 1;
-};
-
-class CodeStream
-{
-public:
- uint32_t read_V32();
- uint8_t read_as3op();
- std::size_t tell();
- void seekBy(int change);
- void seekTo(std::size_t set);
- int32_t read_S24();
- int8_t read_s8();
- uint8_t read_u8();
- void skip_V32();
-};
-
-class FunctionEntry
-{
-public:
- FunctionEntry(Stack<as_value> *s) : mStack(s)
- { mStackReset = s->fixDownstop(); }
-
- ~FunctionEntry()
- { if (mStack) mStack->setDownstop(mStackReset); }
-
-private:
- unsigned int mStackReset;
- Stack<as_value> *mStack;
-};
-
/// This machine is intended to work without relying on the C++ call stack,
/// by resetting its Stream and Stack members (actually, by limiting the stack)
/// to make function calls, rather than calling them directly in C++.
@@ -238,21 +131,63 @@
void execute_as2();
- void pushCall(int param_count, int return_count, asMethod *pMethod);
+ /// push a function call to be executed next.
+ ///
+ /// Any asBinding can be pushed, and it will appropriate value
+ /// into return_slot. This ensures that getter/setter properties
+ /// can be accessed in the same way as other properties, and hides
+ /// the difference between ActionScript methods and native C++ methods.
+ ///
+ /// @param stack_in
+ /// The initial stack size when the function is entered. This can be
used
+ /// to pass 'this' and other parameters to the call.
+ ///
+ /// @param stack_out
+ /// The maximum number of values to leave on the stack when the function
+ /// returns.
+ ///
+ /// @param return_slot
+ /// A space for the return value. An assignment will always be made
here,
+ /// but mVoidSlot can be used for values that will be discarded.
+ ///
+ /// @param pBind
+ /// The non-null binding. If this is only a partial binding, then
+ /// the 'this' value will be used to complete it, when possible.
+ void pushCall(unsigned int stack_in, unsigned int stack_out,
+ as_value &return_slot, asBinding *pBind);
private:
+ /// The state of the machine.
+ class State
+ {
+ public:
+ unsigned int mStackDepth;
+ unsigned int mStackTotalSize;
+ unsigned int mScopeStackDepth;
+ unsigned int mScopeTotalSize;
+ CodeStream *mStream;
+ asNamespace *mDefaultXMLNamespace;
+ asScope *mCurrentScope;
+ asValue *mGlobalReturn;
+ };
+
+ void saveState();
+ void restoreState();
+
Stack<as_value> mStack;
- Stack<FunctionEntry> mCallStack;
- Stack<as_value> mFrame;
- Stack<asScope*> mScopeStack;
- CodeStream mStream;
+ Stack<State> mStateStack;
+ Stack<asScope> mScopeStack;
+ CodeStream *mStream;
ClassHierarchy *mCH;
+ string_table& mST;
asNamespace* mDefaultXMLNamespace;
asScope *mGlobalScope;
asScope *mCurrentScope;
- asScope *mBaseScope;
+
+ asValue *mGlobalReturn;
+ asValue mIgnoreReturn; // Throw away returns go here.
};
} // namespace gnash
Index: server/vm/CodeStream.h
===================================================================
RCS file: /sources/gnash/gnash/server/vm/CodeStream.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- server/vm/CodeStream.h 7 Oct 2007 03:19:48 -0000 1.1
+++ server/vm/CodeStream.h 8 Oct 2007 06:55:11 -0000 1.2
@@ -60,12 +60,48 @@
}
}
+ /// Construct an empty CodeStream. Call reInitialize to fill it.
+ CodeStream() : mRaw(NULL), mRawEnd(NULL), mEnd(NULL), mOwn(false)
+ {/**/}
+
/// Destruct a CodeStream
///
/// If the stream owns the memory, it will destroy it.
~CodeStream()
{ if (mOwn) delete [] mRaw; }
+ /// Pseudo-construct a CodeStream
+ ///
+ /// This has the same parameters as the non-default constructor,
+ /// but it can be used to re-initialize the CodeStream object.
+ void reInitialize(const char *pStart, std::size_t length,
+ bool own = false)
+ {
+ if (own)
+ {
+ // Delete mRaw if it's not large enough and it's ours.
+ if (mOwn && length > static_cast<unsigned int> (mRawEnd
- mRaw))
+ {
+ mOwn = false;
+ delete [] mRaw;
+ }
+ if (!mOwn)
+ mRaw = new char [length];
+ memcpy(const_cast<char *>(mRaw), pStart, length);
+ mEnd = mRawEnd = pStart + length;
+ mCurrent = mRaw;
+ return;
+ }
+
+ if (mOwn)
+ {
+ // We own now, but don't want to.
+ delete [] mRaw;
+ }
+ mCurrent = mRaw = pStart;
+ mEnd = mRawEnd = pStart + length;
+ }
+
/// Read a variable length encoded 32 bit unsigned integer
uint32_t read_V32()
{
@@ -173,6 +209,11 @@
void unset_end()
{ mEnd = mRawEnd; }
+ /// Take ownership of mRaw. mRaw should be a block which can be
+ /// de-allocated by calling delete [] mRaw
+ void takeMemoryOwnership()
+ { mOwn = true; }
+
/// Same as read_V32(), but doesn't bother with the arithmetic for
/// calculating the value.
void skip_V32()
Index: server/vm/SafeStack.h
===================================================================
RCS file: /sources/gnash/gnash/server/vm/SafeStack.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- server/vm/SafeStack.h 7 Oct 2007 05:09:19 -0000 1.1
+++ server/vm/SafeStack.h 8 Oct 2007 06:55:11 -0000 1.2
@@ -105,6 +105,11 @@
/// getDownstop()
unsigned int totalSize() const { return mEnd - 1; }
+ /// Set the total size and local size of the stack, for restoring a
+ /// stack through unknown changes.
+ void setAllSizes(unsigned int total, unsigned int downstop)
+ { mEnd = total + 1; mDownstop = downstop; }
+
/// Default constructor.
SafeStack() : mData(), mDownstop(1), mEnd(1)
{ /**/ }