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 |