| 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 profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell( | 121 profiling_counter_ = isolate()->factory()->NewCell( |
| 122 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); | 122 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); |
| 123 SetFunctionPosition(function()); | 123 SetFunctionPosition(function()); |
| 124 Comment cmnt(masm_, "[ function compiled by full code generator"); | 124 Comment cmnt(masm_, "[ function compiled by full code generator"); |
| 125 | 125 |
| 126 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | 126 ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
| 127 | 127 |
| 128 #ifdef DEBUG | 128 #ifdef DEBUG |
| 129 if (strlen(FLAG_stop_at) > 0 && | 129 if (strlen(FLAG_stop_at) > 0 && |
| 130 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 130 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
| 131 __ int3(); | 131 __ int3(); |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 } | 308 } |
| 309 | 309 |
| 310 | 310 |
| 311 void FullCodeGenerator::ClearAccumulator() { | 311 void FullCodeGenerator::ClearAccumulator() { |
| 312 __ Set(eax, Immediate(Smi::FromInt(0))); | 312 __ Set(eax, Immediate(Smi::FromInt(0))); |
| 313 } | 313 } |
| 314 | 314 |
| 315 | 315 |
| 316 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { | 316 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { |
| 317 __ mov(ebx, Immediate(profiling_counter_)); | 317 __ mov(ebx, Immediate(profiling_counter_)); |
| 318 __ sub(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), | 318 __ sub(FieldOperand(ebx, Cell::kValueOffset), |
| 319 Immediate(Smi::FromInt(delta))); | 319 Immediate(Smi::FromInt(delta))); |
| 320 } | 320 } |
| 321 | 321 |
| 322 | 322 |
| 323 void FullCodeGenerator::EmitProfilingCounterReset() { | 323 void FullCodeGenerator::EmitProfilingCounterReset() { |
| 324 int reset_value = FLAG_interrupt_budget; | 324 int reset_value = FLAG_interrupt_budget; |
| 325 if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) { | 325 if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) { |
| 326 // Self-optimization is a one-off thing: if it fails, don't try again. | 326 // Self-optimization is a one-off thing: if it fails, don't try again. |
| 327 reset_value = Smi::kMaxValue; | 327 reset_value = Smi::kMaxValue; |
| 328 } | 328 } |
| 329 __ mov(ebx, Immediate(profiling_counter_)); | 329 __ mov(ebx, Immediate(profiling_counter_)); |
| 330 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), | 330 __ mov(FieldOperand(ebx, Cell::kValueOffset), |
| 331 Immediate(Smi::FromInt(reset_value))); | 331 Immediate(Smi::FromInt(reset_value))); |
| 332 } | 332 } |
| 333 | 333 |
| 334 | 334 |
| 335 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, | 335 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, |
| 336 Label* back_edge_target) { | 336 Label* back_edge_target) { |
| 337 Comment cmnt(masm_, "[ Back edge bookkeeping"); | 337 Comment cmnt(masm_, "[ Back edge bookkeeping"); |
| 338 Label ok; | 338 Label ok; |
| 339 | 339 |
| 340 int weight = 1; | 340 int weight = 1; |
| 341 if (FLAG_weighted_back_edges) { | 341 if (FLAG_weighted_back_edges) { |
| 342 ASSERT(back_edge_target->is_bound()); | 342 ASSERT(back_edge_target->is_bound()); |
| 343 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); | 343 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); |
| 344 weight = Min(kMaxBackEdgeWeight, | 344 weight = Min(kMaxBackEdgeWeight, |
| 345 Max(1, distance / kBackEdgeDistanceUnit)); | 345 Max(1, distance / kCodeSizeMultiplier)); |
| 346 } | 346 } |
| 347 EmitProfilingCounterDecrement(weight); | 347 EmitProfilingCounterDecrement(weight); |
| 348 __ j(positive, &ok, Label::kNear); | 348 __ j(positive, &ok, Label::kNear); |
| 349 InterruptStub stub; | 349 InterruptStub stub; |
| 350 __ CallStub(&stub); | 350 __ CallStub(&stub); |
| 351 | 351 |
| 352 // Record a mapping of this PC offset to the OSR id. This is used to find | 352 // Record a mapping of this PC offset to the OSR id. This is used to find |
| 353 // the AST id from the unoptimized code in order to use it as a key into | 353 // the AST id from the unoptimized code in order to use it as a key into |
| 354 // the deoptimization input data found in the optimized code. | 354 // the deoptimization input data found in the optimized code. |
| 355 RecordBackEdge(stmt->OsrEntryId()); | 355 RecordBackEdge(stmt->OsrEntryId()); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 377 __ CallRuntime(Runtime::kTraceExit, 1); | 377 __ CallRuntime(Runtime::kTraceExit, 1); |
| 378 } | 378 } |
| 379 if (FLAG_interrupt_at_exit || FLAG_self_optimization) { | 379 if (FLAG_interrupt_at_exit || FLAG_self_optimization) { |
| 380 // Pretend that the exit is a backwards jump to the entry. | 380 // Pretend that the exit is a backwards jump to the entry. |
| 381 int weight = 1; | 381 int weight = 1; |
| 382 if (info_->ShouldSelfOptimize()) { | 382 if (info_->ShouldSelfOptimize()) { |
| 383 weight = FLAG_interrupt_budget / FLAG_self_opt_count; | 383 weight = FLAG_interrupt_budget / FLAG_self_opt_count; |
| 384 } else if (FLAG_weighted_back_edges) { | 384 } else if (FLAG_weighted_back_edges) { |
| 385 int distance = masm_->pc_offset(); | 385 int distance = masm_->pc_offset(); |
| 386 weight = Min(kMaxBackEdgeWeight, | 386 weight = Min(kMaxBackEdgeWeight, |
| 387 Max(1, distance / kBackEdgeDistanceUnit)); | 387 Max(1, distance / kCodeSizeMultiplier)); |
| 388 } | 388 } |
| 389 EmitProfilingCounterDecrement(weight); | 389 EmitProfilingCounterDecrement(weight); |
| 390 Label ok; | 390 Label ok; |
| 391 __ j(positive, &ok, Label::kNear); | 391 __ j(positive, &ok, Label::kNear); |
| 392 __ push(eax); | 392 __ push(eax); |
| 393 if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) { | 393 if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) { |
| 394 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 394 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 395 __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1); | 395 __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1); |
| 396 } else { | 396 } else { |
| 397 InterruptStub stub; | 397 InterruptStub stub; |
| (...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1098 __ jmp(&loop); | 1098 __ jmp(&loop); |
| 1099 | 1099 |
| 1100 __ bind(&no_descriptors); | 1100 __ bind(&no_descriptors); |
| 1101 __ add(esp, Immediate(kPointerSize)); | 1101 __ add(esp, Immediate(kPointerSize)); |
| 1102 __ jmp(&exit); | 1102 __ jmp(&exit); |
| 1103 | 1103 |
| 1104 // We got a fixed array in register eax. Iterate through that. | 1104 // We got a fixed array in register eax. Iterate through that. |
| 1105 Label non_proxy; | 1105 Label non_proxy; |
| 1106 __ bind(&fixed_array); | 1106 __ bind(&fixed_array); |
| 1107 | 1107 |
| 1108 Handle<JSGlobalPropertyCell> cell = | 1108 Handle<Cell> cell = isolate()->factory()->NewCell( |
| 1109 isolate()->factory()->NewJSGlobalPropertyCell( | 1109 Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), |
| 1110 Handle<Object>( | 1110 isolate())); |
| 1111 Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), | |
| 1112 isolate())); | |
| 1113 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); | 1111 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); |
| 1114 __ LoadHeapObject(ebx, cell); | 1112 __ LoadHeapObject(ebx, cell); |
| 1115 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), | 1113 __ mov(FieldOperand(ebx, Cell::kValueOffset), |
| 1116 Immediate(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); | 1114 Immediate(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); |
| 1117 | 1115 |
| 1118 __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check | 1116 __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check |
| 1119 __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object | 1117 __ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object |
| 1120 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 1118 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 1121 __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx); | 1119 __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx); |
| 1122 __ j(above, &non_proxy); | 1120 __ j(above, &non_proxy); |
| 1123 __ mov(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy | 1121 __ mov(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy |
| 1124 __ bind(&non_proxy); | 1122 __ bind(&non_proxy); |
| 1125 __ push(ebx); // Smi | 1123 __ push(ebx); // Smi |
| (...skipping 657 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1783 for (int i = 0; i < length; i++) { | 1781 for (int i = 0; i < length; i++) { |
| 1784 Expression* subexpr = subexprs->at(i); | 1782 Expression* subexpr = subexprs->at(i); |
| 1785 // If the subexpression is a literal or a simple materialized literal it | 1783 // If the subexpression is a literal or a simple materialized literal it |
| 1786 // is already set in the cloned array. | 1784 // is already set in the cloned array. |
| 1787 if (subexpr->AsLiteral() != NULL || | 1785 if (subexpr->AsLiteral() != NULL || |
| 1788 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 1786 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
| 1789 continue; | 1787 continue; |
| 1790 } | 1788 } |
| 1791 | 1789 |
| 1792 if (!result_saved) { | 1790 if (!result_saved) { |
| 1793 __ push(eax); | 1791 __ push(eax); // array literal. |
| 1792 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
| 1794 result_saved = true; | 1793 result_saved = true; |
| 1795 } | 1794 } |
| 1796 VisitForAccumulatorValue(subexpr); | 1795 VisitForAccumulatorValue(subexpr); |
| 1797 | 1796 |
| 1798 if (IsFastObjectElementsKind(constant_elements_kind)) { | 1797 if (IsFastObjectElementsKind(constant_elements_kind)) { |
| 1799 // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they | 1798 // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they |
| 1800 // cannot transition and don't need to call the runtime stub. | 1799 // cannot transition and don't need to call the runtime stub. |
| 1801 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1800 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
| 1802 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. | 1801 __ mov(ebx, Operand(esp, kPointerSize)); // Copy of array literal. |
| 1803 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); | 1802 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); |
| 1804 // Store the subexpression value in the array's elements. | 1803 // Store the subexpression value in the array's elements. |
| 1805 __ mov(FieldOperand(ebx, offset), result_register()); | 1804 __ mov(FieldOperand(ebx, offset), result_register()); |
| 1806 // Update the write barrier for the array store. | 1805 // Update the write barrier for the array store. |
| 1807 __ RecordWriteField(ebx, offset, result_register(), ecx, | 1806 __ RecordWriteField(ebx, offset, result_register(), ecx, |
| 1808 kDontSaveFPRegs, | 1807 kDontSaveFPRegs, |
| 1809 EMIT_REMEMBERED_SET, | 1808 EMIT_REMEMBERED_SET, |
| 1810 INLINE_SMI_CHECK); | 1809 INLINE_SMI_CHECK); |
| 1811 } else { | 1810 } else { |
| 1812 // Store the subexpression value in the array's elements. | 1811 // Store the subexpression value in the array's elements. |
| 1813 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. | |
| 1814 __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset)); | |
| 1815 __ mov(ecx, Immediate(Smi::FromInt(i))); | 1812 __ mov(ecx, Immediate(Smi::FromInt(i))); |
| 1816 __ mov(edx, Immediate(Smi::FromInt(expr->literal_index()))); | |
| 1817 StoreArrayLiteralElementStub stub; | 1813 StoreArrayLiteralElementStub stub; |
| 1818 __ CallStub(&stub); | 1814 __ CallStub(&stub); |
| 1819 } | 1815 } |
| 1820 | 1816 |
| 1821 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); | 1817 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
| 1822 } | 1818 } |
| 1823 | 1819 |
| 1824 if (result_saved) { | 1820 if (result_saved) { |
| 1821 __ add(esp, Immediate(kPointerSize)); // literal index |
| 1825 context()->PlugTOS(); | 1822 context()->PlugTOS(); |
| 1826 } else { | 1823 } else { |
| 1827 context()->Plug(eax); | 1824 context()->Plug(eax); |
| 1828 } | 1825 } |
| 1829 } | 1826 } |
| 1830 | 1827 |
| 1831 | 1828 |
| 1832 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1829 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
| 1833 Comment cmnt(masm_, "[ Assignment"); | 1830 Comment cmnt(masm_, "[ Assignment"); |
| 1834 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 1831 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1943 } | 1940 } |
| 1944 | 1941 |
| 1945 | 1942 |
| 1946 void FullCodeGenerator::VisitYield(Yield* expr) { | 1943 void FullCodeGenerator::VisitYield(Yield* expr) { |
| 1947 Comment cmnt(masm_, "[ Yield"); | 1944 Comment cmnt(masm_, "[ Yield"); |
| 1948 // Evaluate yielded value first; the initial iterator definition depends on | 1945 // Evaluate yielded value first; the initial iterator definition depends on |
| 1949 // this. It stays on the stack while we update the iterator. | 1946 // this. It stays on the stack while we update the iterator. |
| 1950 VisitForStackValue(expr->expression()); | 1947 VisitForStackValue(expr->expression()); |
| 1951 | 1948 |
| 1952 switch (expr->yield_kind()) { | 1949 switch (expr->yield_kind()) { |
| 1953 case Yield::INITIAL: | 1950 case Yield::SUSPEND: |
| 1954 case Yield::SUSPEND: { | 1951 // Pop value from top-of-stack slot; box result into result register. |
| 1952 EmitCreateIteratorResult(false); |
| 1953 __ push(result_register()); |
| 1954 // Fall through. |
| 1955 case Yield::INITIAL: { |
| 1955 VisitForStackValue(expr->generator_object()); | 1956 VisitForStackValue(expr->generator_object()); |
| 1956 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); | 1957 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); |
| 1957 __ mov(context_register(), | 1958 __ mov(context_register(), |
| 1958 Operand(ebp, StandardFrameConstants::kContextOffset)); | 1959 Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 1959 | 1960 |
| 1960 Label resume; | 1961 Label resume; |
| 1961 __ CompareRoot(result_register(), Heap::kTheHoleValueRootIndex); | 1962 __ CompareRoot(result_register(), Heap::kTheHoleValueRootIndex); |
| 1962 __ j(not_equal, &resume); | 1963 __ j(not_equal, &resume); |
| 1963 if (expr->yield_kind() == Yield::SUSPEND) { | 1964 __ pop(result_register()); |
| 1964 EmitReturnIteratorResult(false); | 1965 EmitReturnSequence(); |
| 1965 } else { | |
| 1966 __ pop(result_register()); | |
| 1967 EmitReturnSequence(); | |
| 1968 } | |
| 1969 | 1966 |
| 1970 __ bind(&resume); | 1967 __ bind(&resume); |
| 1971 context()->Plug(result_register()); | 1968 context()->Plug(result_register()); |
| 1972 break; | 1969 break; |
| 1973 } | 1970 } |
| 1974 | 1971 |
| 1975 case Yield::FINAL: { | 1972 case Yield::FINAL: { |
| 1976 VisitForAccumulatorValue(expr->generator_object()); | 1973 VisitForAccumulatorValue(expr->generator_object()); |
| 1977 __ mov(FieldOperand(result_register(), | 1974 __ mov(FieldOperand(result_register(), |
| 1978 JSGeneratorObject::kContinuationOffset), | 1975 JSGeneratorObject::kContinuationOffset), |
| 1979 Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorClosed))); | 1976 Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorClosed))); |
| 1980 EmitReturnIteratorResult(true); | 1977 // Pop value from top-of-stack slot, box result into result register. |
| 1978 EmitCreateIteratorResult(true); |
| 1979 EmitUnwindBeforeReturn(); |
| 1980 EmitReturnSequence(); |
| 1981 break; | 1981 break; |
| 1982 } | 1982 } |
| 1983 | 1983 |
| 1984 case Yield::DELEGATING: { | 1984 case Yield::DELEGATING: { |
| 1985 VisitForStackValue(expr->generator_object()); | 1985 VisitForStackValue(expr->generator_object()); |
| 1986 | 1986 |
| 1987 // Initial stack layout is as follows: | 1987 // Initial stack layout is as follows: |
| 1988 // [sp + 1 * kPointerSize] iter | 1988 // [sp + 1 * kPointerSize] iter |
| 1989 // [sp + 0 * kPointerSize] g | 1989 // [sp + 0 * kPointerSize] g |
| 1990 | 1990 |
| 1991 Label l_catch, l_try, l_resume, l_next, l_call, l_loop; | 1991 Label l_catch, l_try, l_resume, l_next, l_call, l_loop; |
| 1992 // Initial send value is undefined. | 1992 // Initial send value is undefined. |
| 1993 __ mov(eax, isolate()->factory()->undefined_value()); | 1993 __ mov(eax, isolate()->factory()->undefined_value()); |
| 1994 __ jmp(&l_next); | 1994 __ jmp(&l_next); |
| 1995 | 1995 |
| 1996 // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; } | 1996 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; } |
| 1997 __ bind(&l_catch); | 1997 __ bind(&l_catch); |
| 1998 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); | 1998 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); |
| 1999 __ mov(edx, Operand(esp, 1 * kPointerSize)); // iter | 1999 __ mov(ecx, isolate()->factory()->throw_string()); // "throw" |
| 2000 __ push(edx); // iter | 2000 __ push(ecx); // "throw" |
| 2001 __ push(Operand(esp, 2 * kPointerSize)); // iter |
| 2001 __ push(eax); // exception | 2002 __ push(eax); // exception |
| 2002 __ mov(ecx, isolate()->factory()->throw_string()); // "throw" | |
| 2003 Handle<Code> throw_ic = isolate()->builtins()->LoadIC_Initialize(); | |
| 2004 CallIC(throw_ic); // iter.throw in eax | |
| 2005 __ jmp(&l_call); | 2003 __ jmp(&l_call); |
| 2006 | 2004 |
| 2007 // try { received = yield result.value } | 2005 // try { received = %yield result } |
| 2006 // Shuffle the received result above a try handler and yield it without |
| 2007 // re-boxing. |
| 2008 __ bind(&l_try); | 2008 __ bind(&l_try); |
| 2009 __ pop(eax); // result.value | 2009 __ pop(eax); // result |
| 2010 __ PushTryHandler(StackHandler::CATCH, expr->index()); | 2010 __ PushTryHandler(StackHandler::CATCH, expr->index()); |
| 2011 const int handler_size = StackHandlerConstants::kSize; | 2011 const int handler_size = StackHandlerConstants::kSize; |
| 2012 __ push(eax); // result.value | 2012 __ push(eax); // result |
| 2013 __ push(Operand(esp, (0 + 1) * kPointerSize + handler_size)); // g | 2013 __ push(Operand(esp, (0 + 1) * kPointerSize + handler_size)); // g |
| 2014 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); | 2014 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); |
| 2015 __ mov(context_register(), | 2015 __ mov(context_register(), |
| 2016 Operand(ebp, StandardFrameConstants::kContextOffset)); | 2016 Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2017 __ CompareRoot(eax, Heap::kTheHoleValueRootIndex); | 2017 __ CompareRoot(eax, Heap::kTheHoleValueRootIndex); |
| 2018 __ j(not_equal, &l_resume); | 2018 __ j(not_equal, &l_resume); |
| 2019 EmitReturnIteratorResult(false); | 2019 __ pop(eax); // result |
| 2020 EmitReturnSequence(); |
| 2020 __ bind(&l_resume); // received in eax | 2021 __ bind(&l_resume); // received in eax |
| 2021 __ PopTryHandler(); | 2022 __ PopTryHandler(); |
| 2022 | 2023 |
| 2023 // receiver = iter; f = iter.next; arg = received; | 2024 // receiver = iter; f = iter.next; arg = received; |
| 2024 __ bind(&l_next); | 2025 __ bind(&l_next); |
| 2025 __ mov(edx, Operand(esp, 1 * kPointerSize)); // iter | 2026 __ mov(ecx, isolate()->factory()->next_string()); // "next" |
| 2026 __ push(edx); // iter | 2027 __ push(ecx); |
| 2028 __ push(Operand(esp, 2 * kPointerSize)); // iter |
| 2027 __ push(eax); // received | 2029 __ push(eax); // received |
| 2028 __ mov(ecx, isolate()->factory()->next_string()); // "next" | |
| 2029 Handle<Code> next_ic = isolate()->builtins()->LoadIC_Initialize(); | |
| 2030 CallIC(next_ic); // iter.next in eax | |
| 2031 | 2030 |
| 2032 // result = f.call(receiver, arg); | 2031 // result = receiver[f](arg); |
| 2033 __ bind(&l_call); | 2032 __ bind(&l_call); |
| 2034 Label l_call_runtime; | 2033 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); |
| 2035 __ JumpIfSmi(eax, &l_call_runtime); | 2034 CallIC(ic); |
| 2036 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); | |
| 2037 __ j(not_equal, &l_call_runtime); | |
| 2038 __ mov(edi, eax); | |
| 2039 ParameterCount count(1); | |
| 2040 __ InvokeFunction(edi, count, CALL_FUNCTION, | |
| 2041 NullCallWrapper(), CALL_AS_METHOD); | |
| 2042 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2035 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2043 __ jmp(&l_loop); | 2036 __ Drop(1); // The key is still on the stack; drop it. |
| 2044 __ bind(&l_call_runtime); | |
| 2045 __ push(eax); | |
| 2046 __ CallRuntime(Runtime::kCall, 3); | |
| 2047 | 2037 |
| 2048 // val = result.value; if (!result.done) goto l_try; | 2038 // if (!result.done) goto l_try; |
| 2049 __ bind(&l_loop); | 2039 __ bind(&l_loop); |
| 2050 // result.value | |
| 2051 __ push(eax); // save result | 2040 __ push(eax); // save result |
| 2052 __ mov(edx, eax); // result | 2041 __ mov(edx, eax); // result |
| 2053 __ mov(ecx, isolate()->factory()->value_string()); // "value" | |
| 2054 Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize(); | |
| 2055 CallIC(value_ic); // result.value in eax | |
| 2056 __ pop(ebx); // result | |
| 2057 __ push(eax); // result.value | |
| 2058 __ mov(edx, ebx); // result | |
| 2059 __ mov(ecx, isolate()->factory()->done_string()); // "done" | 2042 __ mov(ecx, isolate()->factory()->done_string()); // "done" |
| 2060 Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize(); | 2043 Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize(); |
| 2061 CallIC(done_ic); // result.done in eax | 2044 CallIC(done_ic); // result.done in eax |
| 2062 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); | 2045 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); |
| 2063 CallIC(bool_ic); | 2046 CallIC(bool_ic); |
| 2064 __ test(eax, eax); | 2047 __ test(eax, eax); |
| 2065 __ j(zero, &l_try); | 2048 __ j(zero, &l_try); |
| 2066 | 2049 |
| 2067 // result.value | 2050 // result.value |
| 2068 __ pop(eax); // result.value | 2051 __ pop(edx); // result |
| 2052 __ mov(ecx, isolate()->factory()->value_string()); // "value" |
| 2053 Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize(); |
| 2054 CallIC(value_ic); // result.value in eax |
| 2069 context()->DropAndPlug(2, eax); // drop iter and g | 2055 context()->DropAndPlug(2, eax); // drop iter and g |
| 2070 break; | 2056 break; |
| 2071 } | 2057 } |
| 2072 } | 2058 } |
| 2073 } | 2059 } |
| 2074 | 2060 |
| 2075 | 2061 |
| 2076 void FullCodeGenerator::EmitGeneratorResume(Expression *generator, | 2062 void FullCodeGenerator::EmitGeneratorResume(Expression *generator, |
| 2077 Expression *value, | 2063 Expression *value, |
| 2078 JSGeneratorObject::ResumeMode resume_mode) { | 2064 JSGeneratorObject::ResumeMode resume_mode) { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2162 // Throw error if we attempt to operate on a running generator. | 2148 // Throw error if we attempt to operate on a running generator. |
| 2163 __ bind(&wrong_state); | 2149 __ bind(&wrong_state); |
| 2164 __ push(ebx); | 2150 __ push(ebx); |
| 2165 __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); | 2151 __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); |
| 2166 | 2152 |
| 2167 __ bind(&done); | 2153 __ bind(&done); |
| 2168 context()->Plug(result_register()); | 2154 context()->Plug(result_register()); |
| 2169 } | 2155 } |
| 2170 | 2156 |
| 2171 | 2157 |
| 2172 void FullCodeGenerator::EmitReturnIteratorResult(bool done) { | 2158 void FullCodeGenerator::EmitCreateIteratorResult(bool done) { |
| 2173 Label gc_required; | 2159 Label gc_required; |
| 2174 Label allocated; | 2160 Label allocated; |
| 2175 | 2161 |
| 2176 Handle<Map> map(isolate()->native_context()->generator_result_map()); | 2162 Handle<Map> map(isolate()->native_context()->generator_result_map()); |
| 2177 | 2163 |
| 2178 __ Allocate(map->instance_size(), eax, ecx, edx, &gc_required, TAG_OBJECT); | 2164 __ Allocate(map->instance_size(), eax, ecx, edx, &gc_required, TAG_OBJECT); |
| 2165 __ jmp(&allocated); |
| 2166 |
| 2167 __ bind(&gc_required); |
| 2168 __ Push(Smi::FromInt(map->instance_size())); |
| 2169 __ CallRuntime(Runtime::kAllocateInNewSpace, 1); |
| 2170 __ mov(context_register(), |
| 2171 Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2179 | 2172 |
| 2180 __ bind(&allocated); | 2173 __ bind(&allocated); |
| 2181 __ mov(ebx, map); | 2174 __ mov(ebx, map); |
| 2182 __ pop(ecx); | 2175 __ pop(ecx); |
| 2183 __ mov(edx, isolate()->factory()->ToBoolean(done)); | 2176 __ mov(edx, isolate()->factory()->ToBoolean(done)); |
| 2184 ASSERT_EQ(map->instance_size(), 5 * kPointerSize); | 2177 ASSERT_EQ(map->instance_size(), 5 * kPointerSize); |
| 2185 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx); | 2178 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx); |
| 2186 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), | 2179 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), |
| 2187 isolate()->factory()->empty_fixed_array()); | 2180 isolate()->factory()->empty_fixed_array()); |
| 2188 __ mov(FieldOperand(eax, JSObject::kElementsOffset), | 2181 __ mov(FieldOperand(eax, JSObject::kElementsOffset), |
| 2189 isolate()->factory()->empty_fixed_array()); | 2182 isolate()->factory()->empty_fixed_array()); |
| 2190 __ mov(FieldOperand(eax, JSGeneratorObject::kResultValuePropertyOffset), ecx); | 2183 __ mov(FieldOperand(eax, JSGeneratorObject::kResultValuePropertyOffset), ecx); |
| 2191 __ mov(FieldOperand(eax, JSGeneratorObject::kResultDonePropertyOffset), edx); | 2184 __ mov(FieldOperand(eax, JSGeneratorObject::kResultDonePropertyOffset), edx); |
| 2192 | 2185 |
| 2193 // Only the value field needs a write barrier, as the other values are in the | 2186 // Only the value field needs a write barrier, as the other values are in the |
| 2194 // root set. | 2187 // root set. |
| 2195 __ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset, | 2188 __ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset, |
| 2196 ecx, edx, kDontSaveFPRegs); | 2189 ecx, edx, kDontSaveFPRegs); |
| 2197 | |
| 2198 if (done) { | |
| 2199 // Exit all nested statements. | |
| 2200 NestedStatement* current = nesting_stack_; | |
| 2201 int stack_depth = 0; | |
| 2202 int context_length = 0; | |
| 2203 while (current != NULL) { | |
| 2204 current = current->Exit(&stack_depth, &context_length); | |
| 2205 } | |
| 2206 __ Drop(stack_depth); | |
| 2207 } | |
| 2208 | |
| 2209 EmitReturnSequence(); | |
| 2210 | |
| 2211 __ bind(&gc_required); | |
| 2212 __ Push(Smi::FromInt(map->instance_size())); | |
| 2213 __ CallRuntime(Runtime::kAllocateInNewSpace, 1); | |
| 2214 __ mov(context_register(), | |
| 2215 Operand(ebp, StandardFrameConstants::kContextOffset)); | |
| 2216 __ jmp(&allocated); | |
| 2217 } | 2190 } |
| 2218 | 2191 |
| 2219 | 2192 |
| 2220 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { | 2193 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
| 2221 SetSourcePosition(prop->position()); | 2194 SetSourcePosition(prop->position()); |
| 2222 Literal* key = prop->key()->AsLiteral(); | 2195 Literal* key = prop->key()->AsLiteral(); |
| 2223 ASSERT(!key->handle()->IsSmi()); | 2196 ASSERT(!key->handle()->IsSmi()); |
| 2224 __ mov(ecx, Immediate(key->handle())); | 2197 __ mov(ecx, Immediate(key->handle())); |
| 2225 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 2198 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 2226 CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId()); | 2199 CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId()); |
| (...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2630 VisitForStackValue(args->at(i)); | 2603 VisitForStackValue(args->at(i)); |
| 2631 } | 2604 } |
| 2632 } | 2605 } |
| 2633 // Record source position for debugger. | 2606 // Record source position for debugger. |
| 2634 SetSourcePosition(expr->position()); | 2607 SetSourcePosition(expr->position()); |
| 2635 | 2608 |
| 2636 // Record call targets in unoptimized code. | 2609 // Record call targets in unoptimized code. |
| 2637 flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); | 2610 flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); |
| 2638 Handle<Object> uninitialized = | 2611 Handle<Object> uninitialized = |
| 2639 TypeFeedbackCells::UninitializedSentinel(isolate()); | 2612 TypeFeedbackCells::UninitializedSentinel(isolate()); |
| 2640 Handle<JSGlobalPropertyCell> cell = | 2613 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); |
| 2641 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); | |
| 2642 RecordTypeFeedbackCell(expr->CallFeedbackId(), cell); | 2614 RecordTypeFeedbackCell(expr->CallFeedbackId(), cell); |
| 2643 __ mov(ebx, cell); | 2615 __ mov(ebx, cell); |
| 2644 | 2616 |
| 2645 CallFunctionStub stub(arg_count, flags); | 2617 CallFunctionStub stub(arg_count, flags); |
| 2646 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); | 2618 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); |
| 2647 __ CallStub(&stub, expr->CallFeedbackId()); | 2619 __ CallStub(&stub, expr->CallFeedbackId()); |
| 2648 | 2620 |
| 2649 RecordJSReturnSite(expr); | 2621 RecordJSReturnSite(expr); |
| 2650 // Restore context register. | 2622 // Restore context register. |
| 2651 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2623 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2815 // constructor invocation. | 2787 // constructor invocation. |
| 2816 SetSourcePosition(expr->position()); | 2788 SetSourcePosition(expr->position()); |
| 2817 | 2789 |
| 2818 // Load function and argument count into edi and eax. | 2790 // Load function and argument count into edi and eax. |
| 2819 __ Set(eax, Immediate(arg_count)); | 2791 __ Set(eax, Immediate(arg_count)); |
| 2820 __ mov(edi, Operand(esp, arg_count * kPointerSize)); | 2792 __ mov(edi, Operand(esp, arg_count * kPointerSize)); |
| 2821 | 2793 |
| 2822 // Record call targets in unoptimized code. | 2794 // Record call targets in unoptimized code. |
| 2823 Handle<Object> uninitialized = | 2795 Handle<Object> uninitialized = |
| 2824 TypeFeedbackCells::UninitializedSentinel(isolate()); | 2796 TypeFeedbackCells::UninitializedSentinel(isolate()); |
| 2825 Handle<JSGlobalPropertyCell> cell = | 2797 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); |
| 2826 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); | |
| 2827 RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell); | 2798 RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell); |
| 2828 __ mov(ebx, cell); | 2799 __ mov(ebx, cell); |
| 2829 | 2800 |
| 2830 CallConstructStub stub(RECORD_CALL_TARGET); | 2801 CallConstructStub stub(RECORD_CALL_TARGET); |
| 2831 __ call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); | 2802 __ call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); |
| 2832 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); | 2803 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); |
| 2833 context()->Plug(eax); | 2804 context()->Plug(eax); |
| 2834 } | 2805 } |
| 2835 | 2806 |
| 2836 | 2807 |
| (...skipping 2085 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4922 *stack_depth = 0; | 4893 *stack_depth = 0; |
| 4923 *context_length = 0; | 4894 *context_length = 0; |
| 4924 return previous_; | 4895 return previous_; |
| 4925 } | 4896 } |
| 4926 | 4897 |
| 4927 #undef __ | 4898 #undef __ |
| 4928 | 4899 |
| 4929 } } // namespace v8::internal | 4900 } } // namespace v8::internal |
| 4930 | 4901 |
| 4931 #endif // V8_TARGET_ARCH_IA32 | 4902 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |