| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 // o rsi: our context | 111 // o rsi: our context |
| 112 // o rbp: our caller's frame pointer | 112 // o rbp: our caller's frame pointer |
| 113 // o rsp: stack pointer (pointing to return address) | 113 // o rsp: stack pointer (pointing to return address) |
| 114 // | 114 // |
| 115 // The function builds a JS frame. Please see JavaScriptFrameConstants in | 115 // The function builds a JS frame. Please see JavaScriptFrameConstants in |
| 116 // frames-x64.h for its layout. | 116 // frames-x64.h for its layout. |
| 117 void FullCodeGenerator::Generate() { | 117 void FullCodeGenerator::Generate() { |
| 118 CompilationInfo* info = info_; | 118 CompilationInfo* info = info_; |
| 119 handler_table_ = | 119 handler_table_ = |
| 120 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); | 120 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); |
| 121 |
| 122 InitializeFeedbackVector(); |
| 123 |
| 121 profiling_counter_ = isolate()->factory()->NewCell( | 124 profiling_counter_ = isolate()->factory()->NewCell( |
| 122 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); | 125 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); |
| 123 SetFunctionPosition(function()); | 126 SetFunctionPosition(function()); |
| 124 Comment cmnt(masm_, "[ function compiled by full code generator"); | 127 Comment cmnt(masm_, "[ function compiled by full code generator"); |
| 125 | 128 |
| 126 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | 129 ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
| 127 | 130 |
| 128 #ifdef DEBUG | 131 #ifdef DEBUG |
| 129 if (strlen(FLAG_stop_at) > 0 && | 132 if (strlen(FLAG_stop_at) > 0 && |
| 130 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 133 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 } | 178 } |
| 176 } | 179 } |
| 177 | 180 |
| 178 bool function_in_register = true; | 181 bool function_in_register = true; |
| 179 | 182 |
| 180 // Possibly allocate a local context. | 183 // Possibly allocate a local context. |
| 181 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 184 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 182 if (heap_slots > 0) { | 185 if (heap_slots > 0) { |
| 183 Comment cmnt(masm_, "[ Allocate context"); | 186 Comment cmnt(masm_, "[ Allocate context"); |
| 184 // Argument to NewContext is the function, which is still in rdi. | 187 // Argument to NewContext is the function, which is still in rdi. |
| 185 __ push(rdi); | |
| 186 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) { | 188 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) { |
| 189 __ push(rdi); |
| 187 __ Push(info->scope()->GetScopeInfo()); | 190 __ Push(info->scope()->GetScopeInfo()); |
| 188 __ CallRuntime(Runtime::kNewGlobalContext, 2); | 191 __ CallRuntime(Runtime::kNewGlobalContext, 2); |
| 189 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 192 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 190 FastNewContextStub stub(heap_slots); | 193 FastNewContextStub stub(heap_slots); |
| 191 __ CallStub(&stub); | 194 __ CallStub(&stub); |
| 192 } else { | 195 } else { |
| 196 __ push(rdi); |
| 193 __ CallRuntime(Runtime::kNewFunctionContext, 1); | 197 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
| 194 } | 198 } |
| 195 function_in_register = false; | 199 function_in_register = false; |
| 196 // Context is returned in both rax and rsi. It replaces the context | 200 // Context is returned in rax. It replaces the context passed to us. |
| 197 // passed to us. It's saved in the stack and kept live in rsi. | 201 // It's saved in the stack and kept live in rsi. |
| 198 __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); | 202 __ movp(rsi, rax); |
| 203 __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rax); |
| 199 | 204 |
| 200 // Copy any necessary parameters into the context. | 205 // Copy any necessary parameters into the context. |
| 201 int num_parameters = info->scope()->num_parameters(); | 206 int num_parameters = info->scope()->num_parameters(); |
| 202 for (int i = 0; i < num_parameters; i++) { | 207 for (int i = 0; i < num_parameters; i++) { |
| 203 Variable* var = scope()->parameter(i); | 208 Variable* var = scope()->parameter(i); |
| 204 if (var->IsContextSlot()) { | 209 if (var->IsContextSlot()) { |
| 205 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 210 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 206 (num_parameters - 1 - i) * kPointerSize; | 211 (num_parameters - 1 - i) * kPointerSize; |
| 207 // Load parameter from stack. | 212 // Load parameter from stack. |
| 208 __ movp(rax, Operand(rbp, parameter_offset)); | 213 __ movp(rax, Operand(rbp, parameter_offset)); |
| (...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 629 if (false_label_ != fall_through_) __ jmp(false_label_); | 634 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 630 } | 635 } |
| 631 } | 636 } |
| 632 | 637 |
| 633 | 638 |
| 634 void FullCodeGenerator::DoTest(Expression* condition, | 639 void FullCodeGenerator::DoTest(Expression* condition, |
| 635 Label* if_true, | 640 Label* if_true, |
| 636 Label* if_false, | 641 Label* if_false, |
| 637 Label* fall_through) { | 642 Label* fall_through) { |
| 638 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); | 643 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); |
| 639 CallIC(ic, NOT_CONTEXTUAL, condition->test_id()); | 644 CallIC(ic, condition->test_id()); |
| 640 __ testq(result_register(), result_register()); | 645 __ testq(result_register(), result_register()); |
| 641 // The stub returns nonzero for true. | 646 // The stub returns nonzero for true. |
| 642 Split(not_zero, if_true, if_false, fall_through); | 647 Split(not_zero, if_true, if_false, fall_through); |
| 643 } | 648 } |
| 644 | 649 |
| 645 | 650 |
| 646 void FullCodeGenerator::Split(Condition cc, | 651 void FullCodeGenerator::Split(Condition cc, |
| 647 Label* if_true, | 652 Label* if_true, |
| 648 Label* if_false, | 653 Label* if_false, |
| 649 Label* fall_through) { | 654 Label* fall_through) { |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 982 __ cmpq(rdx, rax); | 987 __ cmpq(rdx, rax); |
| 983 __ j(not_equal, &next_test); | 988 __ j(not_equal, &next_test); |
| 984 __ Drop(1); // Switch value is no longer needed. | 989 __ Drop(1); // Switch value is no longer needed. |
| 985 __ jmp(clause->body_target()); | 990 __ jmp(clause->body_target()); |
| 986 __ bind(&slow_case); | 991 __ bind(&slow_case); |
| 987 } | 992 } |
| 988 | 993 |
| 989 // Record position before stub call for type feedback. | 994 // Record position before stub call for type feedback. |
| 990 SetSourcePosition(clause->position()); | 995 SetSourcePosition(clause->position()); |
| 991 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); | 996 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); |
| 992 CallIC(ic, NOT_CONTEXTUAL, clause->CompareId()); | 997 CallIC(ic, clause->CompareId()); |
| 993 patch_site.EmitPatchInfo(); | 998 patch_site.EmitPatchInfo(); |
| 994 | 999 |
| 995 Label skip; | 1000 Label skip; |
| 996 __ jmp(&skip, Label::kNear); | 1001 __ jmp(&skip, Label::kNear); |
| 997 PrepareForBailout(clause, TOS_REG); | 1002 PrepareForBailout(clause, TOS_REG); |
| 998 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 1003 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 999 __ j(not_equal, &next_test); | 1004 __ j(not_equal, &next_test); |
| 1000 __ Drop(1); | 1005 __ Drop(1); |
| 1001 __ jmp(clause->body_target()); | 1006 __ jmp(clause->body_target()); |
| 1002 __ bind(&skip); | 1007 __ bind(&skip); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1026 VisitStatements(clause->statements()); | 1031 VisitStatements(clause->statements()); |
| 1027 } | 1032 } |
| 1028 | 1033 |
| 1029 __ bind(nested_statement.break_label()); | 1034 __ bind(nested_statement.break_label()); |
| 1030 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); | 1035 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 1031 } | 1036 } |
| 1032 | 1037 |
| 1033 | 1038 |
| 1034 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 1039 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 1035 Comment cmnt(masm_, "[ ForInStatement"); | 1040 Comment cmnt(masm_, "[ ForInStatement"); |
| 1041 int slot = stmt->ForInFeedbackSlot(); |
| 1036 SetStatementPosition(stmt); | 1042 SetStatementPosition(stmt); |
| 1037 | 1043 |
| 1038 Label loop, exit; | 1044 Label loop, exit; |
| 1039 ForIn loop_statement(this, stmt); | 1045 ForIn loop_statement(this, stmt); |
| 1040 increment_loop_depth(); | 1046 increment_loop_depth(); |
| 1041 | 1047 |
| 1042 // Get the object to enumerate over. If the object is null or undefined, skip | 1048 // Get the object to enumerate over. If the object is null or undefined, skip |
| 1043 // over the loop. See ECMA-262 version 5, section 12.6.4. | 1049 // over the loop. See ECMA-262 version 5, section 12.6.4. |
| 1044 VisitForAccumulatorValue(stmt->enumerable()); | 1050 VisitForAccumulatorValue(stmt->enumerable()); |
| 1045 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 1051 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1114 __ jmp(&loop); | 1120 __ jmp(&loop); |
| 1115 | 1121 |
| 1116 __ bind(&no_descriptors); | 1122 __ bind(&no_descriptors); |
| 1117 __ addq(rsp, Immediate(kPointerSize)); | 1123 __ addq(rsp, Immediate(kPointerSize)); |
| 1118 __ jmp(&exit); | 1124 __ jmp(&exit); |
| 1119 | 1125 |
| 1120 // We got a fixed array in register rax. Iterate through that. | 1126 // We got a fixed array in register rax. Iterate through that. |
| 1121 Label non_proxy; | 1127 Label non_proxy; |
| 1122 __ bind(&fixed_array); | 1128 __ bind(&fixed_array); |
| 1123 | 1129 |
| 1124 Handle<Cell> cell = isolate()->factory()->NewCell( | 1130 Handle<Object> feedback = Handle<Object>( |
| 1125 Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), | 1131 Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker), |
| 1126 isolate())); | 1132 isolate()); |
| 1127 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); | 1133 StoreFeedbackVectorSlot(slot, feedback); |
| 1128 __ Move(rbx, cell); | |
| 1129 __ Move(FieldOperand(rbx, Cell::kValueOffset), | |
| 1130 Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker)); | |
| 1131 | 1134 |
| 1135 // No need for a write barrier, we are storing a Smi in the feedback vector. |
| 1136 __ Move(rbx, FeedbackVector()); |
| 1137 __ Move(FieldOperand(rbx, FixedArray::OffsetOfElementAt(slot)), |
| 1138 Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker)); |
| 1132 __ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check | 1139 __ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check |
| 1133 __ movp(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object | 1140 __ movp(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object |
| 1134 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 1141 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 1135 __ CmpObjectType(rcx, LAST_JS_PROXY_TYPE, rcx); | 1142 __ CmpObjectType(rcx, LAST_JS_PROXY_TYPE, rcx); |
| 1136 __ j(above, &non_proxy); | 1143 __ j(above, &non_proxy); |
| 1137 __ Move(rbx, Smi::FromInt(0)); // Zero indicates proxy | 1144 __ Move(rbx, Smi::FromInt(0)); // Zero indicates proxy |
| 1138 __ bind(&non_proxy); | 1145 __ bind(&non_proxy); |
| 1139 __ push(rbx); // Smi | 1146 __ push(rbx); // Smi |
| 1140 __ push(rax); // Array | 1147 __ push(rax); // Array |
| 1141 __ movp(rax, FieldOperand(rax, FixedArray::kLengthOffset)); | 1148 __ movp(rax, FieldOperand(rax, FixedArray::kLengthOffset)); |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1430 | 1437 |
| 1431 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1438 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
| 1432 // Record position before possible IC call. | 1439 // Record position before possible IC call. |
| 1433 SetSourcePosition(proxy->position()); | 1440 SetSourcePosition(proxy->position()); |
| 1434 Variable* var = proxy->var(); | 1441 Variable* var = proxy->var(); |
| 1435 | 1442 |
| 1436 // Three cases: global variables, lookup variables, and all other types of | 1443 // Three cases: global variables, lookup variables, and all other types of |
| 1437 // variables. | 1444 // variables. |
| 1438 switch (var->location()) { | 1445 switch (var->location()) { |
| 1439 case Variable::UNALLOCATED: { | 1446 case Variable::UNALLOCATED: { |
| 1440 Comment cmnt(masm_, "Global variable"); | 1447 Comment cmnt(masm_, "[ Global variable"); |
| 1441 // Use inline caching. Variable name is passed in rcx and the global | 1448 // Use inline caching. Variable name is passed in rcx and the global |
| 1442 // object on the stack. | 1449 // object on the stack. |
| 1443 __ Move(rcx, var->name()); | 1450 __ Move(rcx, var->name()); |
| 1444 __ movp(rax, GlobalObjectOperand()); | 1451 __ movp(rax, GlobalObjectOperand()); |
| 1445 CallLoadIC(CONTEXTUAL); | 1452 CallLoadIC(CONTEXTUAL); |
| 1446 context()->Plug(rax); | 1453 context()->Plug(rax); |
| 1447 break; | 1454 break; |
| 1448 } | 1455 } |
| 1449 | 1456 |
| 1450 case Variable::PARAMETER: | 1457 case Variable::PARAMETER: |
| 1451 case Variable::LOCAL: | 1458 case Variable::LOCAL: |
| 1452 case Variable::CONTEXT: { | 1459 case Variable::CONTEXT: { |
| 1453 Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot"); | 1460 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context slot" |
| 1461 : "[ Stack slot"); |
| 1454 if (var->binding_needs_init()) { | 1462 if (var->binding_needs_init()) { |
| 1455 // var->scope() may be NULL when the proxy is located in eval code and | 1463 // var->scope() may be NULL when the proxy is located in eval code and |
| 1456 // refers to a potential outside binding. Currently those bindings are | 1464 // refers to a potential outside binding. Currently those bindings are |
| 1457 // always looked up dynamically, i.e. in that case | 1465 // always looked up dynamically, i.e. in that case |
| 1458 // var->location() == LOOKUP. | 1466 // var->location() == LOOKUP. |
| 1459 // always holds. | 1467 // always holds. |
| 1460 ASSERT(var->scope() != NULL); | 1468 ASSERT(var->scope() != NULL); |
| 1461 | 1469 |
| 1462 // Check if the binding really needs an initialization check. The check | 1470 // Check if the binding really needs an initialization check. The check |
| 1463 // can be skipped in the following situation: we have a LET or CONST | 1471 // can be skipped in the following situation: we have a LET or CONST |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1505 __ bind(&done); | 1513 __ bind(&done); |
| 1506 context()->Plug(rax); | 1514 context()->Plug(rax); |
| 1507 break; | 1515 break; |
| 1508 } | 1516 } |
| 1509 } | 1517 } |
| 1510 context()->Plug(var); | 1518 context()->Plug(var); |
| 1511 break; | 1519 break; |
| 1512 } | 1520 } |
| 1513 | 1521 |
| 1514 case Variable::LOOKUP: { | 1522 case Variable::LOOKUP: { |
| 1523 Comment cmnt(masm_, "[ Lookup slot"); |
| 1515 Label done, slow; | 1524 Label done, slow; |
| 1516 // Generate code for loading from variables potentially shadowed | 1525 // Generate code for loading from variables potentially shadowed |
| 1517 // by eval-introduced variables. | 1526 // by eval-introduced variables. |
| 1518 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); | 1527 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1519 __ bind(&slow); | 1528 __ bind(&slow); |
| 1520 Comment cmnt(masm_, "Lookup slot"); | |
| 1521 __ push(rsi); // Context. | 1529 __ push(rsi); // Context. |
| 1522 __ Push(var->name()); | 1530 __ Push(var->name()); |
| 1523 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1531 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1524 __ bind(&done); | 1532 __ bind(&done); |
| 1525 context()->Plug(rax); | 1533 context()->Plug(rax); |
| 1526 break; | 1534 break; |
| 1527 } | 1535 } |
| 1528 } | 1536 } |
| 1529 } | 1537 } |
| 1530 | 1538 |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1649 UNREACHABLE(); | 1657 UNREACHABLE(); |
| 1650 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1658 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 1651 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 1659 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 1652 // Fall through. | 1660 // Fall through. |
| 1653 case ObjectLiteral::Property::COMPUTED: | 1661 case ObjectLiteral::Property::COMPUTED: |
| 1654 if (key->value()->IsInternalizedString()) { | 1662 if (key->value()->IsInternalizedString()) { |
| 1655 if (property->emit_store()) { | 1663 if (property->emit_store()) { |
| 1656 VisitForAccumulatorValue(value); | 1664 VisitForAccumulatorValue(value); |
| 1657 __ Move(rcx, key->value()); | 1665 __ Move(rcx, key->value()); |
| 1658 __ movp(rdx, Operand(rsp, 0)); | 1666 __ movp(rdx, Operand(rsp, 0)); |
| 1659 CallStoreIC(NOT_CONTEXTUAL, key->LiteralFeedbackId()); | 1667 CallStoreIC(key->LiteralFeedbackId()); |
| 1660 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1668 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1661 } else { | 1669 } else { |
| 1662 VisitForEffect(value); | 1670 VisitForEffect(value); |
| 1663 } | 1671 } |
| 1664 break; | 1672 break; |
| 1665 } | 1673 } |
| 1666 __ push(Operand(rsp, 0)); // Duplicate receiver. | 1674 __ push(Operand(rsp, 0)); // Duplicate receiver. |
| 1667 VisitForStackValue(key); | 1675 VisitForStackValue(key); |
| 1668 VisitForStackValue(value); | 1676 VisitForStackValue(value); |
| 1669 if (property->emit_store()) { | 1677 if (property->emit_store()) { |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2061 | 2069 |
| 2062 // receiver = iter; f = 'next'; arg = received; | 2070 // receiver = iter; f = 'next'; arg = received; |
| 2063 __ bind(&l_next); | 2071 __ bind(&l_next); |
| 2064 __ LoadRoot(rcx, Heap::knext_stringRootIndex); // "next" | 2072 __ LoadRoot(rcx, Heap::knext_stringRootIndex); // "next" |
| 2065 __ push(rcx); | 2073 __ push(rcx); |
| 2066 __ push(Operand(rsp, 2 * kPointerSize)); // iter | 2074 __ push(Operand(rsp, 2 * kPointerSize)); // iter |
| 2067 __ push(rax); // received | 2075 __ push(rax); // received |
| 2068 | 2076 |
| 2069 // result = receiver[f](arg); | 2077 // result = receiver[f](arg); |
| 2070 __ bind(&l_call); | 2078 __ bind(&l_call); |
| 2071 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); | 2079 __ movp(rdx, Operand(rsp, kPointerSize)); |
| 2072 CallIC(ic); | 2080 __ movp(rax, Operand(rsp, 2 * kPointerSize)); |
| 2081 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2082 CallIC(ic, TypeFeedbackId::None()); |
| 2083 __ movp(rdi, rax); |
| 2084 __ movp(Operand(rsp, 2 * kPointerSize), rdi); |
| 2085 CallFunctionStub stub(1, CALL_AS_METHOD); |
| 2086 __ CallStub(&stub); |
| 2087 |
| 2073 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2088 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2074 __ Drop(1); // The key is still on the stack; drop it. | 2089 __ Drop(1); // The function is still on the stack; drop it. |
| 2075 | 2090 |
| 2076 // if (!result.done) goto l_try; | 2091 // if (!result.done) goto l_try; |
| 2077 __ bind(&l_loop); | 2092 __ bind(&l_loop); |
| 2078 __ push(rax); // save result | 2093 __ push(rax); // save result |
| 2079 __ LoadRoot(rcx, Heap::kdone_stringRootIndex); // "done" | 2094 __ LoadRoot(rcx, Heap::kdone_stringRootIndex); // "done" |
| 2080 CallLoadIC(NOT_CONTEXTUAL); // result.done in rax | 2095 CallLoadIC(NOT_CONTEXTUAL); // result.done in rax |
| 2081 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); | 2096 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); |
| 2082 CallIC(bool_ic); | 2097 CallIC(bool_ic); |
| 2083 __ testq(result_register(), result_register()); | 2098 __ testq(result_register(), result_register()); |
| 2084 __ j(zero, &l_try); | 2099 __ j(zero, &l_try); |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2248 SetSourcePosition(prop->position()); | 2263 SetSourcePosition(prop->position()); |
| 2249 Literal* key = prop->key()->AsLiteral(); | 2264 Literal* key = prop->key()->AsLiteral(); |
| 2250 __ Move(rcx, key->value()); | 2265 __ Move(rcx, key->value()); |
| 2251 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); | 2266 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); |
| 2252 } | 2267 } |
| 2253 | 2268 |
| 2254 | 2269 |
| 2255 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 2270 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 2256 SetSourcePosition(prop->position()); | 2271 SetSourcePosition(prop->position()); |
| 2257 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 2272 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2258 CallIC(ic, NOT_CONTEXTUAL, prop->PropertyFeedbackId()); | 2273 CallIC(ic, prop->PropertyFeedbackId()); |
| 2259 } | 2274 } |
| 2260 | 2275 |
| 2261 | 2276 |
| 2262 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, | 2277 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, |
| 2263 Token::Value op, | 2278 Token::Value op, |
| 2264 OverwriteMode mode, | 2279 OverwriteMode mode, |
| 2265 Expression* left, | 2280 Expression* left, |
| 2266 Expression* right) { | 2281 Expression* right) { |
| 2267 // Do combined smi check of the operands. Left operand is on the | 2282 // Do combined smi check of the operands. Left operand is on the |
| 2268 // stack (popped into rdx). Right operand is in rax but moved into | 2283 // stack (popped into rdx). Right operand is in rax but moved into |
| 2269 // rcx to make the shifts easier. | 2284 // rcx to make the shifts easier. |
| 2270 Label done, stub_call, smi_case; | 2285 Label done, stub_call, smi_case; |
| 2271 __ pop(rdx); | 2286 __ pop(rdx); |
| 2272 __ movp(rcx, rax); | 2287 __ movp(rcx, rax); |
| 2273 __ or_(rax, rdx); | 2288 __ or_(rax, rdx); |
| 2274 JumpPatchSite patch_site(masm_); | 2289 JumpPatchSite patch_site(masm_); |
| 2275 patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear); | 2290 patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear); |
| 2276 | 2291 |
| 2277 __ bind(&stub_call); | 2292 __ bind(&stub_call); |
| 2278 __ movp(rax, rcx); | 2293 __ movp(rax, rcx); |
| 2279 BinaryOpICStub stub(op, mode); | 2294 BinaryOpICStub stub(op, mode); |
| 2280 CallIC(stub.GetCode(isolate()), NOT_CONTEXTUAL, | 2295 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId()); |
| 2281 expr->BinaryOperationFeedbackId()); | |
| 2282 patch_site.EmitPatchInfo(); | 2296 patch_site.EmitPatchInfo(); |
| 2283 __ jmp(&done, Label::kNear); | 2297 __ jmp(&done, Label::kNear); |
| 2284 | 2298 |
| 2285 __ bind(&smi_case); | 2299 __ bind(&smi_case); |
| 2286 switch (op) { | 2300 switch (op) { |
| 2287 case Token::SAR: | 2301 case Token::SAR: |
| 2288 __ SmiShiftArithmeticRight(rax, rdx, rcx); | 2302 __ SmiShiftArithmeticRight(rax, rdx, rcx); |
| 2289 break; | 2303 break; |
| 2290 case Token::SHL: | 2304 case Token::SHL: |
| 2291 __ SmiShiftLeft(rax, rdx, rcx); | 2305 __ SmiShiftLeft(rax, rdx, rcx); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2320 context()->Plug(rax); | 2334 context()->Plug(rax); |
| 2321 } | 2335 } |
| 2322 | 2336 |
| 2323 | 2337 |
| 2324 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, | 2338 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, |
| 2325 Token::Value op, | 2339 Token::Value op, |
| 2326 OverwriteMode mode) { | 2340 OverwriteMode mode) { |
| 2327 __ pop(rdx); | 2341 __ pop(rdx); |
| 2328 BinaryOpICStub stub(op, mode); | 2342 BinaryOpICStub stub(op, mode); |
| 2329 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. | 2343 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
| 2330 CallIC(stub.GetCode(isolate()), NOT_CONTEXTUAL, | 2344 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId()); |
| 2331 expr->BinaryOperationFeedbackId()); | |
| 2332 patch_site.EmitPatchInfo(); | 2345 patch_site.EmitPatchInfo(); |
| 2333 context()->Plug(rax); | 2346 context()->Plug(rax); |
| 2334 } | 2347 } |
| 2335 | 2348 |
| 2336 | 2349 |
| 2337 void FullCodeGenerator::EmitAssignment(Expression* expr) { | 2350 void FullCodeGenerator::EmitAssignment(Expression* expr) { |
| 2338 // Invalid left-hand sides are rewritten by the parser to have a 'throw | 2351 // Invalid left-hand sides are rewritten by the parser to have a 'throw |
| 2339 // ReferenceError' on the left-hand side. | 2352 // ReferenceError' on the left-hand side. |
| 2340 if (!expr->IsValidLeftHandSide()) { | 2353 if (!expr->IsValidLeftHandSide()) { |
| 2341 VisitForEffect(expr); | 2354 VisitForEffect(expr); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2359 EffectContext context(this); | 2372 EffectContext context(this); |
| 2360 EmitVariableAssignment(var, Token::ASSIGN); | 2373 EmitVariableAssignment(var, Token::ASSIGN); |
| 2361 break; | 2374 break; |
| 2362 } | 2375 } |
| 2363 case NAMED_PROPERTY: { | 2376 case NAMED_PROPERTY: { |
| 2364 __ push(rax); // Preserve value. | 2377 __ push(rax); // Preserve value. |
| 2365 VisitForAccumulatorValue(prop->obj()); | 2378 VisitForAccumulatorValue(prop->obj()); |
| 2366 __ movp(rdx, rax); | 2379 __ movp(rdx, rax); |
| 2367 __ pop(rax); // Restore value. | 2380 __ pop(rax); // Restore value. |
| 2368 __ Move(rcx, prop->key()->AsLiteral()->value()); | 2381 __ Move(rcx, prop->key()->AsLiteral()->value()); |
| 2369 CallStoreIC(NOT_CONTEXTUAL); | 2382 CallStoreIC(); |
| 2370 break; | 2383 break; |
| 2371 } | 2384 } |
| 2372 case KEYED_PROPERTY: { | 2385 case KEYED_PROPERTY: { |
| 2373 __ push(rax); // Preserve value. | 2386 __ push(rax); // Preserve value. |
| 2374 VisitForStackValue(prop->obj()); | 2387 VisitForStackValue(prop->obj()); |
| 2375 VisitForAccumulatorValue(prop->key()); | 2388 VisitForAccumulatorValue(prop->key()); |
| 2376 __ movp(rcx, rax); | 2389 __ movp(rcx, rax); |
| 2377 __ pop(rdx); | 2390 __ pop(rdx); |
| 2378 __ pop(rax); // Restore value. | 2391 __ pop(rax); // Restore value. |
| 2379 Handle<Code> ic = is_classic_mode() | 2392 Handle<Code> ic = is_classic_mode() |
| 2380 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2393 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2381 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2394 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2382 CallIC(ic); | 2395 CallIC(ic); |
| 2383 break; | 2396 break; |
| 2384 } | 2397 } |
| 2385 } | 2398 } |
| 2386 context()->Plug(rax); | 2399 context()->Plug(rax); |
| 2387 } | 2400 } |
| 2388 | 2401 |
| 2389 | 2402 |
| 2403 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( |
| 2404 Variable* var, MemOperand location) { |
| 2405 __ movp(location, rax); |
| 2406 if (var->IsContextSlot()) { |
| 2407 __ movp(rdx, rax); |
| 2408 __ RecordWriteContextSlot( |
| 2409 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); |
| 2410 } |
| 2411 } |
| 2412 |
| 2413 |
| 2414 void FullCodeGenerator::EmitCallStoreContextSlot( |
| 2415 Handle<String> name, LanguageMode mode) { |
| 2416 __ push(rax); // Value. |
| 2417 __ push(rsi); // Context. |
| 2418 __ Push(name); |
| 2419 __ Push(Smi::FromInt(mode)); |
| 2420 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
| 2421 } |
| 2422 |
| 2423 |
| 2390 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 2424 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 2391 Token::Value op) { | 2425 Token::Value op) { |
| 2392 if (var->IsUnallocated()) { | 2426 if (var->IsUnallocated()) { |
| 2393 // Global var, const, or let. | 2427 // Global var, const, or let. |
| 2394 __ Move(rcx, var->name()); | 2428 __ Move(rcx, var->name()); |
| 2395 __ movp(rdx, GlobalObjectOperand()); | 2429 __ movp(rdx, GlobalObjectOperand()); |
| 2396 CallStoreIC(CONTEXTUAL); | 2430 CallStoreIC(); |
| 2431 |
| 2397 } else if (op == Token::INIT_CONST) { | 2432 } else if (op == Token::INIT_CONST) { |
| 2398 // Const initializers need a write barrier. | 2433 // Const initializers need a write barrier. |
| 2399 ASSERT(!var->IsParameter()); // No const parameters. | 2434 ASSERT(!var->IsParameter()); // No const parameters. |
| 2400 if (var->IsStackLocal()) { | 2435 if (var->IsLookupSlot()) { |
| 2401 Label skip; | |
| 2402 __ movp(rdx, StackOperand(var)); | |
| 2403 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | |
| 2404 __ j(not_equal, &skip); | |
| 2405 __ movp(StackOperand(var), rax); | |
| 2406 __ bind(&skip); | |
| 2407 } else { | |
| 2408 ASSERT(var->IsContextSlot() || var->IsLookupSlot()); | |
| 2409 // Like var declarations, const declarations are hoisted to function | |
| 2410 // scope. However, unlike var initializers, const initializers are | |
| 2411 // able to drill a hole to that function context, even from inside a | |
| 2412 // 'with' context. We thus bypass the normal static scope lookup for | |
| 2413 // var->IsContextSlot(). | |
| 2414 __ push(rax); | 2436 __ push(rax); |
| 2415 __ push(rsi); | 2437 __ push(rsi); |
| 2416 __ Push(var->name()); | 2438 __ Push(var->name()); |
| 2417 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 2439 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 2440 } else { |
| 2441 ASSERT(var->IsStackLocal() || var->IsContextSlot()); |
| 2442 Label skip; |
| 2443 MemOperand location = VarOperand(var, rcx); |
| 2444 __ movp(rdx, location); |
| 2445 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 2446 __ j(not_equal, &skip); |
| 2447 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2448 __ bind(&skip); |
| 2418 } | 2449 } |
| 2419 | 2450 |
| 2420 } else if (var->mode() == LET && op != Token::INIT_LET) { | 2451 } else if (var->mode() == LET && op != Token::INIT_LET) { |
| 2421 // Non-initializing assignment to let variable needs a write barrier. | 2452 // Non-initializing assignment to let variable needs a write barrier. |
| 2422 if (var->IsLookupSlot()) { | 2453 if (var->IsLookupSlot()) { |
| 2423 __ push(rax); // Value. | 2454 EmitCallStoreContextSlot(var->name(), language_mode()); |
| 2424 __ push(rsi); // Context. | |
| 2425 __ Push(var->name()); | |
| 2426 __ Push(Smi::FromInt(language_mode())); | |
| 2427 __ CallRuntime(Runtime::kStoreContextSlot, 4); | |
| 2428 } else { | 2455 } else { |
| 2429 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2456 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
| 2430 Label assign; | 2457 Label assign; |
| 2431 MemOperand location = VarOperand(var, rcx); | 2458 MemOperand location = VarOperand(var, rcx); |
| 2432 __ movp(rdx, location); | 2459 __ movp(rdx, location); |
| 2433 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | 2460 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 2434 __ j(not_equal, &assign, Label::kNear); | 2461 __ j(not_equal, &assign, Label::kNear); |
| 2435 __ Push(var->name()); | 2462 __ Push(var->name()); |
| 2436 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 2463 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 2437 __ bind(&assign); | 2464 __ bind(&assign); |
| 2438 __ movp(location, rax); | 2465 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2439 if (var->IsContextSlot()) { | |
| 2440 __ movp(rdx, rax); | |
| 2441 __ RecordWriteContextSlot( | |
| 2442 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); | |
| 2443 } | |
| 2444 } | 2466 } |
| 2445 | 2467 |
| 2446 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { | 2468 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { |
| 2447 // Assignment to var or initializing assignment to let/const | 2469 // Assignment to var or initializing assignment to let/const |
| 2448 // in harmony mode. | 2470 // in harmony mode. |
| 2449 if (var->IsStackAllocated() || var->IsContextSlot()) { | 2471 if (var->IsLookupSlot()) { |
| 2472 EmitCallStoreContextSlot(var->name(), language_mode()); |
| 2473 } else { |
| 2474 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
| 2450 MemOperand location = VarOperand(var, rcx); | 2475 MemOperand location = VarOperand(var, rcx); |
| 2451 if (generate_debug_code_ && op == Token::INIT_LET) { | 2476 if (generate_debug_code_ && op == Token::INIT_LET) { |
| 2452 // Check for an uninitialized let binding. | 2477 // Check for an uninitialized let binding. |
| 2453 __ movp(rdx, location); | 2478 __ movp(rdx, location); |
| 2454 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | 2479 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 2455 __ Check(equal, kLetBindingReInitialization); | 2480 __ Check(equal, kLetBindingReInitialization); |
| 2456 } | 2481 } |
| 2457 // Perform the assignment. | 2482 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2458 __ movp(location, rax); | |
| 2459 if (var->IsContextSlot()) { | |
| 2460 __ movp(rdx, rax); | |
| 2461 __ RecordWriteContextSlot( | |
| 2462 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); | |
| 2463 } | |
| 2464 } else { | |
| 2465 ASSERT(var->IsLookupSlot()); | |
| 2466 __ push(rax); // Value. | |
| 2467 __ push(rsi); // Context. | |
| 2468 __ Push(var->name()); | |
| 2469 __ Push(Smi::FromInt(language_mode())); | |
| 2470 __ CallRuntime(Runtime::kStoreContextSlot, 4); | |
| 2471 } | 2483 } |
| 2472 } | 2484 } |
| 2473 // Non-initializing assignments to consts are ignored. | 2485 // Non-initializing assignments to consts are ignored. |
| 2474 } | 2486 } |
| 2475 | 2487 |
| 2476 | 2488 |
| 2477 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 2489 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 2478 // Assignment to a property, using a named store IC. | 2490 // Assignment to a property, using a named store IC. |
| 2479 Property* prop = expr->target()->AsProperty(); | 2491 Property* prop = expr->target()->AsProperty(); |
| 2480 ASSERT(prop != NULL); | 2492 ASSERT(prop != NULL); |
| 2481 ASSERT(prop->key()->AsLiteral() != NULL); | 2493 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2482 | 2494 |
| 2483 // Record source code position before IC call. | 2495 // Record source code position before IC call. |
| 2484 SetSourcePosition(expr->position()); | 2496 SetSourcePosition(expr->position()); |
| 2485 __ Move(rcx, prop->key()->AsLiteral()->value()); | 2497 __ Move(rcx, prop->key()->AsLiteral()->value()); |
| 2486 __ pop(rdx); | 2498 __ pop(rdx); |
| 2487 CallStoreIC(NOT_CONTEXTUAL, expr->AssignmentFeedbackId()); | 2499 CallStoreIC(expr->AssignmentFeedbackId()); |
| 2488 | 2500 |
| 2489 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2501 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2490 context()->Plug(rax); | 2502 context()->Plug(rax); |
| 2491 } | 2503 } |
| 2492 | 2504 |
| 2493 | 2505 |
| 2494 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 2506 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
| 2495 // Assignment to a property, using a keyed store IC. | 2507 // Assignment to a property, using a keyed store IC. |
| 2496 | 2508 |
| 2497 __ pop(rcx); | 2509 __ pop(rcx); |
| 2498 __ pop(rdx); | 2510 __ pop(rdx); |
| 2499 // Record source code position before IC call. | 2511 // Record source code position before IC call. |
| 2500 SetSourcePosition(expr->position()); | 2512 SetSourcePosition(expr->position()); |
| 2501 Handle<Code> ic = is_classic_mode() | 2513 Handle<Code> ic = is_classic_mode() |
| 2502 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2514 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2503 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2515 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2504 CallIC(ic, NOT_CONTEXTUAL, expr->AssignmentFeedbackId()); | 2516 CallIC(ic, expr->AssignmentFeedbackId()); |
| 2505 | 2517 |
| 2506 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2518 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2507 context()->Plug(rax); | 2519 context()->Plug(rax); |
| 2508 } | 2520 } |
| 2509 | 2521 |
| 2510 | 2522 |
| 2511 void FullCodeGenerator::VisitProperty(Property* expr) { | 2523 void FullCodeGenerator::VisitProperty(Property* expr) { |
| 2512 Comment cmnt(masm_, "[ Property"); | 2524 Comment cmnt(masm_, "[ Property"); |
| 2513 Expression* key = expr->key(); | 2525 Expression* key = expr->key(); |
| 2514 | 2526 |
| 2515 if (key->IsPropertyName()) { | 2527 if (key->IsPropertyName()) { |
| 2516 VisitForAccumulatorValue(expr->obj()); | 2528 VisitForAccumulatorValue(expr->obj()); |
| 2517 EmitNamedPropertyLoad(expr); | 2529 EmitNamedPropertyLoad(expr); |
| 2518 PrepareForBailoutForId(expr->LoadId(), TOS_REG); | 2530 PrepareForBailoutForId(expr->LoadId(), TOS_REG); |
| 2519 context()->Plug(rax); | 2531 context()->Plug(rax); |
| 2520 } else { | 2532 } else { |
| 2521 VisitForStackValue(expr->obj()); | 2533 VisitForStackValue(expr->obj()); |
| 2522 VisitForAccumulatorValue(expr->key()); | 2534 VisitForAccumulatorValue(expr->key()); |
| 2523 __ pop(rdx); | 2535 __ pop(rdx); |
| 2524 EmitKeyedPropertyLoad(expr); | 2536 EmitKeyedPropertyLoad(expr); |
| 2525 context()->Plug(rax); | 2537 context()->Plug(rax); |
| 2526 } | 2538 } |
| 2527 } | 2539 } |
| 2528 | 2540 |
| 2529 | 2541 |
| 2530 void FullCodeGenerator::CallIC(Handle<Code> code, | 2542 void FullCodeGenerator::CallIC(Handle<Code> code, |
| 2531 ContextualMode mode, | |
| 2532 TypeFeedbackId ast_id) { | 2543 TypeFeedbackId ast_id) { |
| 2533 ic_total_count_++; | 2544 ic_total_count_++; |
| 2534 ASSERT(mode != CONTEXTUAL || ast_id.IsNone()); | |
| 2535 __ call(code, RelocInfo::CODE_TARGET, ast_id); | 2545 __ call(code, RelocInfo::CODE_TARGET, ast_id); |
| 2536 } | 2546 } |
| 2537 | 2547 |
| 2538 | 2548 |
| 2539 void FullCodeGenerator::EmitCallWithIC(Call* expr, | 2549 // Code common for calls using the IC. |
| 2540 Handle<Object> name, | 2550 void FullCodeGenerator::EmitCallWithIC(Call* expr) { |
| 2541 ContextualMode mode) { | 2551 Expression* callee = expr->expression(); |
| 2542 // Code common for calls using the IC. | |
| 2543 ZoneList<Expression*>* args = expr->arguments(); | 2552 ZoneList<Expression*>* args = expr->arguments(); |
| 2544 int arg_count = args->length(); | 2553 int arg_count = args->length(); |
| 2554 |
| 2555 CallFunctionFlags flags; |
| 2556 // Get the target function; |
| 2557 if (callee->IsVariableProxy()) { |
| 2558 { StackValueContext context(this); |
| 2559 EmitVariableLoad(callee->AsVariableProxy()); |
| 2560 PrepareForBailout(callee, NO_REGISTERS); |
| 2561 } |
| 2562 // Push undefined as receiver. This is patched in the method prologue if it |
| 2563 // is a classic mode method. |
| 2564 __ Push(isolate()->factory()->undefined_value()); |
| 2565 flags = NO_CALL_FUNCTION_FLAGS; |
| 2566 } else { |
| 2567 // Load the function from the receiver. |
| 2568 ASSERT(callee->IsProperty()); |
| 2569 __ movp(rax, Operand(rsp, 0)); |
| 2570 EmitNamedPropertyLoad(callee->AsProperty()); |
| 2571 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); |
| 2572 // Push the target function under the receiver. |
| 2573 __ push(Operand(rsp, 0)); |
| 2574 __ movp(Operand(rsp, kPointerSize), rax); |
| 2575 flags = CALL_AS_METHOD; |
| 2576 } |
| 2577 |
| 2578 // Load the arguments. |
| 2545 { PreservePositionScope scope(masm()->positions_recorder()); | 2579 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2546 for (int i = 0; i < arg_count; i++) { | 2580 for (int i = 0; i < arg_count; i++) { |
| 2547 VisitForStackValue(args->at(i)); | 2581 VisitForStackValue(args->at(i)); |
| 2548 } | 2582 } |
| 2549 __ Move(rcx, name); | |
| 2550 } | 2583 } |
| 2584 |
| 2551 // Record source position for debugger. | 2585 // Record source position for debugger. |
| 2552 SetSourcePosition(expr->position()); | 2586 SetSourcePosition(expr->position()); |
| 2553 // Call the IC initialization code. | 2587 CallFunctionStub stub(arg_count, flags); |
| 2554 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count); | 2588 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize)); |
| 2555 TypeFeedbackId ast_id = mode == CONTEXTUAL | 2589 __ CallStub(&stub); |
| 2556 ? TypeFeedbackId::None() | 2590 |
| 2557 : expr->CallFeedbackId(); | |
| 2558 CallIC(ic, mode, ast_id); | |
| 2559 RecordJSReturnSite(expr); | 2591 RecordJSReturnSite(expr); |
| 2592 |
| 2560 // Restore context register. | 2593 // Restore context register. |
| 2561 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2594 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2562 context()->Plug(rax); | 2595 |
| 2596 context()->DropAndPlug(1, rax); |
| 2563 } | 2597 } |
| 2564 | 2598 |
| 2565 | 2599 |
| 2600 // Common code for calls using the IC. |
| 2566 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 2601 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 2567 Expression* key) { | 2602 Expression* key) { |
| 2568 // Load the key. | 2603 // Load the key. |
| 2569 VisitForAccumulatorValue(key); | 2604 VisitForAccumulatorValue(key); |
| 2570 | 2605 |
| 2571 // Swap the name of the function and the receiver on the stack to follow | 2606 Expression* callee = expr->expression(); |
| 2572 // the calling convention for call ICs. | 2607 ZoneList<Expression*>* args = expr->arguments(); |
| 2573 __ pop(rcx); | 2608 int arg_count = args->length(); |
| 2574 __ push(rax); | 2609 |
| 2575 __ push(rcx); | 2610 // Load the function from the receiver. |
| 2611 ASSERT(callee->IsProperty()); |
| 2612 __ movp(rdx, Operand(rsp, 0)); |
| 2613 EmitKeyedPropertyLoad(callee->AsProperty()); |
| 2614 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); |
| 2615 |
| 2616 // Push the target function under the receiver. |
| 2617 __ push(Operand(rsp, 0)); |
| 2618 __ movp(Operand(rsp, kPointerSize), rax); |
| 2576 | 2619 |
| 2577 // Load the arguments. | 2620 // Load the arguments. |
| 2578 ZoneList<Expression*>* args = expr->arguments(); | |
| 2579 int arg_count = args->length(); | |
| 2580 { PreservePositionScope scope(masm()->positions_recorder()); | 2621 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2581 for (int i = 0; i < arg_count; i++) { | 2622 for (int i = 0; i < arg_count; i++) { |
| 2582 VisitForStackValue(args->at(i)); | 2623 VisitForStackValue(args->at(i)); |
| 2583 } | 2624 } |
| 2584 } | 2625 } |
| 2626 |
| 2585 // Record source position for debugger. | 2627 // Record source position for debugger. |
| 2586 SetSourcePosition(expr->position()); | 2628 SetSourcePosition(expr->position()); |
| 2587 // Call the IC initialization code. | 2629 CallFunctionStub stub(arg_count, CALL_AS_METHOD); |
| 2588 Handle<Code> ic = | 2630 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize)); |
| 2589 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); | 2631 __ CallStub(&stub); |
| 2590 __ movp(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key. | 2632 |
| 2591 CallIC(ic, NOT_CONTEXTUAL, expr->CallFeedbackId()); | |
| 2592 RecordJSReturnSite(expr); | 2633 RecordJSReturnSite(expr); |
| 2593 // Restore context register. | 2634 // Restore context register. |
| 2594 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2635 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2595 context()->DropAndPlug(1, rax); // Drop the key still on the stack. | 2636 |
| 2637 context()->DropAndPlug(1, rax); |
| 2596 } | 2638 } |
| 2597 | 2639 |
| 2598 | 2640 |
| 2599 void FullCodeGenerator::EmitCallWithStub(Call* expr) { | 2641 void FullCodeGenerator::EmitCallWithStub(Call* expr) { |
| 2600 // Code common for calls using the call stub. | 2642 // Code common for calls using the call stub. |
| 2601 ZoneList<Expression*>* args = expr->arguments(); | 2643 ZoneList<Expression*>* args = expr->arguments(); |
| 2602 int arg_count = args->length(); | 2644 int arg_count = args->length(); |
| 2603 { PreservePositionScope scope(masm()->positions_recorder()); | 2645 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2604 for (int i = 0; i < arg_count; i++) { | 2646 for (int i = 0; i < arg_count; i++) { |
| 2605 VisitForStackValue(args->at(i)); | 2647 VisitForStackValue(args->at(i)); |
| 2606 } | 2648 } |
| 2607 } | 2649 } |
| 2608 // Record source position for debugger. | 2650 // Record source position for debugger. |
| 2609 SetSourcePosition(expr->position()); | 2651 SetSourcePosition(expr->position()); |
| 2610 | 2652 |
| 2611 Handle<Object> uninitialized = | 2653 Handle<Object> uninitialized = |
| 2612 TypeFeedbackCells::UninitializedSentinel(isolate()); | 2654 TypeFeedbackInfo::UninitializedSentinel(isolate()); |
| 2613 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); | 2655 StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized); |
| 2614 RecordTypeFeedbackCell(expr->CallFeedbackId(), cell); | 2656 __ Move(rbx, FeedbackVector()); |
| 2615 __ Move(rbx, cell); | 2657 __ Move(rdx, Smi::FromInt(expr->CallFeedbackSlot())); |
| 2616 | 2658 |
| 2617 // Record call targets in unoptimized code. | 2659 // Record call targets in unoptimized code. |
| 2618 CallFunctionStub stub(arg_count, RECORD_CALL_TARGET); | 2660 CallFunctionStub stub(arg_count, RECORD_CALL_TARGET); |
| 2619 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize)); | 2661 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize)); |
| 2620 __ CallStub(&stub, expr->CallFeedbackId()); | 2662 __ CallStub(&stub); |
| 2621 RecordJSReturnSite(expr); | 2663 RecordJSReturnSite(expr); |
| 2622 // Restore context register. | 2664 // Restore context register. |
| 2623 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2665 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2624 // Discard the function left on TOS. | 2666 // Discard the function left on TOS. |
| 2625 context()->DropAndPlug(1, rax); | 2667 context()->DropAndPlug(1, rax); |
| 2626 } | 2668 } |
| 2627 | 2669 |
| 2628 | 2670 |
| 2629 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { | 2671 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { |
| 2630 // Push copy of the first argument or undefined if it doesn't exist. | 2672 // Push copy of the first argument or undefined if it doesn't exist. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2688 // Record source position for debugger. | 2730 // Record source position for debugger. |
| 2689 SetSourcePosition(expr->position()); | 2731 SetSourcePosition(expr->position()); |
| 2690 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); | 2732 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); |
| 2691 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize)); | 2733 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize)); |
| 2692 __ CallStub(&stub); | 2734 __ CallStub(&stub); |
| 2693 RecordJSReturnSite(expr); | 2735 RecordJSReturnSite(expr); |
| 2694 // Restore context register. | 2736 // Restore context register. |
| 2695 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2737 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2696 context()->DropAndPlug(1, rax); | 2738 context()->DropAndPlug(1, rax); |
| 2697 } else if (call_type == Call::GLOBAL_CALL) { | 2739 } else if (call_type == Call::GLOBAL_CALL) { |
| 2698 // Call to a global variable. Push global object as receiver for the | 2740 EmitCallWithIC(expr); |
| 2699 // call IC lookup. | 2741 |
| 2700 __ push(GlobalObjectOperand()); | |
| 2701 VariableProxy* proxy = callee->AsVariableProxy(); | |
| 2702 EmitCallWithIC(expr, proxy->name(), CONTEXTUAL); | |
| 2703 } else if (call_type == Call::LOOKUP_SLOT_CALL) { | 2742 } else if (call_type == Call::LOOKUP_SLOT_CALL) { |
| 2704 // Call to a lookup slot (dynamically introduced variable). | 2743 // Call to a lookup slot (dynamically introduced variable). |
| 2705 VariableProxy* proxy = callee->AsVariableProxy(); | 2744 VariableProxy* proxy = callee->AsVariableProxy(); |
| 2706 Label slow, done; | 2745 Label slow, done; |
| 2707 | 2746 |
| 2708 { PreservePositionScope scope(masm()->positions_recorder()); | 2747 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2709 // Generate code for loading from variables potentially shadowed by | 2748 // Generate code for loading from variables potentially shadowed by |
| 2710 // eval-introduced variables. | 2749 // eval-introduced variables. |
| 2711 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); | 2750 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); |
| 2712 } | 2751 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2735 | 2774 |
| 2736 // The receiver is either the global receiver or an object found by | 2775 // The receiver is either the global receiver or an object found by |
| 2737 // LoadContextSlot. | 2776 // LoadContextSlot. |
| 2738 EmitCallWithStub(expr); | 2777 EmitCallWithStub(expr); |
| 2739 } else if (call_type == Call::PROPERTY_CALL) { | 2778 } else if (call_type == Call::PROPERTY_CALL) { |
| 2740 Property* property = callee->AsProperty(); | 2779 Property* property = callee->AsProperty(); |
| 2741 { PreservePositionScope scope(masm()->positions_recorder()); | 2780 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2742 VisitForStackValue(property->obj()); | 2781 VisitForStackValue(property->obj()); |
| 2743 } | 2782 } |
| 2744 if (property->key()->IsPropertyName()) { | 2783 if (property->key()->IsPropertyName()) { |
| 2745 EmitCallWithIC(expr, | 2784 EmitCallWithIC(expr); |
| 2746 property->key()->AsLiteral()->value(), | |
| 2747 NOT_CONTEXTUAL); | |
| 2748 } else { | 2785 } else { |
| 2749 EmitKeyedCallWithIC(expr, property->key()); | 2786 EmitKeyedCallWithIC(expr, property->key()); |
| 2750 } | 2787 } |
| 2751 } else { | 2788 } else { |
| 2752 ASSERT(call_type == Call::OTHER_CALL); | 2789 ASSERT(call_type == Call::OTHER_CALL); |
| 2753 // Call to an arbitrary expression not handled specially above. | 2790 // Call to an arbitrary expression not handled specially above. |
| 2754 { PreservePositionScope scope(masm()->positions_recorder()); | 2791 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2755 VisitForStackValue(callee); | 2792 VisitForStackValue(callee); |
| 2756 } | 2793 } |
| 2757 __ PushRoot(Heap::kUndefinedValueRootIndex); | 2794 __ PushRoot(Heap::kUndefinedValueRootIndex); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 2787 // Call the construct call builtin that handles allocation and | 2824 // Call the construct call builtin that handles allocation and |
| 2788 // constructor invocation. | 2825 // constructor invocation. |
| 2789 SetSourcePosition(expr->position()); | 2826 SetSourcePosition(expr->position()); |
| 2790 | 2827 |
| 2791 // Load function and argument count into rdi and rax. | 2828 // Load function and argument count into rdi and rax. |
| 2792 __ Set(rax, arg_count); | 2829 __ Set(rax, arg_count); |
| 2793 __ movp(rdi, Operand(rsp, arg_count * kPointerSize)); | 2830 __ movp(rdi, Operand(rsp, arg_count * kPointerSize)); |
| 2794 | 2831 |
| 2795 // Record call targets in unoptimized code, but not in the snapshot. | 2832 // Record call targets in unoptimized code, but not in the snapshot. |
| 2796 Handle<Object> uninitialized = | 2833 Handle<Object> uninitialized = |
| 2797 TypeFeedbackCells::UninitializedSentinel(isolate()); | 2834 TypeFeedbackInfo::UninitializedSentinel(isolate()); |
| 2798 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); | 2835 StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized); |
| 2799 RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell); | 2836 __ Move(rbx, FeedbackVector()); |
| 2800 __ Move(rbx, cell); | 2837 __ Move(rdx, Smi::FromInt(expr->CallNewFeedbackSlot())); |
| 2801 | 2838 |
| 2802 CallConstructStub stub(RECORD_CALL_TARGET); | 2839 CallConstructStub stub(RECORD_CALL_TARGET); |
| 2803 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); | 2840 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); |
| 2804 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); | 2841 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); |
| 2805 context()->Plug(rax); | 2842 context()->Plug(rax); |
| 2806 } | 2843 } |
| 2807 | 2844 |
| 2808 | 2845 |
| 2809 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { | 2846 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { |
| 2810 ZoneList<Expression*>* args = expr->arguments(); | 2847 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 544 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3355 __ movp(scratch, stamp_operand); | 3392 __ movp(scratch, stamp_operand); |
| 3356 __ cmpq(scratch, FieldOperand(object, JSDate::kCacheStampOffset)); | 3393 __ cmpq(scratch, FieldOperand(object, JSDate::kCacheStampOffset)); |
| 3357 __ j(not_equal, &runtime, Label::kNear); | 3394 __ j(not_equal, &runtime, Label::kNear); |
| 3358 __ movp(result, FieldOperand(object, JSDate::kValueOffset + | 3395 __ movp(result, FieldOperand(object, JSDate::kValueOffset + |
| 3359 kPointerSize * index->value())); | 3396 kPointerSize * index->value())); |
| 3360 __ jmp(&done); | 3397 __ jmp(&done); |
| 3361 } | 3398 } |
| 3362 __ bind(&runtime); | 3399 __ bind(&runtime); |
| 3363 __ PrepareCallCFunction(2); | 3400 __ PrepareCallCFunction(2); |
| 3364 __ movp(arg_reg_1, object); | 3401 __ movp(arg_reg_1, object); |
| 3365 __ Move(arg_reg_2, index, RelocInfo::NONE64); | 3402 __ Move(arg_reg_2, index, Assembler::RelocInfoNone()); |
| 3366 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2); | 3403 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2); |
| 3367 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 3404 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 3368 __ jmp(&done); | 3405 __ jmp(&done); |
| 3369 } | 3406 } |
| 3370 | 3407 |
| 3371 __ bind(¬_date_object); | 3408 __ bind(¬_date_object); |
| 3372 __ CallRuntime(Runtime::kThrowNotDateError, 0); | 3409 __ CallRuntime(Runtime::kThrowNotDateError, 0); |
| 3373 __ bind(&done); | 3410 __ bind(&done); |
| 3374 context()->Plug(rax); | 3411 context()->Plug(rax); |
| 3375 } | 3412 } |
| 3376 | 3413 |
| 3377 | 3414 |
| 3378 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { | 3415 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { |
| 3379 ZoneList<Expression*>* args = expr->arguments(); | 3416 ZoneList<Expression*>* args = expr->arguments(); |
| 3380 ASSERT_EQ(3, args->length()); | 3417 ASSERT_EQ(3, args->length()); |
| 3381 | 3418 |
| 3382 Register string = rax; | 3419 Register string = rax; |
| 3383 Register index = rbx; | 3420 Register index = rbx; |
| 3384 Register value = rcx; | 3421 Register value = rcx; |
| 3385 | 3422 |
| 3386 VisitForStackValue(args->at(1)); // index | 3423 VisitForStackValue(args->at(1)); // index |
| 3387 VisitForStackValue(args->at(2)); // value | 3424 VisitForStackValue(args->at(2)); // value |
| 3388 VisitForAccumulatorValue(args->at(0)); // string | 3425 VisitForAccumulatorValue(args->at(0)); // string |
| 3389 __ pop(value); | 3426 __ pop(value); |
| 3390 __ pop(index); | 3427 __ pop(index); |
| 3391 | 3428 |
| 3392 if (FLAG_debug_code) { | 3429 if (FLAG_debug_code) { |
| 3393 __ ThrowIf(NegateCondition(__ CheckSmi(value)), kNonSmiValue); | 3430 __ Check(__ CheckSmi(value), kNonSmiValue); |
| 3394 __ ThrowIf(NegateCondition(__ CheckSmi(index)), kNonSmiValue); | 3431 __ Check(__ CheckSmi(index), kNonSmiValue); |
| 3395 } | 3432 } |
| 3396 | 3433 |
| 3397 __ SmiToInteger32(value, value); | 3434 __ SmiToInteger32(value, value); |
| 3398 __ SmiToInteger32(index, index); | 3435 __ SmiToInteger32(index, index); |
| 3399 | 3436 |
| 3400 if (FLAG_debug_code) { | 3437 if (FLAG_debug_code) { |
| 3401 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; | 3438 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; |
| 3402 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type); | 3439 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type); |
| 3403 } | 3440 } |
| 3404 | 3441 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3416 Register index = rbx; | 3453 Register index = rbx; |
| 3417 Register value = rcx; | 3454 Register value = rcx; |
| 3418 | 3455 |
| 3419 VisitForStackValue(args->at(1)); // index | 3456 VisitForStackValue(args->at(1)); // index |
| 3420 VisitForStackValue(args->at(2)); // value | 3457 VisitForStackValue(args->at(2)); // value |
| 3421 VisitForAccumulatorValue(args->at(0)); // string | 3458 VisitForAccumulatorValue(args->at(0)); // string |
| 3422 __ pop(value); | 3459 __ pop(value); |
| 3423 __ pop(index); | 3460 __ pop(index); |
| 3424 | 3461 |
| 3425 if (FLAG_debug_code) { | 3462 if (FLAG_debug_code) { |
| 3426 __ ThrowIf(NegateCondition(__ CheckSmi(value)), kNonSmiValue); | 3463 __ Check(__ CheckSmi(value), kNonSmiValue); |
| 3427 __ ThrowIf(NegateCondition(__ CheckSmi(index)), kNonSmiValue); | 3464 __ Check(__ CheckSmi(index), kNonSmiValue); |
| 3428 } | 3465 } |
| 3429 | 3466 |
| 3430 __ SmiToInteger32(value, value); | 3467 __ SmiToInteger32(value, value); |
| 3431 __ SmiToInteger32(index, index); | 3468 __ SmiToInteger32(index, index); |
| 3432 | 3469 |
| 3433 if (FLAG_debug_code) { | 3470 if (FLAG_debug_code) { |
| 3434 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; | 3471 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; |
| 3435 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); | 3472 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); |
| 3436 } | 3473 } |
| 3437 | 3474 |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3603 generator.GenerateSlow(masm_, call_helper); | 3640 generator.GenerateSlow(masm_, call_helper); |
| 3604 | 3641 |
| 3605 __ bind(&done); | 3642 __ bind(&done); |
| 3606 context()->Plug(result); | 3643 context()->Plug(result); |
| 3607 } | 3644 } |
| 3608 | 3645 |
| 3609 | 3646 |
| 3610 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { | 3647 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { |
| 3611 ZoneList<Expression*>* args = expr->arguments(); | 3648 ZoneList<Expression*>* args = expr->arguments(); |
| 3612 ASSERT_EQ(2, args->length()); | 3649 ASSERT_EQ(2, args->length()); |
| 3650 VisitForStackValue(args->at(0)); |
| 3651 VisitForAccumulatorValue(args->at(1)); |
| 3613 | 3652 |
| 3614 if (FLAG_new_string_add) { | 3653 __ pop(rdx); |
| 3615 VisitForStackValue(args->at(0)); | 3654 StringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); |
| 3616 VisitForAccumulatorValue(args->at(1)); | 3655 __ CallStub(&stub); |
| 3617 | |
| 3618 __ pop(rdx); | |
| 3619 NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); | |
| 3620 __ CallStub(&stub); | |
| 3621 } else { | |
| 3622 VisitForStackValue(args->at(0)); | |
| 3623 VisitForStackValue(args->at(1)); | |
| 3624 | |
| 3625 StringAddStub stub(STRING_ADD_CHECK_BOTH); | |
| 3626 __ CallStub(&stub); | |
| 3627 } | |
| 3628 context()->Plug(rax); | 3656 context()->Plug(rax); |
| 3629 } | 3657 } |
| 3630 | 3658 |
| 3631 | 3659 |
| 3632 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { | 3660 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { |
| 3633 ZoneList<Expression*>* args = expr->arguments(); | 3661 ZoneList<Expression*>* args = expr->arguments(); |
| 3634 ASSERT_EQ(2, args->length()); | 3662 ASSERT_EQ(2, args->length()); |
| 3635 | 3663 |
| 3636 VisitForStackValue(args->at(0)); | 3664 VisitForStackValue(args->at(0)); |
| 3637 VisitForStackValue(args->at(1)); | 3665 VisitForStackValue(args->at(1)); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3693 context()->Plug(rax); | 3721 context()->Plug(rax); |
| 3694 } | 3722 } |
| 3695 | 3723 |
| 3696 | 3724 |
| 3697 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { | 3725 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { |
| 3698 RegExpConstructResultStub stub; | 3726 RegExpConstructResultStub stub; |
| 3699 ZoneList<Expression*>* args = expr->arguments(); | 3727 ZoneList<Expression*>* args = expr->arguments(); |
| 3700 ASSERT(args->length() == 3); | 3728 ASSERT(args->length() == 3); |
| 3701 VisitForStackValue(args->at(0)); | 3729 VisitForStackValue(args->at(0)); |
| 3702 VisitForStackValue(args->at(1)); | 3730 VisitForStackValue(args->at(1)); |
| 3703 VisitForStackValue(args->at(2)); | 3731 VisitForAccumulatorValue(args->at(2)); |
| 3732 __ pop(rbx); |
| 3733 __ pop(rcx); |
| 3704 __ CallStub(&stub); | 3734 __ CallStub(&stub); |
| 3705 context()->Plug(rax); | 3735 context()->Plug(rax); |
| 3706 } | 3736 } |
| 3707 | 3737 |
| 3708 | 3738 |
| 3709 void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { | 3739 void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { |
| 3710 ZoneList<Expression*>* args = expr->arguments(); | 3740 ZoneList<Expression*>* args = expr->arguments(); |
| 3711 ASSERT_EQ(2, args->length()); | 3741 ASSERT_EQ(2, args->length()); |
| 3712 | 3742 |
| 3713 ASSERT_NE(NULL, args->at(0)->AsLiteral()); | 3743 ASSERT_NE(NULL, args->at(0)->AsLiteral()); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3729 Register tmp = rcx; | 3759 Register tmp = rcx; |
| 3730 __ movp(cache, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX)); | 3760 __ movp(cache, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX)); |
| 3731 __ movp(cache, | 3761 __ movp(cache, |
| 3732 FieldOperand(cache, GlobalObject::kNativeContextOffset)); | 3762 FieldOperand(cache, GlobalObject::kNativeContextOffset)); |
| 3733 __ movp(cache, | 3763 __ movp(cache, |
| 3734 ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); | 3764 ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); |
| 3735 __ movp(cache, | 3765 __ movp(cache, |
| 3736 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); | 3766 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); |
| 3737 | 3767 |
| 3738 Label done, not_found; | 3768 Label done, not_found; |
| 3739 // tmp now holds finger offset as a smi. | |
| 3740 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 3769 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| 3741 __ movp(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); | 3770 __ movp(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); |
| 3771 // tmp now holds finger offset as a smi. |
| 3742 SmiIndex index = | 3772 SmiIndex index = |
| 3743 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2); | 3773 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2); |
| 3744 __ cmpq(key, FieldOperand(cache, | 3774 __ cmpq(key, FieldOperand(cache, |
| 3745 index.reg, | 3775 index.reg, |
| 3746 index.scale, | 3776 index.scale, |
| 3747 FixedArray::kHeaderSize)); | 3777 FixedArray::kHeaderSize)); |
| 3748 __ j(not_equal, ¬_found, Label::kNear); | 3778 __ j(not_equal, ¬_found, Label::kNear); |
| 3749 __ movp(rax, FieldOperand(cache, | 3779 __ movp(rax, FieldOperand(cache, |
| 3750 index.reg, | 3780 index.reg, |
| 3751 index.scale, | 3781 index.scale, |
| 3752 FixedArray::kHeaderSize + kPointerSize)); | 3782 FixedArray::kHeaderSize + kPointerSize)); |
| 3753 __ jmp(&done, Label::kNear); | 3783 __ jmp(&done, Label::kNear); |
| 3754 | 3784 |
| 3755 __ bind(¬_found); | 3785 __ bind(¬_found); |
| 3756 // Call runtime to perform the lookup. | 3786 // Call runtime to perform the lookup. |
| 3757 __ push(cache); | 3787 __ push(cache); |
| 3758 __ push(key); | 3788 __ push(key); |
| 3759 __ CallRuntime(Runtime::kGetFromCache, 2); | 3789 __ CallRuntime(Runtime::kGetFromCache, 2); |
| 3760 | 3790 |
| 3761 __ bind(&done); | 3791 __ bind(&done); |
| 3762 context()->Plug(rax); | 3792 context()->Plug(rax); |
| 3763 } | 3793 } |
| 3764 | 3794 |
| 3765 | 3795 |
| 3766 void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) { | |
| 3767 ZoneList<Expression*>* args = expr->arguments(); | |
| 3768 ASSERT_EQ(2, args->length()); | |
| 3769 | |
| 3770 Register right = rax; | |
| 3771 Register left = rbx; | |
| 3772 Register tmp = rcx; | |
| 3773 | |
| 3774 VisitForStackValue(args->at(0)); | |
| 3775 VisitForAccumulatorValue(args->at(1)); | |
| 3776 __ pop(left); | |
| 3777 | |
| 3778 Label done, fail, ok; | |
| 3779 __ cmpq(left, right); | |
| 3780 __ j(equal, &ok, Label::kNear); | |
| 3781 // Fail if either is a non-HeapObject. | |
| 3782 Condition either_smi = masm()->CheckEitherSmi(left, right, tmp); | |
| 3783 __ j(either_smi, &fail, Label::kNear); | |
| 3784 __ j(zero, &fail, Label::kNear); | |
| 3785 __ movp(tmp, FieldOperand(left, HeapObject::kMapOffset)); | |
| 3786 __ cmpb(FieldOperand(tmp, Map::kInstanceTypeOffset), | |
| 3787 Immediate(JS_REGEXP_TYPE)); | |
| 3788 __ j(not_equal, &fail, Label::kNear); | |
| 3789 __ cmpq(tmp, FieldOperand(right, HeapObject::kMapOffset)); | |
| 3790 __ j(not_equal, &fail, Label::kNear); | |
| 3791 __ movp(tmp, FieldOperand(left, JSRegExp::kDataOffset)); | |
| 3792 __ cmpq(tmp, FieldOperand(right, JSRegExp::kDataOffset)); | |
| 3793 __ j(equal, &ok, Label::kNear); | |
| 3794 __ bind(&fail); | |
| 3795 __ Move(rax, isolate()->factory()->false_value()); | |
| 3796 __ jmp(&done, Label::kNear); | |
| 3797 __ bind(&ok); | |
| 3798 __ Move(rax, isolate()->factory()->true_value()); | |
| 3799 __ bind(&done); | |
| 3800 | |
| 3801 context()->Plug(rax); | |
| 3802 } | |
| 3803 | |
| 3804 | |
| 3805 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { | 3796 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { |
| 3806 ZoneList<Expression*>* args = expr->arguments(); | 3797 ZoneList<Expression*>* args = expr->arguments(); |
| 3807 ASSERT(args->length() == 1); | 3798 ASSERT(args->length() == 1); |
| 3808 | 3799 |
| 3809 VisitForAccumulatorValue(args->at(0)); | 3800 VisitForAccumulatorValue(args->at(0)); |
| 3810 | 3801 |
| 3811 Label materialize_true, materialize_false; | 3802 Label materialize_true, materialize_false; |
| 3812 Label* if_true = NULL; | 3803 Label* if_true = NULL; |
| 3813 Label* if_false = NULL; | 3804 Label* if_false = NULL; |
| 3814 Label* fall_through = NULL; | 3805 Label* fall_through = NULL; |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4128 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 4119 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 4129 Handle<String> name = expr->name(); | 4120 Handle<String> name = expr->name(); |
| 4130 if (name->length() > 0 && name->Get(0) == '_') { | 4121 if (name->length() > 0 && name->Get(0) == '_') { |
| 4131 Comment cmnt(masm_, "[ InlineRuntimeCall"); | 4122 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
| 4132 EmitInlineRuntimeCall(expr); | 4123 EmitInlineRuntimeCall(expr); |
| 4133 return; | 4124 return; |
| 4134 } | 4125 } |
| 4135 | 4126 |
| 4136 Comment cmnt(masm_, "[ CallRuntime"); | 4127 Comment cmnt(masm_, "[ CallRuntime"); |
| 4137 ZoneList<Expression*>* args = expr->arguments(); | 4128 ZoneList<Expression*>* args = expr->arguments(); |
| 4129 int arg_count = args->length(); |
| 4138 | 4130 |
| 4139 if (expr->is_jsruntime()) { | 4131 if (expr->is_jsruntime()) { |
| 4140 // Prepare for calling JS runtime function. | 4132 // Push the builtins object as receiver. |
| 4141 __ movp(rax, GlobalObjectOperand()); | 4133 __ movp(rax, GlobalObjectOperand()); |
| 4142 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); | 4134 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); |
| 4143 } | |
| 4144 | 4135 |
| 4145 // Push the arguments ("left-to-right"). | 4136 // Load the function from the receiver. |
| 4146 int arg_count = args->length(); | 4137 __ movp(rax, Operand(rsp, 0)); |
| 4147 for (int i = 0; i < arg_count; i++) { | 4138 __ Move(rcx, expr->name()); |
| 4148 VisitForStackValue(args->at(i)); | 4139 CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); |
| 4149 } | |
| 4150 | 4140 |
| 4151 if (expr->is_jsruntime()) { | 4141 // Push the target function under the receiver. |
| 4152 // Call the JS runtime function using a call IC. | 4142 __ push(Operand(rsp, 0)); |
| 4153 __ Move(rcx, expr->name()); | 4143 __ movp(Operand(rsp, kPointerSize), rax); |
| 4154 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count); | 4144 |
| 4155 CallIC(ic, NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); | 4145 // Push the arguments ("left-to-right"). |
| 4146 for (int i = 0; i < arg_count; i++) { |
| 4147 VisitForStackValue(args->at(i)); |
| 4148 } |
| 4149 |
| 4150 // Record source position of the IC call. |
| 4151 SetSourcePosition(expr->position()); |
| 4152 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); |
| 4153 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize)); |
| 4154 __ CallStub(&stub); |
| 4155 |
| 4156 // Restore context register. | 4156 // Restore context register. |
| 4157 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 4157 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 4158 context()->DropAndPlug(1, rax); |
| 4159 |
| 4158 } else { | 4160 } else { |
| 4161 // Push the arguments ("left-to-right"). |
| 4162 for (int i = 0; i < arg_count; i++) { |
| 4163 VisitForStackValue(args->at(i)); |
| 4164 } |
| 4165 |
| 4166 // Call the C runtime. |
| 4159 __ CallRuntime(expr->function(), arg_count); | 4167 __ CallRuntime(expr->function(), arg_count); |
| 4168 context()->Plug(rax); |
| 4160 } | 4169 } |
| 4161 context()->Plug(rax); | |
| 4162 } | 4170 } |
| 4163 | 4171 |
| 4164 | 4172 |
| 4165 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 4173 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 4166 switch (expr->op()) { | 4174 switch (expr->op()) { |
| 4167 case Token::DELETE: { | 4175 case Token::DELETE: { |
| 4168 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 4176 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
| 4169 Property* property = expr->expression()->AsProperty(); | 4177 Property* property = expr->expression()->AsProperty(); |
| 4170 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 4178 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
| 4171 | 4179 |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4395 } | 4403 } |
| 4396 | 4404 |
| 4397 // Record position before stub call. | 4405 // Record position before stub call. |
| 4398 SetSourcePosition(expr->position()); | 4406 SetSourcePosition(expr->position()); |
| 4399 | 4407 |
| 4400 // Call stub for +1/-1. | 4408 // Call stub for +1/-1. |
| 4401 __ bind(&stub_call); | 4409 __ bind(&stub_call); |
| 4402 __ movp(rdx, rax); | 4410 __ movp(rdx, rax); |
| 4403 __ Move(rax, Smi::FromInt(1)); | 4411 __ Move(rax, Smi::FromInt(1)); |
| 4404 BinaryOpICStub stub(expr->binary_op(), NO_OVERWRITE); | 4412 BinaryOpICStub stub(expr->binary_op(), NO_OVERWRITE); |
| 4405 CallIC(stub.GetCode(isolate()), | 4413 CallIC(stub.GetCode(isolate()), expr->CountBinOpFeedbackId()); |
| 4406 NOT_CONTEXTUAL, | |
| 4407 expr->CountBinOpFeedbackId()); | |
| 4408 patch_site.EmitPatchInfo(); | 4414 patch_site.EmitPatchInfo(); |
| 4409 __ bind(&done); | 4415 __ bind(&done); |
| 4410 | 4416 |
| 4411 // Store the value returned in rax. | 4417 // Store the value returned in rax. |
| 4412 switch (assign_type) { | 4418 switch (assign_type) { |
| 4413 case VARIABLE: | 4419 case VARIABLE: |
| 4414 if (expr->is_postfix()) { | 4420 if (expr->is_postfix()) { |
| 4415 // Perform the assignment as if via '='. | 4421 // Perform the assignment as if via '='. |
| 4416 { EffectContext context(this); | 4422 { EffectContext context(this); |
| 4417 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 4423 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| (...skipping 10 matching lines...) Expand all Loading... |
| 4428 // Perform the assignment as if via '='. | 4434 // Perform the assignment as if via '='. |
| 4429 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 4435 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 4430 Token::ASSIGN); | 4436 Token::ASSIGN); |
| 4431 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4437 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4432 context()->Plug(rax); | 4438 context()->Plug(rax); |
| 4433 } | 4439 } |
| 4434 break; | 4440 break; |
| 4435 case NAMED_PROPERTY: { | 4441 case NAMED_PROPERTY: { |
| 4436 __ Move(rcx, prop->key()->AsLiteral()->value()); | 4442 __ Move(rcx, prop->key()->AsLiteral()->value()); |
| 4437 __ pop(rdx); | 4443 __ pop(rdx); |
| 4438 CallStoreIC(NOT_CONTEXTUAL, expr->CountStoreFeedbackId()); | 4444 CallStoreIC(expr->CountStoreFeedbackId()); |
| 4439 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4445 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4440 if (expr->is_postfix()) { | 4446 if (expr->is_postfix()) { |
| 4441 if (!context()->IsEffect()) { | 4447 if (!context()->IsEffect()) { |
| 4442 context()->PlugTOS(); | 4448 context()->PlugTOS(); |
| 4443 } | 4449 } |
| 4444 } else { | 4450 } else { |
| 4445 context()->Plug(rax); | 4451 context()->Plug(rax); |
| 4446 } | 4452 } |
| 4447 break; | 4453 break; |
| 4448 } | 4454 } |
| 4449 case KEYED_PROPERTY: { | 4455 case KEYED_PROPERTY: { |
| 4450 __ pop(rcx); | 4456 __ pop(rcx); |
| 4451 __ pop(rdx); | 4457 __ pop(rdx); |
| 4452 Handle<Code> ic = is_classic_mode() | 4458 Handle<Code> ic = is_classic_mode() |
| 4453 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 4459 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 4454 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 4460 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 4455 CallIC(ic, NOT_CONTEXTUAL, expr->CountStoreFeedbackId()); | 4461 CallIC(ic, expr->CountStoreFeedbackId()); |
| 4456 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4462 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4457 if (expr->is_postfix()) { | 4463 if (expr->is_postfix()) { |
| 4458 if (!context()->IsEffect()) { | 4464 if (!context()->IsEffect()) { |
| 4459 context()->PlugTOS(); | 4465 context()->PlugTOS(); |
| 4460 } | 4466 } |
| 4461 } else { | 4467 } else { |
| 4462 context()->Plug(rax); | 4468 context()->Plug(rax); |
| 4463 } | 4469 } |
| 4464 break; | 4470 break; |
| 4465 } | 4471 } |
| 4466 } | 4472 } |
| 4467 } | 4473 } |
| 4468 | 4474 |
| 4469 | 4475 |
| 4470 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 4476 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 4471 VariableProxy* proxy = expr->AsVariableProxy(); | 4477 VariableProxy* proxy = expr->AsVariableProxy(); |
| 4472 ASSERT(!context()->IsEffect()); | 4478 ASSERT(!context()->IsEffect()); |
| 4473 ASSERT(!context()->IsTest()); | 4479 ASSERT(!context()->IsTest()); |
| 4474 | 4480 |
| 4475 if (proxy != NULL && proxy->var()->IsUnallocated()) { | 4481 if (proxy != NULL && proxy->var()->IsUnallocated()) { |
| 4476 Comment cmnt(masm_, "Global variable"); | 4482 Comment cmnt(masm_, "[ Global variable"); |
| 4477 __ Move(rcx, proxy->name()); | 4483 __ Move(rcx, proxy->name()); |
| 4478 __ movp(rax, GlobalObjectOperand()); | 4484 __ movp(rax, GlobalObjectOperand()); |
| 4479 // Use a regular load, not a contextual load, to avoid a reference | 4485 // Use a regular load, not a contextual load, to avoid a reference |
| 4480 // error. | 4486 // error. |
| 4481 CallLoadIC(NOT_CONTEXTUAL); | 4487 CallLoadIC(NOT_CONTEXTUAL); |
| 4482 PrepareForBailout(expr, TOS_REG); | 4488 PrepareForBailout(expr, TOS_REG); |
| 4483 context()->Plug(rax); | 4489 context()->Plug(rax); |
| 4484 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { | 4490 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { |
| 4491 Comment cmnt(masm_, "[ Lookup slot"); |
| 4485 Label done, slow; | 4492 Label done, slow; |
| 4486 | 4493 |
| 4487 // Generate code for loading from variables potentially shadowed | 4494 // Generate code for loading from variables potentially shadowed |
| 4488 // by eval-introduced variables. | 4495 // by eval-introduced variables. |
| 4489 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); | 4496 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); |
| 4490 | 4497 |
| 4491 __ bind(&slow); | 4498 __ bind(&slow); |
| 4492 __ push(rsi); | 4499 __ push(rsi); |
| 4493 __ Push(proxy->name()); | 4500 __ Push(proxy->name()); |
| 4494 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 4501 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4633 __ or_(rcx, rax); | 4640 __ or_(rcx, rax); |
| 4634 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear); | 4641 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear); |
| 4635 __ cmpq(rdx, rax); | 4642 __ cmpq(rdx, rax); |
| 4636 Split(cc, if_true, if_false, NULL); | 4643 Split(cc, if_true, if_false, NULL); |
| 4637 __ bind(&slow_case); | 4644 __ bind(&slow_case); |
| 4638 } | 4645 } |
| 4639 | 4646 |
| 4640 // Record position and call the compare IC. | 4647 // Record position and call the compare IC. |
| 4641 SetSourcePosition(expr->position()); | 4648 SetSourcePosition(expr->position()); |
| 4642 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); | 4649 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); |
| 4643 CallIC(ic, NOT_CONTEXTUAL, expr->CompareOperationFeedbackId()); | 4650 CallIC(ic, expr->CompareOperationFeedbackId()); |
| 4644 patch_site.EmitPatchInfo(); | 4651 patch_site.EmitPatchInfo(); |
| 4645 | 4652 |
| 4646 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 4653 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 4647 __ testq(rax, rax); | 4654 __ testq(rax, rax); |
| 4648 Split(cc, if_true, if_false, fall_through); | 4655 Split(cc, if_true, if_false, fall_through); |
| 4649 } | 4656 } |
| 4650 } | 4657 } |
| 4651 | 4658 |
| 4652 // Convert the result of the comparison into one expected for this | 4659 // Convert the result of the comparison into one expected for this |
| 4653 // expression's context. | 4660 // expression's context. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 4668 VisitForAccumulatorValue(sub_expr); | 4675 VisitForAccumulatorValue(sub_expr); |
| 4669 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 4676 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 4670 if (expr->op() == Token::EQ_STRICT) { | 4677 if (expr->op() == Token::EQ_STRICT) { |
| 4671 Heap::RootListIndex nil_value = nil == kNullValue ? | 4678 Heap::RootListIndex nil_value = nil == kNullValue ? |
| 4672 Heap::kNullValueRootIndex : | 4679 Heap::kNullValueRootIndex : |
| 4673 Heap::kUndefinedValueRootIndex; | 4680 Heap::kUndefinedValueRootIndex; |
| 4674 __ CompareRoot(rax, nil_value); | 4681 __ CompareRoot(rax, nil_value); |
| 4675 Split(equal, if_true, if_false, fall_through); | 4682 Split(equal, if_true, if_false, fall_through); |
| 4676 } else { | 4683 } else { |
| 4677 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); | 4684 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); |
| 4678 CallIC(ic, NOT_CONTEXTUAL, expr->CompareOperationFeedbackId()); | 4685 CallIC(ic, expr->CompareOperationFeedbackId()); |
| 4679 __ testq(rax, rax); | 4686 __ testq(rax, rax); |
| 4680 Split(not_zero, if_true, if_false, fall_through); | 4687 Split(not_zero, if_true, if_false, fall_through); |
| 4681 } | 4688 } |
| 4682 context()->Plug(if_true, if_false); | 4689 context()->Plug(if_true, if_false); |
| 4683 } | 4690 } |
| 4684 | 4691 |
| 4685 | 4692 |
| 4686 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 4693 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
| 4687 __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 4694 __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4688 context()->Plug(rax); | 4695 context()->Plug(rax); |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4900 | 4907 |
| 4901 ASSERT_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(), | 4908 ASSERT_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(), |
| 4902 Assembler::target_address_at(call_target_address)); | 4909 Assembler::target_address_at(call_target_address)); |
| 4903 return OSR_AFTER_STACK_CHECK; | 4910 return OSR_AFTER_STACK_CHECK; |
| 4904 } | 4911 } |
| 4905 | 4912 |
| 4906 | 4913 |
| 4907 } } // namespace v8::internal | 4914 } } // namespace v8::internal |
| 4908 | 4915 |
| 4909 #endif // V8_TARGET_ARCH_X64 | 4916 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |