| Index: src/ia32/full-codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/full-codegen-ia32.cc (revision 7180)
|
| +++ src/ia32/full-codegen-ia32.cc (working copy)
|
| @@ -199,10 +199,13 @@
|
| // stack frame was an arguments adapter frame.
|
| ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
|
| __ CallStub(&stub);
|
| - __ mov(ecx, eax); // Duplicate result.
|
| +
|
| + Variable* arguments_shadow = scope()->arguments_shadow();
|
| + if (arguments_shadow != NULL) {
|
| + __ mov(ecx, eax); // Duplicate result.
|
| + Move(arguments_shadow->AsSlot(), ecx, ebx, edx);
|
| + }
|
| Move(arguments->AsSlot(), eax, ebx, edx);
|
| - Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot();
|
| - Move(dot_arguments_slot, ecx, ebx, edx);
|
| }
|
|
|
| if (FLAG_trace) {
|
| @@ -322,22 +325,6 @@
|
| }
|
|
|
|
|
| -FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
|
| - Token::Value op, Expression* left, Expression* right) {
|
| - ASSERT(ShouldInlineSmiCase(op));
|
| - if (op == Token::DIV || op == Token::MOD || op == Token::MUL) {
|
| - // We never generate inlined constant smi operations for these.
|
| - return kNoConstants;
|
| - } else if (right->IsSmiLiteral()) {
|
| - return kRightConstant;
|
| - } else if (left->IsSmiLiteral() && !Token::IsShiftOp(op)) {
|
| - return kLeftConstant;
|
| - } else {
|
| - return kNoConstants;
|
| - }
|
| -}
|
| -
|
| -
|
| void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
|
| }
|
|
|
| @@ -547,7 +534,7 @@
|
| __ j(equal, if_true);
|
| __ cmp(result_register(), Factory::false_value());
|
| __ j(equal, if_false);
|
| - ASSERT_EQ(0, kSmiTag);
|
| + STATIC_ASSERT(kSmiTag == 0);
|
| __ test(result_register(), Operand(result_register()));
|
| __ j(zero, if_false);
|
| __ test(result_register(), Immediate(kSmiTagMask));
|
| @@ -655,6 +642,7 @@
|
| ASSERT(variable != NULL); // Must have been resolved.
|
| Slot* slot = variable->AsSlot();
|
| Property* prop = variable->AsProperty();
|
| +
|
| if (slot != NULL) {
|
| switch (slot->type()) {
|
| case Slot::PARAMETER:
|
| @@ -740,7 +728,9 @@
|
| prop->key()->AsLiteral()->handle()->IsSmi());
|
| __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle()));
|
|
|
| - Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict
|
| + : Builtins::KeyedStoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| }
|
| }
|
| @@ -757,7 +747,8 @@
|
| __ push(esi); // The context is the first argument.
|
| __ push(Immediate(pairs));
|
| __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
|
| - __ CallRuntime(Runtime::kDeclareGlobals, 3);
|
| + __ push(Immediate(Smi::FromInt(strict_mode_flag())));
|
| + __ CallRuntime(Runtime::kDeclareGlobals, 4);
|
| // Return value is ignored.
|
| }
|
|
|
| @@ -814,7 +805,6 @@
|
| SetSourcePosition(clause->position());
|
| Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
|
| EmitCallIC(ic, &patch_site);
|
| -
|
| __ test(eax, Operand(eax));
|
| __ j(not_equal, &next_test);
|
| __ Drop(1); // Switch value is no longer needed.
|
| @@ -836,6 +826,7 @@
|
| Comment cmnt(masm_, "[ Case body");
|
| CaseClause* clause = clauses->at(i);
|
| __ bind(clause->body_target()->entry_label());
|
| + PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
|
| VisitStatements(clause->statements());
|
| }
|
|
|
| @@ -895,7 +886,7 @@
|
| __ cmp(edx, Factory::empty_descriptor_array());
|
| __ j(equal, &call_runtime);
|
|
|
| - // Check that there in an enum cache in the non-empty instance
|
| + // Check that there is an enum cache in the non-empty instance
|
| // descriptors (edx). This is the case if the next enumeration
|
| // index field does not contain a smi.
|
| __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
|
| @@ -1380,7 +1371,9 @@
|
| VisitForAccumulatorValue(value);
|
| __ mov(ecx, Immediate(key->handle()));
|
| __ mov(edx, Operand(esp, 0));
|
| - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
|
| + : Builtins::StoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| PrepareForBailoutForId(key->id(), NO_REGISTERS);
|
| } else {
|
| @@ -1394,7 +1387,8 @@
|
| VisitForStackValue(key);
|
| VisitForStackValue(value);
|
| if (property->emit_store()) {
|
| - __ CallRuntime(Runtime::kSetProperty, 3);
|
| + __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
|
| + __ CallRuntime(Runtime::kSetProperty, 4);
|
| } else {
|
| __ Drop(3);
|
| }
|
| @@ -1572,14 +1566,8 @@
|
| }
|
|
|
| Token::Value op = expr->binary_op();
|
| - ConstantOperand constant = ShouldInlineSmiCase(op)
|
| - ? GetConstantOperand(op, expr->target(), expr->value())
|
| - : kNoConstants;
|
| - ASSERT(constant == kRightConstant || constant == kNoConstants);
|
| - if (constant == kNoConstants) {
|
| - __ push(eax); // Left operand goes on the stack.
|
| - VisitForAccumulatorValue(expr->value());
|
| - }
|
| + __ push(eax); // Left operand goes on the stack.
|
| + VisitForAccumulatorValue(expr->value());
|
|
|
| OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
|
| ? OVERWRITE_RIGHT
|
| @@ -1591,8 +1579,7 @@
|
| op,
|
| mode,
|
| expr->target(),
|
| - expr->value(),
|
| - constant);
|
| + expr->value());
|
| } else {
|
| EmitBinaryOp(op, mode);
|
| }
|
| @@ -1640,214 +1627,11 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr,
|
| - OverwriteMode mode,
|
| - bool left_is_constant_smi,
|
| - Smi* value) {
|
| - NearLabel call_stub, done;
|
| - __ add(Operand(eax), Immediate(value));
|
| - __ j(overflow, &call_stub);
|
| - JumpPatchSite patch_site(masm_);
|
| - patch_site.EmitJumpIfSmi(eax, &done);
|
| -
|
| - // Undo the optimistic add operation and call the shared stub.
|
| - __ bind(&call_stub);
|
| - __ sub(Operand(eax), Immediate(value));
|
| - Token::Value op = Token::ADD;
|
| - TypeRecordingBinaryOpStub stub(op, mode);
|
| - if (left_is_constant_smi) {
|
| - __ mov(edx, Immediate(value));
|
| - } else {
|
| - __ mov(edx, eax);
|
| - __ mov(eax, Immediate(value));
|
| - }
|
| - EmitCallIC(stub.GetCode(), &patch_site);
|
| -
|
| - __ bind(&done);
|
| - context()->Plug(eax);
|
| -}
|
| -
|
| -
|
| -void FullCodeGenerator::EmitConstantSmiSub(Expression* expr,
|
| - OverwriteMode mode,
|
| - bool left_is_constant_smi,
|
| - Smi* value) {
|
| - NearLabel call_stub, done;
|
| - if (left_is_constant_smi) {
|
| - __ mov(ecx, eax);
|
| - __ mov(eax, Immediate(value));
|
| - __ sub(Operand(eax), ecx);
|
| - } else {
|
| - __ sub(Operand(eax), Immediate(value));
|
| - }
|
| - __ j(overflow, &call_stub);
|
| - JumpPatchSite patch_site(masm_);
|
| - patch_site.EmitJumpIfSmi(eax, &done);
|
| -
|
| - __ bind(&call_stub);
|
| - if (left_is_constant_smi) {
|
| - __ mov(edx, Immediate(value));
|
| - __ mov(eax, ecx);
|
| - } else {
|
| - __ add(Operand(eax), Immediate(value)); // Undo the subtraction.
|
| - __ mov(edx, eax);
|
| - __ mov(eax, Immediate(value));
|
| - }
|
| - Token::Value op = Token::SUB;
|
| - TypeRecordingBinaryOpStub stub(op, mode);
|
| - EmitCallIC(stub.GetCode(), &patch_site);
|
| -
|
| - __ bind(&done);
|
| - context()->Plug(eax);
|
| -}
|
| -
|
| -
|
| -void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr,
|
| - Token::Value op,
|
| - OverwriteMode mode,
|
| - Smi* value) {
|
| - NearLabel call_stub, smi_case, done;
|
| - int shift_value = value->value() & 0x1f;
|
| -
|
| - JumpPatchSite patch_site(masm_);
|
| - patch_site.EmitJumpIfSmi(eax, &smi_case);
|
| -
|
| - // Call stub.
|
| - __ bind(&call_stub);
|
| - __ mov(edx, eax);
|
| - __ mov(eax, Immediate(value));
|
| - TypeRecordingBinaryOpStub stub(op, mode);
|
| - EmitCallIC(stub.GetCode(), &patch_site);
|
| - __ jmp(&done);
|
| -
|
| - // Smi case.
|
| - __ bind(&smi_case);
|
| - switch (op) {
|
| - case Token::SHL:
|
| - if (shift_value != 0) {
|
| - __ mov(edx, eax);
|
| - if (shift_value > 1) {
|
| - __ shl(edx, shift_value - 1);
|
| - }
|
| - // Convert int result to smi, checking that it is in int range.
|
| - ASSERT(kSmiTagSize == 1); // Adjust code if not the case.
|
| - __ add(edx, Operand(edx));
|
| - __ j(overflow, &call_stub);
|
| - __ mov(eax, edx); // Put result back into eax.
|
| - }
|
| - break;
|
| - case Token::SAR:
|
| - if (shift_value != 0) {
|
| - __ sar(eax, shift_value);
|
| - __ and_(eax, ~kSmiTagMask);
|
| - }
|
| - break;
|
| - case Token::SHR:
|
| - if (shift_value < 2) {
|
| - __ mov(edx, eax);
|
| - __ SmiUntag(edx);
|
| - __ shr(edx, shift_value);
|
| - __ test(edx, Immediate(0xc0000000));
|
| - __ j(not_zero, &call_stub);
|
| - __ SmiTag(edx);
|
| - __ mov(eax, edx); // Put result back into eax.
|
| - } else {
|
| - __ SmiUntag(eax);
|
| - __ shr(eax, shift_value);
|
| - __ SmiTag(eax);
|
| - }
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -
|
| - __ bind(&done);
|
| - context()->Plug(eax);
|
| -}
|
| -
|
| -
|
| -void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr,
|
| - Token::Value op,
|
| - OverwriteMode mode,
|
| - Smi* value) {
|
| - NearLabel smi_case, done;
|
| -
|
| - JumpPatchSite patch_site(masm_);
|
| - patch_site.EmitJumpIfSmi(eax, &smi_case);
|
| -
|
| - // The order of the arguments does not matter for bit-ops with a
|
| - // constant operand.
|
| - __ mov(edx, Immediate(value));
|
| - TypeRecordingBinaryOpStub stub(op, mode);
|
| - EmitCallIC(stub.GetCode(), &patch_site);
|
| - __ jmp(&done);
|
| -
|
| - // Smi case.
|
| - __ bind(&smi_case);
|
| - switch (op) {
|
| - case Token::BIT_OR:
|
| - __ or_(Operand(eax), Immediate(value));
|
| - break;
|
| - case Token::BIT_XOR:
|
| - __ xor_(Operand(eax), Immediate(value));
|
| - break;
|
| - case Token::BIT_AND:
|
| - __ and_(Operand(eax), Immediate(value));
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -
|
| - __ bind(&done);
|
| - context()->Plug(eax);
|
| -}
|
| -
|
| -
|
| -void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr,
|
| - Token::Value op,
|
| - OverwriteMode mode,
|
| - bool left_is_constant_smi,
|
| - Smi* value) {
|
| - switch (op) {
|
| - case Token::BIT_OR:
|
| - case Token::BIT_XOR:
|
| - case Token::BIT_AND:
|
| - EmitConstantSmiBitOp(expr, op, mode, value);
|
| - break;
|
| - case Token::SHL:
|
| - case Token::SAR:
|
| - case Token::SHR:
|
| - ASSERT(!left_is_constant_smi);
|
| - EmitConstantSmiShiftOp(expr, op, mode, value);
|
| - break;
|
| - case Token::ADD:
|
| - EmitConstantSmiAdd(expr, mode, left_is_constant_smi, value);
|
| - break;
|
| - case Token::SUB:
|
| - EmitConstantSmiSub(expr, mode, left_is_constant_smi, value);
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -}
|
| -
|
| -
|
| void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
|
| Token::Value op,
|
| OverwriteMode mode,
|
| Expression* left,
|
| - Expression* right,
|
| - ConstantOperand constant) {
|
| - if (constant == kRightConstant) {
|
| - Smi* value = Smi::cast(*right->AsLiteral()->handle());
|
| - EmitConstantSmiBinaryOp(expr, op, mode, false, value);
|
| - return;
|
| - } else if (constant == kLeftConstant) {
|
| - Smi* value = Smi::cast(*left->AsLiteral()->handle());
|
| - EmitConstantSmiBinaryOp(expr, op, mode, true, value);
|
| - return;
|
| - }
|
| -
|
| + Expression* right) {
|
| // Do combined smi check of the operands. Left operand is on the
|
| // stack. Right operand is in eax.
|
| NearLabel done, smi_case, stub_call;
|
| @@ -1979,7 +1763,9 @@
|
| __ mov(edx, eax);
|
| __ pop(eax); // Restore value.
|
| __ mov(ecx, prop->key()->AsLiteral()->handle());
|
| - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
|
| + : Builtins::StoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| break;
|
| }
|
| @@ -2000,7 +1786,9 @@
|
| __ pop(edx);
|
| }
|
| __ pop(eax); // Restore value.
|
| - Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict
|
| + : Builtins::KeyedStoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| break;
|
| }
|
| @@ -2025,8 +1813,8 @@
|
| __ mov(ecx, var->name());
|
| __ mov(edx, GlobalObjectOperand());
|
| Handle<Code> ic(Builtins::builtin(
|
| - is_strict() ? Builtins::StoreIC_Initialize_Strict
|
| - : Builtins::StoreIC_Initialize));
|
| + is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
|
| + : Builtins::StoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
|
|
| } else if (op == Token::INIT_CONST) {
|
| @@ -2096,7 +1884,8 @@
|
| __ push(eax); // Value.
|
| __ push(esi); // Context.
|
| __ push(Immediate(var->name()));
|
| - __ CallRuntime(Runtime::kStoreContextSlot, 3);
|
| + __ push(Immediate(Smi::FromInt(strict_mode_flag())));
|
| + __ CallRuntime(Runtime::kStoreContextSlot, 4);
|
| break;
|
| }
|
| }
|
| @@ -2127,7 +1916,9 @@
|
| } else {
|
| __ pop(edx);
|
| }
|
| - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
|
| + : Builtins::StoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
|
|
| // If the assignment ends an initialization block, revert to fast case.
|
| @@ -2165,7 +1956,9 @@
|
| }
|
| // Record source code position before IC call.
|
| SetSourcePosition(expr->position());
|
| - Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict
|
| + : Builtins::KeyedStoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
|
|
| // If the assignment ends an initialization block, revert to fast case.
|
| @@ -2278,6 +2071,27 @@
|
| }
|
|
|
|
|
| +void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
|
| + int arg_count) {
|
| + // Push copy of the first argument or undefined if it doesn't exist.
|
| + if (arg_count > 0) {
|
| + __ push(Operand(esp, arg_count * kPointerSize));
|
| + } else {
|
| + __ push(Immediate(Factory::undefined_value()));
|
| + }
|
| +
|
| + // Push the receiver of the enclosing function.
|
| + __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
|
| +
|
| + // Push the strict mode flag.
|
| + __ push(Immediate(Smi::FromInt(strict_mode_flag())));
|
| +
|
| + __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
|
| + ? Runtime::kResolvePossiblyDirectEvalNoLookup
|
| + : Runtime::kResolvePossiblyDirectEval, 4);
|
| +}
|
| +
|
| +
|
| void FullCodeGenerator::VisitCall(Call* expr) {
|
| #ifdef DEBUG
|
| // We want to verify that RecordJSReturnSite gets called on all paths
|
| @@ -2306,22 +2120,31 @@
|
| VisitForStackValue(args->at(i));
|
| }
|
|
|
| - // Push copy of the function - found below the arguments.
|
| - __ push(Operand(esp, (arg_count + 1) * kPointerSize));
|
| + // If we know that eval can only be shadowed by eval-introduced
|
| + // variables we attempt to load the global eval function directly
|
| + // in generated code. If we succeed, there is no need to perform a
|
| + // context lookup in the runtime system.
|
| + Label done;
|
| + if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
|
| + Label slow;
|
| + EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
|
| + NOT_INSIDE_TYPEOF,
|
| + &slow);
|
| + // Push the function and resolve eval.
|
| + __ push(eax);
|
| + EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
|
| + __ jmp(&done);
|
| + __ bind(&slow);
|
| + }
|
|
|
| - // Push copy of the first argument or undefined if it doesn't exist.
|
| - if (arg_count > 0) {
|
| - __ push(Operand(esp, arg_count * kPointerSize));
|
| - } else {
|
| - __ push(Immediate(Factory::undefined_value()));
|
| + // Push copy of the function (found below the arguments) and
|
| + // resolve eval.
|
| + __ push(Operand(esp, (arg_count + 1) * kPointerSize));
|
| + EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
|
| + if (done.is_linked()) {
|
| + __ bind(&done);
|
| }
|
|
|
| - // Push the receiver of the enclosing function and do runtime call.
|
| - __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
|
| - // Push the strict mode flag.
|
| - __ push(Immediate(Smi::FromInt(strict_mode_flag())));
|
| - __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4);
|
| -
|
| // The runtime call returns a pair of values in eax (function) and
|
| // edx (receiver). Touch up the stack with the right values.
|
| __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
|
| @@ -2385,7 +2208,9 @@
|
| Literal* key = prop->key()->AsLiteral();
|
| if (key != NULL && key->handle()->IsSymbol()) {
|
| // Call to a named property, use call IC.
|
| - VisitForStackValue(prop->obj());
|
| + { PreservePositionScope scope(masm()->positions_recorder());
|
| + VisitForStackValue(prop->obj());
|
| + }
|
| EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
| } else {
|
| // Call to a keyed property.
|
| @@ -3227,8 +3052,8 @@
|
| // Fetch the map and check if array is in fast case.
|
| // Check that object doesn't require security checks and
|
| // has no indexed interceptor.
|
| - __ CmpObjectType(object, FIRST_JS_OBJECT_TYPE, temp);
|
| - __ j(below, &slow_case);
|
| + __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
|
| + __ j(not_equal, &slow_case);
|
| __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
|
| KeyedLoadIC::kSlowCaseBitFieldMask);
|
| __ j(not_zero, &slow_case);
|
| @@ -3398,7 +3223,6 @@
|
|
|
| void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
| -
|
| VisitForAccumulatorValue(args->at(0));
|
|
|
| if (FLAG_debug_code) {
|
| @@ -3414,7 +3238,7 @@
|
|
|
| void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
|
| Label bailout, done, one_char_separator, long_separator,
|
| - non_trivial_array, not_size_one_array, loop, loop_condition,
|
| + non_trivial_array, not_size_one_array, loop,
|
| loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
|
|
|
| ASSERT(args->length() == 2);
|
| @@ -3456,7 +3280,7 @@
|
|
|
| // If the array has length zero, return the empty string.
|
| __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
|
| - __ sar(array_length, 1);
|
| + __ SmiUntag(array_length);
|
| __ j(not_zero, &non_trivial_array);
|
| __ mov(result_operand, Factory::empty_string());
|
| __ jmp(&done);
|
| @@ -3479,14 +3303,15 @@
|
| // Loop condition: while (index < length).
|
| // Live loop registers: index, array_length, string,
|
| // scratch, string_length, elements.
|
| - __ jmp(&loop_condition);
|
| + if (FLAG_debug_code) {
|
| + __ cmp(index, Operand(array_length));
|
| + __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin");
|
| + }
|
| __ bind(&loop);
|
| - __ cmp(index, Operand(array_length));
|
| - __ j(greater_equal, &done);
|
| -
|
| - __ mov(string, FieldOperand(elements, index,
|
| - times_pointer_size,
|
| - FixedArray::kHeaderSize));
|
| + __ mov(string, FieldOperand(elements,
|
| + index,
|
| + times_pointer_size,
|
| + FixedArray::kHeaderSize));
|
| __ test(string, Immediate(kSmiTagMask));
|
| __ j(zero, &bailout);
|
| __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
|
| @@ -3499,7 +3324,6 @@
|
| FieldOperand(string, SeqAsciiString::kLengthOffset));
|
| __ j(overflow, &bailout);
|
| __ add(Operand(index), Immediate(1));
|
| - __ bind(&loop_condition);
|
| __ cmp(index, Operand(array_length));
|
| __ j(less, &loop);
|
|
|
| @@ -3528,7 +3352,7 @@
|
| __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
|
| __ and_(scratch, Immediate(
|
| kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
|
| - __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag);
|
| + __ cmp(scratch, ASCII_STRING_TYPE);
|
| __ j(not_equal, &bailout);
|
|
|
| // Add (separator length times array_length) - separator length
|
| @@ -3740,8 +3564,8 @@
|
| }
|
| } else if (var != NULL) {
|
| // Delete of an unqualified identifier is disallowed in strict mode
|
| - // so this code can only be reached in non-strict mode.
|
| - ASSERT(strict_mode_flag() == kNonStrictMode);
|
| + // but "delete this" is.
|
| + ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
|
| if (var->is_global()) {
|
| __ push(GlobalObjectOperand());
|
| __ push(Immediate(var->name()));
|
| @@ -3779,17 +3603,23 @@
|
|
|
| case Token::NOT: {
|
| Comment cmnt(masm_, "[ UnaryOperation (NOT)");
|
| + if (context()->IsEffect()) {
|
| + // Unary NOT has no side effects so it's only necessary to visit the
|
| + // subexpression. Match the optimizing compiler by not branching.
|
| + VisitForEffect(expr->expression());
|
| + } else {
|
| + Label materialize_true, materialize_false;
|
| + Label* if_true = NULL;
|
| + Label* if_false = NULL;
|
| + Label* fall_through = NULL;
|
|
|
| - Label materialize_true, materialize_false;
|
| - Label* if_true = NULL;
|
| - Label* if_false = NULL;
|
| - Label* fall_through = NULL;
|
| - // Notice that the labels are swapped.
|
| - context()->PrepareTest(&materialize_true, &materialize_false,
|
| - &if_false, &if_true, &fall_through);
|
| - if (context()->IsTest()) ForwardBailoutToChild(expr);
|
| - VisitForControl(expr->expression(), if_true, if_false, fall_through);
|
| - context()->Plug(if_false, if_true); // Labels swapped.
|
| + // Notice that the labels are swapped.
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_false, &if_true, &fall_through);
|
| + if (context()->IsTest()) ForwardBailoutToChild(expr);
|
| + VisitForControl(expr->expression(), if_true, if_false, fall_through);
|
| + context()->Plug(if_false, if_true); // Labels swapped.
|
| + }
|
| break;
|
| }
|
|
|
| @@ -4015,7 +3845,9 @@
|
| case NAMED_PROPERTY: {
|
| __ mov(ecx, prop->key()->AsLiteral()->handle());
|
| __ pop(edx);
|
| - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
|
| + : Builtins::StoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| if (expr->is_postfix()) {
|
| @@ -4030,7 +3862,9 @@
|
| case KEYED_PROPERTY: {
|
| __ pop(ecx);
|
| __ pop(edx);
|
| - Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict
|
| + : Builtins::KeyedStoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| if (expr->is_postfix()) {
|
| @@ -4110,21 +3944,18 @@
|
| PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
|
|
| if (check->Equals(Heap::number_symbol())) {
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, if_true);
|
| + __ JumpIfSmi(eax, if_true);
|
| __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
|
| Factory::heap_number_map());
|
| Split(equal, if_true, if_false, fall_through);
|
| } else if (check->Equals(Heap::string_symbol())) {
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, if_false);
|
| + __ JumpIfSmi(eax, if_false);
|
| + __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
|
| + __ j(above_equal, if_false);
|
| // Check for undetectable objects => false.
|
| - __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
|
| - __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
|
| - __ test(ecx, Immediate(1 << Map::kIsUndetectable));
|
| - __ j(not_zero, if_false);
|
| - __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE);
|
| - Split(below, if_true, if_false, fall_through);
|
| + __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
|
| + 1 << Map::kIsUndetectable);
|
| + Split(zero, if_true, if_false, fall_through);
|
| } else if (check->Equals(Heap::boolean_symbol())) {
|
| __ cmp(eax, Factory::true_value());
|
| __ j(equal, if_true);
|
| @@ -4133,39 +3964,28 @@
|
| } else if (check->Equals(Heap::undefined_symbol())) {
|
| __ cmp(eax, Factory::undefined_value());
|
| __ j(equal, if_true);
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, if_false);
|
| + __ JumpIfSmi(eax, if_false);
|
| // Check for undetectable objects => true.
|
| __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
|
| __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
|
| __ test(ecx, Immediate(1 << Map::kIsUndetectable));
|
| Split(not_zero, if_true, if_false, fall_through);
|
| } else if (check->Equals(Heap::function_symbol())) {
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, if_false);
|
| - __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
|
| - __ j(equal, if_true);
|
| - // Regular expressions => 'function' (they are callable).
|
| - __ CmpInstanceType(edx, JS_REGEXP_TYPE);
|
| - Split(equal, if_true, if_false, fall_through);
|
| + __ JumpIfSmi(eax, if_false);
|
| + __ CmpObjectType(eax, FIRST_FUNCTION_CLASS_TYPE, edx);
|
| + Split(above_equal, if_true, if_false, fall_through);
|
| } else if (check->Equals(Heap::object_symbol())) {
|
| - __ test(eax, Immediate(kSmiTagMask));
|
| - __ j(zero, if_false);
|
| + __ JumpIfSmi(eax, if_false);
|
| __ cmp(eax, Factory::null_value());
|
| __ j(equal, if_true);
|
| - // Regular expressions => 'function', not 'object'.
|
| - __ CmpObjectType(eax, JS_REGEXP_TYPE, edx);
|
| - __ j(equal, if_false);
|
| + __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, edx);
|
| + __ j(below, if_false);
|
| + __ CmpInstanceType(edx, FIRST_FUNCTION_CLASS_TYPE);
|
| + __ j(above_equal, if_false);
|
| // Check for undetectable objects => false.
|
| - __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
|
| - __ test(ecx, Immediate(1 << Map::kIsUndetectable));
|
| - __ j(not_zero, if_false);
|
| - // Check for JS objects => true.
|
| - __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
|
| - __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
|
| - __ j(less, if_false);
|
| - __ cmp(ecx, LAST_JS_OBJECT_TYPE);
|
| - Split(less_equal, if_true, if_false, fall_through);
|
| + __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
|
| + 1 << Map::kIsUndetectable);
|
| + Split(zero, if_true, if_false, fall_through);
|
| } else {
|
| if (if_false != fall_through) __ jmp(if_false);
|
| }
|
| @@ -4378,6 +4198,22 @@
|
|
|
|
|
| void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
|
| + switch (ic->kind()) {
|
| + case Code::LOAD_IC:
|
| + __ IncrementCounter(&Counters::named_load_full, 1);
|
| + break;
|
| + case Code::KEYED_LOAD_IC:
|
| + __ IncrementCounter(&Counters::keyed_load_full, 1);
|
| + break;
|
| + case Code::STORE_IC:
|
| + __ IncrementCounter(&Counters::named_store_full, 1);
|
| + break;
|
| + case Code::KEYED_STORE_IC:
|
| + __ IncrementCounter(&Counters::keyed_store_full, 1);
|
| + default:
|
| + break;
|
| + }
|
| +
|
| __ call(ic, RelocInfo::CODE_TARGET);
|
| if (patch_site != NULL && patch_site->is_bound()) {
|
| patch_site->EmitPatchInfo();
|
|
|