Support assigning structs.
Support assigning structs.
1.1 --- a/src/BytecodeCompiler.cpp Sat Aug 04 21:47:30 2012 -0700
1.2 +++ b/src/BytecodeCompiler.cpp Sat Aug 04 23:26:49 2012 -0700
1.3 @@ -201,6 +201,8 @@
1.4 void
1.5 BytecodeCompiler::visit(Assignment *node)
1.6 {
1.7 + Local<Type> type(zone_, node->expression()->type());
1.8 +
1.9 // The first step is three sub-steps:
1.10 //
1.11 // (1) Bind the left-hand side.
1.12 @@ -213,8 +215,12 @@
1.13 Variable *var = proxy->binding()->toVariable();
1.14
1.15 // Bind.
1.16 - if (var->type()->isReference() || var->type()->isArray())
1.17 + if (var->type()->isReference() ||
1.18 + var->type()->isArray() ||
1.19 + var->type()->isStruct())
1.20 + {
1.21 __ get(var);
1.22 + }
1.23
1.24 // Get the value if needed.
1.25 if (node->token() != TOK_ASSIGN) {
1.26 @@ -234,15 +240,16 @@
1.27
1.28 expr->left()->accept(this);
1.29
1.30 - if (node->token() != TOK_ASSIGN) {
1.31 + if (node->token() != TOK_ASSIGN)
1.32 __ dup();
1.33 +
1.34 + if (node->token() != TOK_ASSIGN || (type->isStruct() || type->isArray()))
1.35 __ getfield(expr->fieldIndex(), expr->type());
1.36 - }
1.37 } else {
1.38 IndexExpression *index = node->lvalue()->toIndexExpression();
1.39 __ note_position(index->pos());
1.40
1.41 - // Note: Eventually, watch out for a whole here. An expression like:
1.42 + // Note: Eventually, watch out for a hole here. An expression like:
1.43 //
1.44 // (a[4] = (5, a = []))
1.45 //
1.46 @@ -252,13 +259,12 @@
1.47 index->left()->accept(this);
1.48 index->right()->accept(this);
1.49
1.50 - if (node->token() != TOK_ASSIGN) {
1.51 + if (node->token() != TOK_ASSIGN)
1.52 __ dup2();
1.53 +
1.54 + if (node->token() != TOK_ASSIGN || (type->isStruct() || type->isArray())) {
1.55 __ bounds();
1.56 - if (node->type()->isArray())
1.57 - __ getarray_o();
1.58 - else
1.59 - __ getarray(node->type());
1.60 + __ getarray(index->type());
1.61 }
1.62 }
1.63
1.64 @@ -273,11 +279,16 @@
1.65 }
1.66
1.67 // Emit the store.
1.68 - if (node->expression()->type()->isArray()) {
1.69 + if (type->isArray()) {
1.70 // Unlike references, which can only be computed from a NamePRoxy,
1.71 // arrays can be computed from multiple lvalue types.
1.72 __ note_position(node->pos());
1.73 - __ arraycopy();
1.74 + __ copyarray();
1.75 + } else if (type->isStruct()) {
1.76 + // Structs have value semantics, so emit a full copy. We don't break
1.77 + // this down into u-ops, to avoid unnecessary bytecode explosion.
1.78 + __ note_position(node->pos());
1.79 + __ copystruct();
1.80 } else if (node->lvalue()->isNameProxy()) {
1.81 NameProxy *proxy = node->lvalue()->toNameProxy();
1.82 Variable *var = proxy->binding()->toVariable();
1.83 @@ -793,7 +804,7 @@
1.84 if (node->initialization()) {
1.85 node->initialization()->accept(this);
1.86 __ note_position(node->pos());
1.87 - __ arraycopy();
1.88 + __ copyarray();
1.89 }
1.90 } else if (type->isStruct()) {
1.91 Local<Map> map(zone_, type->newMap());
2.1 --- a/src/BytecodeEmitter.h Sat Aug 04 21:47:30 2012 -0700
2.2 +++ b/src/BytecodeEmitter.h Sat Aug 04 23:26:49 2012 -0700
2.3 @@ -535,8 +535,12 @@
2.4 writeObject(obj);
2.5 markOop(1);
2.6 }
2.7 - void arraycopy() {
2.8 - singleByteOp(OP_ARRAYCOPY);
2.9 + void copyarray() {
2.10 + singleByteOp(OP_COPYARRAY);
2.11 + markOop(1);
2.12 + }
2.13 + void copystruct() {
2.14 + singleByteOp(OP_COPYSTRUCT);
2.15 markOop(1);
2.16 }
2.17
3.1 --- a/src/Interpreter.cpp Sat Aug 04 21:47:30 2012 -0700
3.2 +++ b/src/Interpreter.cpp Sat Aug 04 23:26:49 2012 -0700
3.3 @@ -106,6 +106,8 @@
3.4 return array;
3.5 }
3.6
3.7 +// Even though this function can fail, we immediately bail out, so it doesn't
3.8 +// matter if we've leaving things unrooted.
3.9 static bool
3.10 CopyArray(Zone *zone, Array *source, Array *dest)
3.11 {
3.12 @@ -120,6 +122,95 @@
3.13 return true;
3.14 }
3.15
3.16 +static void
3.17 +GetField(Struct *obj, Descriptor *desc, LocalSlot *vp)
3.18 +{
3.19 + // :TODO: assert no GC.
3.20 + if (desc->type()->isTraceable()) {
3.21 + vp->obj = obj->get<Object *>(desc);
3.22 + } else {
3.23 + switch (desc->type()->pod()) {
3.24 + case PrimitiveType_Float:
3.25 + vp->f = obj->get<float>(desc);
3.26 + break;
3.27 +
3.28 + default:
3.29 + assert(desc->type()->pod() == PrimitiveType_Int32);
3.30 + vp->i32 = obj->get<int>(desc);
3.31 + break;
3.32 + }
3.33 + }
3.34 +}
3.35 +
3.36 +static void
3.37 +GetField(Struct *obj, unsigned index, LocalSlot *vp)
3.38 +{
3.39 + Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
3.40 + GetField(obj, desc, vp);
3.41 +}
3.42 +
3.43 +static void
3.44 +SetField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
3.45 +{
3.46 + // :TODO: assert no GC.
3.47 + if (desc->type()->isTraceable()) {
3.48 + obj->set(zone, desc, v.obj);
3.49 + } else {
3.50 + switch (desc->type()->pod()) {
3.51 + case PrimitiveType_Float:
3.52 + obj->set<float>(desc, v.f);
3.53 + break;
3.54 +
3.55 + default:
3.56 + assert(desc->type()->pod() == PrimitiveType_Int32);
3.57 + obj->set<int>(desc, v.i32);
3.58 + break;
3.59 + }
3.60 + }
3.61 +}
3.62 +
3.63 +static void
3.64 +SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
3.65 +{
3.66 + Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
3.67 + SetField(zone, obj, desc, v);
3.68 +}
3.69 +
3.70 +// Even though this function can fail, we immediately bail out, so it doesn't
3.71 +// matter if we've leaving things unrooted.
3.72 +static bool
3.73 +CopyStruct(Zone *zone, Struct *left, Struct *right)
3.74 +{
3.75 + assert(left->map()->type() == right->map()->type());
3.76 +
3.77 + Type *type = left->map()->type();
3.78 + for (unsigned i = 0; i < type->fields()->length(); i++) {
3.79 + Descriptor *desc = Descriptor::cast(type->fields()->at(i));
3.80 +
3.81 + LocalSlot rval;
3.82 + GetField(right, desc, &rval);
3.83 +
3.84 + // If the field is a struct, we need to deep-copy.
3.85 + if (desc->type()->isStruct()) {
3.86 + LocalSlot lval;
3.87 +
3.88 + GetField(left, desc, &lval);
3.89 + if (!CopyStruct(zone, Struct::cast(lval.obj), Struct::cast(rval.obj)))
3.90 + return false;
3.91 + } else if (desc->type()->isArray()) {
3.92 + LocalSlot lval;
3.93 +
3.94 + GetField(left, desc, &lval);
3.95 + if (!CopyArray(zone, Array::cast(lval.obj), Array::cast(rval.obj)))
3.96 + return false;
3.97 + } else {
3.98 + SetField(zone, left, desc, rval);
3.99 + }
3.100 + }
3.101 +
3.102 + return true;
3.103 +}
3.104 +
3.105 static bool
3.106 InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
3.107 int *result)
3.108 @@ -795,7 +886,7 @@
3.109 break;
3.110 }
3.111
3.112 -case OP_ARRAYCOPY:
3.113 +case OP_COPYARRAY:
3.114 {
3.115 // Note for this assignment opcode, we return the left-hand side, not the
3.116 // right, since in this case the result of the expression could be different.
3.117 @@ -952,6 +1043,31 @@
3.118 break;
3.119 }
3.120
3.121 +case OP_GETFIELD:
3.122 +{
3.123 + Struct *obj = Struct::cast(top.sp[-1].obj);
3.124 + GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
3.125 + break;
3.126 +}
3.127 +
3.128 +case OP_SETFIELD:
3.129 +{
3.130 + Struct *obj = Struct::cast(top.sp[-2].obj);
3.131 + SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
3.132 + top.sp[-2] = top.sp[-1];
3.133 + top.sp--;
3.134 + break;
3.135 +}
3.136 +
3.137 +case OP_COPYSTRUCT:
3.138 +{
3.139 + if (!CopyStruct(zone, Struct::cast(top.sp[-2].obj), Struct::cast(top.sp[-1].obj)))
3.140 + goto error;
3.141 + top.sp[-2].obj = top.sp[-1].obj;
3.142 + top.sp--;
3.143 + break;
3.144 +}
3.145 +
3.146 default:
3.147 assert(false);
3.148 return false;
4.1 --- a/src/Opcodes.cpp Sat Aug 04 21:47:30 2012 -0700
4.2 +++ b/src/Opcodes.cpp Sat Aug 04 23:26:49 2012 -0700
4.3 @@ -80,7 +80,7 @@
4.4 Opcode op = Opcode(*(start() + pcOffset));
4.5 assert(op == OP_CALL || op == OP_NEWARRAY || op == OP_VARREF_LIFO ||
4.6 op == OP_ARGREF_LIFO || op == OP_SLOTREF_LIFO || op == OP_ARRAYREF_LIFO ||
4.7 - op == OP_ARRAYCOPY);
4.8 + op == OP_COPYARRAY);
4.9 #endif
4.10
4.11 if (!safepoints_)
4.12 @@ -180,7 +180,8 @@
4.13 case OP_SETREF_F:
4.14 case OP_SLOTREF_LIFO:
4.15 case OP_ARRAYREF_LIFO:
4.16 - case OP_ARRAYCOPY:
4.17 + case OP_COPYARRAY:
4.18 + case OP_COPYSTRUCT:
4.19 case OP_DUP:
4.20 case OP_DUP2:
4.21 case OP_SWAP:
5.1 --- a/src/Opcodes.tbl Sat Aug 04 21:47:30 2012 -0700
5.2 +++ b/src/Opcodes.tbl Sat Aug 04 23:26:49 2012 -0700
5.3 @@ -188,7 +188,7 @@
5.4 // Right = pop()
5.5 // copy(Left, Right)
5.6 // push(Left)
5.7 -OPDEF(OP_ARRAYCOPY, 82, "arraycopy", 1, 2, 1)
5.8 +OPDEF(OP_COPYARRAY, 82, "arraycopy", 1, 2, 1)
5.9
5.10 // Duplicates the top item on the stack.
5.11 OPDEF(OP_DUP, 83, "dup", 1, 1, 2)
5.12 @@ -266,3 +266,10 @@
5.13 OPDEF(OP_GETFIELD, 104, "getfield", 5, 1, 1)
5.14 OPDEF(OP_SETFIELD, 105, "setfield", 5, 2, 1)
5.15
5.16 +// Performs a struct-to-struct assignment.
5.17 +// Left = pop()
5.18 +// Right = pop()
5.19 +// copy(Left, Right)
5.20 +// push(Left)
5.21 +OPDEF(OP_COPYSTRUCT, 106, "structcopy", 1, 2, 1)
5.22 +
6.1 --- a/src/Structures.h Sat Aug 04 21:47:30 2012 -0700
6.2 +++ b/src/Structures.h Sat Aug 04 23:26:49 2012 -0700
6.3 @@ -150,6 +150,26 @@
6.4 return StructMap::cast(Object::map());
6.5 }
6.6
6.7 + // This must NOT be used with any Object * type!
6.8 + template <typename T> T get(Descriptor *desc) {
6.9 + return *reinterpret_cast<T *>(
6.10 + reinterpret_cast<Address>(this) +
6.11 + offsetOfSlotOffset(desc->offset()));
6.12 + }
6.13 +
6.14 + template <typename T> void set(Descriptor *desc, const T &t) {
6.15 + *reinterpret_cast<T *>(
6.16 + reinterpret_cast<Address>(this) +
6.17 + offsetOfSlotOffset(desc->offset())) = t;
6.18 + }
6.19 +
6.20 + void set(Zone *zone, Descriptor *desc, Object *obj) {
6.21 + // :TODO: write barrier
6.22 + *reinterpret_cast<Object **>(
6.23 + reinterpret_cast<Address>(this) +
6.24 + offsetOfSlotOffset(desc->offset())) = obj;
6.25 + }
6.26 +
6.27 static inline size_t offsetOfSlotOffset(unsigned offset) {
6.28 return sizeof(Struct) + offset;
6.29 }
7.1 --- a/src/Types.h Sat Aug 04 21:47:30 2012 -0700
7.2 +++ b/src/Types.h Sat Aug 04 23:26:49 2012 -0700
7.3 @@ -125,7 +125,9 @@
7.4 PrimitiveType pod() {
7.5 assert(isPrimitive() || isEnum());
7.6 return isPrimitive()
7.7 - ? primitive()
7.8 + ? (primitive() == PrimitiveType_Bool)
7.9 + ? PrimitiveType_Int32
7.10 + : primitive()
7.11 : PrimitiveType_Int32;
7.12 }
7.13 Type *contained() {