Generate LLVM code for constructor calls

This commit is contained in:
Roberto Raggi 2012-06-07 15:28:45 +02:00
parent 5c869a3c81
commit 56de925f00
6 changed files with 94 additions and 24 deletions

View File

@ -175,9 +175,9 @@ void __qmljs_llvm_not(Context *ctx, Value *result, const Value *value)
__qmljs_not(ctx, result, value);
}
String *__qmljs_llvm_get_identifier(Context *ctx, const char *str)
String *__qmljs_llvm_identifier_from_utf8(Context *ctx, const char *str)
{
return __qmljs_string_from_utf8(ctx, str); // ### make it unique
return __qmljs_identifier_from_utf8(ctx, str); // ### make it unique
}
void __qmljs_llvm_call_activation_property(Context *context, Value *result, String *name, Value *args, int argc)
@ -195,6 +195,11 @@ void __qmljs_llvm_construct_activation_property(Context *context, Value *result,
__qmljs_construct_activation_property(context, result, name, args, argc);
}
void __qmljs_llvm_construct_value(Context *context, Value *result, const Value *func, Value *args, int argc)
{
__qmljs_construct_value(context, result, func, args, argc);
}
void __qmljs_llvm_get_activation_property(Context *ctx, Value *result, String *name)
{
__qmljs_get_activation_property(ctx, result, name);
@ -275,4 +280,10 @@ void __qmljs_llvm_delete_value(Context *ctx, Value *result, Value *value)
__qmljs_delete_value(ctx, result, value);
}
void __qmljs_llvm_init_this_object(Context *ctx)
{
if (ctx->calledAsConstructor)
__qmljs_new_object(ctx, &ctx->thisObject);
}
} // extern "C"

View File

@ -494,6 +494,11 @@ String *__qmljs_string_from_utf8(Context *ctx, const char *s)
return ctx->engine->newString(QString::fromUtf8(s));
}
String *__qmljs_identifier_from_utf8(Context *ctx, const char *s)
{
return ctx->engine->identifier(QString::fromUtf8(s));
}
int __qmljs_string_length(Context *, String *string)
{
return string->toQString().length();
@ -581,6 +586,11 @@ void __qmljs_throw_type_error(Context *ctx, Value *result)
*result = ctx->result;
}
void __qmljs_new_object(Context *ctx, Value *result)
{
__qmljs_init_object(result, ctx->engine->newObject());
}
void __qmljs_new_boolean_object(Context *ctx, Value *result, bool boolean)
{
Value value;

View File

@ -99,10 +99,12 @@ void __qmljs_string_from_number(Context *ctx, Value *result, double number);
bool __qmljs_string_compare(Context *ctx, String *left, String *right);
bool __qmljs_string_equal(Context *ctx, String *left, String *right);
String *__qmljs_string_concat(Context *ctx, String *first, String *second);
String *__qmljs_identifier_from_utf8(Context *ctx, const char *s);
// objects
void __qmljs_object_default_value(Context *ctx, Value *result, const Value *object, int typeHint);
void __qmljs_throw_type_error(Context *ctx, Value *result);
void __qmljs_new_object(Context *ctx, Value *result);
void __qmljs_new_boolean_object(Context *ctx, Value *result, bool boolean);
void __qmljs_new_number_object(Context *ctx, Value *result, double n);
void __qmljs_new_string_object(Context *ctx, Value *result, String *string);

View File

@ -106,6 +106,10 @@ llvm::Function *LLVMInstructionSelection::compileLLVMFunction(IR::Function *func
qSwap(_tempMap, tempMap);
qSwap(_blockMap, blockMap);
// create the LLVM blocks
foreach (IR::BasicBlock *block, _function->basicBlocks)
(void) getLLVMBasicBlock(block);
// entry block
SetInsertPoint(getLLVMBasicBlock(_function->basicBlocks.first()));
@ -122,6 +126,9 @@ llvm::Function *LLVMInstructionSelection::compileLLVMFunction(IR::Function *func
CreateStore(llvm::Constant::getNullValue(_valueTy), t);
}
CreateCall(_llvmModule->getFunction("__qmljs_llvm_init_this_object"),
_llvmFunction->arg_begin());
foreach (IR::BasicBlock *block, _function->basicBlocks) {
qSwap(_block, block);
SetInsertPoint(getLLVMBasicBlock(_block));
@ -222,7 +229,7 @@ llvm::Value *LLVMInstructionSelection::getStringPtr(const QString &s)
llvm::Value *LLVMInstructionSelection::getIdentifier(const QString &s)
{
llvm::Value *str = getStringPtr(s);
llvm::Value *id = CreateCall2(_llvmModule->getFunction("__qmljs_llvm_get_identifier"),
llvm::Value *id = CreateCall2(_llvmModule->getFunction("__qmljs_identifier_from_utf8"),
_llvmFunction->arg_begin(), str);
return id;
}
@ -576,6 +583,29 @@ void LLVMInstructionSelection::genCallTemp(IR::Call *e, llvm::Value *result)
_llvmValue = CreateLoad(result);
}
void LLVMInstructionSelection::genConstructTemp(IR::New *e, llvm::Value *result)
{
if (! result)
result = newLLVMTemp(_valueTy);
llvm::Value *func = getLLVMTempReference(e->base);
int argc = 0;
llvm::Value *args = genArguments(e->args, argc);
llvm::Value *actuals[] = {
_llvmFunction->arg_begin(),
result,
func,
args,
getInt32(argc)
};
CreateCall(_llvmModule->getFunction("__qmljs_llvm_construct_value"), actuals);
_llvmValue = CreateLoad(result);
}
void LLVMInstructionSelection::genCallName(IR::Call *e, llvm::Value *result)
{
IR::Name *base = e->base->asName();
@ -656,6 +686,28 @@ void LLVMInstructionSelection::genCallName(IR::Call *e, llvm::Value *result)
}
}
void LLVMInstructionSelection::genConstructName(IR::New *e, llvm::Value *result)
{
IR::Name *base = e->base->asName();
if (! result)
result = newLLVMTemp(_valueTy);
if (! base->id) {
Q_UNREACHABLE();
} else {
llvm::Value *name = getIdentifier(*base->id);
int argc = 0;
llvm::Value *args = genArguments(e->args, argc);
CreateCall5(_llvmModule->getFunction("__qmljs_construct_activation_property"),
_llvmFunction->arg_begin(), result, name, args, getInt32(argc));
_llvmValue = CreateLoad(result);
}
}
void LLVMInstructionSelection::visitCall(IR::Call *e)
{
if (e->base->asMember()) {
@ -684,30 +736,20 @@ void LLVMInstructionSelection::visitNew(IR::New *e)
{
if (e->base->asMember()) {
genConstructMember(e);
return;
}
} else if (e->base->asTemp()) {
genConstructTemp(e);
} else if (e->base->asName()) {
genConstructName(e);
} else if (IR::Temp *t = e->base->asTemp()) {
llvm::Value *base = getLLVMTemp(t);
llvm::Value *func = 0;
llvm::Value *base = 0;
if (IR::Temp *t = e->base->asTemp()) {
base = getLLVMTemp(t);
func = _llvmModule->getFunction("__qmljs_llvm_construct_value");
} else if (IR::Name *n = e->base->asName()) {
if (n->id) {
llvm::Value *str = getStringPtr(*n->id);
base = CreateCall2(_llvmModule->getFunction("__qmljs_llvm_get_identifier"),
_llvmFunction->arg_begin(), str);
func = _llvmModule->getFunction("__qmljs_llvm_construct_activation_property");
}
}
int argc = 0;
llvm::Value *args = genArguments(e->args, argc);
int argc = 0;
llvm::Value *args = genArguments(e->args, argc);
if (func) {
llvm::Value *result = newLLVMTemp(_valueTy);
CreateStore(llvm::Constant::getNullValue(_valueTy), result);
CreateCall5(func, _llvmFunction->arg_begin(), result, base, args, getInt32(argc));
CreateCall5(_llvmModule->getFunction("__qmljs_llvm_construct_value"),
_llvmFunction->arg_begin(), result, base, args, getInt32(argc));
_llvmValue = CreateLoad(result);
} else {
Q_UNIMPLEMENTED();

View File

@ -30,9 +30,11 @@ public:
void genBinop(llvm::Value *result, IR::Binop *e);
llvm::AllocaInst *newLLVMTemp(llvm::Type *type, llvm::Value *size = 0);
llvm::Value * genArguments(IR::ExprList *args, int &argc);
void genCallMember(IR::Call *e, llvm::Value *result = 0);
void genCallTemp(IR::Call *e, llvm::Value *result = 0);
void genCallName(IR::Call *e, llvm::Value *result = 0);
void genCallMember(IR::Call *e, llvm::Value *result = 0);
void genConstructTemp(IR::New *e, llvm::Value *result = 0);
void genConstructName(IR::New *e, llvm::Value *result = 0);
void genConstructMember(IR::New *e, llvm::Value *result = 0);
void genMoveSubscript(IR::Move *s);
void genMoveMember(IR::Move *s);

View File

@ -219,6 +219,9 @@ void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *resu
amd64_mov_reg_imm(_codePtr, AMD64_RCX, argc);
amd64_call_code(_codePtr, __qmljs_builtin_typeof);
break;
case IR::Name::builtin_delete:
Q_UNREACHABLE();
break;
case IR::Name::builtin_throw:
amd64_lea_membase(_codePtr, AMD64_RDX, AMD64_RSP, 0);
amd64_mov_reg_imm(_codePtr, AMD64_RCX, argc);