From 15326415d127e17016b60820b85c85016c3682e6 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sun, 25 Nov 2012 00:26:28 +0100 Subject: [PATCH] Fix some issues with the delete operator Properly implement delete operator for identifiers and local variables. Change-Id: I8ac55edc80c31a94d11444c9f5c78caf4b131c95 Reviewed-by: Simon Hausmann --- llvm_runtime.cpp | 9 ++------- moth/qv4vme_moth.cpp | 4 ++-- qmljs_environment.cpp | 20 ++++++++++++++++++++ qmljs_environment.h | 1 + qmljs_objects.h | 2 +- qmljs_runtime.cpp | 13 ++----------- qmljs_runtime.h | 3 +-- qv4isel_masm.cpp | 12 +++++++++--- 8 files changed, 38 insertions(+), 26 deletions(-) diff --git a/llvm_runtime.cpp b/llvm_runtime.cpp index e63ab62d7e..2ecbee6e59 100644 --- a/llvm_runtime.cpp +++ b/llvm_runtime.cpp @@ -500,14 +500,9 @@ void __qmljs_llvm_delete_member(ExecutionContext *ctx, Value *result, Value *bas *result = __qmljs_delete_member(ctx, *base, name); } -void __qmljs_llvm_delete_property(ExecutionContext *ctx, Value *result, String *name) +void __qmljs_llvm_delete_name(ExecutionContext *ctx, Value *result, String *name) { - *result = __qmljs_delete_property(ctx, name); -} - -void __qmljs_llvm_delete_value(ExecutionContext *ctx, Value *result, Value *value) -{ - *result = __qmljs_delete_value(ctx, *value); + *result = __qmljs_delete_name(ctx, name); } } // extern "C" diff --git a/moth/qv4vme_moth.cpp b/moth/qv4vme_moth.cpp index d8871f40c5..46bd64299c 100644 --- a/moth/qv4vme_moth.cpp +++ b/moth/qv4vme_moth.cpp @@ -262,11 +262,11 @@ VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *co MOTH_END_INSTR(CallBuiltinDeleteSubscript) MOTH_BEGIN_INSTR(CallBuiltinDeleteName) - TEMP(instr.targetTempIndex) = __qmljs_delete_property(context, instr.name); + TEMP(instr.targetTempIndex) = __qmljs_delete_name(context, instr.name); MOTH_END_INSTR(CallBuiltinDeleteName) MOTH_BEGIN_INSTR(CallBuiltinDeleteValue) - TEMP(instr.targetTempIndex) = __qmljs_delete_value(context, TEMP(instr.tempIndex)); + TEMP(instr.targetTempIndex) = VM::Value::fromBoolean(false); MOTH_END_INSTR(CallBuiltinDeleteValue) MOTH_BEGIN_INSTR(CreateValue) diff --git a/qmljs_environment.cpp b/qmljs_environment.cpp index 5504763b31..8093c120f2 100644 --- a/qmljs_environment.cpp +++ b/qmljs_environment.cpp @@ -221,6 +221,26 @@ PropertyDescriptor *ExecutionContext::lookupPropertyDescriptor(String *name, Pro return 0; } +bool ExecutionContext::deleteProperty(String *name) +{ + for (DeclarativeEnvironment *ctx = lexicalEnvironment; ctx; ctx = ctx->outer) { + if (ctx->withObject) { + DeclarativeEnvironment::With *w = ctx->withObject; + while (w) { + if (w->object->__hasProperty__(this, name)) + w->object->__delete__(this, name); + w = w->next; + } + } + if (ctx->activation) { + if (ctx->activation->__hasProperty__(this, name)) + ctx->activation->__delete__(this, name); + } + } + // ### throw syntax error in strict mode + return true; +} + void ExecutionContext::inplaceBitOp(Value value, String *name, BinOp op) { for (DeclarativeEnvironment *ctx = lexicalEnvironment; ctx; ctx = ctx->outer) { diff --git a/qmljs_environment.h b/qmljs_environment.h index 7a3a012b01..47376649d0 100644 --- a/qmljs_environment.h +++ b/qmljs_environment.h @@ -118,6 +118,7 @@ struct ExecutionContext PropertyDescriptor *lookupPropertyDescriptor(String *name, PropertyDescriptor *tmp); void inplaceBitOp(Value value, String *name, BinOp op); + bool deleteProperty(String *name); inline uint argumentCount() const { return variableEnvironment->argumentCount; } inline Value argument(unsigned int index = 0) diff --git a/qmljs_objects.h b/qmljs_objects.h index 31d493a790..b54e6062d1 100644 --- a/qmljs_objects.h +++ b/qmljs_objects.h @@ -411,7 +411,7 @@ struct Object { virtual void __put__(ExecutionContext *ctx, String *name, const Value &value, bool throwException = false); virtual bool __canPut__(ExecutionContext *ctx, String *name); virtual bool __hasProperty__(ExecutionContext *ctx, String *name) const; - virtual bool __delete__(ExecutionContext *ctx, String *name, bool throwException); + virtual bool __delete__(ExecutionContext *ctx, String *name, bool throwException = false); virtual bool __defineOwnProperty__(ExecutionContext *ctx, String *name, PropertyDescriptor *desc, bool throwException = false); // diff --git a/qmljs_runtime.cpp b/qmljs_runtime.cpp index eabceeff7f..86d1bbea09 100644 --- a/qmljs_runtime.cpp +++ b/qmljs_runtime.cpp @@ -195,18 +195,9 @@ Value __qmljs_delete_member(ExecutionContext *ctx, Value base, String *name) return Value::fromBoolean(obj.objectValue()->__delete__(ctx, name, true)); } -Value __qmljs_delete_property(ExecutionContext *ctx, String *name) +Value __qmljs_delete_name(ExecutionContext *ctx, String *name) { - Object *obj = ctx->lexicalEnvironment->activation; - if (!obj) - obj = ctx->engine->globalObject.objectValue(); - return Value::fromBoolean(obj->__delete__(ctx, name, true)); -} - -Value __qmljs_delete_value(ExecutionContext *ctx, Value value) -{ - Q_UNUSED(value); - return __qmljs_throw_type_error(ctx); // ### throw syntax error + return Value::fromBoolean(ctx->deleteProperty(name)); } Value __qmljs_add_helper(Value left, Value right, ExecutionContext *ctx) diff --git a/qmljs_runtime.h b/qmljs_runtime.h index ff8395af13..1831f68d60 100644 --- a/qmljs_runtime.h +++ b/qmljs_runtime.h @@ -177,8 +177,7 @@ Value __qmljs_not(Value value, ExecutionContext *ctx); Value __qmljs_delete_subscript(ExecutionContext *ctx, Value base, Value index); Value __qmljs_delete_member(ExecutionContext *ctx, Value base, String *name); -Value __qmljs_delete_property(ExecutionContext *ctx, String *name); -Value __qmljs_delete_value(ExecutionContext *ctx, Value value); +Value __qmljs_delete_name(ExecutionContext *ctx, String *name); Value __qmljs_typeof(Value value, ExecutionContext *ctx); void __qmljs_throw(Value value, ExecutionContext *context); diff --git a/qv4isel_masm.cpp b/qv4isel_masm.cpp index 270209a37f..f39c3b75b1 100644 --- a/qv4isel_masm.cpp +++ b/qv4isel_masm.cpp @@ -230,9 +230,15 @@ void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *resu } else if (IR::Subscript *ss = call->args->expr->asSubscript()) { generateFunctionCall(result, __qmljs_delete_subscript, ContextRegister, ss->base->asTemp(), ss->index->asTemp()); return; - } else { - assert(!"builtin_delete: unimplemented"); - Q_UNIMPLEMENTED(); + } else if (IR::Name *n = call->args->expr->asName()) { + generateFunctionCall(result, __qmljs_delete_name, ContextRegister, n); + return; + } else if (call->args->expr->asTemp()){ + // ### should throw in strict mode + Address dest = loadTempAddress(ScratchRegister, result); + Value v = Value::fromBoolean(false); + storeValue(v, dest); + return; } break; }