| 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 esi: our context | 111 // o esi: our context |
| 112 // o ebp: our caller's frame pointer | 112 // o ebp: our caller's frame pointer |
| 113 // o esp: stack pointer (pointing to return address) | 113 // o esp: 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-ia32.h for its layout. | 116 // frames-ia32.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 edi. | 187 // Argument to NewContext is the function, which is still in edi. |
| 185 __ push(edi); | |
| 186 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) { | 188 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) { |
| 189 __ push(edi); |
| 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(edi); |
| 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 eax and esi. It replaces the context | 200 // Context is returned in eax. It replaces the context passed to us. |
| 197 // passed to us. It's saved in the stack and kept live in esi. | 201 // It's saved in the stack and kept live in esi. |
| 198 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); | 202 __ mov(esi, eax); |
| 203 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), eax); |
| 199 | 204 |
| 200 // Copy parameters into context if necessary. | 205 // Copy parameters into context if necessary. |
| 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 __ mov(eax, Operand(ebp, parameter_offset)); | 213 __ mov(eax, Operand(ebp, parameter_offset)); |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 617 if (false_label_ != fall_through_) __ jmp(false_label_); | 622 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 618 } | 623 } |
| 619 } | 624 } |
| 620 | 625 |
| 621 | 626 |
| 622 void FullCodeGenerator::DoTest(Expression* condition, | 627 void FullCodeGenerator::DoTest(Expression* condition, |
| 623 Label* if_true, | 628 Label* if_true, |
| 624 Label* if_false, | 629 Label* if_false, |
| 625 Label* fall_through) { | 630 Label* fall_through) { |
| 626 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); | 631 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); |
| 627 CallIC(ic, NOT_CONTEXTUAL, condition->test_id()); | 632 CallIC(ic, condition->test_id()); |
| 628 __ test(result_register(), result_register()); | 633 __ test(result_register(), result_register()); |
| 629 // The stub returns nonzero for true. | 634 // The stub returns nonzero for true. |
| 630 Split(not_zero, if_true, if_false, fall_through); | 635 Split(not_zero, if_true, if_false, fall_through); |
| 631 } | 636 } |
| 632 | 637 |
| 633 | 638 |
| 634 void FullCodeGenerator::Split(Condition cc, | 639 void FullCodeGenerator::Split(Condition cc, |
| 635 Label* if_true, | 640 Label* if_true, |
| 636 Label* if_false, | 641 Label* if_false, |
| 637 Label* fall_through) { | 642 Label* fall_through) { |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 968 __ cmp(edx, eax); | 973 __ cmp(edx, eax); |
| 969 __ j(not_equal, &next_test); | 974 __ j(not_equal, &next_test); |
| 970 __ Drop(1); // Switch value is no longer needed. | 975 __ Drop(1); // Switch value is no longer needed. |
| 971 __ jmp(clause->body_target()); | 976 __ jmp(clause->body_target()); |
| 972 __ bind(&slow_case); | 977 __ bind(&slow_case); |
| 973 } | 978 } |
| 974 | 979 |
| 975 // Record position before stub call for type feedback. | 980 // Record position before stub call for type feedback. |
| 976 SetSourcePosition(clause->position()); | 981 SetSourcePosition(clause->position()); |
| 977 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); | 982 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); |
| 978 CallIC(ic, NOT_CONTEXTUAL, clause->CompareId()); | 983 CallIC(ic, clause->CompareId()); |
| 979 patch_site.EmitPatchInfo(); | 984 patch_site.EmitPatchInfo(); |
| 980 | 985 |
| 981 Label skip; | 986 Label skip; |
| 982 __ jmp(&skip, Label::kNear); | 987 __ jmp(&skip, Label::kNear); |
| 983 PrepareForBailout(clause, TOS_REG); | 988 PrepareForBailout(clause, TOS_REG); |
| 984 __ cmp(eax, isolate()->factory()->true_value()); | 989 __ cmp(eax, isolate()->factory()->true_value()); |
| 985 __ j(not_equal, &next_test); | 990 __ j(not_equal, &next_test); |
| 986 __ Drop(1); | 991 __ Drop(1); |
| 987 __ jmp(clause->body_target()); | 992 __ jmp(clause->body_target()); |
| 988 __ bind(&skip); | 993 __ bind(&skip); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1012 VisitStatements(clause->statements()); | 1017 VisitStatements(clause->statements()); |
| 1013 } | 1018 } |
| 1014 | 1019 |
| 1015 __ bind(nested_statement.break_label()); | 1020 __ bind(nested_statement.break_label()); |
| 1016 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); | 1021 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 1017 } | 1022 } |
| 1018 | 1023 |
| 1019 | 1024 |
| 1020 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 1025 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 1021 Comment cmnt(masm_, "[ ForInStatement"); | 1026 Comment cmnt(masm_, "[ ForInStatement"); |
| 1027 int slot = stmt->ForInFeedbackSlot(); |
| 1028 |
| 1022 SetStatementPosition(stmt); | 1029 SetStatementPosition(stmt); |
| 1023 | 1030 |
| 1024 Label loop, exit; | 1031 Label loop, exit; |
| 1025 ForIn loop_statement(this, stmt); | 1032 ForIn loop_statement(this, stmt); |
| 1026 increment_loop_depth(); | 1033 increment_loop_depth(); |
| 1027 | 1034 |
| 1028 // Get the object to enumerate over. If the object is null or undefined, skip | 1035 // Get the object to enumerate over. If the object is null or undefined, skip |
| 1029 // over the loop. See ECMA-262 version 5, section 12.6.4. | 1036 // over the loop. See ECMA-262 version 5, section 12.6.4. |
| 1030 VisitForAccumulatorValue(stmt->enumerable()); | 1037 VisitForAccumulatorValue(stmt->enumerable()); |
| 1031 __ cmp(eax, isolate()->factory()->undefined_value()); | 1038 __ cmp(eax, isolate()->factory()->undefined_value()); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1090 __ jmp(&loop); | 1097 __ jmp(&loop); |
| 1091 | 1098 |
| 1092 __ bind(&no_descriptors); | 1099 __ bind(&no_descriptors); |
| 1093 __ add(esp, Immediate(kPointerSize)); | 1100 __ add(esp, Immediate(kPointerSize)); |
| 1094 __ jmp(&exit); | 1101 __ jmp(&exit); |
| 1095 | 1102 |
| 1096 // We got a fixed array in register eax. Iterate through that. | 1103 // We got a fixed array in register eax. Iterate through that. |
| 1097 Label non_proxy; | 1104 Label non_proxy; |
| 1098 __ bind(&fixed_array); | 1105 __ bind(&fixed_array); |
| 1099 | 1106 |
| 1100 Handle<Cell> cell = isolate()->factory()->NewCell( | 1107 Handle<Object> feedback = Handle<Object>( |
| 1101 Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), | 1108 Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker), |
| 1102 isolate())); | 1109 isolate()); |
| 1103 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); | 1110 StoreFeedbackVectorSlot(slot, feedback); |
| 1104 __ LoadHeapObject(ebx, cell); | 1111 |
| 1105 __ mov(FieldOperand(ebx, Cell::kValueOffset), | 1112 // No need for a write barrier, we are storing a Smi in the feedback vector. |
| 1106 Immediate(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); | 1113 __ LoadHeapObject(ebx, FeedbackVector()); |
| 1114 __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(slot)), |
| 1115 Immediate(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker))); |
| 1107 | 1116 |
| 1108 __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check | 1117 __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check |
| 1109 __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object | 1118 __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object |
| 1110 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 1119 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 1111 __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx); | 1120 __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx); |
| 1112 __ j(above, &non_proxy); | 1121 __ j(above, &non_proxy); |
| 1113 __ Set(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy | 1122 __ Set(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy |
| 1114 __ bind(&non_proxy); | 1123 __ bind(&non_proxy); |
| 1115 __ push(ebx); // Smi | 1124 __ push(ebx); // Smi |
| 1116 __ push(eax); // Array | 1125 __ push(eax); // Array |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1403 | 1412 |
| 1404 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1413 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
| 1405 // Record position before possible IC call. | 1414 // Record position before possible IC call. |
| 1406 SetSourcePosition(proxy->position()); | 1415 SetSourcePosition(proxy->position()); |
| 1407 Variable* var = proxy->var(); | 1416 Variable* var = proxy->var(); |
| 1408 | 1417 |
| 1409 // Three cases: global variables, lookup variables, and all other types of | 1418 // Three cases: global variables, lookup variables, and all other types of |
| 1410 // variables. | 1419 // variables. |
| 1411 switch (var->location()) { | 1420 switch (var->location()) { |
| 1412 case Variable::UNALLOCATED: { | 1421 case Variable::UNALLOCATED: { |
| 1413 Comment cmnt(masm_, "Global variable"); | 1422 Comment cmnt(masm_, "[ Global variable"); |
| 1414 // Use inline caching. Variable name is passed in ecx and the global | 1423 // Use inline caching. Variable name is passed in ecx and the global |
| 1415 // object in eax. | 1424 // object in eax. |
| 1416 __ mov(edx, GlobalObjectOperand()); | 1425 __ mov(edx, GlobalObjectOperand()); |
| 1417 __ mov(ecx, var->name()); | 1426 __ mov(ecx, var->name()); |
| 1418 CallLoadIC(CONTEXTUAL); | 1427 CallLoadIC(CONTEXTUAL); |
| 1419 context()->Plug(eax); | 1428 context()->Plug(eax); |
| 1420 break; | 1429 break; |
| 1421 } | 1430 } |
| 1422 | 1431 |
| 1423 case Variable::PARAMETER: | 1432 case Variable::PARAMETER: |
| 1424 case Variable::LOCAL: | 1433 case Variable::LOCAL: |
| 1425 case Variable::CONTEXT: { | 1434 case Variable::CONTEXT: { |
| 1426 Comment cmnt(masm_, var->IsContextSlot() | 1435 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" |
| 1427 ? "Context variable" | 1436 : "[ Stack variable"); |
| 1428 : "Stack variable"); | |
| 1429 if (var->binding_needs_init()) { | 1437 if (var->binding_needs_init()) { |
| 1430 // var->scope() may be NULL when the proxy is located in eval code and | 1438 // var->scope() may be NULL when the proxy is located in eval code and |
| 1431 // refers to a potential outside binding. Currently those bindings are | 1439 // refers to a potential outside binding. Currently those bindings are |
| 1432 // always looked up dynamically, i.e. in that case | 1440 // always looked up dynamically, i.e. in that case |
| 1433 // var->location() == LOOKUP. | 1441 // var->location() == LOOKUP. |
| 1434 // always holds. | 1442 // always holds. |
| 1435 ASSERT(var->scope() != NULL); | 1443 ASSERT(var->scope() != NULL); |
| 1436 | 1444 |
| 1437 // Check if the binding really needs an initialization check. The check | 1445 // Check if the binding really needs an initialization check. The check |
| 1438 // can be skipped in the following situation: we have a LET or CONST | 1446 // 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... |
| 1480 __ bind(&done); | 1488 __ bind(&done); |
| 1481 context()->Plug(eax); | 1489 context()->Plug(eax); |
| 1482 break; | 1490 break; |
| 1483 } | 1491 } |
| 1484 } | 1492 } |
| 1485 context()->Plug(var); | 1493 context()->Plug(var); |
| 1486 break; | 1494 break; |
| 1487 } | 1495 } |
| 1488 | 1496 |
| 1489 case Variable::LOOKUP: { | 1497 case Variable::LOOKUP: { |
| 1498 Comment cmnt(masm_, "[ Lookup variable"); |
| 1490 Label done, slow; | 1499 Label done, slow; |
| 1491 // Generate code for loading from variables potentially shadowed | 1500 // Generate code for loading from variables potentially shadowed |
| 1492 // by eval-introduced variables. | 1501 // by eval-introduced variables. |
| 1493 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); | 1502 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1494 __ bind(&slow); | 1503 __ bind(&slow); |
| 1495 Comment cmnt(masm_, "Lookup variable"); | |
| 1496 __ push(esi); // Context. | 1504 __ push(esi); // Context. |
| 1497 __ push(Immediate(var->name())); | 1505 __ push(Immediate(var->name())); |
| 1498 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1506 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1499 __ bind(&done); | 1507 __ bind(&done); |
| 1500 context()->Plug(eax); | 1508 context()->Plug(eax); |
| 1501 break; | 1509 break; |
| 1502 } | 1510 } |
| 1503 } | 1511 } |
| 1504 } | 1512 } |
| 1505 | 1513 |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1624 UNREACHABLE(); | 1632 UNREACHABLE(); |
| 1625 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1633 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 1626 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 1634 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 1627 // Fall through. | 1635 // Fall through. |
| 1628 case ObjectLiteral::Property::COMPUTED: | 1636 case ObjectLiteral::Property::COMPUTED: |
| 1629 if (key->value()->IsInternalizedString()) { | 1637 if (key->value()->IsInternalizedString()) { |
| 1630 if (property->emit_store()) { | 1638 if (property->emit_store()) { |
| 1631 VisitForAccumulatorValue(value); | 1639 VisitForAccumulatorValue(value); |
| 1632 __ mov(ecx, Immediate(key->value())); | 1640 __ mov(ecx, Immediate(key->value())); |
| 1633 __ mov(edx, Operand(esp, 0)); | 1641 __ mov(edx, Operand(esp, 0)); |
| 1634 CallStoreIC(NOT_CONTEXTUAL, key->LiteralFeedbackId()); | 1642 CallStoreIC(key->LiteralFeedbackId()); |
| 1635 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1643 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1636 } else { | 1644 } else { |
| 1637 VisitForEffect(value); | 1645 VisitForEffect(value); |
| 1638 } | 1646 } |
| 1639 break; | 1647 break; |
| 1640 } | 1648 } |
| 1641 __ push(Operand(esp, 0)); // Duplicate receiver. | 1649 __ push(Operand(esp, 0)); // Duplicate receiver. |
| 1642 VisitForStackValue(key); | 1650 VisitForStackValue(key); |
| 1643 VisitForStackValue(value); | 1651 VisitForStackValue(value); |
| 1644 if (property->emit_store()) { | 1652 if (property->emit_store()) { |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2036 | 2044 |
| 2037 // receiver = iter; f = iter.next; arg = received; | 2045 // receiver = iter; f = iter.next; arg = received; |
| 2038 __ bind(&l_next); | 2046 __ bind(&l_next); |
| 2039 __ mov(ecx, isolate()->factory()->next_string()); // "next" | 2047 __ mov(ecx, isolate()->factory()->next_string()); // "next" |
| 2040 __ push(ecx); | 2048 __ push(ecx); |
| 2041 __ push(Operand(esp, 2 * kPointerSize)); // iter | 2049 __ push(Operand(esp, 2 * kPointerSize)); // iter |
| 2042 __ push(eax); // received | 2050 __ push(eax); // received |
| 2043 | 2051 |
| 2044 // result = receiver[f](arg); | 2052 // result = receiver[f](arg); |
| 2045 __ bind(&l_call); | 2053 __ bind(&l_call); |
| 2046 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); | 2054 __ mov(edx, Operand(esp, kPointerSize)); |
| 2047 CallIC(ic); | 2055 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2056 CallIC(ic, TypeFeedbackId::None()); |
| 2057 __ mov(edi, eax); |
| 2058 __ mov(Operand(esp, 2 * kPointerSize), edi); |
| 2059 CallFunctionStub stub(1, CALL_AS_METHOD); |
| 2060 __ CallStub(&stub); |
| 2061 |
| 2048 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2062 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2049 __ Drop(1); // The key is still on the stack; drop it. | 2063 __ Drop(1); // The function is still on the stack; drop it. |
| 2050 | 2064 |
| 2051 // if (!result.done) goto l_try; | 2065 // if (!result.done) goto l_try; |
| 2052 __ bind(&l_loop); | 2066 __ bind(&l_loop); |
| 2053 __ push(eax); // save result | 2067 __ push(eax); // save result |
| 2054 __ mov(edx, eax); // result | 2068 __ mov(edx, eax); // result |
| 2055 __ mov(ecx, isolate()->factory()->done_string()); // "done" | 2069 __ mov(ecx, isolate()->factory()->done_string()); // "done" |
| 2056 CallLoadIC(NOT_CONTEXTUAL); // result.done in eax | 2070 CallLoadIC(NOT_CONTEXTUAL); // result.done in eax |
| 2057 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); | 2071 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); |
| 2058 CallIC(bool_ic); | 2072 CallIC(bool_ic); |
| 2059 __ test(eax, eax); | 2073 __ test(eax, eax); |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2222 Literal* key = prop->key()->AsLiteral(); | 2236 Literal* key = prop->key()->AsLiteral(); |
| 2223 ASSERT(!key->value()->IsSmi()); | 2237 ASSERT(!key->value()->IsSmi()); |
| 2224 __ mov(ecx, Immediate(key->value())); | 2238 __ mov(ecx, Immediate(key->value())); |
| 2225 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); | 2239 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); |
| 2226 } | 2240 } |
| 2227 | 2241 |
| 2228 | 2242 |
| 2229 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 2243 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 2230 SetSourcePosition(prop->position()); | 2244 SetSourcePosition(prop->position()); |
| 2231 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 2245 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2232 CallIC(ic, NOT_CONTEXTUAL, prop->PropertyFeedbackId()); | 2246 CallIC(ic, prop->PropertyFeedbackId()); |
| 2233 } | 2247 } |
| 2234 | 2248 |
| 2235 | 2249 |
| 2236 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, | 2250 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, |
| 2237 Token::Value op, | 2251 Token::Value op, |
| 2238 OverwriteMode mode, | 2252 OverwriteMode mode, |
| 2239 Expression* left, | 2253 Expression* left, |
| 2240 Expression* right) { | 2254 Expression* right) { |
| 2241 // Do combined smi check of the operands. Left operand is on the | 2255 // Do combined smi check of the operands. Left operand is on the |
| 2242 // stack. Right operand is in eax. | 2256 // stack. Right operand is in eax. |
| 2243 Label smi_case, done, stub_call; | 2257 Label smi_case, done, stub_call; |
| 2244 __ pop(edx); | 2258 __ pop(edx); |
| 2245 __ mov(ecx, eax); | 2259 __ mov(ecx, eax); |
| 2246 __ or_(eax, edx); | 2260 __ or_(eax, edx); |
| 2247 JumpPatchSite patch_site(masm_); | 2261 JumpPatchSite patch_site(masm_); |
| 2248 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear); | 2262 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear); |
| 2249 | 2263 |
| 2250 __ bind(&stub_call); | 2264 __ bind(&stub_call); |
| 2251 __ mov(eax, ecx); | 2265 __ mov(eax, ecx); |
| 2252 BinaryOpICStub stub(op, mode); | 2266 BinaryOpICStub stub(op, mode); |
| 2253 CallIC(stub.GetCode(isolate()), NOT_CONTEXTUAL, | 2267 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId()); |
| 2254 expr->BinaryOperationFeedbackId()); | |
| 2255 patch_site.EmitPatchInfo(); | 2268 patch_site.EmitPatchInfo(); |
| 2256 __ jmp(&done, Label::kNear); | 2269 __ jmp(&done, Label::kNear); |
| 2257 | 2270 |
| 2258 // Smi case. | 2271 // Smi case. |
| 2259 __ bind(&smi_case); | 2272 __ bind(&smi_case); |
| 2260 __ mov(eax, edx); // Copy left operand in case of a stub call. | 2273 __ mov(eax, edx); // Copy left operand in case of a stub call. |
| 2261 | 2274 |
| 2262 switch (op) { | 2275 switch (op) { |
| 2263 case Token::SAR: | 2276 case Token::SAR: |
| 2264 __ SmiUntag(eax); | 2277 __ SmiUntag(eax); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2329 context()->Plug(eax); | 2342 context()->Plug(eax); |
| 2330 } | 2343 } |
| 2331 | 2344 |
| 2332 | 2345 |
| 2333 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, | 2346 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, |
| 2334 Token::Value op, | 2347 Token::Value op, |
| 2335 OverwriteMode mode) { | 2348 OverwriteMode mode) { |
| 2336 __ pop(edx); | 2349 __ pop(edx); |
| 2337 BinaryOpICStub stub(op, mode); | 2350 BinaryOpICStub stub(op, mode); |
| 2338 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. | 2351 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
| 2339 CallIC(stub.GetCode(isolate()), NOT_CONTEXTUAL, | 2352 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId()); |
| 2340 expr->BinaryOperationFeedbackId()); | |
| 2341 patch_site.EmitPatchInfo(); | 2353 patch_site.EmitPatchInfo(); |
| 2342 context()->Plug(eax); | 2354 context()->Plug(eax); |
| 2343 } | 2355 } |
| 2344 | 2356 |
| 2345 | 2357 |
| 2346 void FullCodeGenerator::EmitAssignment(Expression* expr) { | 2358 void FullCodeGenerator::EmitAssignment(Expression* expr) { |
| 2347 // Invalid left-hand sides are rewritten by the parser to have a 'throw | 2359 // Invalid left-hand sides are rewritten by the parser to have a 'throw |
| 2348 // ReferenceError' on the left-hand side. | 2360 // ReferenceError' on the left-hand side. |
| 2349 if (!expr->IsValidLeftHandSide()) { | 2361 if (!expr->IsValidLeftHandSide()) { |
| 2350 VisitForEffect(expr); | 2362 VisitForEffect(expr); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2368 EffectContext context(this); | 2380 EffectContext context(this); |
| 2369 EmitVariableAssignment(var, Token::ASSIGN); | 2381 EmitVariableAssignment(var, Token::ASSIGN); |
| 2370 break; | 2382 break; |
| 2371 } | 2383 } |
| 2372 case NAMED_PROPERTY: { | 2384 case NAMED_PROPERTY: { |
| 2373 __ push(eax); // Preserve value. | 2385 __ push(eax); // Preserve value. |
| 2374 VisitForAccumulatorValue(prop->obj()); | 2386 VisitForAccumulatorValue(prop->obj()); |
| 2375 __ mov(edx, eax); | 2387 __ mov(edx, eax); |
| 2376 __ pop(eax); // Restore value. | 2388 __ pop(eax); // Restore value. |
| 2377 __ mov(ecx, prop->key()->AsLiteral()->value()); | 2389 __ mov(ecx, prop->key()->AsLiteral()->value()); |
| 2378 CallStoreIC(NOT_CONTEXTUAL); | 2390 CallStoreIC(); |
| 2379 break; | 2391 break; |
| 2380 } | 2392 } |
| 2381 case KEYED_PROPERTY: { | 2393 case KEYED_PROPERTY: { |
| 2382 __ push(eax); // Preserve value. | 2394 __ push(eax); // Preserve value. |
| 2383 VisitForStackValue(prop->obj()); | 2395 VisitForStackValue(prop->obj()); |
| 2384 VisitForAccumulatorValue(prop->key()); | 2396 VisitForAccumulatorValue(prop->key()); |
| 2385 __ mov(ecx, eax); | 2397 __ mov(ecx, eax); |
| 2386 __ pop(edx); // Receiver. | 2398 __ pop(edx); // Receiver. |
| 2387 __ pop(eax); // Restore value. | 2399 __ pop(eax); // Restore value. |
| 2388 Handle<Code> ic = is_classic_mode() | 2400 Handle<Code> ic = is_classic_mode() |
| 2389 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2401 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2390 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2402 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2391 CallIC(ic); | 2403 CallIC(ic); |
| 2392 break; | 2404 break; |
| 2393 } | 2405 } |
| 2394 } | 2406 } |
| 2395 context()->Plug(eax); | 2407 context()->Plug(eax); |
| 2396 } | 2408 } |
| 2397 | 2409 |
| 2398 | 2410 |
| 2411 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( |
| 2412 Variable* var, MemOperand location) { |
| 2413 __ mov(location, eax); |
| 2414 if (var->IsContextSlot()) { |
| 2415 __ mov(edx, eax); |
| 2416 int offset = Context::SlotOffset(var->index()); |
| 2417 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); |
| 2418 } |
| 2419 } |
| 2420 |
| 2421 |
| 2422 void FullCodeGenerator::EmitCallStoreContextSlot( |
| 2423 Handle<String> name, LanguageMode mode) { |
| 2424 __ push(eax); // Value. |
| 2425 __ push(esi); // Context. |
| 2426 __ push(Immediate(name)); |
| 2427 __ push(Immediate(Smi::FromInt(mode))); |
| 2428 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
| 2429 } |
| 2430 |
| 2431 |
| 2399 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 2432 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 2400 Token::Value op) { | 2433 Token::Value op) { |
| 2401 if (var->IsUnallocated()) { | 2434 if (var->IsUnallocated()) { |
| 2402 // Global var, const, or let. | 2435 // Global var, const, or let. |
| 2403 __ mov(ecx, var->name()); | 2436 __ mov(ecx, var->name()); |
| 2404 __ mov(edx, GlobalObjectOperand()); | 2437 __ mov(edx, GlobalObjectOperand()); |
| 2405 CallStoreIC(CONTEXTUAL); | 2438 CallStoreIC(); |
| 2439 |
| 2406 } else if (op == Token::INIT_CONST) { | 2440 } else if (op == Token::INIT_CONST) { |
| 2407 // Const initializers need a write barrier. | 2441 // Const initializers need a write barrier. |
| 2408 ASSERT(!var->IsParameter()); // No const parameters. | 2442 ASSERT(!var->IsParameter()); // No const parameters. |
| 2409 if (var->IsStackLocal()) { | 2443 if (var->IsLookupSlot()) { |
| 2410 Label skip; | |
| 2411 __ mov(edx, StackOperand(var)); | |
| 2412 __ cmp(edx, isolate()->factory()->the_hole_value()); | |
| 2413 __ j(not_equal, &skip); | |
| 2414 __ mov(StackOperand(var), eax); | |
| 2415 __ bind(&skip); | |
| 2416 } else { | |
| 2417 ASSERT(var->IsContextSlot() || var->IsLookupSlot()); | |
| 2418 // Like var declarations, const declarations are hoisted to function | |
| 2419 // scope. However, unlike var initializers, const initializers are | |
| 2420 // able to drill a hole to that function context, even from inside a | |
| 2421 // 'with' context. We thus bypass the normal static scope lookup for | |
| 2422 // var->IsContextSlot(). | |
| 2423 __ push(eax); | 2444 __ push(eax); |
| 2424 __ push(esi); | 2445 __ push(esi); |
| 2425 __ push(Immediate(var->name())); | 2446 __ push(Immediate(var->name())); |
| 2426 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 2447 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 2448 } else { |
| 2449 ASSERT(var->IsStackLocal() || var->IsContextSlot()); |
| 2450 Label skip; |
| 2451 MemOperand location = VarOperand(var, ecx); |
| 2452 __ mov(edx, location); |
| 2453 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 2454 __ j(not_equal, &skip, Label::kNear); |
| 2455 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2456 __ bind(&skip); |
| 2427 } | 2457 } |
| 2428 | 2458 |
| 2429 } else if (var->mode() == LET && op != Token::INIT_LET) { | 2459 } else if (var->mode() == LET && op != Token::INIT_LET) { |
| 2430 // Non-initializing assignment to let variable needs a write barrier. | 2460 // Non-initializing assignment to let variable needs a write barrier. |
| 2431 if (var->IsLookupSlot()) { | 2461 if (var->IsLookupSlot()) { |
| 2432 __ push(eax); // Value. | 2462 EmitCallStoreContextSlot(var->name(), language_mode()); |
| 2433 __ push(esi); // Context. | |
| 2434 __ push(Immediate(var->name())); | |
| 2435 __ push(Immediate(Smi::FromInt(language_mode()))); | |
| 2436 __ CallRuntime(Runtime::kStoreContextSlot, 4); | |
| 2437 } else { | 2463 } else { |
| 2438 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2464 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
| 2439 Label assign; | 2465 Label assign; |
| 2440 MemOperand location = VarOperand(var, ecx); | 2466 MemOperand location = VarOperand(var, ecx); |
| 2441 __ mov(edx, location); | 2467 __ mov(edx, location); |
| 2442 __ cmp(edx, isolate()->factory()->the_hole_value()); | 2468 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 2443 __ j(not_equal, &assign, Label::kNear); | 2469 __ j(not_equal, &assign, Label::kNear); |
| 2444 __ push(Immediate(var->name())); | 2470 __ push(Immediate(var->name())); |
| 2445 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 2471 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 2446 __ bind(&assign); | 2472 __ bind(&assign); |
| 2447 __ mov(location, eax); | 2473 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2448 if (var->IsContextSlot()) { | |
| 2449 __ mov(edx, eax); | |
| 2450 int offset = Context::SlotOffset(var->index()); | |
| 2451 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); | |
| 2452 } | |
| 2453 } | 2474 } |
| 2454 | 2475 |
| 2455 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { | 2476 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { |
| 2456 // Assignment to var or initializing assignment to let/const | 2477 // Assignment to var or initializing assignment to let/const |
| 2457 // in harmony mode. | 2478 // in harmony mode. |
| 2458 if (var->IsStackAllocated() || var->IsContextSlot()) { | 2479 if (var->IsLookupSlot()) { |
| 2480 EmitCallStoreContextSlot(var->name(), language_mode()); |
| 2481 } else { |
| 2482 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
| 2459 MemOperand location = VarOperand(var, ecx); | 2483 MemOperand location = VarOperand(var, ecx); |
| 2460 if (generate_debug_code_ && op == Token::INIT_LET) { | 2484 if (generate_debug_code_ && op == Token::INIT_LET) { |
| 2461 // Check for an uninitialized let binding. | 2485 // Check for an uninitialized let binding. |
| 2462 __ mov(edx, location); | 2486 __ mov(edx, location); |
| 2463 __ cmp(edx, isolate()->factory()->the_hole_value()); | 2487 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 2464 __ Check(equal, kLetBindingReInitialization); | 2488 __ Check(equal, kLetBindingReInitialization); |
| 2465 } | 2489 } |
| 2466 // Perform the assignment. | 2490 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2467 __ mov(location, eax); | |
| 2468 if (var->IsContextSlot()) { | |
| 2469 __ mov(edx, eax); | |
| 2470 int offset = Context::SlotOffset(var->index()); | |
| 2471 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); | |
| 2472 } | |
| 2473 } else { | |
| 2474 ASSERT(var->IsLookupSlot()); | |
| 2475 __ push(eax); // Value. | |
| 2476 __ push(esi); // Context. | |
| 2477 __ push(Immediate(var->name())); | |
| 2478 __ push(Immediate(Smi::FromInt(language_mode()))); | |
| 2479 __ CallRuntime(Runtime::kStoreContextSlot, 4); | |
| 2480 } | 2491 } |
| 2481 } | 2492 } |
| 2482 // Non-initializing assignments to consts are ignored. | 2493 // Non-initializing assignments to consts are ignored. |
| 2483 } | 2494 } |
| 2484 | 2495 |
| 2485 | 2496 |
| 2486 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 2497 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 2487 // Assignment to a property, using a named store IC. | 2498 // Assignment to a property, using a named store IC. |
| 2488 // eax : value | 2499 // eax : value |
| 2489 // esp[0] : receiver | 2500 // esp[0] : receiver |
| 2490 | 2501 |
| 2491 Property* prop = expr->target()->AsProperty(); | 2502 Property* prop = expr->target()->AsProperty(); |
| 2492 ASSERT(prop != NULL); | 2503 ASSERT(prop != NULL); |
| 2493 ASSERT(prop->key()->AsLiteral() != NULL); | 2504 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2494 | 2505 |
| 2495 // Record source code position before IC call. | 2506 // Record source code position before IC call. |
| 2496 SetSourcePosition(expr->position()); | 2507 SetSourcePosition(expr->position()); |
| 2497 __ mov(ecx, prop->key()->AsLiteral()->value()); | 2508 __ mov(ecx, prop->key()->AsLiteral()->value()); |
| 2498 __ pop(edx); | 2509 __ pop(edx); |
| 2499 CallStoreIC(NOT_CONTEXTUAL, expr->AssignmentFeedbackId()); | 2510 CallStoreIC(expr->AssignmentFeedbackId()); |
| 2500 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2511 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2501 context()->Plug(eax); | 2512 context()->Plug(eax); |
| 2502 } | 2513 } |
| 2503 | 2514 |
| 2504 | 2515 |
| 2505 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 2516 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
| 2506 // Assignment to a property, using a keyed store IC. | 2517 // Assignment to a property, using a keyed store IC. |
| 2507 // eax : value | 2518 // eax : value |
| 2508 // esp[0] : key | 2519 // esp[0] : key |
| 2509 // esp[kPointerSize] : receiver | 2520 // esp[kPointerSize] : receiver |
| 2510 | 2521 |
| 2511 __ pop(ecx); // Key. | 2522 __ pop(ecx); // Key. |
| 2512 __ pop(edx); | 2523 __ pop(edx); |
| 2513 // Record source code position before IC call. | 2524 // Record source code position before IC call. |
| 2514 SetSourcePosition(expr->position()); | 2525 SetSourcePosition(expr->position()); |
| 2515 Handle<Code> ic = is_classic_mode() | 2526 Handle<Code> ic = is_classic_mode() |
| 2516 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2527 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2517 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2528 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2518 CallIC(ic, NOT_CONTEXTUAL, expr->AssignmentFeedbackId()); | 2529 CallIC(ic, expr->AssignmentFeedbackId()); |
| 2519 | 2530 |
| 2520 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2531 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2521 context()->Plug(eax); | 2532 context()->Plug(eax); |
| 2522 } | 2533 } |
| 2523 | 2534 |
| 2524 | 2535 |
| 2525 void FullCodeGenerator::VisitProperty(Property* expr) { | 2536 void FullCodeGenerator::VisitProperty(Property* expr) { |
| 2526 Comment cmnt(masm_, "[ Property"); | 2537 Comment cmnt(masm_, "[ Property"); |
| 2527 Expression* key = expr->key(); | 2538 Expression* key = expr->key(); |
| 2528 | 2539 |
| 2529 if (key->IsPropertyName()) { | 2540 if (key->IsPropertyName()) { |
| 2530 VisitForAccumulatorValue(expr->obj()); | 2541 VisitForAccumulatorValue(expr->obj()); |
| 2531 __ mov(edx, result_register()); | 2542 __ mov(edx, result_register()); |
| 2532 EmitNamedPropertyLoad(expr); | 2543 EmitNamedPropertyLoad(expr); |
| 2533 PrepareForBailoutForId(expr->LoadId(), TOS_REG); | 2544 PrepareForBailoutForId(expr->LoadId(), TOS_REG); |
| 2534 context()->Plug(eax); | 2545 context()->Plug(eax); |
| 2535 } else { | 2546 } else { |
| 2536 VisitForStackValue(expr->obj()); | 2547 VisitForStackValue(expr->obj()); |
| 2537 VisitForAccumulatorValue(expr->key()); | 2548 VisitForAccumulatorValue(expr->key()); |
| 2538 __ pop(edx); // Object. | 2549 __ pop(edx); // Object. |
| 2539 __ mov(ecx, result_register()); // Key. | 2550 __ mov(ecx, result_register()); // Key. |
| 2540 EmitKeyedPropertyLoad(expr); | 2551 EmitKeyedPropertyLoad(expr); |
| 2541 context()->Plug(eax); | 2552 context()->Plug(eax); |
| 2542 } | 2553 } |
| 2543 } | 2554 } |
| 2544 | 2555 |
| 2545 | 2556 |
| 2546 void FullCodeGenerator::CallIC(Handle<Code> code, | 2557 void FullCodeGenerator::CallIC(Handle<Code> code, |
| 2547 ContextualMode mode, | |
| 2548 TypeFeedbackId ast_id) { | 2558 TypeFeedbackId ast_id) { |
| 2549 ic_total_count_++; | 2559 ic_total_count_++; |
| 2550 ASSERT(mode != CONTEXTUAL || ast_id.IsNone()); | |
| 2551 __ call(code, RelocInfo::CODE_TARGET, ast_id); | 2560 __ call(code, RelocInfo::CODE_TARGET, ast_id); |
| 2552 } | 2561 } |
| 2553 | 2562 |
| 2554 | 2563 |
| 2555 | 2564 |
| 2556 | 2565 |
| 2557 void FullCodeGenerator::EmitCallWithIC(Call* expr, | 2566 // Code common for calls using the IC. |
| 2558 Handle<Object> name, | 2567 void FullCodeGenerator::EmitCallWithIC(Call* expr) { |
| 2559 ContextualMode mode) { | 2568 Expression* callee = expr->expression(); |
| 2560 // Code common for calls using the IC. | |
| 2561 ZoneList<Expression*>* args = expr->arguments(); | 2569 ZoneList<Expression*>* args = expr->arguments(); |
| 2562 int arg_count = args->length(); | 2570 int arg_count = args->length(); |
| 2571 |
| 2572 CallFunctionFlags flags; |
| 2573 // Get the target function. |
| 2574 if (callee->IsVariableProxy()) { |
| 2575 { StackValueContext context(this); |
| 2576 EmitVariableLoad(callee->AsVariableProxy()); |
| 2577 PrepareForBailout(callee, NO_REGISTERS); |
| 2578 } |
| 2579 // Push undefined as receiver. This is patched in the method prologue if it |
| 2580 // is a classic mode method. |
| 2581 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 2582 flags = NO_CALL_FUNCTION_FLAGS; |
| 2583 } else { |
| 2584 // Load the function from the receiver. |
| 2585 ASSERT(callee->IsProperty()); |
| 2586 __ mov(edx, Operand(esp, 0)); |
| 2587 EmitNamedPropertyLoad(callee->AsProperty()); |
| 2588 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); |
| 2589 // Push the target function under the receiver. |
| 2590 __ push(Operand(esp, 0)); |
| 2591 __ mov(Operand(esp, kPointerSize), eax); |
| 2592 flags = CALL_AS_METHOD; |
| 2593 } |
| 2594 |
| 2595 // Load the arguments. |
| 2563 { PreservePositionScope scope(masm()->positions_recorder()); | 2596 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2564 for (int i = 0; i < arg_count; i++) { | 2597 for (int i = 0; i < arg_count; i++) { |
| 2565 VisitForStackValue(args->at(i)); | 2598 VisitForStackValue(args->at(i)); |
| 2566 } | 2599 } |
| 2567 __ Set(ecx, Immediate(name)); | |
| 2568 } | 2600 } |
| 2601 |
| 2569 // Record source position of the IC call. | 2602 // Record source position of the IC call. |
| 2570 SetSourcePosition(expr->position()); | 2603 SetSourcePosition(expr->position()); |
| 2571 Handle<Code> ic = | 2604 CallFunctionStub stub(arg_count, flags); |
| 2572 isolate()->stub_cache()->ComputeCallInitialize(arg_count); | 2605 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); |
| 2573 TypeFeedbackId ast_id = mode == CONTEXTUAL | 2606 __ CallStub(&stub); |
| 2574 ? TypeFeedbackId::None() | |
| 2575 : expr->CallFeedbackId(); | |
| 2576 CallIC(ic, mode, ast_id); | |
| 2577 RecordJSReturnSite(expr); | 2607 RecordJSReturnSite(expr); |
| 2608 |
| 2578 // Restore context register. | 2609 // Restore context register. |
| 2579 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2610 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2580 context()->Plug(eax); | 2611 |
| 2612 context()->DropAndPlug(1, eax); |
| 2581 } | 2613 } |
| 2582 | 2614 |
| 2583 | 2615 |
| 2616 // Code common for calls using the IC. |
| 2584 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 2617 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 2585 Expression* key) { | 2618 Expression* key) { |
| 2586 // Load the key. | 2619 // Load the key. |
| 2587 VisitForAccumulatorValue(key); | 2620 VisitForAccumulatorValue(key); |
| 2588 | 2621 |
| 2589 // Swap the name of the function and the receiver on the stack to follow | 2622 Expression* callee = expr->expression(); |
| 2590 // the calling convention for call ICs. | 2623 ZoneList<Expression*>* args = expr->arguments(); |
| 2591 __ pop(ecx); | 2624 int arg_count = args->length(); |
| 2592 __ push(eax); | 2625 |
| 2593 __ push(ecx); | 2626 // Load the function from the receiver. |
| 2627 ASSERT(callee->IsProperty()); |
| 2628 __ mov(edx, Operand(esp, 0)); |
| 2629 // Move the key into the right register for the keyed load IC. |
| 2630 __ mov(ecx, eax); |
| 2631 EmitKeyedPropertyLoad(callee->AsProperty()); |
| 2632 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); |
| 2633 |
| 2634 // Push the target function under the receiver. |
| 2635 __ push(Operand(esp, 0)); |
| 2636 __ mov(Operand(esp, kPointerSize), eax); |
| 2594 | 2637 |
| 2595 // Load the arguments. | 2638 // Load the arguments. |
| 2596 ZoneList<Expression*>* args = expr->arguments(); | |
| 2597 int arg_count = args->length(); | |
| 2598 { PreservePositionScope scope(masm()->positions_recorder()); | 2639 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2599 for (int i = 0; i < arg_count; i++) { | 2640 for (int i = 0; i < arg_count; i++) { |
| 2600 VisitForStackValue(args->at(i)); | 2641 VisitForStackValue(args->at(i)); |
| 2601 } | 2642 } |
| 2602 } | 2643 } |
| 2644 |
| 2603 // Record source position of the IC call. | 2645 // Record source position of the IC call. |
| 2604 SetSourcePosition(expr->position()); | 2646 SetSourcePosition(expr->position()); |
| 2605 Handle<Code> ic = | 2647 CallFunctionStub stub(arg_count, CALL_AS_METHOD); |
| 2606 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); | 2648 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); |
| 2607 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key. | 2649 __ CallStub(&stub); |
| 2608 CallIC(ic, NOT_CONTEXTUAL, expr->CallFeedbackId()); | |
| 2609 RecordJSReturnSite(expr); | 2650 RecordJSReturnSite(expr); |
| 2651 |
| 2610 // Restore context register. | 2652 // Restore context register. |
| 2611 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2653 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2612 context()->DropAndPlug(1, eax); // Drop the key still on the stack. | 2654 |
| 2655 context()->DropAndPlug(1, eax); |
| 2613 } | 2656 } |
| 2614 | 2657 |
| 2615 | 2658 |
| 2616 void FullCodeGenerator::EmitCallWithStub(Call* expr) { | 2659 void FullCodeGenerator::EmitCallWithStub(Call* expr) { |
| 2617 // Code common for calls using the call stub. | 2660 // Code common for calls using the call stub. |
| 2618 ZoneList<Expression*>* args = expr->arguments(); | 2661 ZoneList<Expression*>* args = expr->arguments(); |
| 2619 int arg_count = args->length(); | 2662 int arg_count = args->length(); |
| 2620 { PreservePositionScope scope(masm()->positions_recorder()); | 2663 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2621 for (int i = 0; i < arg_count; i++) { | 2664 for (int i = 0; i < arg_count; i++) { |
| 2622 VisitForStackValue(args->at(i)); | 2665 VisitForStackValue(args->at(i)); |
| 2623 } | 2666 } |
| 2624 } | 2667 } |
| 2625 // Record source position for debugger. | 2668 // Record source position for debugger. |
| 2626 SetSourcePosition(expr->position()); | 2669 SetSourcePosition(expr->position()); |
| 2627 | 2670 |
| 2628 Handle<Object> uninitialized = | 2671 Handle<Object> uninitialized = |
| 2629 TypeFeedbackCells::UninitializedSentinel(isolate()); | 2672 TypeFeedbackInfo::UninitializedSentinel(isolate()); |
| 2630 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); | 2673 StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized); |
| 2631 RecordTypeFeedbackCell(expr->CallFeedbackId(), cell); | 2674 __ LoadHeapObject(ebx, FeedbackVector()); |
| 2632 __ mov(ebx, cell); | 2675 __ mov(edx, Immediate(Smi::FromInt(expr->CallFeedbackSlot()))); |
| 2633 | 2676 |
| 2634 // Record call targets in unoptimized code. | 2677 // Record call targets in unoptimized code. |
| 2635 CallFunctionStub stub(arg_count, RECORD_CALL_TARGET); | 2678 CallFunctionStub stub(arg_count, RECORD_CALL_TARGET); |
| 2636 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); | 2679 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); |
| 2637 __ CallStub(&stub, expr->CallFeedbackId()); | 2680 __ CallStub(&stub); |
| 2638 | 2681 |
| 2639 RecordJSReturnSite(expr); | 2682 RecordJSReturnSite(expr); |
| 2640 // Restore context register. | 2683 // Restore context register. |
| 2641 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2684 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2642 context()->DropAndPlug(1, eax); | 2685 context()->DropAndPlug(1, eax); |
| 2643 } | 2686 } |
| 2644 | 2687 |
| 2645 | 2688 |
| 2646 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { | 2689 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { |
| 2647 // Push copy of the first argument or undefined if it doesn't exist. | 2690 // Push copy of the first argument or undefined if it doesn't exist. |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2704 SetSourcePosition(expr->position()); | 2747 SetSourcePosition(expr->position()); |
| 2705 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); | 2748 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); |
| 2706 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); | 2749 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); |
| 2707 __ CallStub(&stub); | 2750 __ CallStub(&stub); |
| 2708 RecordJSReturnSite(expr); | 2751 RecordJSReturnSite(expr); |
| 2709 // Restore context register. | 2752 // Restore context register. |
| 2710 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2753 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2711 context()->DropAndPlug(1, eax); | 2754 context()->DropAndPlug(1, eax); |
| 2712 | 2755 |
| 2713 } else if (call_type == Call::GLOBAL_CALL) { | 2756 } else if (call_type == Call::GLOBAL_CALL) { |
| 2714 // Push global object as receiver for the call IC. | 2757 EmitCallWithIC(expr); |
| 2715 __ push(GlobalObjectOperand()); | 2758 |
| 2716 VariableProxy* proxy = callee->AsVariableProxy(); | |
| 2717 EmitCallWithIC(expr, proxy->name(), CONTEXTUAL); | |
| 2718 } else if (call_type == Call::LOOKUP_SLOT_CALL) { | 2759 } else if (call_type == Call::LOOKUP_SLOT_CALL) { |
| 2719 // Call to a lookup slot (dynamically introduced variable). | 2760 // Call to a lookup slot (dynamically introduced variable). |
| 2720 VariableProxy* proxy = callee->AsVariableProxy(); | 2761 VariableProxy* proxy = callee->AsVariableProxy(); |
| 2721 Label slow, done; | 2762 Label slow, done; |
| 2722 { PreservePositionScope scope(masm()->positions_recorder()); | 2763 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2723 // Generate code for loading from variables potentially shadowed by | 2764 // Generate code for loading from variables potentially shadowed by |
| 2724 // eval-introduced variables. | 2765 // eval-introduced variables. |
| 2725 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); | 2766 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); |
| 2726 } | 2767 } |
| 2727 __ bind(&slow); | 2768 __ bind(&slow); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2750 // The receiver is either the global receiver or an object found by | 2791 // The receiver is either the global receiver or an object found by |
| 2751 // LoadContextSlot. | 2792 // LoadContextSlot. |
| 2752 EmitCallWithStub(expr); | 2793 EmitCallWithStub(expr); |
| 2753 | 2794 |
| 2754 } else if (call_type == Call::PROPERTY_CALL) { | 2795 } else if (call_type == Call::PROPERTY_CALL) { |
| 2755 Property* property = callee->AsProperty(); | 2796 Property* property = callee->AsProperty(); |
| 2756 { PreservePositionScope scope(masm()->positions_recorder()); | 2797 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2757 VisitForStackValue(property->obj()); | 2798 VisitForStackValue(property->obj()); |
| 2758 } | 2799 } |
| 2759 if (property->key()->IsPropertyName()) { | 2800 if (property->key()->IsPropertyName()) { |
| 2760 EmitCallWithIC(expr, | 2801 EmitCallWithIC(expr); |
| 2761 property->key()->AsLiteral()->value(), | |
| 2762 NOT_CONTEXTUAL); | |
| 2763 } else { | 2802 } else { |
| 2764 EmitKeyedCallWithIC(expr, property->key()); | 2803 EmitKeyedCallWithIC(expr, property->key()); |
| 2765 } | 2804 } |
| 2766 | 2805 |
| 2767 } else { | 2806 } else { |
| 2768 ASSERT(call_type == Call::OTHER_CALL); | 2807 ASSERT(call_type == Call::OTHER_CALL); |
| 2769 // Call to an arbitrary expression not handled specially above. | 2808 // Call to an arbitrary expression not handled specially above. |
| 2770 { PreservePositionScope scope(masm()->positions_recorder()); | 2809 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2771 VisitForStackValue(callee); | 2810 VisitForStackValue(callee); |
| 2772 } | 2811 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2803 // Call the construct call builtin that handles allocation and | 2842 // Call the construct call builtin that handles allocation and |
| 2804 // constructor invocation. | 2843 // constructor invocation. |
| 2805 SetSourcePosition(expr->position()); | 2844 SetSourcePosition(expr->position()); |
| 2806 | 2845 |
| 2807 // Load function and argument count into edi and eax. | 2846 // Load function and argument count into edi and eax. |
| 2808 __ Set(eax, Immediate(arg_count)); | 2847 __ Set(eax, Immediate(arg_count)); |
| 2809 __ mov(edi, Operand(esp, arg_count * kPointerSize)); | 2848 __ mov(edi, Operand(esp, arg_count * kPointerSize)); |
| 2810 | 2849 |
| 2811 // Record call targets in unoptimized code. | 2850 // Record call targets in unoptimized code. |
| 2812 Handle<Object> uninitialized = | 2851 Handle<Object> uninitialized = |
| 2813 TypeFeedbackCells::UninitializedSentinel(isolate()); | 2852 TypeFeedbackInfo::UninitializedSentinel(isolate()); |
| 2814 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); | 2853 StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized); |
| 2815 RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell); | 2854 __ LoadHeapObject(ebx, FeedbackVector()); |
| 2816 __ mov(ebx, cell); | 2855 __ mov(edx, Immediate(Smi::FromInt(expr->CallNewFeedbackSlot()))); |
| 2817 | 2856 |
| 2818 CallConstructStub stub(RECORD_CALL_TARGET); | 2857 CallConstructStub stub(RECORD_CALL_TARGET); |
| 2819 __ call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); | 2858 __ call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); |
| 2820 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); | 2859 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); |
| 2821 context()->Plug(eax); | 2860 context()->Plug(eax); |
| 2822 } | 2861 } |
| 2823 | 2862 |
| 2824 | 2863 |
| 2825 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { | 2864 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { |
| 2826 ZoneList<Expression*>* args = expr->arguments(); | 2865 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 575 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3402 | 3441 |
| 3403 VisitForStackValue(args->at(1)); // index | 3442 VisitForStackValue(args->at(1)); // index |
| 3404 VisitForStackValue(args->at(2)); // value | 3443 VisitForStackValue(args->at(2)); // value |
| 3405 VisitForAccumulatorValue(args->at(0)); // string | 3444 VisitForAccumulatorValue(args->at(0)); // string |
| 3406 | 3445 |
| 3407 __ pop(value); | 3446 __ pop(value); |
| 3408 __ pop(index); | 3447 __ pop(index); |
| 3409 | 3448 |
| 3410 if (FLAG_debug_code) { | 3449 if (FLAG_debug_code) { |
| 3411 __ test(value, Immediate(kSmiTagMask)); | 3450 __ test(value, Immediate(kSmiTagMask)); |
| 3412 __ ThrowIf(not_zero, kNonSmiValue); | 3451 __ Check(zero, kNonSmiValue); |
| 3413 __ test(index, Immediate(kSmiTagMask)); | 3452 __ test(index, Immediate(kSmiTagMask)); |
| 3414 __ ThrowIf(not_zero, kNonSmiValue); | 3453 __ Check(zero, kNonSmiValue); |
| 3415 } | 3454 } |
| 3416 | 3455 |
| 3417 __ SmiUntag(value); | 3456 __ SmiUntag(value); |
| 3418 __ SmiUntag(index); | 3457 __ SmiUntag(index); |
| 3419 | 3458 |
| 3420 if (FLAG_debug_code) { | 3459 if (FLAG_debug_code) { |
| 3421 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; | 3460 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; |
| 3422 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type); | 3461 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type); |
| 3423 } | 3462 } |
| 3424 | 3463 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3437 Register value = ecx; | 3476 Register value = ecx; |
| 3438 | 3477 |
| 3439 VisitForStackValue(args->at(1)); // index | 3478 VisitForStackValue(args->at(1)); // index |
| 3440 VisitForStackValue(args->at(2)); // value | 3479 VisitForStackValue(args->at(2)); // value |
| 3441 VisitForAccumulatorValue(args->at(0)); // string | 3480 VisitForAccumulatorValue(args->at(0)); // string |
| 3442 __ pop(value); | 3481 __ pop(value); |
| 3443 __ pop(index); | 3482 __ pop(index); |
| 3444 | 3483 |
| 3445 if (FLAG_debug_code) { | 3484 if (FLAG_debug_code) { |
| 3446 __ test(value, Immediate(kSmiTagMask)); | 3485 __ test(value, Immediate(kSmiTagMask)); |
| 3447 __ ThrowIf(not_zero, kNonSmiValue); | 3486 __ Check(zero, kNonSmiValue); |
| 3448 __ test(index, Immediate(kSmiTagMask)); | 3487 __ test(index, Immediate(kSmiTagMask)); |
| 3449 __ ThrowIf(not_zero, kNonSmiValue); | 3488 __ Check(zero, kNonSmiValue); |
| 3450 __ SmiUntag(index); | 3489 __ SmiUntag(index); |
| 3451 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; | 3490 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; |
| 3452 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); | 3491 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); |
| 3453 __ SmiTag(index); | 3492 __ SmiTag(index); |
| 3454 } | 3493 } |
| 3455 | 3494 |
| 3456 __ SmiUntag(value); | 3495 __ SmiUntag(value); |
| 3457 // No need to untag a smi for two-byte addressing. | 3496 // No need to untag a smi for two-byte addressing. |
| 3458 __ mov_w(FieldOperand(string, index, times_1, SeqTwoByteString::kHeaderSize), | 3497 __ mov_w(FieldOperand(string, index, times_1, SeqTwoByteString::kHeaderSize), |
| 3459 value); | 3498 value); |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3629 generator.GenerateSlow(masm_, call_helper); | 3668 generator.GenerateSlow(masm_, call_helper); |
| 3630 | 3669 |
| 3631 __ bind(&done); | 3670 __ bind(&done); |
| 3632 context()->Plug(result); | 3671 context()->Plug(result); |
| 3633 } | 3672 } |
| 3634 | 3673 |
| 3635 | 3674 |
| 3636 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { | 3675 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { |
| 3637 ZoneList<Expression*>* args = expr->arguments(); | 3676 ZoneList<Expression*>* args = expr->arguments(); |
| 3638 ASSERT_EQ(2, args->length()); | 3677 ASSERT_EQ(2, args->length()); |
| 3678 VisitForStackValue(args->at(0)); |
| 3679 VisitForAccumulatorValue(args->at(1)); |
| 3639 | 3680 |
| 3640 if (FLAG_new_string_add) { | 3681 __ pop(edx); |
| 3641 VisitForStackValue(args->at(0)); | 3682 StringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); |
| 3642 VisitForAccumulatorValue(args->at(1)); | 3683 __ CallStub(&stub); |
| 3643 | |
| 3644 __ pop(edx); | |
| 3645 NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); | |
| 3646 __ CallStub(&stub); | |
| 3647 } else { | |
| 3648 VisitForStackValue(args->at(0)); | |
| 3649 VisitForStackValue(args->at(1)); | |
| 3650 | |
| 3651 StringAddStub stub(STRING_ADD_CHECK_BOTH); | |
| 3652 __ CallStub(&stub); | |
| 3653 } | |
| 3654 context()->Plug(eax); | 3684 context()->Plug(eax); |
| 3655 } | 3685 } |
| 3656 | 3686 |
| 3657 | 3687 |
| 3658 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { | 3688 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { |
| 3659 ZoneList<Expression*>* args = expr->arguments(); | 3689 ZoneList<Expression*>* args = expr->arguments(); |
| 3660 ASSERT_EQ(2, args->length()); | 3690 ASSERT_EQ(2, args->length()); |
| 3661 | 3691 |
| 3662 VisitForStackValue(args->at(0)); | 3692 VisitForStackValue(args->at(0)); |
| 3663 VisitForStackValue(args->at(1)); | 3693 VisitForStackValue(args->at(1)); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3720 } | 3750 } |
| 3721 | 3751 |
| 3722 | 3752 |
| 3723 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { | 3753 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { |
| 3724 // Load the arguments on the stack and call the stub. | 3754 // Load the arguments on the stack and call the stub. |
| 3725 RegExpConstructResultStub stub; | 3755 RegExpConstructResultStub stub; |
| 3726 ZoneList<Expression*>* args = expr->arguments(); | 3756 ZoneList<Expression*>* args = expr->arguments(); |
| 3727 ASSERT(args->length() == 3); | 3757 ASSERT(args->length() == 3); |
| 3728 VisitForStackValue(args->at(0)); | 3758 VisitForStackValue(args->at(0)); |
| 3729 VisitForStackValue(args->at(1)); | 3759 VisitForStackValue(args->at(1)); |
| 3730 VisitForStackValue(args->at(2)); | 3760 VisitForAccumulatorValue(args->at(2)); |
| 3761 __ pop(ebx); |
| 3762 __ pop(ecx); |
| 3731 __ CallStub(&stub); | 3763 __ CallStub(&stub); |
| 3732 context()->Plug(eax); | 3764 context()->Plug(eax); |
| 3733 } | 3765 } |
| 3734 | 3766 |
| 3735 | 3767 |
| 3736 void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { | 3768 void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { |
| 3737 ZoneList<Expression*>* args = expr->arguments(); | 3769 ZoneList<Expression*>* args = expr->arguments(); |
| 3738 ASSERT_EQ(2, args->length()); | 3770 ASSERT_EQ(2, args->length()); |
| 3739 | 3771 |
| 3740 ASSERT_NE(NULL, args->at(0)->AsLiteral()); | 3772 ASSERT_NE(NULL, args->at(0)->AsLiteral()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3755 Register cache = ebx; | 3787 Register cache = ebx; |
| 3756 Register tmp = ecx; | 3788 Register tmp = ecx; |
| 3757 __ mov(cache, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX)); | 3789 __ mov(cache, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX)); |
| 3758 __ mov(cache, | 3790 __ mov(cache, |
| 3759 FieldOperand(cache, GlobalObject::kNativeContextOffset)); | 3791 FieldOperand(cache, GlobalObject::kNativeContextOffset)); |
| 3760 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); | 3792 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); |
| 3761 __ mov(cache, | 3793 __ mov(cache, |
| 3762 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); | 3794 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); |
| 3763 | 3795 |
| 3764 Label done, not_found; | 3796 Label done, not_found; |
| 3765 // tmp now holds finger offset as a smi. | |
| 3766 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 3797 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| 3767 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); | 3798 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); |
| 3768 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp)); | 3799 // tmp now holds finger offset as a smi. |
| 3800 __ cmp(key, FixedArrayElementOperand(cache, tmp)); |
| 3769 __ j(not_equal, ¬_found); | 3801 __ j(not_equal, ¬_found); |
| 3770 | 3802 |
| 3771 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1)); | 3803 __ mov(eax, FixedArrayElementOperand(cache, tmp, 1)); |
| 3772 __ jmp(&done); | 3804 __ jmp(&done); |
| 3773 | 3805 |
| 3774 __ bind(¬_found); | 3806 __ bind(¬_found); |
| 3775 // Call runtime to perform the lookup. | 3807 // Call runtime to perform the lookup. |
| 3776 __ push(cache); | 3808 __ push(cache); |
| 3777 __ push(key); | 3809 __ push(key); |
| 3778 __ CallRuntime(Runtime::kGetFromCache, 2); | 3810 __ CallRuntime(Runtime::kGetFromCache, 2); |
| 3779 | 3811 |
| 3780 __ bind(&done); | 3812 __ bind(&done); |
| 3781 context()->Plug(eax); | 3813 context()->Plug(eax); |
| 3782 } | 3814 } |
| 3783 | 3815 |
| 3784 | 3816 |
| 3785 void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) { | |
| 3786 ZoneList<Expression*>* args = expr->arguments(); | |
| 3787 ASSERT_EQ(2, args->length()); | |
| 3788 | |
| 3789 Register right = eax; | |
| 3790 Register left = ebx; | |
| 3791 Register tmp = ecx; | |
| 3792 | |
| 3793 VisitForStackValue(args->at(0)); | |
| 3794 VisitForAccumulatorValue(args->at(1)); | |
| 3795 __ pop(left); | |
| 3796 | |
| 3797 Label done, fail, ok; | |
| 3798 __ cmp(left, right); | |
| 3799 __ j(equal, &ok); | |
| 3800 // Fail if either is a non-HeapObject. | |
| 3801 __ mov(tmp, left); | |
| 3802 __ and_(tmp, right); | |
| 3803 __ JumpIfSmi(tmp, &fail); | |
| 3804 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset)); | |
| 3805 __ CmpInstanceType(tmp, JS_REGEXP_TYPE); | |
| 3806 __ j(not_equal, &fail); | |
| 3807 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset)); | |
| 3808 __ j(not_equal, &fail); | |
| 3809 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset)); | |
| 3810 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset)); | |
| 3811 __ j(equal, &ok); | |
| 3812 __ bind(&fail); | |
| 3813 __ mov(eax, Immediate(isolate()->factory()->false_value())); | |
| 3814 __ jmp(&done); | |
| 3815 __ bind(&ok); | |
| 3816 __ mov(eax, Immediate(isolate()->factory()->true_value())); | |
| 3817 __ bind(&done); | |
| 3818 | |
| 3819 context()->Plug(eax); | |
| 3820 } | |
| 3821 | |
| 3822 | |
| 3823 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { | 3817 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { |
| 3824 ZoneList<Expression*>* args = expr->arguments(); | 3818 ZoneList<Expression*>* args = expr->arguments(); |
| 3825 ASSERT(args->length() == 1); | 3819 ASSERT(args->length() == 1); |
| 3826 | 3820 |
| 3827 VisitForAccumulatorValue(args->at(0)); | 3821 VisitForAccumulatorValue(args->at(0)); |
| 3828 | 3822 |
| 3829 __ AssertString(eax); | 3823 __ AssertString(eax); |
| 3830 | 3824 |
| 3831 Label materialize_true, materialize_false; | 3825 Label materialize_true, materialize_false; |
| 3832 Label* if_true = NULL; | 3826 Label* if_true = NULL; |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4127 if (name->length() > 0 && name->Get(0) == '_') { | 4121 if (name->length() > 0 && name->Get(0) == '_') { |
| 4128 Comment cmnt(masm_, "[ InlineRuntimeCall"); | 4122 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
| 4129 EmitInlineRuntimeCall(expr); | 4123 EmitInlineRuntimeCall(expr); |
| 4130 return; | 4124 return; |
| 4131 } | 4125 } |
| 4132 | 4126 |
| 4133 Comment cmnt(masm_, "[ CallRuntime"); | 4127 Comment cmnt(masm_, "[ CallRuntime"); |
| 4134 ZoneList<Expression*>* args = expr->arguments(); | 4128 ZoneList<Expression*>* args = expr->arguments(); |
| 4135 | 4129 |
| 4136 if (expr->is_jsruntime()) { | 4130 if (expr->is_jsruntime()) { |
| 4137 // Prepare for calling JS runtime function. | 4131 // Push the builtins object as receiver. |
| 4138 __ mov(eax, GlobalObjectOperand()); | 4132 __ mov(eax, GlobalObjectOperand()); |
| 4139 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset)); | 4133 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset)); |
| 4140 } | |
| 4141 | 4134 |
| 4142 // Push the arguments ("left-to-right"). | 4135 // Load the function from the receiver. |
| 4143 int arg_count = args->length(); | 4136 __ mov(edx, Operand(esp, 0)); |
| 4144 for (int i = 0; i < arg_count; i++) { | 4137 __ mov(ecx, Immediate(expr->name())); |
| 4145 VisitForStackValue(args->at(i)); | 4138 CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); |
| 4146 } | |
| 4147 | 4139 |
| 4148 if (expr->is_jsruntime()) { | 4140 // Push the target function under the receiver. |
| 4149 // Call the JS runtime function via a call IC. | 4141 __ push(Operand(esp, 0)); |
| 4150 __ Set(ecx, Immediate(expr->name())); | 4142 __ mov(Operand(esp, kPointerSize), eax); |
| 4151 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count); | 4143 |
| 4152 CallIC(ic, NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); | 4144 // Code common for calls using the IC. |
| 4145 ZoneList<Expression*>* args = expr->arguments(); |
| 4146 int arg_count = args->length(); |
| 4147 for (int i = 0; i < arg_count; i++) { |
| 4148 VisitForStackValue(args->at(i)); |
| 4149 } |
| 4150 |
| 4151 // Record source position of the IC call. |
| 4152 SetSourcePosition(expr->position()); |
| 4153 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); |
| 4154 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); |
| 4155 __ CallStub(&stub); |
| 4153 // Restore context register. | 4156 // Restore context register. |
| 4154 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 4157 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 4158 context()->DropAndPlug(1, eax); |
| 4159 |
| 4155 } else { | 4160 } else { |
| 4161 // Push the arguments ("left-to-right"). |
| 4162 int arg_count = args->length(); |
| 4163 for (int i = 0; i < arg_count; i++) { |
| 4164 VisitForStackValue(args->at(i)); |
| 4165 } |
| 4166 |
| 4156 // Call the C runtime function. | 4167 // Call the C runtime function. |
| 4157 __ CallRuntime(expr->function(), arg_count); | 4168 __ CallRuntime(expr->function(), arg_count); |
| 4169 |
| 4170 context()->Plug(eax); |
| 4158 } | 4171 } |
| 4159 context()->Plug(eax); | |
| 4160 } | 4172 } |
| 4161 | 4173 |
| 4162 | 4174 |
| 4163 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 4175 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 4164 switch (expr->op()) { | 4176 switch (expr->op()) { |
| 4165 case Token::DELETE: { | 4177 case Token::DELETE: { |
| 4166 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 4178 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
| 4167 Property* property = expr->expression()->AsProperty(); | 4179 Property* property = expr->expression()->AsProperty(); |
| 4168 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 4180 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
| 4169 | 4181 |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4398 } | 4410 } |
| 4399 | 4411 |
| 4400 // Record position before stub call. | 4412 // Record position before stub call. |
| 4401 SetSourcePosition(expr->position()); | 4413 SetSourcePosition(expr->position()); |
| 4402 | 4414 |
| 4403 // Call stub for +1/-1. | 4415 // Call stub for +1/-1. |
| 4404 __ bind(&stub_call); | 4416 __ bind(&stub_call); |
| 4405 __ mov(edx, eax); | 4417 __ mov(edx, eax); |
| 4406 __ mov(eax, Immediate(Smi::FromInt(1))); | 4418 __ mov(eax, Immediate(Smi::FromInt(1))); |
| 4407 BinaryOpICStub stub(expr->binary_op(), NO_OVERWRITE); | 4419 BinaryOpICStub stub(expr->binary_op(), NO_OVERWRITE); |
| 4408 CallIC(stub.GetCode(isolate()), | 4420 CallIC(stub.GetCode(isolate()), expr->CountBinOpFeedbackId()); |
| 4409 NOT_CONTEXTUAL, | |
| 4410 expr->CountBinOpFeedbackId()); | |
| 4411 patch_site.EmitPatchInfo(); | 4421 patch_site.EmitPatchInfo(); |
| 4412 __ bind(&done); | 4422 __ bind(&done); |
| 4413 | 4423 |
| 4414 // Store the value returned in eax. | 4424 // Store the value returned in eax. |
| 4415 switch (assign_type) { | 4425 switch (assign_type) { |
| 4416 case VARIABLE: | 4426 case VARIABLE: |
| 4417 if (expr->is_postfix()) { | 4427 if (expr->is_postfix()) { |
| 4418 // Perform the assignment as if via '='. | 4428 // Perform the assignment as if via '='. |
| 4419 { EffectContext context(this); | 4429 { EffectContext context(this); |
| 4420 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 4430 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| (...skipping 10 matching lines...) Expand all Loading... |
| 4431 // Perform the assignment as if via '='. | 4441 // Perform the assignment as if via '='. |
| 4432 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 4442 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 4433 Token::ASSIGN); | 4443 Token::ASSIGN); |
| 4434 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4444 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4435 context()->Plug(eax); | 4445 context()->Plug(eax); |
| 4436 } | 4446 } |
| 4437 break; | 4447 break; |
| 4438 case NAMED_PROPERTY: { | 4448 case NAMED_PROPERTY: { |
| 4439 __ mov(ecx, prop->key()->AsLiteral()->value()); | 4449 __ mov(ecx, prop->key()->AsLiteral()->value()); |
| 4440 __ pop(edx); | 4450 __ pop(edx); |
| 4441 CallStoreIC(NOT_CONTEXTUAL, expr->CountStoreFeedbackId()); | 4451 CallStoreIC(expr->CountStoreFeedbackId()); |
| 4442 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4452 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4443 if (expr->is_postfix()) { | 4453 if (expr->is_postfix()) { |
| 4444 if (!context()->IsEffect()) { | 4454 if (!context()->IsEffect()) { |
| 4445 context()->PlugTOS(); | 4455 context()->PlugTOS(); |
| 4446 } | 4456 } |
| 4447 } else { | 4457 } else { |
| 4448 context()->Plug(eax); | 4458 context()->Plug(eax); |
| 4449 } | 4459 } |
| 4450 break; | 4460 break; |
| 4451 } | 4461 } |
| 4452 case KEYED_PROPERTY: { | 4462 case KEYED_PROPERTY: { |
| 4453 __ pop(ecx); | 4463 __ pop(ecx); |
| 4454 __ pop(edx); | 4464 __ pop(edx); |
| 4455 Handle<Code> ic = is_classic_mode() | 4465 Handle<Code> ic = is_classic_mode() |
| 4456 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 4466 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 4457 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 4467 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 4458 CallIC(ic, NOT_CONTEXTUAL, expr->CountStoreFeedbackId()); | 4468 CallIC(ic, expr->CountStoreFeedbackId()); |
| 4459 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4469 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4460 if (expr->is_postfix()) { | 4470 if (expr->is_postfix()) { |
| 4461 // Result is on the stack | 4471 // Result is on the stack |
| 4462 if (!context()->IsEffect()) { | 4472 if (!context()->IsEffect()) { |
| 4463 context()->PlugTOS(); | 4473 context()->PlugTOS(); |
| 4464 } | 4474 } |
| 4465 } else { | 4475 } else { |
| 4466 context()->Plug(eax); | 4476 context()->Plug(eax); |
| 4467 } | 4477 } |
| 4468 break; | 4478 break; |
| 4469 } | 4479 } |
| 4470 } | 4480 } |
| 4471 } | 4481 } |
| 4472 | 4482 |
| 4473 | 4483 |
| 4474 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 4484 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 4475 VariableProxy* proxy = expr->AsVariableProxy(); | 4485 VariableProxy* proxy = expr->AsVariableProxy(); |
| 4476 ASSERT(!context()->IsEffect()); | 4486 ASSERT(!context()->IsEffect()); |
| 4477 ASSERT(!context()->IsTest()); | 4487 ASSERT(!context()->IsTest()); |
| 4478 | 4488 |
| 4479 if (proxy != NULL && proxy->var()->IsUnallocated()) { | 4489 if (proxy != NULL && proxy->var()->IsUnallocated()) { |
| 4480 Comment cmnt(masm_, "Global variable"); | 4490 Comment cmnt(masm_, "[ Global variable"); |
| 4481 __ mov(edx, GlobalObjectOperand()); | 4491 __ mov(edx, GlobalObjectOperand()); |
| 4482 __ mov(ecx, Immediate(proxy->name())); | 4492 __ mov(ecx, Immediate(proxy->name())); |
| 4483 // Use a regular load, not a contextual load, to avoid a reference | 4493 // Use a regular load, not a contextual load, to avoid a reference |
| 4484 // error. | 4494 // error. |
| 4485 CallLoadIC(NOT_CONTEXTUAL); | 4495 CallLoadIC(NOT_CONTEXTUAL); |
| 4486 PrepareForBailout(expr, TOS_REG); | 4496 PrepareForBailout(expr, TOS_REG); |
| 4487 context()->Plug(eax); | 4497 context()->Plug(eax); |
| 4488 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { | 4498 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { |
| 4499 Comment cmnt(masm_, "[ Lookup slot"); |
| 4489 Label done, slow; | 4500 Label done, slow; |
| 4490 | 4501 |
| 4491 // Generate code for loading from variables potentially shadowed | 4502 // Generate code for loading from variables potentially shadowed |
| 4492 // by eval-introduced variables. | 4503 // by eval-introduced variables. |
| 4493 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); | 4504 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); |
| 4494 | 4505 |
| 4495 __ bind(&slow); | 4506 __ bind(&slow); |
| 4496 __ push(esi); | 4507 __ push(esi); |
| 4497 __ push(Immediate(proxy->name())); | 4508 __ push(Immediate(proxy->name())); |
| 4498 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 4509 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4637 __ or_(ecx, eax); | 4648 __ or_(ecx, eax); |
| 4638 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); | 4649 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); |
| 4639 __ cmp(edx, eax); | 4650 __ cmp(edx, eax); |
| 4640 Split(cc, if_true, if_false, NULL); | 4651 Split(cc, if_true, if_false, NULL); |
| 4641 __ bind(&slow_case); | 4652 __ bind(&slow_case); |
| 4642 } | 4653 } |
| 4643 | 4654 |
| 4644 // Record position and call the compare IC. | 4655 // Record position and call the compare IC. |
| 4645 SetSourcePosition(expr->position()); | 4656 SetSourcePosition(expr->position()); |
| 4646 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); | 4657 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); |
| 4647 CallIC(ic, NOT_CONTEXTUAL, expr->CompareOperationFeedbackId()); | 4658 CallIC(ic, expr->CompareOperationFeedbackId()); |
| 4648 patch_site.EmitPatchInfo(); | 4659 patch_site.EmitPatchInfo(); |
| 4649 | 4660 |
| 4650 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 4661 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 4651 __ test(eax, eax); | 4662 __ test(eax, eax); |
| 4652 Split(cc, if_true, if_false, fall_through); | 4663 Split(cc, if_true, if_false, fall_through); |
| 4653 } | 4664 } |
| 4654 } | 4665 } |
| 4655 | 4666 |
| 4656 // Convert the result of the comparison into one expected for this | 4667 // Convert the result of the comparison into one expected for this |
| 4657 // expression's context. | 4668 // expression's context. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 4673 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 4684 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 4674 | 4685 |
| 4675 Handle<Object> nil_value = nil == kNullValue | 4686 Handle<Object> nil_value = nil == kNullValue |
| 4676 ? isolate()->factory()->null_value() | 4687 ? isolate()->factory()->null_value() |
| 4677 : isolate()->factory()->undefined_value(); | 4688 : isolate()->factory()->undefined_value(); |
| 4678 if (expr->op() == Token::EQ_STRICT) { | 4689 if (expr->op() == Token::EQ_STRICT) { |
| 4679 __ cmp(eax, nil_value); | 4690 __ cmp(eax, nil_value); |
| 4680 Split(equal, if_true, if_false, fall_through); | 4691 Split(equal, if_true, if_false, fall_through); |
| 4681 } else { | 4692 } else { |
| 4682 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); | 4693 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); |
| 4683 CallIC(ic, NOT_CONTEXTUAL, expr->CompareOperationFeedbackId()); | 4694 CallIC(ic, expr->CompareOperationFeedbackId()); |
| 4684 __ test(eax, eax); | 4695 __ test(eax, eax); |
| 4685 Split(not_zero, if_true, if_false, fall_through); | 4696 Split(not_zero, if_true, if_false, fall_through); |
| 4686 } | 4697 } |
| 4687 context()->Plug(if_true, if_false); | 4698 context()->Plug(if_true, if_false); |
| 4688 } | 4699 } |
| 4689 | 4700 |
| 4690 | 4701 |
| 4691 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 4702 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
| 4692 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 4703 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4693 context()->Plug(eax); | 4704 context()->Plug(eax); |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4901 | 4912 |
| 4902 ASSERT_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(), | 4913 ASSERT_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(), |
| 4903 Assembler::target_address_at(call_target_address)); | 4914 Assembler::target_address_at(call_target_address)); |
| 4904 return OSR_AFTER_STACK_CHECK; | 4915 return OSR_AFTER_STACK_CHECK; |
| 4905 } | 4916 } |
| 4906 | 4917 |
| 4907 | 4918 |
| 4908 } } // namespace v8::internal | 4919 } } // namespace v8::internal |
| 4909 | 4920 |
| 4910 #endif // V8_TARGET_ARCH_IA32 | 4921 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |