diff options
Diffstat (limited to 'deps/v8/src/ia32/codegen-ia32.cc')
-rw-r--r-- | deps/v8/src/ia32/codegen-ia32.cc | 338 |
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(¬_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); |