From d8e0c2e0e5c8f80d8a6d929fdb9153136bf03b7d Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sun, 27 Jan 2013 21:16:09 +0100 Subject: [PATCH] Properly working post increment/decrement operators This required some larger changes in our infrastructure. Unfortunately the post increment/decrement operators don't return the old value unmodified, but return toNumber(oldValue). At the same time they need to properly store the new value into the referenced expression. The only way to solve this (as we can't have two return values) is to pass a proper reference into runtime methods. Change-Id: I0e0c2cc011ab22d5d4b27924abc8c18372c104a5 Reviewed-by: Simon Hausmann --- moth/qv4instr_moth_p.h | 60 +++++++++++++++++++ moth/qv4isel_moth.cpp | 68 +++++++++++++++++++++ moth/qv4isel_moth_p.h | 8 +++ moth/qv4vme_moth.cpp | 33 +++++++++++ qmljs_runtime.cpp | 156 +++++++++++++++++++++++++++++++++++++++++++++++++ qmljs_runtime.h | 10 ++++ qv4codegen.cpp | 28 ++++----- qv4ir.cpp | 4 ++ qv4ir_p.h | 2 + qv4isel_masm.cpp | 40 +++++++++++++ qv4isel_masm_p.h | 30 ++++++++++ qv4isel_p.cpp | 34 +++++++++++ qv4isel_p.h | 8 +++ tests/TestExpectations | 10 ---- 14 files changed, 465 insertions(+), 26 deletions(-) diff --git a/moth/qv4instr_moth_p.h b/moth/qv4instr_moth_p.h index eb48a0b..5f7d649 100644 --- a/moth/qv4instr_moth_p.h +++ b/moth/qv4instr_moth_p.h @@ -30,6 +30,14 @@ F(CallBuiltinTypeofSubscript, callBuiltinTypeofSubscript) \ F(CallBuiltinTypeofName, callBuiltinTypeofName) \ F(CallBuiltinTypeofValue, callBuiltinTypeofValue) \ + F(CallBuiltinPostIncMember, callBuiltinPostIncMember) \ + F(CallBuiltinPostIncSubscript, callBuiltinPostIncSubscript) \ + F(CallBuiltinPostIncName, callBuiltinPostIncName) \ + F(CallBuiltinPostIncValue, callBuiltinPostIncValue) \ + F(CallBuiltinPostDecMember, callBuiltinPostDecMember) \ + F(CallBuiltinPostDecSubscript, callBuiltinPostDecSubscript) \ + F(CallBuiltinPostDecName, callBuiltinPostDecName) \ + F(CallBuiltinPostDecValue, callBuiltinPostDecValue) \ F(CallBuiltinDeclareVar, callBuiltinDeclareVar) \ F(CallBuiltinDefineGetterSetter, callBuiltinDefineGetterSetter) \ F(CallBuiltinDefineProperty, callBuiltinDefineProperty) \ @@ -232,6 +240,50 @@ union Instr int tempIndex; int targetTempIndex; }; + struct instr_callBuiltinPostIncMember { + MOTH_INSTR_HEADER + int base; + VM::String *member; + int targetTempIndex; + }; + struct instr_callBuiltinPostIncSubscript { + MOTH_INSTR_HEADER + int base; + int index; + int targetTempIndex; + }; + struct instr_callBuiltinPostIncName { + MOTH_INSTR_HEADER + VM::String *name; + int targetTempIndex; + }; + struct instr_callBuiltinPostIncValue { + MOTH_INSTR_HEADER + int tempIndex; + int targetTempIndex; + }; + struct instr_callBuiltinPostDecMember { + MOTH_INSTR_HEADER + int base; + VM::String *member; + int targetTempIndex; + }; + struct instr_callBuiltinPostDecSubscript { + MOTH_INSTR_HEADER + int base; + int index; + int targetTempIndex; + }; + struct instr_callBuiltinPostDecName { + MOTH_INSTR_HEADER + VM::String *name; + int targetTempIndex; + }; + struct instr_callBuiltinPostDecValue { + MOTH_INSTR_HEADER + int tempIndex; + int targetTempIndex; + }; struct instr_callBuiltinDeclareVar { MOTH_INSTR_HEADER bool isDeletable; @@ -356,6 +408,14 @@ union Instr instr_callBuiltinTypeofSubscript callBuiltinTypeofSubscript; instr_callBuiltinTypeofName callBuiltinTypeofName; instr_callBuiltinTypeofValue callBuiltinTypeofValue; + instr_callBuiltinPostIncMember callBuiltinPostIncMember; + instr_callBuiltinPostIncSubscript callBuiltinPostIncSubscript; + instr_callBuiltinPostIncName callBuiltinPostIncName; + instr_callBuiltinPostIncValue callBuiltinPostIncValue; + instr_callBuiltinPostDecMember callBuiltinPostDecMember; + instr_callBuiltinPostDecSubscript callBuiltinPostDecSubscript; + instr_callBuiltinPostDecName callBuiltinPostDecName; + instr_callBuiltinPostDecValue callBuiltinPostDecValue; instr_callBuiltinDeclareVar callBuiltinDeclareVar; instr_callBuiltinDefineGetterSetter callBuiltinDefineGetterSetter; instr_callBuiltinDefineProperty callBuiltinDefineProperty; diff --git a/moth/qv4isel_moth.cpp b/moth/qv4isel_moth.cpp index b2e6781..46cff05 100644 --- a/moth/qv4isel_moth.cpp +++ b/moth/qv4isel_moth.cpp @@ -769,6 +769,74 @@ void InstructionSelection::callBuiltinDeleteValue(IR::Temp *result) addInstruction(load); } +void InstructionSelection::callBuiltinPostDecrementMember(IR::Temp *base, const QString &name, IR::Temp *result) +{ + Instruction::CallBuiltinPostDecMember call; + call.base = base->index; + call.member = engine()->identifier(name); + call.targetTempIndex = result ? result->index : scratchTempIndex(); + addInstruction(call); +} + +void InstructionSelection::callBuiltinPostDecrementSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result) +{ + Instruction::CallBuiltinPostDecSubscript call; + call.base = base->index; + call.index = index->index; + call.targetTempIndex = result ? result->index : scratchTempIndex(); + addInstruction(call); +} + +void InstructionSelection::callBuiltinPostDecrementName(const QString &name, IR::Temp *result) +{ + Instruction::CallBuiltinPostDecName call; + call.name = engine()->identifier(name); + call.targetTempIndex = result ? result->index : scratchTempIndex(); + addInstruction(call); +} + +void InstructionSelection::callBuiltinPostDecrementValue(IR::Temp *value, IR::Temp *result) +{ + Instruction::CallBuiltinPostDecValue call; + call.tempIndex = value->index; + call.targetTempIndex = result ? result->index : scratchTempIndex(); + addInstruction(call); +} + +void InstructionSelection::callBuiltinPostIncrementMember(IR::Temp *base, const QString &name, IR::Temp *result) +{ + Instruction::CallBuiltinPostIncMember call; + call.base = base->index; + call.member = engine()->identifier(name); + call.targetTempIndex = result ? result->index : scratchTempIndex(); + addInstruction(call); +} + +void InstructionSelection::callBuiltinPostIncrementSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result) +{ + Instruction::CallBuiltinPostIncSubscript call; + call.base = base->index; + call.index = index->index; + call.targetTempIndex = result ? result->index : scratchTempIndex(); + addInstruction(call); +} + +void InstructionSelection::callBuiltinPostIncrementName(const QString &name, IR::Temp *result) +{ + Instruction::CallBuiltinPostIncName call; + call.name = engine()->identifier(name); + call.targetTempIndex = result ? result->index : scratchTempIndex(); + addInstruction(call); +} + +void InstructionSelection::callBuiltinPostIncrementValue(IR::Temp *value, IR::Temp *result) +{ + Instruction::CallBuiltinPostIncValue call; + call.tempIndex = value->index; + call.targetTempIndex = result ? result->index : scratchTempIndex(); + addInstruction(call); +} + void InstructionSelection::callBuiltinThrow(IR::Temp *arg) { Instruction::CallBuiltin call; diff --git a/moth/qv4isel_moth_p.h b/moth/qv4isel_moth_p.h index 1f67fef..c9b32d6 100644 --- a/moth/qv4isel_moth_p.h +++ b/moth/qv4isel_moth_p.h @@ -33,6 +33,14 @@ protected: virtual void callBuiltinDeleteSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result); virtual void callBuiltinDeleteName(const QString &name, IR::Temp *result); virtual void callBuiltinDeleteValue(IR::Temp *result); + virtual void callBuiltinPostDecrementMember(IR::Temp *base, const QString &name, IR::Temp *result); + virtual void callBuiltinPostDecrementSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result); + virtual void callBuiltinPostDecrementName(const QString &name, IR::Temp *result); + virtual void callBuiltinPostDecrementValue(IR::Temp *value, IR::Temp *result); + virtual void callBuiltinPostIncrementMember(IR::Temp *base, const QString &name, IR::Temp *result); + virtual void callBuiltinPostIncrementSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result); + virtual void callBuiltinPostIncrementName(const QString &name, IR::Temp *result); + virtual void callBuiltinPostIncrementValue(IR::Temp *value, IR::Temp *result); virtual void callBuiltinThrow(IR::Temp *arg); virtual void callBuiltinCreateExceptionHandler(IR::Temp *result); virtual void callBuiltinDeleteExceptionHandler(); diff --git a/moth/qv4vme_moth.cpp b/moth/qv4vme_moth.cpp index 6358e21..5786a54 100644 --- a/moth/qv4vme_moth.cpp +++ b/moth/qv4vme_moth.cpp @@ -116,6 +116,7 @@ private: }; #define TEMP(index) *tempValue(context, stack, index) +#define TEMPPTR(index) tempValue(context, stack, index) VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *code #ifdef MOTH_THREADED_INTERPRETER @@ -336,6 +337,38 @@ VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *co TEMP(instr.targetTempIndex) = __qmljs_builtin_typeof(TEMP(instr.tempIndex), context); MOTH_END_INSTR(CallBuiltinTypeofValue) + MOTH_BEGIN_INSTR(CallBuiltinPostIncMember) + TEMP(instr.targetTempIndex) = __qmljs_builtin_post_increment_member(TEMP(instr.base), instr.member, context); + MOTH_END_INSTR(CallBuiltinTypeofMember) + + MOTH_BEGIN_INSTR(CallBuiltinPostIncSubscript) + TEMP(instr.targetTempIndex) = __qmljs_builtin_post_increment_element(TEMP(instr.base), TEMP(instr.index), context); + MOTH_END_INSTR(CallBuiltinTypeofSubscript) + + MOTH_BEGIN_INSTR(CallBuiltinPostIncName) + TEMP(instr.targetTempIndex) = __qmljs_builtin_post_increment_name(instr.name, context); + MOTH_END_INSTR(CallBuiltinTypeofName) + + MOTH_BEGIN_INSTR(CallBuiltinPostIncValue) + TEMP(instr.targetTempIndex) = __qmljs_builtin_post_increment(TEMPPTR(instr.tempIndex), context); + MOTH_END_INSTR(CallBuiltinTypeofValue) + + MOTH_BEGIN_INSTR(CallBuiltinPostDecMember) + TEMP(instr.targetTempIndex) = __qmljs_builtin_post_decrement_member(TEMP(instr.base), instr.member, context); + MOTH_END_INSTR(CallBuiltinTypeofMember) + + MOTH_BEGIN_INSTR(CallBuiltinPostDecSubscript) + TEMP(instr.targetTempIndex) = __qmljs_builtin_post_decrement_element(TEMP(instr.base), TEMP(instr.index), context); + MOTH_END_INSTR(CallBuiltinTypeofSubscript) + + MOTH_BEGIN_INSTR(CallBuiltinPostDecName) + TEMP(instr.targetTempIndex) = __qmljs_builtin_post_decrement_name(instr.name, context); + MOTH_END_INSTR(CallBuiltinTypeofName) + + MOTH_BEGIN_INSTR(CallBuiltinPostDecValue) + TEMP(instr.targetTempIndex) = __qmljs_builtin_post_decrement(TEMPPTR(instr.tempIndex), context); + MOTH_END_INSTR(CallBuiltinTypeofValue) + MOTH_BEGIN_INSTR(CallBuiltinDeclareVar) __qmljs_builtin_declare_var(context, instr.isDeletable, instr.varName); MOTH_END_INSTR(CallBuiltinDeclareVar) diff --git a/qmljs_runtime.cpp b/qmljs_runtime.cpp index fca7e2e..4fdf2d3 100644 --- a/qmljs_runtime.cpp +++ b/qmljs_runtime.cpp @@ -906,6 +906,162 @@ Value __qmljs_builtin_typeof_element(Value base, Value index, ExecutionContext * return __qmljs_builtin_typeof(obj.objectValue()->__get__(context, name), context); } +Value __qmljs_builtin_post_increment(Value *val, ExecutionContext *ctx) +{ + if (val->isInteger() && val->integerValue() < INT_MAX) { + Value retval = *val; + val->int_32 += 1; + return retval; + } + + double d = __qmljs_to_number(*val, ctx); + *val = Value::fromDouble(d + 1); + return Value::fromDouble(d); +} + +Value __qmljs_builtin_post_increment_name(String *name, ExecutionContext *context) +{ + Value v = context->getProperty(name); + Value retval; + + if (v.isInteger() && v.integerValue() < INT_MAX) { + retval = v; + v.int_32 += 1; + } else { + double d = __qmljs_to_number(v, context); + retval = Value::fromDouble(d); + v = Value::fromDouble(d + 1); + } + + context->setProperty(name, v); + return retval; +} + +Value __qmljs_builtin_post_increment_member(Value base, String *name, ExecutionContext *context) +{ + Object *o = __qmljs_to_object(base, context).objectValue(); + + Value v = o->__get__(context, name); + Value retval; + + if (v.isInteger() && v.integerValue() < INT_MAX) { + retval = v; + v.int_32 += 1; + } else { + double d = __qmljs_to_number(v, context); + retval = Value::fromDouble(d); + v = Value::fromDouble(d + 1); + } + + o->__put__(context, name, v); + return retval; +} + +Value __qmljs_builtin_post_increment_element(Value base, Value index, ExecutionContext *context) +{ + Object *o = __qmljs_to_object(base, context).objectValue(); + + uint idx = index.asArrayIndex(); + + if (idx == UINT_MAX) { + String *s = index.toString(context); + return __qmljs_builtin_post_increment_member(base, s, context); + } + + Value v = o->__get__(context, idx); + Value retval; + + if (v.isInteger() && v.integerValue() < INT_MAX) { + retval = v; + v.int_32 += 1; + } else { + double d = __qmljs_to_number(v, context); + retval = Value::fromDouble(d); + v = Value::fromDouble(d + 1); + } + + o->__put__(context, idx, v); + return retval; +} + +Value __qmljs_builtin_post_decrement(Value *val, ExecutionContext *ctx) +{ + if (val->isInteger() && val->integerValue() > INT_MIN) { + Value retval = *val; + val->int_32 -= 1; + return retval; + } + + double d = __qmljs_to_number(*val, ctx); + *val = Value::fromDouble(d - 1); + return Value::fromDouble(d); +} + +Value __qmljs_builtin_post_decrement_name(String *name, ExecutionContext *context) +{ + Value v = context->getProperty(name); + Value retval; + + if (v.isInteger() && v.integerValue() > INT_MIN) { + retval = v; + v.int_32 -= 1; + } else { + double d = __qmljs_to_number(v, context); + retval = Value::fromDouble(d); + v = Value::fromDouble(d - 1); + } + + context->setProperty(name, v); + return retval; +} + +Value __qmljs_builtin_post_decrement_member(Value base, String *name, ExecutionContext *context) +{ + Object *o = __qmljs_to_object(base, context).objectValue(); + + Value v = o->__get__(context, name); + Value retval; + + if (v.isInteger() && v.integerValue() > INT_MIN) { + retval = v; + v.int_32 -= 1; + } else { + double d = __qmljs_to_number(v, context); + retval = Value::fromDouble(d); + v = Value::fromDouble(d - 1); + } + + o->__put__(context, name, v); + return retval; +} + +Value __qmljs_builtin_post_decrement_element(Value base, Value index, ExecutionContext *context) +{ + Object *o = __qmljs_to_object(base, context).objectValue(); + + uint idx = index.asArrayIndex(); + + if (idx == UINT_MAX) { + String *s = index.toString(context); + return __qmljs_builtin_post_decrement_member(base, s, context); + } + + Value v = o->__get__(context, idx); + Value retval; + + if (v.isInteger() && v.integerValue() > INT_MIN) { + retval = v; + v.int_32 -= 1; + } else { + double d = __qmljs_to_number(v, context); + retval = Value::fromDouble(d); + v = Value::fromDouble(d - 1); + } + + o->__put__(context, idx, v); + return retval; +} + void __qmljs_builtin_throw(Value val, ExecutionContext *context) { __qmljs_throw(val, context); diff --git a/qmljs_runtime.h b/qmljs_runtime.h index 11437cd..830dc9a 100644 --- a/qmljs_runtime.h +++ b/qmljs_runtime.h @@ -100,6 +100,16 @@ Value __qmljs_builtin_typeof_name(String *name, ExecutionContext *context); Value __qmljs_builtin_typeof_member(Value base, String *name, ExecutionContext *context); Value __qmljs_builtin_typeof_element(Value base, Value index, ExecutionContext *context); +Value __qmljs_builtin_post_increment(Value *val, ExecutionContext *ctx); +Value __qmljs_builtin_post_increment_name(String *name, ExecutionContext *context); +Value __qmljs_builtin_post_increment_member(Value base, String *name, ExecutionContext *context); +Value __qmljs_builtin_post_increment_element(Value base, Value index, ExecutionContext *context); + +Value __qmljs_builtin_post_decrement(Value *val, ExecutionContext *ctx); +Value __qmljs_builtin_post_decrement_name(String *name, ExecutionContext *context); +Value __qmljs_builtin_post_decrement_member(Value base, String *name, ExecutionContext *context); +Value __qmljs_builtin_post_decrement_element(Value base, Value index, ExecutionContext *context); + void __qmljs_builtin_throw(Value val, ExecutionContext *context); void __qmljs_builtin_rethrow(ExecutionContext *context); ExecutionContext *__qmljs_builtin_push_with_scope(Value o, ExecutionContext *ctx); diff --git a/qv4codegen.cpp b/qv4codegen.cpp index 9b1b7cd..4c4f7dd 100644 --- a/qv4codegen.cpp +++ b/qv4codegen.cpp @@ -1539,30 +1539,26 @@ bool Codegen::visit(ObjectLiteral *ast) bool Codegen::visit(PostDecrementExpression *ast) { Result expr = expression(ast->base); + if (!expr->isLValue()) + throwReferenceError(ast->base->lastSourceLocation(), "Invalid left-hand side expression in postfix operation"); throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->decrementToken); - if (_expr.accept(nx)) { - move(*expr, unop(IR::OpDecrement, *expr)); - } else { - const unsigned t = _block->newTemp(); - move(_block->TEMP(t), *expr); - move(*expr, unop(IR::OpDecrement, _block->TEMP(t))); - _expr.code = _block->TEMP(t); - } + + IR::ExprList *args = _function->New(); + args->init(*expr); + _expr.code = call(_block->NAME(IR::Name::builtin_postdecrement, ast->lastSourceLocation().startLine, ast->lastSourceLocation().startColumn), args); return false; } bool Codegen::visit(PostIncrementExpression *ast) { Result expr = expression(ast->base); + if (!expr->isLValue()) + throwReferenceError(ast->base->lastSourceLocation(), "Invalid left-hand side expression in postfix operation"); throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->incrementToken); - if (_expr.accept(nx)) { - move(*expr, unop(IR::OpIncrement, *expr)); - } else { - const unsigned t = _block->newTemp(); - move(_block->TEMP(t), *expr); - move(*expr, unop(IR::OpIncrement, _block->TEMP(t))); - _expr.code = _block->TEMP(t); - } + + IR::ExprList *args = _function->New(); + args->init(*expr); + _expr.code = call(_block->NAME(IR::Name::builtin_postincrement, ast->lastSourceLocation().startLine, ast->lastSourceLocation().startColumn), args); return false; } diff --git a/qv4ir.cpp b/qv4ir.cpp index a34a294..1c2a9d9 100644 --- a/qv4ir.cpp +++ b/qv4ir.cpp @@ -224,6 +224,10 @@ static const char *builtin_to_string(Name::Builtin b) return "builtin_typeof"; case Name::builtin_delete: return "builtin_delete"; + case Name::builtin_postincrement: + return "builtin_postincrement"; + case Name::builtin_postdecrement: + return "builtin_postdecrement"; case Name::builtin_throw: return "builtin_throw"; case Name::builtin_create_exception_handler: diff --git a/qv4ir_p.h b/qv4ir_p.h index f77cb58..64f59f4 100644 --- a/qv4ir_p.h +++ b/qv4ir_p.h @@ -275,6 +275,8 @@ struct Name: Expr { builtin_invalid, builtin_typeof, builtin_delete, + builtin_postincrement, + builtin_postdecrement, builtin_throw, builtin_create_exception_handler, builtin_delete_exception_handler, diff --git a/qv4isel_masm.cpp b/qv4isel_masm.cpp index 88c6417..e6bd218 100644 --- a/qv4isel_masm.cpp +++ b/qv4isel_masm.cpp @@ -478,6 +478,46 @@ void InstructionSelection::callBuiltinDeleteValue(IR::Temp *result) _asm->storeValue(Value::fromBoolean(false), result); } +void InstructionSelection::callBuiltinPostIncrementMember(IR::Temp *base, const QString &name, IR::Temp *result) +{ + generateFunctionCall(result, __qmljs_builtin_post_increment_member, base, identifier(name), Assembler::ContextRegister); +} + +void InstructionSelection::callBuiltinPostIncrementSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result) +{ + generateFunctionCall(result, __qmljs_builtin_post_increment_element, base, index, Assembler::ContextRegister); +} + +void InstructionSelection::callBuiltinPostIncrementName(const QString &name, IR::Temp *result) +{ + generateFunctionCall(result, __qmljs_builtin_post_increment_name, identifier(name), Assembler::ContextRegister); +} + +void InstructionSelection::callBuiltinPostIncrementValue(IR::Temp *value, IR::Temp *result) +{ + generateFunctionCall(result, __qmljs_builtin_post_increment, Assembler::PointerToValue(value), Assembler::ContextRegister); +} + +void InstructionSelection::callBuiltinPostDecrementMember(IR::Temp *base, const QString &name, IR::Temp *result) +{ + generateFunctionCall(result, __qmljs_builtin_post_decrement_member, base, identifier(name), Assembler::ContextRegister); +} + +void InstructionSelection::callBuiltinPostDecrementSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result) +{ + generateFunctionCall(result, __qmljs_builtin_post_decrement_element, base, index, Assembler::ContextRegister); +} + +void InstructionSelection::callBuiltinPostDecrementName(const QString &name, IR::Temp *result) +{ + generateFunctionCall(result, __qmljs_builtin_post_decrement_name, identifier(name), Assembler::ContextRegister); +} + +void InstructionSelection::callBuiltinPostDecrementValue(IR::Temp *value, IR::Temp *result) +{ + generateFunctionCall(result, __qmljs_builtin_post_decrement, Assembler::PointerToValue(value), Assembler::ContextRegister); +} + void InstructionSelection::callBuiltinThrow(IR::Temp *arg) { generateFunctionCall(Assembler::Void, __qmljs_builtin_throw, arg, Assembler::ContextRegister); diff --git a/qv4isel_masm_p.h b/qv4isel_masm_p.h index 64b6311..347db94 100644 --- a/qv4isel_masm_p.h +++ b/qv4isel_masm_p.h @@ -165,6 +165,10 @@ public: FunctionPtr externalFunction; const char* functionName; }; + struct PointerToValue { + PointerToValue(IR::Temp *value) : value(value) {} + IR::Temp *value; + }; void callAbsolute(const char* functionName, FunctionPtr function) { CallToLink ctl; @@ -196,6 +200,14 @@ public: } #ifdef VALUE_FITS_IN_REGISTER + void loadArgument(PointerToValue temp, RegisterID dest) + { + assert(temp.value); + + Pointer addr = loadTempAddress(dest, temp.value); + loadArgument(addr, dest); + } + void loadArgument(IR::Temp* temp, RegisterID dest) { if (!temp) { @@ -297,6 +309,14 @@ public: #endif } + void push(PointerToValue temp) + { + assert (temp.value); + + Pointer ptr = loadTempAddress(ScratchRegister, temp.value); + push(ptr); + } + void push(IR::Temp* temp) { if (temp) { @@ -401,6 +421,8 @@ public: { return sizeof(void*); } static inline int sizeOfArgument(VM::String* string) { return sizeof(string); } + static inline int sizeOfArgument(const PointerToValue &) + { return sizeof(void *); } static inline int sizeOfArgument(TrustedImmPtr) { return sizeof(void*); } static inline int sizeOfArgument(TrustedImm32) @@ -661,6 +683,14 @@ protected: virtual void callBuiltinDeleteSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result); virtual void callBuiltinDeleteName(const QString &name, IR::Temp *result); virtual void callBuiltinDeleteValue(IR::Temp *result); + virtual void callBuiltinPostDecrementMember(IR::Temp *base, const QString &name, IR::Temp *result); + virtual void callBuiltinPostDecrementSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result); + virtual void callBuiltinPostDecrementName(const QString &name, IR::Temp *result); + virtual void callBuiltinPostDecrementValue(IR::Temp *value, IR::Temp *result); + virtual void callBuiltinPostIncrementMember(IR::Temp *base, const QString &name, IR::Temp *result); + virtual void callBuiltinPostIncrementSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result); + virtual void callBuiltinPostIncrementName(const QString &name, IR::Temp *result); + virtual void callBuiltinPostIncrementValue(IR::Temp *value, IR::Temp *result); virtual void callBuiltinThrow(IR::Temp *arg); virtual void callBuiltinCreateExceptionHandler(IR::Temp *result); virtual void callBuiltinDeleteExceptionHandler(); diff --git a/qv4isel_p.cpp b/qv4isel_p.cpp index c7ed89e..8cc7feb 100644 --- a/qv4isel_p.cpp +++ b/qv4isel_p.cpp @@ -267,6 +267,40 @@ void InstructionSelection::callBuiltin(IR::Call *call, IR::Temp *result) } } break; + case IR::Name::builtin_postincrement: { + if (IR::Member *m = call->args->expr->asMember()) { + callBuiltinPostIncrementMember(m->base->asTemp(), *m->name, result); + return; + } else if (IR::Subscript *ss = call->args->expr->asSubscript()) { + callBuiltinPostIncrementSubscript(ss->base->asTemp(), ss->index->asTemp(), result); + return; + } else if (IR::Name *n = call->args->expr->asName()) { + callBuiltinPostIncrementName(*n->id, result); + return; + } else if (IR::Temp *arg = call->args->expr->asTemp()){ + assert(arg != 0); + callBuiltinPostIncrementValue(arg, result); + return; + } + } break; + + case IR::Name::builtin_postdecrement: { + if (IR::Member *m = call->args->expr->asMember()) { + callBuiltinPostDecrementMember(m->base->asTemp(), *m->name, result); + return; + } else if (IR::Subscript *ss = call->args->expr->asSubscript()) { + callBuiltinPostDecrementSubscript(ss->base->asTemp(), ss->index->asTemp(), result); + return; + } else if (IR::Name *n = call->args->expr->asName()) { + callBuiltinPostDecrementName(*n->id, result); + return; + } else if (IR::Temp *arg = call->args->expr->asTemp()){ + assert(arg != 0); + callBuiltinPostDecrementValue(arg, result); + return; + } + } break; + case IR::Name::builtin_throw: { IR::Temp *arg = call->args->expr->asTemp(); assert(arg != 0); diff --git a/qv4isel_p.h b/qv4isel_p.h index 8861484..0fb3e8d 100644 --- a/qv4isel_p.h +++ b/qv4isel_p.h @@ -89,6 +89,14 @@ public: // to implement by subclasses: virtual void callBuiltinDeleteSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result) = 0; virtual void callBuiltinDeleteName(const QString &name, IR::Temp *result) = 0; virtual void callBuiltinDeleteValue(IR::Temp *result) = 0; + virtual void callBuiltinPostDecrementMember(IR::Temp *base, const QString &name, IR::Temp *result) = 0; + virtual void callBuiltinPostDecrementSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result) = 0; + virtual void callBuiltinPostDecrementName(const QString &name, IR::Temp *result) = 0; + virtual void callBuiltinPostDecrementValue(IR::Temp *value, IR::Temp *result) = 0; + virtual void callBuiltinPostIncrementMember(IR::Temp *base, const QString &name, IR::Temp *result) = 0; + virtual void callBuiltinPostIncrementSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result) = 0; + virtual void callBuiltinPostIncrementName(const QString &name, IR::Temp *result) = 0; + virtual void callBuiltinPostIncrementValue(IR::Temp *value, IR::Temp *result) = 0; virtual void callBuiltinThrow(IR::Temp *arg) = 0; virtual void callBuiltinCreateExceptionHandler(IR::Temp *result) = 0; virtual void callBuiltinDeleteExceptionHandler() = 0; diff --git a/tests/TestExpectations b/tests/TestExpectations index 7469238..265d083 100644 --- a/tests/TestExpectations +++ b/tests/TestExpectations @@ -14,16 +14,6 @@ S15.1.3.2_A2.5_T1 10.4.3-1-63-s failing 10.4.3-1-82-s failing 11.2.3-3_3 failing -S11.3.1_A2.2_T1 failing -S11.3.1_A4_T1 failing -S11.3.1_A4_T2 failing -S11.3.1_A4_T3 failing -S11.3.1_A4_T4 failing -S11.3.2_A2.2_T1 failing -S11.3.2_A4_T1 failing -S11.3.2_A4_T2 failing -S11.3.2_A4_T3 failing -S11.3.2_A4_T4 failing S11.5.3_A4_T2 failing S11.8.6_A3 failing S11.8.6_A5_T2 failing -- 2.7.4