summaryrefslogtreecommitdiff
path: root/deps/v8/src/ia32/codegen-ia32.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/ia32/codegen-ia32.cc')
-rw-r--r--deps/v8/src/ia32/codegen-ia32.cc338
1 files changed, 197 insertions, 141 deletions
diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc
index 4ac5527699..69a17cd9b5 100644
--- a/deps/v8/src/ia32/codegen-ia32.cc
+++ b/deps/v8/src/ia32/codegen-ia32.cc
@@ -29,6 +29,7 @@
#include "bootstrapper.h"
#include "codegen-inl.h"
+#include "compiler.h"
#include "debug.h"
#include "ic-inl.h"
#include "parser.h"
@@ -75,7 +76,6 @@ void DeferredCode::RestoreRegisters() {
CodeGenState::CodeGenState(CodeGenerator* owner)
: owner_(owner),
- typeof_state_(NOT_INSIDE_TYPEOF),
destination_(NULL),
previous_(NULL) {
owner_->set_state(this);
@@ -83,10 +83,8 @@ CodeGenState::CodeGenState(CodeGenerator* owner)
CodeGenState::CodeGenState(CodeGenerator* owner,
- TypeofState typeof_state,
ControlDestination* destination)
: owner_(owner),
- typeof_state_(typeof_state),
destination_(destination),
previous_(owner->state()) {
owner_->set_state(this);
@@ -415,13 +413,12 @@ Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot,
// partially compiled) into control flow to the control destination.
// If force_control is true, control flow is forced.
void CodeGenerator::LoadCondition(Expression* x,
- TypeofState typeof_state,
ControlDestination* dest,
bool force_control) {
ASSERT(!in_spilled_code());
int original_height = frame_->height();
- { CodeGenState new_state(this, typeof_state, dest);
+ { CodeGenState new_state(this, dest);
Visit(x);
// If we hit a stack overflow, we may not have actually visited
@@ -450,17 +447,16 @@ void CodeGenerator::LoadCondition(Expression* x,
}
-void CodeGenerator::LoadAndSpill(Expression* expression,
- TypeofState typeof_state) {
+void CodeGenerator::LoadAndSpill(Expression* expression) {
ASSERT(in_spilled_code());
set_in_spilled_code(false);
- Load(expression, typeof_state);
+ Load(expression);
frame_->SpillAll();
set_in_spilled_code(true);
}
-void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
+void CodeGenerator::Load(Expression* expr) {
#ifdef DEBUG
int original_height = frame_->height();
#endif
@@ -468,7 +464,7 @@ void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
JumpTarget true_target;
JumpTarget false_target;
ControlDestination dest(&true_target, &false_target, true);
- LoadCondition(x, typeof_state, &dest, false);
+ LoadCondition(expr, &dest, false);
if (dest.false_was_fall_through()) {
// The false target was just bound.
@@ -543,23 +539,25 @@ void CodeGenerator::LoadGlobalReceiver() {
}
-// TODO(1241834): Get rid of this function in favor of just using Load, now
-// that we have the INSIDE_TYPEOF typeof state. => Need to handle global
-// variables w/o reference errors elsewhere.
-void CodeGenerator::LoadTypeofExpression(Expression* x) {
- Variable* variable = x->AsVariableProxy()->AsVariable();
+void CodeGenerator::LoadTypeofExpression(Expression* expr) {
+ // Special handling of identifiers as subexpressions of typeof.
+ Variable* variable = expr->AsVariableProxy()->AsVariable();
if (variable != NULL && !variable->is_this() && variable->is_global()) {
- // NOTE: This is somewhat nasty. We force the compiler to load
- // the variable as if through '<global>.<variable>' to make sure we
- // do not get reference errors.
+ // For a global variable we build the property reference
+ // <global>.<variable> and perform a (regular non-contextual) property
+ // load to make sure we do not get reference errors.
Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX);
Literal key(variable->name());
- // TODO(1241834): Fetch the position from the variable instead of using
- // no position.
Property property(&global, &key, RelocInfo::kNoPosition);
- Load(&property);
+ Reference ref(this, &property);
+ ref.GetValue();
+ } else if (variable != NULL && variable->slot() != NULL) {
+ // For a variable that rewrites to a slot, we signal it is the immediate
+ // subexpression of a typeof.
+ LoadFromSlotCheckForArguments(variable->slot(), INSIDE_TYPEOF);
} else {
- Load(x, INSIDE_TYPEOF);
+ // Anything else can be handled normally.
+ Load(expr);
}
}
@@ -1190,12 +1188,12 @@ void CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
// Perform the operation.
switch (op) {
case Token::SAR:
- __ sar(answer.reg());
+ __ sar_cl(answer.reg());
// No checks of result necessary
break;
case Token::SHR: {
Label result_ok;
- __ shr(answer.reg());
+ __ shr_cl(answer.reg());
// Check that the *unsigned* result fits in a smi. Neither of
// the two high-order bits can be set:
// * 0x80000000: high bit would be lost when smi tagging.
@@ -1216,7 +1214,7 @@ void CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
}
case Token::SHL: {
Label result_ok;
- __ shl(answer.reg());
+ __ shl_cl(answer.reg());
// Check that the *signed* result fits in a smi.
__ cmp(answer.reg(), 0xc0000000);
__ j(positive, &result_ok);
@@ -1970,27 +1968,6 @@ void CodeGenerator::Comparison(Condition cc,
}
-class CallFunctionStub: public CodeStub {
- public:
- CallFunctionStub(int argc, InLoopFlag in_loop)
- : argc_(argc), in_loop_(in_loop) { }
-
- void Generate(MacroAssembler* masm);
-
- private:
- int argc_;
- InLoopFlag in_loop_;
-
-#ifdef DEBUG
- void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); }
-#endif
-
- Major MajorKey() { return CallFunction; }
- int MinorKey() { return argc_; }
- InLoopFlag InLoop() { return in_loop_; }
-};
-
-
// Call the function just below TOS on the stack with the given
// arguments. The receiver is the TOS.
void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
@@ -2027,7 +2004,7 @@ void CodeGenerator::CallApplyLazy(Property* apply,
// Load the apply function onto the stack. This will usually
// give us a megamorphic load site. Not super, but it works.
Reference ref(this, apply);
- ref.GetValue(NOT_INSIDE_TYPEOF);
+ ref.GetValue();
ASSERT(ref.type() == Reference::NAMED);
// Load the receiver and the existing arguments object onto the
@@ -2204,9 +2181,9 @@ void DeferredStackCheck::Generate() {
void CodeGenerator::CheckStack() {
DeferredStackCheck* deferred = new DeferredStackCheck;
- ExternalReference stack_guard_limit =
- ExternalReference::address_of_stack_guard_limit();
- __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit();
+ __ cmp(esp, Operand::StaticVariable(stack_limit));
deferred->Branch(below);
deferred->BindExit();
}
@@ -2366,7 +2343,7 @@ void CodeGenerator::VisitIfStatement(IfStatement* node) {
JumpTarget then;
JumpTarget else_;
ControlDestination dest(&then, &else_, true);
- LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true);
+ LoadCondition(node->condition(), &dest, true);
if (dest.false_was_fall_through()) {
// The else target was bound, so we compile the else part first.
@@ -2393,7 +2370,7 @@ void CodeGenerator::VisitIfStatement(IfStatement* node) {
ASSERT(!has_else_stm);
JumpTarget then;
ControlDestination dest(&then, &exit, true);
- LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true);
+ LoadCondition(node->condition(), &dest, true);
if (dest.false_was_fall_through()) {
// The exit label was bound. We may have dangling jumps to the
@@ -2413,7 +2390,7 @@ void CodeGenerator::VisitIfStatement(IfStatement* node) {
ASSERT(!has_then_stm);
JumpTarget else_;
ControlDestination dest(&exit, &else_, false);
- LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true);
+ LoadCondition(node->condition(), &dest, true);
if (dest.true_was_fall_through()) {
// The exit label was bound. We may have dangling jumps to the
@@ -2435,7 +2412,7 @@ void CodeGenerator::VisitIfStatement(IfStatement* node) {
// or control flow effect). LoadCondition is called without
// forcing control flow.
ControlDestination dest(&exit, &exit, true);
- LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, false);
+ LoadCondition(node->condition(), &dest, false);
if (!dest.is_used()) {
// We got a value on the frame rather than (or in addition to)
// control flow.
@@ -2472,6 +2449,7 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
CodeForStatementPosition(node);
Load(node->expression());
Result return_value = frame_->Pop();
+ masm()->WriteRecordedPositions();
if (function_return_is_shadowed_) {
function_return_.Jump(&return_value);
} else {
@@ -2735,8 +2713,10 @@ void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) {
node->continue_target()->Bind();
}
if (has_valid_frame()) {
+ Comment cmnt(masm_, "[ DoWhileCondition");
+ CodeForDoWhileConditionPosition(node);
ControlDestination dest(&body, node->break_target(), false);
- LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
+ LoadCondition(node->cond(), &dest, true);
}
if (node->break_target()->is_linked()) {
node->break_target()->Bind();
@@ -2791,7 +2771,7 @@ void CodeGenerator::VisitWhileStatement(WhileStatement* node) {
// Compile the test with the body as the true target and preferred
// fall-through and with the break target as the false target.
ControlDestination dest(&body, node->break_target(), true);
- LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
+ LoadCondition(node->cond(), &dest, true);
if (dest.false_was_fall_through()) {
// If we got the break target as fall-through, the test may have
@@ -2838,7 +2818,7 @@ void CodeGenerator::VisitWhileStatement(WhileStatement* node) {
// The break target is the fall-through (body is a backward
// jump from here and thus an invalid fall-through).
ControlDestination dest(&body, node->break_target(), false);
- LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
+ LoadCondition(node->cond(), &dest, true);
}
} else {
// If we have chosen not to recompile the test at the bottom,
@@ -2929,7 +2909,7 @@ void CodeGenerator::VisitForStatement(ForStatement* node) {
// Compile the test with the body as the true target and preferred
// fall-through and with the break target as the false target.
ControlDestination dest(&body, node->break_target(), true);
- LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
+ LoadCondition(node->cond(), &dest, true);
if (dest.false_was_fall_through()) {
// If we got the break target as fall-through, the test may have
@@ -2999,7 +2979,7 @@ void CodeGenerator::VisitForStatement(ForStatement* node) {
// The break target is the fall-through (body is a backward
// jump from here).
ControlDestination dest(&body, node->break_target(), false);
- LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
+ LoadCondition(node->cond(), &dest, true);
}
} else {
// Otherwise, jump back to the test at the top.
@@ -3574,7 +3554,8 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
Comment cmnt(masm_, "[ FunctionLiteral");
// Build the function boilerplate and instantiate it.
- Handle<JSFunction> boilerplate = BuildBoilerplate(node);
+ Handle<JSFunction> boilerplate =
+ Compiler::BuildBoilerplate(node, script_, this);
// Check for stack-overflow exception.
if (HasStackOverflow()) return;
InstantiateBoilerplate(boilerplate);
@@ -3594,25 +3575,25 @@ void CodeGenerator::VisitConditional(Conditional* node) {
JumpTarget else_;
JumpTarget exit;
ControlDestination dest(&then, &else_, true);
- LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &dest, true);
+ LoadCondition(node->condition(), &dest, true);
if (dest.false_was_fall_through()) {
// The else target was bound, so we compile the else part first.
- Load(node->else_expression(), typeof_state());
+ Load(node->else_expression());
if (then.is_linked()) {
exit.Jump();
then.Bind();
- Load(node->then_expression(), typeof_state());
+ Load(node->then_expression());
}
} else {
// The then target was bound, so we compile the then part first.
- Load(node->then_expression(), typeof_state());
+ Load(node->then_expression());
if (else_.is_linked()) {
exit.Jump();
else_.Bind();
- Load(node->else_expression(), typeof_state());
+ Load(node->else_expression());
}
}
@@ -3934,7 +3915,7 @@ void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
void CodeGenerator::VisitSlot(Slot* node) {
Comment cmnt(masm_, "[ Slot");
- LoadFromSlotCheckForArguments(node, typeof_state());
+ LoadFromSlotCheckForArguments(node, NOT_INSIDE_TYPEOF);
}
@@ -3947,7 +3928,7 @@ void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
} else {
ASSERT(var->is_global());
Reference ref(this, node);
- ref.GetValue(typeof_state());
+ ref.GetValue();
}
}
@@ -3958,12 +3939,28 @@ void CodeGenerator::VisitLiteral(Literal* node) {
}
-void CodeGenerator::LoadUnsafeSmi(Register target, Handle<Object> value) {
+void CodeGenerator::PushUnsafeSmi(Handle<Object> value) {
+ ASSERT(value->IsSmi());
+ int bits = reinterpret_cast<int>(*value);
+ __ push(Immediate(bits & 0x0000FFFF));
+ __ or_(Operand(esp, 0), Immediate(bits & 0xFFFF0000));
+}
+
+
+void CodeGenerator::StoreUnsafeSmiToLocal(int offset, Handle<Object> value) {
+ ASSERT(value->IsSmi());
+ int bits = reinterpret_cast<int>(*value);
+ __ mov(Operand(ebp, offset), Immediate(bits & 0x0000FFFF));
+ __ or_(Operand(ebp, offset), Immediate(bits & 0xFFFF0000));
+}
+
+
+void CodeGenerator::MoveUnsafeSmi(Register target, Handle<Object> value) {
ASSERT(target.is_valid());
ASSERT(value->IsSmi());
int bits = reinterpret_cast<int>(*value);
__ Set(target, Immediate(bits & 0x0000FFFF));
- __ xor_(target, bits & 0xFFFF0000);
+ __ or_(target, bits & 0xFFFF0000);
}
@@ -4354,9 +4351,9 @@ void CodeGenerator::VisitAssignment(Assignment* node) {
// the target, with an implicit promise that it will be written to again
// before it is read.
if (literal != NULL || (right_var != NULL && right_var != var)) {
- target.TakeValue(NOT_INSIDE_TYPEOF);
+ target.TakeValue();
} else {
- target.GetValue(NOT_INSIDE_TYPEOF);
+ target.GetValue();
}
Load(node->value());
GenericBinaryOperation(node->binary_op(),
@@ -4404,7 +4401,7 @@ void CodeGenerator::VisitThrow(Throw* node) {
void CodeGenerator::VisitProperty(Property* node) {
Comment cmnt(masm_, "[ Property");
Reference property(this, node);
- property.GetValue(typeof_state());
+ property.GetValue();
}
@@ -4589,7 +4586,7 @@ void CodeGenerator::VisitCall(Call* node) {
// Load the function to call from the property through a reference.
Reference ref(this, property);
- ref.GetValue(NOT_INSIDE_TYPEOF);
+ ref.GetValue();
// Pass receiver to called function.
if (property->is_synthetic()) {
@@ -4699,10 +4696,10 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
// This generates code that performs a charCodeAt() call or returns
// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
-// It can handle flat and sliced strings, 8 and 16 bit characters and
-// cons strings where the answer is found in the left hand branch of the
-// cons. The slow case will flatten the string, which will ensure that
-// the answer is in the left hand side the next time around.
+// It can handle flat, 8 and 16 bit characters and cons strings where the
+// answer is found in the left hand branch of the cons. The slow case will
+// flatten the string, which will ensure that the answer is in the left hand
+// side the next time around.
void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
Comment(masm_, "[ GenerateFastCharCodeAt");
ASSERT(args->length() == 2);
@@ -4710,7 +4707,6 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
Label slow_case;
Label end;
Label not_a_flat_string;
- Label a_cons_string;
Label try_again_with_new_string;
Label ascii_string;
Label got_char_code;
@@ -4792,7 +4788,7 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
__ add(Operand(ecx), Immediate(String::kLongLengthShift));
// Fetch the length field into the temporary register.
__ mov(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset));
- __ shr(temp.reg()); // The shift amount in ecx is implicit operand.
+ __ shr_cl(temp.reg());
// Check for index out of range.
__ cmp(index.reg(), Operand(temp.reg()));
__ j(greater_equal, &slow_case);
@@ -4832,21 +4828,16 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
__ bind(&not_a_flat_string);
__ and_(temp.reg(), kStringRepresentationMask);
__ cmp(temp.reg(), kConsStringTag);
- __ j(equal, &a_cons_string);
- __ cmp(temp.reg(), kSlicedStringTag);
__ j(not_equal, &slow_case);
- // SlicedString.
- // Add the offset to the index and trigger the slow case on overflow.
- __ add(index.reg(), FieldOperand(object.reg(), SlicedString::kStartOffset));
- __ j(overflow, &slow_case);
- // Getting the underlying string is done by running the cons string code.
-
// ConsString.
- __ bind(&a_cons_string);
- // Get the first of the two strings. Both sliced and cons strings
- // store their source string at the same offset.
- ASSERT(SlicedString::kBufferOffset == ConsString::kFirstOffset);
+ // Check that the right hand side is the empty string (ie if this is really a
+ // flat string in a cons string). If that is not the case we would rather go
+ // to the runtime system now, to flatten the string.
+ __ mov(temp.reg(), FieldOperand(object.reg(), ConsString::kSecondOffset));
+ __ cmp(Operand(temp.reg()), Immediate(Handle<String>(Heap::empty_string())));
+ __ j(not_equal, &slow_case);
+ // Get the first of the two strings.
__ mov(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset));
__ jmp(&try_again_with_new_string);
@@ -5224,9 +5215,6 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
- // Note that because of NOT and an optimization in comparison of a typeof
- // expression to a literal string, this function can fail to leave a value
- // on top of the frame or in the cc register.
Comment cmnt(masm_, "[ UnaryOperation");
Token::Value op = node->op();
@@ -5235,7 +5223,7 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
// Swap the true and false targets but keep the same actual label
// as the fall through.
destination()->Invert();
- LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, destination(), true);
+ LoadCondition(node->expression(), destination(), true);
// Swap the labels back.
destination()->Invert();
@@ -5485,7 +5473,7 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
if (!is_postfix) frame_->Push(Smi::FromInt(0));
return;
}
- target.TakeValue(NOT_INSIDE_TYPEOF);
+ target.TakeValue();
Result new_value = frame_->Pop();
new_value.ToRegister();
@@ -5563,9 +5551,6 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
- // Note that due to an optimization in comparison operations (typeof
- // compared to a string literal), we can evaluate a binary expression such
- // as AND or OR and not leave a value on the frame or in the cc register.
Comment cmnt(masm_, "[ BinaryOperation");
Token::Value op = node->op();
@@ -5581,7 +5566,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
if (op == Token::AND) {
JumpTarget is_true;
ControlDestination dest(&is_true, destination()->false_target(), true);
- LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &dest, false);
+ LoadCondition(node->left(), &dest, false);
if (dest.false_was_fall_through()) {
// The current false target was used as the fall-through. If
@@ -5600,7 +5585,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
is_true.Bind();
// The left subexpression compiled to control flow, so the
// right one is free to do so as well.
- LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false);
+ LoadCondition(node->right(), destination(), false);
} else {
// We have actually just jumped to or bound the current false
// target but the current control destination is not marked as
@@ -5611,7 +5596,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
} else if (dest.is_used()) {
// The left subexpression compiled to control flow (and is_true
// was just bound), so the right is free to do so as well.
- LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false);
+ LoadCondition(node->right(), destination(), false);
} else {
// We have a materialized value on the frame, so we exit with
@@ -5644,7 +5629,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
} else if (op == Token::OR) {
JumpTarget is_false;
ControlDestination dest(destination()->true_target(), &is_false, false);
- LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &dest, false);
+ LoadCondition(node->left(), &dest, false);
if (dest.true_was_fall_through()) {
// The current true target was used as the fall-through. If
@@ -5663,7 +5648,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
is_false.Bind();
// The left subexpression compiled to control flow, so the
// right one is free to do so as well.
- LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false);
+ LoadCondition(node->right(), destination(), false);
} else {
// We have just jumped to or bound the current true target but
// the current control destination is not marked as used.
@@ -5673,7 +5658,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
} else if (dest.is_used()) {
// The left subexpression compiled to control flow (and is_false
// was just bound), so the right is free to do so as well.
- LoadCondition(node->right(), NOT_INSIDE_TYPEOF, destination(), false);
+ LoadCondition(node->right(), destination(), false);
} else {
// We have a materialized value on the frame, so we exit with
@@ -5805,6 +5790,9 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
destination()->false_target()->Branch(zero);
frame_->Spill(answer.reg());
__ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg());
+ destination()->true_target()->Branch(equal);
+ // Regular expressions are callable so typeof == 'function'.
+ __ CmpInstanceType(answer.reg(), JS_REGEXP_TYPE);
answer.Unuse();
destination()->Split(equal);
@@ -5814,10 +5802,13 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
__ cmp(answer.reg(), Factory::null_value());
destination()->true_target()->Branch(equal);
- // It can be an undetectable object.
Result map = allocator()->Allocate();
ASSERT(map.is_valid());
- __ mov(map.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
+ // Regular expressions are typeof == 'function', not 'object'.
+ __ CmpObjectType(answer.reg(), JS_REGEXP_TYPE, map.reg());
+ destination()->false_target()->Branch(equal);
+
+ // It can be an undetectable object.
__ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset));
__ test(map.reg(), Immediate(1 << Map::kIsUndetectable));
destination()->false_target()->Branch(not_zero);
@@ -6066,7 +6057,7 @@ Handle<String> Reference::GetName() {
}
-void Reference::GetValue(TypeofState typeof_state) {
+void Reference::GetValue() {
ASSERT(!cgen_->in_spilled_code());
ASSERT(cgen_->HasValidEntryRegisters());
ASSERT(!is_illegal());
@@ -6083,17 +6074,11 @@ void Reference::GetValue(TypeofState typeof_state) {
Comment cmnt(masm, "[ Load from Slot");
Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
ASSERT(slot != NULL);
- cgen_->LoadFromSlotCheckForArguments(slot, typeof_state);
+ cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF);
break;
}
case NAMED: {
- // TODO(1241834): Make sure that it is safe to ignore the
- // distinction between expressions in a typeof and not in a
- // typeof. If there is a chance that reference errors can be
- // thrown below, we must distinguish between the two kinds of
- // loads (typeof expression loads must not throw a reference
- // error).
Variable* var = expression_->AsVariableProxy()->AsVariable();
bool is_global = var != NULL;
ASSERT(!is_global || var->is_global());
@@ -6163,8 +6148,6 @@ void Reference::GetValue(TypeofState typeof_state) {
}
case KEYED: {
- // TODO(1241834): Make sure that this it is safe to ignore the
- // distinction between expressions in a typeof and not in a typeof.
Comment cmnt(masm, "[ Load from keyed Property");
Variable* var = expression_->AsVariableProxy()->AsVariable();
bool is_global = var != NULL;
@@ -6283,13 +6266,13 @@ void Reference::GetValue(TypeofState typeof_state) {
}
-void Reference::TakeValue(TypeofState typeof_state) {
+void Reference::TakeValue() {
// For non-constant frame-allocated slots, we invalidate the value in the
// slot. For all others, we fall back on GetValue.
ASSERT(!cgen_->in_spilled_code());
ASSERT(!is_illegal());
if (type_ != SLOT) {
- GetValue(typeof_state);
+ GetValue();
return;
}
@@ -6299,7 +6282,7 @@ void Reference::TakeValue(TypeofState typeof_state) {
slot->type() == Slot::CONTEXT ||
slot->var()->mode() == Variable::CONST ||
slot->is_arguments()) {
- GetValue(typeof_state);
+ GetValue();
return;
}
@@ -6728,11 +6711,11 @@ void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
// Perform the operation.
switch (op_) {
case Token::SAR:
- __ sar(eax);
+ __ sar_cl(eax);
// No checks of result necessary
break;
case Token::SHR:
- __ shr(eax);
+ __ shr_cl(eax);
// Check that the *unsigned* result fits in a smi.
// Neither of the two high-order bits can be set:
// - 0x80000000: high bit would be lost when smi tagging.
@@ -6743,7 +6726,7 @@ void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
__ j(not_zero, slow, not_taken);
break;
case Token::SHL:
- __ shl(eax);
+ __ shl_cl(eax);
// Check that the *signed* result fits in a smi.
__ cmp(eax, 0xc0000000);
__ j(sign, slow, not_taken);
@@ -6793,8 +6776,8 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
// eax: y
// edx: x
- if (CpuFeatures::IsSupported(CpuFeatures::SSE2)) {
- CpuFeatures::Scope use_sse2(CpuFeatures::SSE2);
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures::Scope use_sse2(SSE2);
FloatingPointHelper::LoadSse2Operands(masm, &call_runtime);
switch (op_) {
@@ -6889,7 +6872,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
if (use_sse3_) {
// Truncate the operands to 32-bit integers and check for
// exceptions in doing so.
- CpuFeatures::Scope scope(CpuFeatures::SSE3);
+ CpuFeatures::Scope scope(SSE3);
__ fisttp_s(Operand(esp, 0 * kPointerSize));
__ fisttp_s(Operand(esp, 1 * kPointerSize));
__ fnstsw_ax();
@@ -6918,9 +6901,9 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
case Token::BIT_OR: __ or_(eax, Operand(ecx)); break;
case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
- case Token::SAR: __ sar(eax); break;
- case Token::SHL: __ shl(eax); break;
- case Token::SHR: __ shr(eax); break;
+ case Token::SAR: __ sar_cl(eax); break;
+ case Token::SHL: __ shl_cl(eax); break;
+ case Token::SHR: __ shr_cl(eax); break;
default: UNREACHABLE();
}
if (op_ == Token::SHR) {
@@ -7516,9 +7499,9 @@ void CompareStub::Generate(MacroAssembler* masm) {
// Call builtin if operands are not floating point or smi.
Label check_for_symbols;
Label unordered;
- if (CpuFeatures::IsSupported(CpuFeatures::SSE2)) {
- CpuFeatures::Scope use_sse2(CpuFeatures::SSE2);
- CpuFeatures::Scope use_cmov(CpuFeatures::CMOV);
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures::Scope use_sse2(SSE2);
+ CpuFeatures::Scope use_cmov(CMOV);
FloatingPointHelper::LoadSse2Operands(masm, &check_for_symbols);
__ comisd(xmm0, xmm1);
@@ -7707,11 +7690,84 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
}
+// If true, a Handle<T> passed by value is passed and returned by
+// using the location_ field directly. If false, it is passed and
+// returned as a pointer to a handle.
+#ifdef USING_MAC_ABI
+static const bool kPassHandlesDirectly = true;
+#else
+static const bool kPassHandlesDirectly = false;
+#endif
+
+
+void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
+ Label get_result;
+ Label prologue;
+ Label promote_scheduled_exception;
+ __ EnterApiExitFrame(ExitFrame::MODE_NORMAL, kStackSpace, kArgc);
+ ASSERT_EQ(kArgc, 4);
+ if (kPassHandlesDirectly) {
+ // When handles as passed directly we don't have to allocate extra
+ // space for and pass an out parameter.
+ __ mov(Operand(esp, 0 * kPointerSize), ebx); // name.
+ __ mov(Operand(esp, 1 * kPointerSize), eax); // arguments pointer.
+ } else {
+ // The function expects three arguments to be passed but we allocate
+ // four to get space for the output cell. The argument slots are filled
+ // as follows:
+ //
+ // 3: output cell
+ // 2: arguments pointer
+ // 1: name
+ // 0: pointer to the output cell
+ //
+ // Note that this is one more "argument" than the function expects
+ // so the out cell will have to be popped explicitly after returning
+ // from the function.
+ __ mov(Operand(esp, 1 * kPointerSize), ebx); // name.
+ __ mov(Operand(esp, 2 * kPointerSize), eax); // arguments pointer.
+ __ mov(ebx, esp);
+ __ add(Operand(ebx), Immediate(3 * kPointerSize));
+ __ mov(Operand(esp, 0 * kPointerSize), ebx); // output
+ __ mov(Operand(esp, 3 * kPointerSize), Immediate(0)); // out cell.
+ }
+ // Call the api function!
+ __ call(fun()->address(), RelocInfo::RUNTIME_ENTRY);
+ // Check if the function scheduled an exception.
+ ExternalReference scheduled_exception_address =
+ ExternalReference::scheduled_exception_address();
+ __ cmp(Operand::StaticVariable(scheduled_exception_address),
+ Immediate(Factory::the_hole_value()));
+ __ j(not_equal, &promote_scheduled_exception, not_taken);
+ if (!kPassHandlesDirectly) {
+ // The returned value is a pointer to the handle holding the result.
+ // Dereference this to get to the location.
+ __ mov(eax, Operand(eax, 0));
+ }
+ // Check if the result handle holds 0
+ __ test(eax, Operand(eax));
+ __ j(not_zero, &get_result, taken);
+ // It was zero; the result is undefined.
+ __ mov(eax, Factory::undefined_value());
+ __ jmp(&prologue);
+ // It was non-zero. Dereference to get the result value.
+ __ bind(&get_result);
+ __ mov(eax, Operand(eax, 0));
+ __ bind(&prologue);
+ __ LeaveExitFrame(ExitFrame::MODE_NORMAL);
+ __ ret(0);
+ __ bind(&promote_scheduled_exception);
+ __ TailCallRuntime(ExternalReference(Runtime::kPromoteScheduledException),
+ 0,
+ 1);
+}
+
+
void CEntryStub::GenerateCore(MacroAssembler* masm,
Label* throw_normal_exception,
Label* throw_termination_exception,
Label* throw_out_of_memory_exception,
- StackFrame::Type frame_type,
+ ExitFrame::Mode mode,
bool do_gc,
bool always_allocate_scope) {
// eax: result parameter for PerformGC, if any
@@ -7761,7 +7817,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ j(zero, &failure_returned, not_taken);
// Exit the JavaScript to C++ exit frame.
- __ LeaveExitFrame(frame_type);
+ __ LeaveExitFrame(mode);
__ ret(0);
// Handling of failure.
@@ -7860,12 +7916,12 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
// of a proper result. The builtin entry handles this by performing
// a garbage collection and retrying the builtin (twice).
- StackFrame::Type frame_type = is_debug_break ?
- StackFrame::EXIT_DEBUG :
- StackFrame::EXIT;
+ ExitFrame::Mode mode = is_debug_break
+ ? ExitFrame::MODE_DEBUG
+ : ExitFrame::MODE_NORMAL;
// Enter the exit frame that transitions from JavaScript to C++.
- __ EnterExitFrame(frame_type);
+ __ EnterExitFrame(mode);
// eax: result parameter for PerformGC, if any (setup below)
// ebx: pointer to builtin function (C callee-saved)
@@ -7883,7 +7939,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
&throw_normal_exception,
&throw_termination_exception,
&throw_out_of_memory_exception,
- frame_type,
+ mode,
false,
false);
@@ -7892,7 +7948,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
&throw_normal_exception,
&throw_termination_exception,
&throw_out_of_memory_exception,
- frame_type,
+ mode,
true,
false);
@@ -7903,7 +7959,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
&throw_normal_exception,
&throw_termination_exception,
&throw_out_of_memory_exception,
- frame_type,
+ mode,
true,
true);