summaryrefslogtreecommitdiff
path: root/deps/v8/src/arm/fast-codegen-arm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/arm/fast-codegen-arm.cc')
-rw-r--r--deps/v8/src/arm/fast-codegen-arm.cc350
1 files changed, 192 insertions, 158 deletions
diff --git a/deps/v8/src/arm/fast-codegen-arm.cc b/deps/v8/src/arm/fast-codegen-arm.cc
index ab636b6b88..55d87b7c2d 100644
--- a/deps/v8/src/arm/fast-codegen-arm.cc
+++ b/deps/v8/src/arm/fast-codegen-arm.cc
@@ -414,78 +414,98 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
Variable* var = decl->proxy()->var();
ASSERT(var != NULL); // Must have been resolved.
Slot* slot = var->slot();
- ASSERT(slot != NULL); // No global declarations here.
-
- // We have 3 cases for slots: LOOKUP, LOCAL, CONTEXT.
- switch (slot->type()) {
- case Slot::LOOKUP: {
- __ mov(r2, Operand(var->name()));
- // Declaration nodes are always introduced in one of two modes.
- ASSERT(decl->mode() == Variable::VAR || decl->mode() == Variable::CONST);
- PropertyAttributes attr = decl->mode() == Variable::VAR ?
- NONE : READ_ONLY;
- __ mov(r1, Operand(Smi::FromInt(attr)));
- // Push initial value, if any.
- // Note: For variables we must not push an initial value (such as
- // 'undefined') because we may have a (legal) redeclaration and we
- // must not destroy the current value.
- if (decl->mode() == Variable::CONST) {
- __ mov(r0, Operand(Factory::the_hole_value()));
- __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit());
- } else if (decl->fun() != NULL) {
- __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit());
- Visit(decl->fun()); // Initial value for function decl.
- } else {
- __ mov(r0, Operand(Smi::FromInt(0))); // No initial value!
- __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit());
- }
- __ CallRuntime(Runtime::kDeclareContextSlot, 4);
- break;
- }
- case Slot::LOCAL:
- if (decl->mode() == Variable::CONST) {
- __ mov(r0, Operand(Factory::the_hole_value()));
- __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
- } else if (decl->fun() != NULL) {
- Visit(decl->fun());
- __ pop(r0);
- __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
- }
- break;
- case Slot::CONTEXT:
- // The variable in the decl always resides in the current context.
- ASSERT(function_->scope()->ContextChainLength(slot->var()->scope()) == 0);
- if (decl->mode() == Variable::CONST) {
- __ mov(r0, Operand(Factory::the_hole_value()));
+ Property* prop = var->AsProperty();
+
+ if (slot != NULL) {
+ switch (slot->type()) {
+ case Slot::PARAMETER: // Fall through.
+ case Slot::LOCAL:
+ if (decl->mode() == Variable::CONST) {
+ __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+ __ str(ip, MemOperand(fp, SlotOffset(var->slot())));
+ } else if (decl->fun() != NULL) {
+ Visit(decl->fun());
+ __ pop(ip);
+ __ str(ip, MemOperand(fp, SlotOffset(var->slot())));
+ }
+ break;
+
+ case Slot::CONTEXT:
+ // The variable in the decl always resides in the current context.
+ ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope()));
if (FLAG_debug_code) {
// Check if we have the correct context pointer.
- __ ldr(r1, CodeGenerator::ContextOperand(cp,
- Context::FCONTEXT_INDEX));
+ __ ldr(r1,
+ CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX));
__ cmp(r1, cp);
__ Check(eq, "Unexpected declaration in current context.");
}
- __ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
- // No write barrier since the_hole_value is in old space.
- ASSERT(!Heap::InNewSpace(*Factory::the_hole_value()));
- } else if (decl->fun() != NULL) {
+ if (decl->mode() == Variable::CONST) {
+ __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+ __ str(ip, CodeGenerator::ContextOperand(cp, slot->index()));
+ // No write barrier since the_hole_value is in old space.
+ } else if (decl->fun() != NULL) {
+ Visit(decl->fun());
+ __ pop(r0);
+ __ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
+ int offset = Context::SlotOffset(slot->index());
+ __ mov(r2, Operand(offset));
+ // We know that we have written a function, which is not a smi.
+ __ RecordWrite(cp, r2, r0);
+ }
+ break;
+
+ case Slot::LOOKUP: {
+ __ mov(r2, Operand(var->name()));
+ // Declaration nodes are always introduced in one of two modes.
+ ASSERT(decl->mode() == Variable::VAR ||
+ decl->mode() == Variable::CONST);
+ PropertyAttributes attr =
+ (decl->mode() == Variable::VAR) ? NONE : READ_ONLY;
+ __ mov(r1, Operand(Smi::FromInt(attr)));
+ // Push initial value, if any.
+ // Note: For variables we must not push an initial value (such as
+ // 'undefined') because we may have a (legal) redeclaration and we
+ // must not destroy the current value.
+ if (decl->mode() == Variable::CONST) {
+ __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
+ __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit());
+ } else if (decl->fun() != NULL) {
+ __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit());
+ Visit(decl->fun()); // Initial value for function decl.
+ } else {
+ __ mov(r0, Operand(Smi::FromInt(0))); // No initial value!
+ __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit());
+ }
+ __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ break;
+ }
+ }
+
+ } else if (prop != NULL) {
+ if (decl->fun() != NULL || decl->mode() == Variable::CONST) {
+ // We are declaring a function or constant that rewrites to a
+ // property. Use (keyed) IC to set the initial value.
+ ASSERT_EQ(Expression::kValue, prop->obj()->context());
+ Visit(prop->obj());
+ ASSERT_EQ(Expression::kValue, prop->key()->context());
+ Visit(prop->key());
+
+ if (decl->fun() != NULL) {
+ ASSERT_EQ(Expression::kValue, decl->fun()->context());
Visit(decl->fun());
__ pop(r0);
- if (FLAG_debug_code) {
- // Check if we have the correct context pointer.
- __ ldr(r1, CodeGenerator::ContextOperand(cp,
- Context::FCONTEXT_INDEX));
- __ cmp(r1, cp);
- __ Check(eq, "Unexpected declaration in current context.");
- }
- __ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
- int offset = Context::SlotOffset(slot->index());
- __ mov(r2, Operand(offset));
- // We know that we have written a function, which is not a smi.
- __ RecordWrite(cp, r2, r0);
+ } else {
+ __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
}
- break;
- default:
- UNREACHABLE();
+
+ Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+ __ Call(ic, RelocInfo::CODE_TARGET);
+
+ // Value in r0 is ignored (declarations are statements). Receiver
+ // and key on stack are discarded.
+ __ add(sp, sp, Operand(2 * kPointerSize));
+ }
}
}
@@ -501,21 +521,6 @@ void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
}
-void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
- Comment cmnt(masm_, "[ ReturnStatement");
- Expression* expr = stmt->expression();
- // Complete the statement based on the type of the subexpression.
- if (expr->AsLiteral() != NULL) {
- __ mov(r0, Operand(expr->AsLiteral()->handle()));
- } else {
- ASSERT_EQ(Expression::kValue, expr->context());
- Visit(expr);
- __ pop(r0);
- }
- EmitReturnSequence(stmt->statement_pos());
-}
-
-
void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
Comment cmnt(masm_, "[ FunctionLiteral");
@@ -536,18 +541,24 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Comment cmnt(masm_, "[ VariableProxy");
- Expression* rewrite = expr->var()->rewrite();
+ EmitVariableLoad(expr->var(), expr->context());
+}
+
+
+void FastCodeGenerator::EmitVariableLoad(Variable* var,
+ Expression::Context context) {
+ Expression* rewrite = var->rewrite();
if (rewrite == NULL) {
- ASSERT(expr->var()->is_global());
+ ASSERT(var->is_global());
Comment cmnt(masm_, "Global variable");
// Use inline caching. Variable name is passed in r2 and the global
// object on the stack.
__ ldr(ip, CodeGenerator::GlobalObject());
__ push(ip);
- __ mov(r2, Operand(expr->name()));
+ __ mov(r2, Operand(var->name()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
- DropAndMove(expr->context(), r0);
+ DropAndMove(context, r0);
} else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
if (FLAG_debug_code) {
@@ -568,7 +579,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
UNREACHABLE();
}
}
- Move(expr->context(), slot, r0);
+ Move(context, slot, r0);
} else {
// A variable has been rewritten into an explicit access to
// an object property.
@@ -603,7 +614,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
__ Call(ic, RelocInfo::CODE_TARGET);
// Drop key and object left on the stack by IC, and push the result.
- DropAndMove(expr->context(), r0, 2);
+ DropAndMove(context, r0, 2);
}
}
@@ -637,32 +648,15 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral");
- Label boilerplate_exists;
__ ldr(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
- // r2 = literal array (0).
__ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset));
- int literal_offset =
- FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
- __ ldr(r0, FieldMemOperand(r2, literal_offset));
- // Check whether we need to materialize the object literal boilerplate.
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
- __ cmp(r0, Operand(ip));
- __ b(ne, &boilerplate_exists);
- // Create boilerplate if it does not exist.
- // r1 = literal index (1).
__ mov(r1, Operand(Smi::FromInt(expr->literal_index())));
- // r0 = constant properties (2).
__ mov(r0, Operand(expr->constant_properties()));
__ stm(db_w, sp, r2.bit() | r1.bit() | r0.bit());
- __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
- __ bind(&boilerplate_exists);
- // r0 contains boilerplate.
- // Clone boilerplate.
- __ push(r0);
if (expr->depth() > 1) {
- __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
+ __ CallRuntime(Runtime::kCreateObjectLiteral, 3);
} else {
- __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
+ __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
}
// If result_saved == true: The result is saved on top of the
@@ -763,32 +757,15 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral");
- Label make_clone;
-
- // Fetch the function's literals array.
__ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
- // Check if the literal's boilerplate has been instantiated.
- int offset =
- FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize);
- __ ldr(r0, FieldMemOperand(r3, offset));
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
- __ cmp(r0, ip);
- __ b(&make_clone, ne);
-
- // Instantiate the boilerplate.
__ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
__ mov(r1, Operand(expr->literals()));
__ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit());
- __ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
-
- __ bind(&make_clone);
- // Clone the boilerplate.
- __ push(r0);
if (expr->depth() > 1) {
- __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
+ __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
} else {
- __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
+ __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
}
bool result_saved = false; // Is the result saved to the stack?
@@ -860,10 +837,38 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
}
+void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
+ Expression::Context context) {
+ Literal* key = prop->key()->AsLiteral();
+ __ mov(r2, Operand(key->handle()));
+ Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ __ Call(ic, RelocInfo::CODE_TARGET);
+ Move(context, r0);
+}
+
+
+void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) {
+ Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ __ Call(ic, RelocInfo::CODE_TARGET);
+ Move(context, r0);
+}
+
+
+void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
+ Expression::Context context) {
+ __ pop(r0);
+ __ pop(r1);
+ GenericBinaryOpStub stub(op,
+ NO_OVERWRITE);
+ __ CallStub(&stub);
+ Move(context, r0);
+}
+
+
void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL);
-
+ ASSERT(var->is_global() || var->slot() != NULL);
if (var->is_global()) {
// Assignment to a global variable. Use inline caching for the
// assignment. Right-hand-side value is passed in r0, variable name in
@@ -976,35 +981,6 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
UNREACHABLE();
break;
}
- } else {
- Property* property = var->rewrite()->AsProperty();
- ASSERT_NOT_NULL(property);
-
- // Load object and key onto the stack.
- Slot* object_slot = property->obj()->AsSlot();
- ASSERT_NOT_NULL(object_slot);
- Move(Expression::kValue, object_slot, r0);
-
- Literal* key_literal = property->key()->AsLiteral();
- ASSERT_NOT_NULL(key_literal);
- Move(Expression::kValue, key_literal);
-
- // Value to store was pushed before object and key on the stack.
- __ ldr(r0, MemOperand(sp, 2 * kPointerSize));
-
- // Arguments to ic is value in r0, object and key on stack.
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
- __ Call(ic, RelocInfo::CODE_TARGET);
-
- if (expr->context() == Expression::kEffect) {
- __ add(sp, sp, Operand(3 * kPointerSize));
- } else if (expr->context() == Expression::kValue) {
- // Value is still on the stack in esp[2 * kPointerSize]
- __ add(sp, sp, Operand(2 * kPointerSize));
- } else {
- __ ldr(r0, MemOperand(sp, 2 * kPointerSize));
- DropAndMove(expr->context(), r0, 3);
- }
}
}
@@ -1104,7 +1080,9 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
DropAndMove(expr->context(), r0);
}
-void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) {
+void FastCodeGenerator::EmitCallWithIC(Call* expr,
+ Handle<Object> ignored,
+ RelocInfo::Mode mode) {
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
@@ -1117,7 +1095,7 @@ void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) {
// Call the IC initialization code.
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
NOT_IN_LOOP);
- __ Call(ic, reloc_info);
+ __ Call(ic, mode);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
@@ -1157,7 +1135,7 @@ void FastCodeGenerator::VisitCall(Call* expr) {
// Push global object as receiver for the call IC lookup.
__ ldr(r0, CodeGenerator::GlobalObject());
__ stm(db_w, sp, r1.bit() | r0.bit());
- EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT);
+ EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
} else if (var != NULL && var->slot() != NULL &&
var->slot()->type() == Slot::LOOKUP) {
// Call to a lookup slot.
@@ -1171,7 +1149,7 @@ void FastCodeGenerator::VisitCall(Call* expr) {
__ mov(r0, Operand(key->handle()));
__ push(r0);
Visit(prop->obj());
- EmitCallWithIC(expr, RelocInfo::CODE_TARGET);
+ EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else {
// Call to a keyed property, use keyed load IC followed by function
// call.
@@ -1706,7 +1684,63 @@ void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
}
-#undef __
+void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
+ __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ Move(expr->context(), r0);
+}
+
+
+Register FastCodeGenerator::result_register() { return r0; }
+
+
+Register FastCodeGenerator::context_register() { return cp; }
+
+
+void FastCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
+ ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
+ __ str(value, MemOperand(fp, frame_offset));
+}
+
+void FastCodeGenerator::LoadContextField(Register dst, int context_index) {
+ __ ldr(dst, CodeGenerator::ContextOperand(cp, context_index));
+}
+
+
+// ----------------------------------------------------------------------------
+// Non-local control flow support.
+
+void FastCodeGenerator::EnterFinallyBlock() {
+ ASSERT(!result_register().is(r1));
+ // Store result register while executing finally block.
+ __ push(result_register());
+ // Cook return address in link register to stack (smi encoded Code* delta)
+ __ sub(r1, lr, Operand(masm_->CodeObject()));
+ ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
+ ASSERT_EQ(0, kSmiTag);
+ __ add(r1, r1, Operand(r1)); // Convert to smi.
+ __ push(r1);
+}
+
+
+void FastCodeGenerator::ExitFinallyBlock() {
+ ASSERT(!result_register().is(r1));
+ // Restore result register from stack.
+ __ pop(r1);
+ // Uncook return address and return.
+ __ pop(result_register());
+ ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
+ __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value.
+ __ add(pc, r1, Operand(masm_->CodeObject()));
+}
+
+
+void FastCodeGenerator::ThrowException() {
+ __ push(result_register());
+ __ CallRuntime(Runtime::kThrow, 1);
+}
+
+
+#undef __
} } // namespace v8::internal