| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 | 367 |
| 368 int LCodeGen::ToInteger32(LConstantOperand* op) const { | 368 int LCodeGen::ToInteger32(LConstantOperand* op) const { |
| 369 Handle<Object> value = chunk_->LookupLiteral(op); | 369 Handle<Object> value = chunk_->LookupLiteral(op); |
| 370 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32()); | 370 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32()); |
| 371 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) == | 371 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) == |
| 372 value->Number()); | 372 value->Number()); |
| 373 return static_cast<int32_t>(value->Number()); | 373 return static_cast<int32_t>(value->Number()); |
| 374 } | 374 } |
| 375 | 375 |
| 376 | 376 |
| 377 double LCodeGen::ToDouble(LConstantOperand* op) const { |
| 378 Handle<Object> value = chunk_->LookupLiteral(op); |
| 379 return value->Number(); |
| 380 } |
| 381 |
| 382 |
| 377 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { | 383 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { |
| 378 Handle<Object> literal = chunk_->LookupLiteral(op); | 384 Handle<Object> literal = chunk_->LookupLiteral(op); |
| 379 ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged()); | 385 ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged()); |
| 380 return literal; | 386 return literal; |
| 381 } | 387 } |
| 382 | 388 |
| 383 | 389 |
| 384 Operand LCodeGen::ToOperand(LOperand* op) const { | 390 Operand LCodeGen::ToOperand(LOperand* op) const { |
| 385 // Does not handle registers. In X64 assembler, plain registers are not | 391 // Does not handle registers. In X64 assembler, plain registers are not |
| 386 // representable as an Operand. | 392 // representable as an Operand. |
| (...skipping 1132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1519 break; | 1525 break; |
| 1520 case Token::IN: | 1526 case Token::IN: |
| 1521 case Token::INSTANCEOF: | 1527 case Token::INSTANCEOF: |
| 1522 default: | 1528 default: |
| 1523 UNREACHABLE(); | 1529 UNREACHABLE(); |
| 1524 } | 1530 } |
| 1525 return cond; | 1531 return cond; |
| 1526 } | 1532 } |
| 1527 | 1533 |
| 1528 | 1534 |
| 1529 void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { | |
| 1530 if (right->IsConstantOperand()) { | |
| 1531 int32_t value = ToInteger32(LConstantOperand::cast(right)); | |
| 1532 if (left->IsRegister()) { | |
| 1533 __ cmpl(ToRegister(left), Immediate(value)); | |
| 1534 } else { | |
| 1535 __ cmpl(ToOperand(left), Immediate(value)); | |
| 1536 } | |
| 1537 } else if (right->IsRegister()) { | |
| 1538 __ cmpl(ToRegister(left), ToRegister(right)); | |
| 1539 } else { | |
| 1540 __ cmpl(ToRegister(left), ToOperand(right)); | |
| 1541 } | |
| 1542 } | |
| 1543 | |
| 1544 | |
| 1545 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { | 1535 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
| 1546 LOperand* left = instr->InputAt(0); | 1536 LOperand* left = instr->InputAt(0); |
| 1547 LOperand* right = instr->InputAt(1); | 1537 LOperand* right = instr->InputAt(1); |
| 1548 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1538 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1549 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1539 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1540 Condition cc = TokenToCondition(instr->op(), instr->is_double()); |
| 1550 | 1541 |
| 1551 if (instr->is_double()) { | 1542 if (left->IsConstantOperand() && right->IsConstantOperand()) { |
| 1552 // Don't base result on EFLAGS when a NaN is involved. Instead | 1543 // We can statically evaluate the comparison. |
| 1553 // jump to the false block. | 1544 double left_val = ToDouble(LConstantOperand::cast(left)); |
| 1554 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); | 1545 double right_val = ToDouble(LConstantOperand::cast(right)); |
| 1555 __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); | 1546 int next_block = |
| 1547 EvalComparison(instr->op(), left_val, right_val) ? true_block |
| 1548 : false_block; |
| 1549 EmitGoto(next_block); |
| 1556 } else { | 1550 } else { |
| 1557 EmitCmpI(left, right); | 1551 if (instr->is_double()) { |
| 1552 // Don't base result on EFLAGS when a NaN is involved. Instead |
| 1553 // jump to the false block. |
| 1554 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); |
| 1555 __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); |
| 1556 } else { |
| 1557 int32_t value; |
| 1558 if (right->IsConstantOperand()) { |
| 1559 value = ToInteger32(LConstantOperand::cast(right)); |
| 1560 __ cmpl(ToRegister(left), Immediate(value)); |
| 1561 } else if (left->IsConstantOperand()) { |
| 1562 value = ToInteger32(LConstantOperand::cast(left)); |
| 1563 if (right->IsRegister()) { |
| 1564 __ cmpl(ToRegister(right), Immediate(value)); |
| 1565 } else { |
| 1566 __ cmpl(ToOperand(right), Immediate(value)); |
| 1567 } |
| 1568 // We transposed the operands. Reverse the condition. |
| 1569 cc = ReverseCondition(cc); |
| 1570 } else { |
| 1571 if (right->IsRegister()) { |
| 1572 __ cmpl(ToRegister(left), ToRegister(right)); |
| 1573 } else { |
| 1574 __ cmpl(ToRegister(left), ToOperand(right)); |
| 1575 } |
| 1576 } |
| 1577 } |
| 1578 EmitBranch(true_block, false_block, cc); |
| 1558 } | 1579 } |
| 1559 | |
| 1560 Condition cc = TokenToCondition(instr->op(), instr->is_double()); | |
| 1561 EmitBranch(true_block, false_block, cc); | |
| 1562 } | 1580 } |
| 1563 | 1581 |
| 1564 | 1582 |
| 1565 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { | 1583 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { |
| 1566 Register left = ToRegister(instr->InputAt(0)); | 1584 Register left = ToRegister(instr->InputAt(0)); |
| 1567 Register right = ToRegister(instr->InputAt(1)); | 1585 Register right = ToRegister(instr->InputAt(1)); |
| 1568 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1586 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1569 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1587 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1570 | 1588 |
| 1571 __ cmpq(left, right); | 1589 __ cmpq(left, right); |
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1972 } | 1990 } |
| 1973 | 1991 |
| 1974 | 1992 |
| 1975 void LCodeGen::DoCmpT(LCmpT* instr) { | 1993 void LCodeGen::DoCmpT(LCmpT* instr) { |
| 1976 Token::Value op = instr->op(); | 1994 Token::Value op = instr->op(); |
| 1977 | 1995 |
| 1978 Handle<Code> ic = CompareIC::GetUninitialized(op); | 1996 Handle<Code> ic = CompareIC::GetUninitialized(op); |
| 1979 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 1997 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 1980 | 1998 |
| 1981 Condition condition = TokenToCondition(op, false); | 1999 Condition condition = TokenToCondition(op, false); |
| 1982 if (op == Token::GT || op == Token::LTE) { | |
| 1983 condition = ReverseCondition(condition); | |
| 1984 } | |
| 1985 Label true_value, done; | 2000 Label true_value, done; |
| 1986 __ testq(rax, rax); | 2001 __ testq(rax, rax); |
| 1987 __ j(condition, &true_value, Label::kNear); | 2002 __ j(condition, &true_value, Label::kNear); |
| 1988 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); | 2003 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); |
| 1989 __ jmp(&done, Label::kNear); | 2004 __ jmp(&done, Label::kNear); |
| 1990 __ bind(&true_value); | 2005 __ bind(&true_value); |
| 1991 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); | 2006 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); |
| 1992 __ bind(&done); | 2007 __ bind(&done); |
| 1993 } | 2008 } |
| 1994 | 2009 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2048 // to update the property details in the property dictionary to mark | 2063 // to update the property details in the property dictionary to mark |
| 2049 // it as no longer deleted. We deoptimize in that case. | 2064 // it as no longer deleted. We deoptimize in that case. |
| 2050 if (instr->hydrogen()->RequiresHoleCheck()) { | 2065 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2051 __ CompareRoot(Operand(address, 0), Heap::kTheHoleValueRootIndex); | 2066 __ CompareRoot(Operand(address, 0), Heap::kTheHoleValueRootIndex); |
| 2052 DeoptimizeIf(equal, instr->environment()); | 2067 DeoptimizeIf(equal, instr->environment()); |
| 2053 } | 2068 } |
| 2054 | 2069 |
| 2055 // Store the value. | 2070 // Store the value. |
| 2056 __ movq(Operand(address, 0), value); | 2071 __ movq(Operand(address, 0), value); |
| 2057 | 2072 |
| 2058 Label smi_store; | 2073 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 2059 __ JumpIfSmi(value, &smi_store, Label::kNear); | 2074 Label smi_store; |
| 2075 HType type = instr->hydrogen()->value()->type(); |
| 2076 if (!type.IsHeapNumber() && !type.IsString() && !type.IsNonPrimitive()) { |
| 2077 __ JumpIfSmi(value, &smi_store, Label::kNear); |
| 2078 } |
| 2060 | 2079 |
| 2061 int offset = JSGlobalPropertyCell::kValueOffset - kHeapObjectTag; | 2080 int offset = JSGlobalPropertyCell::kValueOffset - kHeapObjectTag; |
| 2062 __ lea(object, Operand(address, -offset)); | 2081 __ lea(object, Operand(address, -offset)); |
| 2063 // Cells are always in the remembered set. | 2082 // Cells are always in the remembered set. |
| 2064 __ RecordWrite(object, | 2083 __ RecordWrite(object, |
| 2065 address, | 2084 address, |
| 2066 value, | 2085 value, |
| 2067 kSaveFPRegs, | 2086 kSaveFPRegs, |
| 2068 OMIT_REMEMBERED_SET, | 2087 OMIT_REMEMBERED_SET, |
| 2069 OMIT_SMI_CHECK); | 2088 OMIT_SMI_CHECK); |
| 2070 __ bind(&smi_store); | 2089 __ bind(&smi_store); |
| 2090 } |
| 2071 } | 2091 } |
| 2072 | 2092 |
| 2073 | 2093 |
| 2074 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { | 2094 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { |
| 2075 ASSERT(ToRegister(instr->global_object()).is(rdx)); | 2095 ASSERT(ToRegister(instr->global_object()).is(rdx)); |
| 2076 ASSERT(ToRegister(instr->value()).is(rax)); | 2096 ASSERT(ToRegister(instr->value()).is(rax)); |
| 2077 | 2097 |
| 2078 __ Move(rcx, instr->name()); | 2098 __ Move(rcx, instr->name()); |
| 2079 Handle<Code> ic = instr->strict_mode() | 2099 Handle<Code> ic = instr->strict_mode() |
| 2080 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 2100 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 2081 : isolate()->builtins()->StoreIC_Initialize(); | 2101 : isolate()->builtins()->StoreIC_Initialize(); |
| 2082 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); | 2102 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); |
| 2083 } | 2103 } |
| 2084 | 2104 |
| 2085 | 2105 |
| 2086 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { | 2106 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { |
| 2087 Register context = ToRegister(instr->context()); | 2107 Register context = ToRegister(instr->context()); |
| 2088 Register result = ToRegister(instr->result()); | 2108 Register result = ToRegister(instr->result()); |
| 2089 __ movq(result, ContextOperand(context, instr->slot_index())); | 2109 __ movq(result, ContextOperand(context, instr->slot_index())); |
| 2090 } | 2110 } |
| 2091 | 2111 |
| 2092 | 2112 |
| 2093 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { | 2113 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { |
| 2094 Register context = ToRegister(instr->context()); | 2114 Register context = ToRegister(instr->context()); |
| 2095 Register value = ToRegister(instr->value()); | 2115 Register value = ToRegister(instr->value()); |
| 2096 __ movq(ContextOperand(context, instr->slot_index()), value); | 2116 __ movq(ContextOperand(context, instr->slot_index()), value); |
| 2097 if (instr->needs_write_barrier()) { | 2117 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 2118 HType type = instr->hydrogen()->value()->type(); |
| 2119 SmiCheck check_needed = |
| 2120 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 2098 int offset = Context::SlotOffset(instr->slot_index()); | 2121 int offset = Context::SlotOffset(instr->slot_index()); |
| 2099 Register scratch = ToRegister(instr->TempAt(0)); | 2122 Register scratch = ToRegister(instr->TempAt(0)); |
| 2100 __ RecordWriteContextSlot(context, offset, value, scratch, kSaveFPRegs); | 2123 __ RecordWriteContextSlot(context, |
| 2124 offset, |
| 2125 value, |
| 2126 scratch, |
| 2127 kSaveFPRegs, |
| 2128 EMIT_REMEMBERED_SET, |
| 2129 check_needed); |
| 2101 } | 2130 } |
| 2102 } | 2131 } |
| 2103 | 2132 |
| 2104 | 2133 |
| 2105 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { | 2134 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { |
| 2106 Register object = ToRegister(instr->InputAt(0)); | 2135 Register object = ToRegister(instr->InputAt(0)); |
| 2107 Register result = ToRegister(instr->result()); | 2136 Register result = ToRegister(instr->result()); |
| 2108 if (instr->hydrogen()->is_in_object()) { | 2137 if (instr->hydrogen()->is_in_object()) { |
| 2109 __ movq(result, FieldOperand(object, instr->hydrogen()->offset())); | 2138 __ movq(result, FieldOperand(object, instr->hydrogen()->offset())); |
| 2110 } else { | 2139 } else { |
| 2111 __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset)); | 2140 __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset)); |
| 2112 __ movq(result, FieldOperand(result, instr->hydrogen()->offset())); | 2141 __ movq(result, FieldOperand(result, instr->hydrogen()->offset())); |
| 2113 } | 2142 } |
| 2114 } | 2143 } |
| 2115 | 2144 |
| 2116 | 2145 |
| 2117 void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, | 2146 void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, |
| 2118 Register object, | 2147 Register object, |
| 2119 Handle<Map> type, | 2148 Handle<Map> type, |
| 2120 Handle<String> name) { | 2149 Handle<String> name) { |
| 2121 LookupResult lookup; | 2150 LookupResult lookup(isolate()); |
| 2122 type->LookupInDescriptors(NULL, *name, &lookup); | 2151 type->LookupInDescriptors(NULL, *name, &lookup); |
| 2123 ASSERT(lookup.IsProperty() && | 2152 ASSERT(lookup.IsProperty() && |
| 2124 (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); | 2153 (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); |
| 2125 if (lookup.type() == FIELD) { | 2154 if (lookup.type() == FIELD) { |
| 2126 int index = lookup.GetLocalFieldIndexFromMap(*type); | 2155 int index = lookup.GetLocalFieldIndexFromMap(*type); |
| 2127 int offset = index * kPointerSize; | 2156 int offset = index * kPointerSize; |
| 2128 if (index < 0) { | 2157 if (index < 0) { |
| 2129 // Negative property indices are in-object properties, indexed | 2158 // Negative property indices are in-object properties, indexed |
| 2130 // from the end of the fixed part of the object. | 2159 // from the end of the fixed part of the object. |
| 2131 __ movq(result, FieldOperand(object, offset + type->instance_size())); | 2160 __ movq(result, FieldOperand(object, offset + type->instance_size())); |
| (...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2554 | 2583 |
| 2555 | 2584 |
| 2556 void LCodeGen::DoPushArgument(LPushArgument* instr) { | 2585 void LCodeGen::DoPushArgument(LPushArgument* instr) { |
| 2557 LOperand* argument = instr->InputAt(0); | 2586 LOperand* argument = instr->InputAt(0); |
| 2558 EmitPushTaggedOperand(argument); | 2587 EmitPushTaggedOperand(argument); |
| 2559 } | 2588 } |
| 2560 | 2589 |
| 2561 | 2590 |
| 2562 void LCodeGen::DoThisFunction(LThisFunction* instr) { | 2591 void LCodeGen::DoThisFunction(LThisFunction* instr) { |
| 2563 Register result = ToRegister(instr->result()); | 2592 Register result = ToRegister(instr->result()); |
| 2564 __ movq(result, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 2593 LoadHeapObject(result, instr->hydrogen()->closure()); |
| 2565 } | 2594 } |
| 2566 | 2595 |
| 2567 | 2596 |
| 2568 void LCodeGen::DoContext(LContext* instr) { | 2597 void LCodeGen::DoContext(LContext* instr) { |
| 2569 Register result = ToRegister(instr->result()); | 2598 Register result = ToRegister(instr->result()); |
| 2570 __ movq(result, rsi); | 2599 __ movq(result, rsi); |
| 2571 } | 2600 } |
| 2572 | 2601 |
| 2573 | 2602 |
| 2574 void LCodeGen::DoOuterContext(LOuterContext* instr) { | 2603 void LCodeGen::DoOuterContext(LOuterContext* instr) { |
| (...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3054 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { | 3083 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { |
| 3055 Register object = ToRegister(instr->object()); | 3084 Register object = ToRegister(instr->object()); |
| 3056 Register value = ToRegister(instr->value()); | 3085 Register value = ToRegister(instr->value()); |
| 3057 int offset = instr->offset(); | 3086 int offset = instr->offset(); |
| 3058 | 3087 |
| 3059 if (!instr->transition().is_null()) { | 3088 if (!instr->transition().is_null()) { |
| 3060 __ Move(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); | 3089 __ Move(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); |
| 3061 } | 3090 } |
| 3062 | 3091 |
| 3063 // Do the store. | 3092 // Do the store. |
| 3093 HType type = instr->hydrogen()->value()->type(); |
| 3094 SmiCheck check_needed = |
| 3095 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 3064 if (instr->is_in_object()) { | 3096 if (instr->is_in_object()) { |
| 3065 __ movq(FieldOperand(object, offset), value); | 3097 __ movq(FieldOperand(object, offset), value); |
| 3066 if (instr->needs_write_barrier()) { | 3098 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 3067 Register temp = ToRegister(instr->TempAt(0)); | 3099 Register temp = ToRegister(instr->TempAt(0)); |
| 3068 // Update the write barrier for the object for in-object properties. | 3100 // Update the write barrier for the object for in-object properties. |
| 3069 __ RecordWriteField(object, offset, value, temp, kSaveFPRegs); | 3101 __ RecordWriteField(object, |
| 3102 offset, |
| 3103 value, |
| 3104 temp, |
| 3105 kSaveFPRegs, |
| 3106 EMIT_REMEMBERED_SET, |
| 3107 check_needed); |
| 3070 } | 3108 } |
| 3071 } else { | 3109 } else { |
| 3072 Register temp = ToRegister(instr->TempAt(0)); | 3110 Register temp = ToRegister(instr->TempAt(0)); |
| 3073 __ movq(temp, FieldOperand(object, JSObject::kPropertiesOffset)); | 3111 __ movq(temp, FieldOperand(object, JSObject::kPropertiesOffset)); |
| 3074 __ movq(FieldOperand(temp, offset), value); | 3112 __ movq(FieldOperand(temp, offset), value); |
| 3075 if (instr->needs_write_barrier()) { | 3113 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 3076 // Update the write barrier for the properties array. | 3114 // Update the write barrier for the properties array. |
| 3077 // object is used as a scratch register. | 3115 // object is used as a scratch register. |
| 3078 __ RecordWriteField(temp, offset, value, object, kSaveFPRegs); | 3116 __ RecordWriteField(temp, |
| 3117 offset, |
| 3118 value, |
| 3119 object, |
| 3120 kSaveFPRegs, |
| 3121 EMIT_REMEMBERED_SET, |
| 3122 check_needed); |
| 3079 } | 3123 } |
| 3080 } | 3124 } |
| 3081 } | 3125 } |
| 3082 | 3126 |
| 3083 | 3127 |
| 3084 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { | 3128 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { |
| 3085 ASSERT(ToRegister(instr->object()).is(rdx)); | 3129 ASSERT(ToRegister(instr->object()).is(rdx)); |
| 3086 ASSERT(ToRegister(instr->value()).is(rax)); | 3130 ASSERT(ToRegister(instr->value()).is(rax)); |
| 3087 | 3131 |
| 3088 __ Move(rcx, instr->hydrogen()->name()); | 3132 __ Move(rcx, instr->hydrogen()->name()); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3175 __ movq(FieldOperand(elements, offset), value); | 3219 __ movq(FieldOperand(elements, offset), value); |
| 3176 } else { | 3220 } else { |
| 3177 __ movq(FieldOperand(elements, | 3221 __ movq(FieldOperand(elements, |
| 3178 key, | 3222 key, |
| 3179 times_pointer_size, | 3223 times_pointer_size, |
| 3180 FixedArray::kHeaderSize), | 3224 FixedArray::kHeaderSize), |
| 3181 value); | 3225 value); |
| 3182 } | 3226 } |
| 3183 | 3227 |
| 3184 if (instr->hydrogen()->NeedsWriteBarrier()) { | 3228 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 3229 HType type = instr->hydrogen()->value()->type(); |
| 3230 SmiCheck check_needed = |
| 3231 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 3185 // Compute address of modified element and store it into key register. | 3232 // Compute address of modified element and store it into key register. |
| 3186 __ lea(key, FieldOperand(elements, | 3233 __ lea(key, FieldOperand(elements, |
| 3187 key, | 3234 key, |
| 3188 times_pointer_size, | 3235 times_pointer_size, |
| 3189 FixedArray::kHeaderSize)); | 3236 FixedArray::kHeaderSize)); |
| 3190 __ RecordWrite(elements, key, value, kSaveFPRegs); | 3237 __ RecordWrite(elements, |
| 3238 key, |
| 3239 value, |
| 3240 kSaveFPRegs, |
| 3241 EMIT_REMEMBERED_SET, |
| 3242 check_needed); |
| 3191 } | 3243 } |
| 3192 } | 3244 } |
| 3193 | 3245 |
| 3194 | 3246 |
| 3195 void LCodeGen::DoStoreKeyedFastDoubleElement( | 3247 void LCodeGen::DoStoreKeyedFastDoubleElement( |
| 3196 LStoreKeyedFastDoubleElement* instr) { | 3248 LStoreKeyedFastDoubleElement* instr) { |
| 3197 XMMRegister value = ToDoubleRegister(instr->value()); | 3249 XMMRegister value = ToDoubleRegister(instr->value()); |
| 3198 Label have_value; | 3250 Label have_value; |
| 3199 | 3251 |
| 3200 __ ucomisd(value, value); | 3252 __ ucomisd(value, value); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3216 ASSERT(ToRegister(instr->key()).is(rcx)); | 3268 ASSERT(ToRegister(instr->key()).is(rcx)); |
| 3217 ASSERT(ToRegister(instr->value()).is(rax)); | 3269 ASSERT(ToRegister(instr->value()).is(rax)); |
| 3218 | 3270 |
| 3219 Handle<Code> ic = instr->strict_mode() | 3271 Handle<Code> ic = instr->strict_mode() |
| 3220 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 3272 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 3221 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 3273 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 3222 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 3274 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 3223 } | 3275 } |
| 3224 | 3276 |
| 3225 | 3277 |
| 3278 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { |
| 3279 Register object_reg = ToRegister(instr->object()); |
| 3280 Register new_map_reg = ToRegister(instr->new_map_reg()); |
| 3281 |
| 3282 Handle<Map> from_map = instr->original_map(); |
| 3283 Handle<Map> to_map = instr->transitioned_map(); |
| 3284 ElementsKind from_kind = from_map->elements_kind(); |
| 3285 ElementsKind to_kind = to_map->elements_kind(); |
| 3286 |
| 3287 Label not_applicable; |
| 3288 __ Cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map); |
| 3289 __ j(not_equal, ¬_applicable); |
| 3290 __ movq(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT); |
| 3291 if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) { |
| 3292 __ movq(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg); |
| 3293 // Write barrier. |
| 3294 ASSERT_NE(instr->temp_reg(), NULL); |
| 3295 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, |
| 3296 ToRegister(instr->temp_reg()), kDontSaveFPRegs); |
| 3297 } else if (from_kind == FAST_SMI_ONLY_ELEMENTS && |
| 3298 to_kind == FAST_DOUBLE_ELEMENTS) { |
| 3299 Register fixed_object_reg = ToRegister(instr->temp_reg()); |
| 3300 ASSERT(fixed_object_reg.is(rdx)); |
| 3301 ASSERT(new_map_reg.is(rbx)); |
| 3302 __ movq(fixed_object_reg, object_reg); |
| 3303 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(), |
| 3304 RelocInfo::CODE_TARGET, instr); |
| 3305 } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) { |
| 3306 Register fixed_object_reg = ToRegister(instr->temp_reg()); |
| 3307 ASSERT(fixed_object_reg.is(rdx)); |
| 3308 ASSERT(new_map_reg.is(rbx)); |
| 3309 __ movq(fixed_object_reg, object_reg); |
| 3310 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(), |
| 3311 RelocInfo::CODE_TARGET, instr); |
| 3312 } else { |
| 3313 UNREACHABLE(); |
| 3314 } |
| 3315 __ bind(¬_applicable); |
| 3316 } |
| 3317 |
| 3318 |
| 3226 void LCodeGen::DoStringAdd(LStringAdd* instr) { | 3319 void LCodeGen::DoStringAdd(LStringAdd* instr) { |
| 3227 EmitPushTaggedOperand(instr->left()); | 3320 EmitPushTaggedOperand(instr->left()); |
| 3228 EmitPushTaggedOperand(instr->right()); | 3321 EmitPushTaggedOperand(instr->right()); |
| 3229 StringAddStub stub(NO_STRING_CHECK_IN_STUB); | 3322 StringAddStub stub(NO_STRING_CHECK_IN_STUB); |
| 3230 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 3323 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 3231 } | 3324 } |
| 3232 | 3325 |
| 3233 | 3326 |
| 3234 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { | 3327 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
| 3235 class DeferredStringCharCodeAt: public LDeferredCode { | 3328 class DeferredStringCharCodeAt: public LDeferredCode { |
| (...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3818 } | 3911 } |
| 3819 | 3912 |
| 3820 // Check the holder map. | 3913 // Check the holder map. |
| 3821 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), | 3914 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), |
| 3822 Handle<Map>(current_prototype->map())); | 3915 Handle<Map>(current_prototype->map())); |
| 3823 DeoptimizeIf(not_equal, instr->environment()); | 3916 DeoptimizeIf(not_equal, instr->environment()); |
| 3824 } | 3917 } |
| 3825 | 3918 |
| 3826 | 3919 |
| 3827 void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { | 3920 void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { |
| 3921 Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements(); |
| 3922 ASSERT_EQ(2, constant_elements->length()); |
| 3923 ElementsKind constant_elements_kind = |
| 3924 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); |
| 3925 |
| 3828 // Setup the parameters to the stub/runtime call. | 3926 // Setup the parameters to the stub/runtime call. |
| 3829 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 3927 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 3830 __ push(FieldOperand(rax, JSFunction::kLiteralsOffset)); | 3928 __ push(FieldOperand(rax, JSFunction::kLiteralsOffset)); |
| 3831 __ Push(Smi::FromInt(instr->hydrogen()->literal_index())); | 3929 __ Push(Smi::FromInt(instr->hydrogen()->literal_index())); |
| 3832 __ Push(instr->hydrogen()->constant_elements()); | 3930 __ Push(instr->hydrogen()->constant_elements()); |
| 3833 | 3931 |
| 3834 // Pick the right runtime function or stub to call. | 3932 // Pick the right runtime function or stub to call. |
| 3835 int length = instr->hydrogen()->length(); | 3933 int length = instr->hydrogen()->length(); |
| 3836 if (instr->hydrogen()->IsCopyOnWrite()) { | 3934 if (instr->hydrogen()->IsCopyOnWrite()) { |
| 3837 ASSERT(instr->hydrogen()->depth() == 1); | 3935 ASSERT(instr->hydrogen()->depth() == 1); |
| 3838 FastCloneShallowArrayStub::Mode mode = | 3936 FastCloneShallowArrayStub::Mode mode = |
| 3839 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS; | 3937 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS; |
| 3840 FastCloneShallowArrayStub stub(mode, length); | 3938 FastCloneShallowArrayStub stub(mode, length); |
| 3841 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 3939 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 3842 } else if (instr->hydrogen()->depth() > 1) { | 3940 } else if (instr->hydrogen()->depth() > 1) { |
| 3843 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr); | 3941 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr); |
| 3844 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { | 3942 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { |
| 3845 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr); | 3943 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr); |
| 3846 } else { | 3944 } else { |
| 3847 FastCloneShallowArrayStub::Mode mode = | 3945 FastCloneShallowArrayStub::Mode mode = |
| 3848 FastCloneShallowArrayStub::CLONE_ELEMENTS; | 3946 constant_elements_kind == FAST_DOUBLE_ELEMENTS |
| 3947 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS |
| 3948 : FastCloneShallowArrayStub::CLONE_ELEMENTS; |
| 3849 FastCloneShallowArrayStub stub(mode, length); | 3949 FastCloneShallowArrayStub stub(mode, length); |
| 3850 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 3950 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 3851 } | 3951 } |
| 3852 } | 3952 } |
| 3853 | 3953 |
| 3854 | 3954 |
| 3855 void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { | 3955 void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { |
| 3856 // Setup the parameters to the stub/runtime call. | 3956 // Setup the parameters to the stub/runtime call. |
| 3857 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 3957 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 3858 __ push(FieldOperand(rax, JSFunction::kLiteralsOffset)); | 3958 __ push(FieldOperand(rax, JSFunction::kLiteralsOffset)); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3927 } | 4027 } |
| 3928 } | 4028 } |
| 3929 | 4029 |
| 3930 | 4030 |
| 3931 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { | 4031 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { |
| 3932 // Use the fast case closure allocation code that allocates in new | 4032 // Use the fast case closure allocation code that allocates in new |
| 3933 // space for nested functions that don't need literals cloning. | 4033 // space for nested functions that don't need literals cloning. |
| 3934 Handle<SharedFunctionInfo> shared_info = instr->shared_info(); | 4034 Handle<SharedFunctionInfo> shared_info = instr->shared_info(); |
| 3935 bool pretenure = instr->hydrogen()->pretenure(); | 4035 bool pretenure = instr->hydrogen()->pretenure(); |
| 3936 if (!pretenure && shared_info->num_literals() == 0) { | 4036 if (!pretenure && shared_info->num_literals() == 0) { |
| 3937 FastNewClosureStub stub( | 4037 FastNewClosureStub stub(shared_info->strict_mode_flag()); |
| 3938 shared_info->strict_mode() ? kStrictMode : kNonStrictMode); | |
| 3939 __ Push(shared_info); | 4038 __ Push(shared_info); |
| 3940 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 4039 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 3941 } else { | 4040 } else { |
| 3942 __ push(rsi); | 4041 __ push(rsi); |
| 3943 __ Push(shared_info); | 4042 __ Push(shared_info); |
| 3944 __ PushRoot(pretenure ? | 4043 __ PushRoot(pretenure ? |
| 3945 Heap::kTrueValueRootIndex : | 4044 Heap::kTrueValueRootIndex : |
| 3946 Heap::kFalseValueRootIndex); | 4045 Heap::kFalseValueRootIndex); |
| 3947 CallRuntime(Runtime::kNewClosure, 3, instr); | 4046 CallRuntime(Runtime::kNewClosure, 3, instr); |
| 3948 } | 4047 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3968 } | 4067 } |
| 3969 | 4068 |
| 3970 | 4069 |
| 3971 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { | 4070 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { |
| 3972 Register input = ToRegister(instr->InputAt(0)); | 4071 Register input = ToRegister(instr->InputAt(0)); |
| 3973 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 4072 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 3974 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 4073 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 3975 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 4074 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 3976 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 4075 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 3977 | 4076 |
| 3978 Condition final_branch_condition = EmitTypeofIs(true_label, | 4077 Condition final_branch_condition = |
| 3979 false_label, | 4078 EmitTypeofIs(true_label, false_label, input, instr->type_literal()); |
| 3980 input, | 4079 if (final_branch_condition != no_condition) { |
| 3981 instr->type_literal()); | 4080 EmitBranch(true_block, false_block, final_branch_condition); |
| 3982 | 4081 } |
| 3983 EmitBranch(true_block, false_block, final_branch_condition); | |
| 3984 } | 4082 } |
| 3985 | 4083 |
| 3986 | 4084 |
| 3987 Condition LCodeGen::EmitTypeofIs(Label* true_label, | 4085 Condition LCodeGen::EmitTypeofIs(Label* true_label, |
| 3988 Label* false_label, | 4086 Label* false_label, |
| 3989 Register input, | 4087 Register input, |
| 3990 Handle<String> type_name) { | 4088 Handle<String> type_name) { |
| 3991 Condition final_branch_condition = no_condition; | 4089 Condition final_branch_condition = no_condition; |
| 3992 if (type_name->Equals(heap()->number_symbol())) { | 4090 if (type_name->Equals(heap()->number_symbol())) { |
| 3993 __ JumpIfSmi(input, true_label); | 4091 __ JumpIfSmi(input, true_label); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4041 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); | 4139 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); |
| 4042 __ j(below, false_label); | 4140 __ j(below, false_label); |
| 4043 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); | 4141 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 4044 __ j(above, false_label); | 4142 __ j(above, false_label); |
| 4045 // Check for undetectable objects => false. | 4143 // Check for undetectable objects => false. |
| 4046 __ testb(FieldOperand(input, Map::kBitFieldOffset), | 4144 __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| 4047 Immediate(1 << Map::kIsUndetectable)); | 4145 Immediate(1 << Map::kIsUndetectable)); |
| 4048 final_branch_condition = zero; | 4146 final_branch_condition = zero; |
| 4049 | 4147 |
| 4050 } else { | 4148 } else { |
| 4051 final_branch_condition = never; | |
| 4052 __ jmp(false_label); | 4149 __ jmp(false_label); |
| 4053 } | 4150 } |
| 4054 | 4151 |
| 4055 return final_branch_condition; | 4152 return final_branch_condition; |
| 4056 } | 4153 } |
| 4057 | 4154 |
| 4058 | 4155 |
| 4059 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { | 4156 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { |
| 4060 Register temp = ToRegister(instr->TempAt(0)); | 4157 Register temp = ToRegister(instr->TempAt(0)); |
| 4061 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 4158 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4196 RegisterEnvironmentForDeoptimization(environment); | 4293 RegisterEnvironmentForDeoptimization(environment); |
| 4197 ASSERT(osr_pc_offset_ == -1); | 4294 ASSERT(osr_pc_offset_ == -1); |
| 4198 osr_pc_offset_ = masm()->pc_offset(); | 4295 osr_pc_offset_ = masm()->pc_offset(); |
| 4199 } | 4296 } |
| 4200 | 4297 |
| 4201 #undef __ | 4298 #undef __ |
| 4202 | 4299 |
| 4203 } } // namespace v8::internal | 4300 } } // namespace v8::internal |
| 4204 | 4301 |
| 4205 #endif // V8_TARGET_ARCH_X64 | 4302 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |