diff options
Diffstat (limited to 'deps/v8/src/ia32/code-stubs-ia32.cc')
-rw-r--r-- | deps/v8/src/ia32/code-stubs-ia32.cc | 371 |
1 files changed, 306 insertions, 65 deletions
diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index 9b7d9023bd..5436eee951 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -12,6 +12,7 @@ #include "src/codegen.h" #include "src/ic/handler-compiler.h" #include "src/ic/ic.h" +#include "src/ic/stub-cache.h" #include "src/isolate.h" #include "src/jsregexp.h" #include "src/regexp-macro-assembler.h" @@ -729,7 +730,7 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) { __ ret(0); StubRuntimeCallHelper call_helper; - char_at_generator.GenerateSlow(masm, call_helper); + char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper); __ bind(&miss); PropertyAccessCompiler::TailCallBuiltin( @@ -1078,8 +1079,15 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); if (has_new_target()) { + // If the constructor was [[Call]]ed, the call will not push a new.target + // onto the stack. In that case the arguments array we construct is bogus, + // bu we do not care as the constructor throws immediately. + __ cmp(ecx, Immediate(Smi::FromInt(0))); + Label skip_decrement; + __ j(equal, &skip_decrement); // Subtract 1 from smi-tagged arguments count. __ sub(ecx, Immediate(2)); + __ bind(&skip_decrement); } __ lea(edx, Operand(edx, ecx, times_2, @@ -1189,7 +1197,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // time or if regexp entry in generated code is turned off runtime switch or // at compilation. #ifdef V8_INTERPRETED_REGEXP - __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1); + __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); #else // V8_INTERPRETED_REGEXP // Stack frame on entry. @@ -1465,22 +1473,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ mov(eax, Operand::StaticVariable(pending_exception)); __ cmp(edx, eax); __ j(equal, &runtime); - // For exception, throw the exception again. - - // Clear the pending exception variable. - __ mov(Operand::StaticVariable(pending_exception), edx); - - // Special handling of termination exceptions which are uncatchable - // by javascript code. - __ cmp(eax, factory->termination_exception()); - Label throw_termination_exception; - __ j(equal, &throw_termination_exception, Label::kNear); - - // Handle normal exception by following handler chain. - __ Throw(eax); - __ bind(&throw_termination_exception); - __ ThrowUncatchable(eax); + // For exception, throw the exception again. + __ TailCallRuntime(Runtime::kRegExpExecReThrow, 4, 1); __ bind(&failure); // For failure to match, return null. @@ -1572,7 +1567,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Do the runtime call to execute the regexp. __ bind(&runtime); - __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1); + __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); // Deferred code for string handling. // (7) Not a long external string? If yes, go to (10). @@ -2516,15 +2511,14 @@ void CEntryStub::Generate(MacroAssembler* masm) { __ cmp(eax, isolate()->factory()->exception()); __ j(equal, &exception_returned); - ExternalReference pending_exception_address( - Isolate::kPendingExceptionAddress, isolate()); - // Check that there is no pending exception, otherwise we // should have returned the exception sentinel. if (FLAG_debug_code) { __ push(edx); __ mov(edx, Immediate(isolate()->factory()->the_hole_value())); Label okay; + ExternalReference pending_exception_address( + Isolate::kPendingExceptionAddress, isolate()); __ cmp(edx, Operand::StaticVariable(pending_exception_address)); // Cannot use check here as it attempts to generate call into runtime. __ j(equal, &okay, Label::kNear); @@ -2540,24 +2534,48 @@ void CEntryStub::Generate(MacroAssembler* masm) { // Handling of exception. __ bind(&exception_returned); - // Retrieve the pending exception. - __ mov(eax, Operand::StaticVariable(pending_exception_address)); - - // Clear the pending exception. - __ mov(edx, Immediate(isolate()->factory()->the_hole_value())); - __ mov(Operand::StaticVariable(pending_exception_address), edx); - - // Special handling of termination exceptions which are uncatchable - // by javascript code. - Label throw_termination_exception; - __ cmp(eax, isolate()->factory()->termination_exception()); - __ j(equal, &throw_termination_exception); - - // Handle normal exception. - __ Throw(eax); + ExternalReference pending_handler_context_address( + Isolate::kPendingHandlerContextAddress, isolate()); + ExternalReference pending_handler_code_address( + Isolate::kPendingHandlerCodeAddress, isolate()); + ExternalReference pending_handler_offset_address( + Isolate::kPendingHandlerOffsetAddress, isolate()); + ExternalReference pending_handler_fp_address( + Isolate::kPendingHandlerFPAddress, isolate()); + ExternalReference pending_handler_sp_address( + Isolate::kPendingHandlerSPAddress, isolate()); + + // Ask the runtime for help to determine the handler. This will set eax to + // contain the current pending exception, don't clobber it. + ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate()); + { + FrameScope scope(masm, StackFrame::MANUAL); + __ PrepareCallCFunction(3, eax); + __ mov(Operand(esp, 0 * kPointerSize), Immediate(0)); // argc. + __ mov(Operand(esp, 1 * kPointerSize), Immediate(0)); // argv. + __ mov(Operand(esp, 2 * kPointerSize), + Immediate(ExternalReference::isolate_address(isolate()))); + __ CallCFunction(find_handler, 3); + } - __ bind(&throw_termination_exception); - __ ThrowUncatchable(eax); + // Retrieve the handler context, SP and FP. + __ mov(esi, Operand::StaticVariable(pending_handler_context_address)); + __ mov(esp, Operand::StaticVariable(pending_handler_sp_address)); + __ mov(ebp, Operand::StaticVariable(pending_handler_fp_address)); + + // If the handler is a JS frame, restore the context to the frame. Note that + // the context will be set to (esi == 0) for non-JS frames. + Label skip; + __ test(esi, esi); + __ j(zero, &skip, Label::kNear); + __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); + __ bind(&skip); + + // Compute the handler entry address and jump to it. + __ mov(edi, Operand::StaticVariable(pending_handler_code_address)); + __ mov(edx, Operand::StaticVariable(pending_handler_offset_address)); + __ lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize)); + __ jmp(edi); } @@ -2607,10 +2625,9 @@ void JSEntryStub::Generate(MacroAssembler* masm) { __ mov(eax, Immediate(isolate()->factory()->exception())); __ jmp(&exit); - // Invoke: Link this frame into the handler chain. There's only one - // handler block in this code object, so its index is 0. + // Invoke: Link this frame into the handler chain. __ bind(&invoke); - __ PushTryHandler(StackHandler::JS_ENTRY, 0); + __ PushStackHandler(); // Clear any pending exceptions. __ mov(edx, Immediate(isolate()->factory()->the_hole_value())); @@ -2636,7 +2653,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) { __ call(edx); // Unlink this frame from the handler chain. - __ PopTryHandler(); + __ PopStackHandler(); __ bind(&exit); // Check if the current stack frame is marked as the outermost JS frame. @@ -2924,7 +2941,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { void StringCharCodeAtGenerator::GenerateSlow( - MacroAssembler* masm, + MacroAssembler* masm, EmbedMode embed_mode, const RuntimeCallHelper& call_helper) { __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase); @@ -2936,6 +2953,10 @@ void StringCharCodeAtGenerator::GenerateSlow( index_not_number_, DONT_DO_SMI_CHECK); call_helper.BeforeCall(masm); + if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) { + __ push(VectorLoadICDescriptor::VectorRegister()); + __ push(VectorLoadICDescriptor::SlotRegister()); + } __ push(object_); __ push(index_); // Consumed by runtime conversion function. if (index_flags_ == STRING_INDEX_IS_NUMBER) { @@ -2951,6 +2972,10 @@ void StringCharCodeAtGenerator::GenerateSlow( __ mov(index_, eax); } __ pop(object_); + if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) { + __ pop(VectorLoadICDescriptor::SlotRegister()); + __ pop(VectorLoadICDescriptor::VectorRegister()); + } // Reload the instance type. __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); @@ -3266,7 +3291,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { // Just jump to runtime to create the sub string. __ bind(&runtime); - __ TailCallRuntime(Runtime::kSubString, 3, 1); + __ TailCallRuntime(Runtime::kSubStringRT, 3, 1); __ bind(&single_char); // eax: string @@ -3489,7 +3514,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) { // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) // tagged as a small integer. __ bind(&runtime); - __ TailCallRuntime(Runtime::kStringCompare, 2, 1); + __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1); } @@ -3801,7 +3826,7 @@ void CompareICStub::GenerateStrings(MacroAssembler* masm) { if (equality) { __ TailCallRuntime(Runtime::kStringEquals, 2, 1); } else { - __ TailCallRuntime(Runtime::kStringCompare, 2, 1); + __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1); } __ bind(&miss); @@ -4381,15 +4406,234 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { void LoadICTrampolineStub::Generate(MacroAssembler* masm) { EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister()); - VectorLoadStub stub(isolate(), state()); - __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); + VectorRawLoadStub stub(isolate(), state()); + stub.GenerateForTrampoline(masm); } void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) { EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister()); - VectorKeyedLoadStub stub(isolate()); - __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); + VectorRawKeyedLoadStub stub(isolate()); + stub.GenerateForTrampoline(masm); +} + + +static void HandleArrayCases(MacroAssembler* masm, Register receiver, + Register key, Register vector, Register slot, + Register feedback, bool is_polymorphic, + Label* miss) { + // feedback initially contains the feedback array + Label next, next_loop, prepare_next; + Label load_smi_map, compare_map; + Label start_polymorphic; + + __ push(receiver); + __ push(vector); + + Register receiver_map = receiver; + Register cached_map = vector; + + // Receiver might not be a heap object. + __ JumpIfSmi(receiver, &load_smi_map); + __ mov(receiver_map, FieldOperand(receiver, 0)); + __ bind(&compare_map); + __ mov(cached_map, FieldOperand(feedback, FixedArray::OffsetOfElementAt(0))); + + // A named keyed load might have a 2 element array, all other cases can count + // on an array with at least 2 {map, handler} pairs, so they can go right + // into polymorphic array handling. + __ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset)); + __ j(not_equal, is_polymorphic ? &start_polymorphic : &next); + + // found, now call handler. + Register handler = feedback; + __ mov(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1))); + __ pop(vector); + __ pop(receiver); + __ lea(handler, FieldOperand(handler, Code::kHeaderSize)); + __ jmp(handler); + + if (!is_polymorphic) { + __ bind(&next); + __ cmp(FieldOperand(feedback, FixedArray::kLengthOffset), + Immediate(Smi::FromInt(2))); + __ j(not_equal, &start_polymorphic); + __ pop(vector); + __ pop(receiver); + __ jmp(miss); + } + + // Polymorphic, we have to loop from 2 to N + __ bind(&start_polymorphic); + __ push(key); + Register counter = key; + __ mov(counter, Immediate(Smi::FromInt(2))); + __ bind(&next_loop); + __ mov(cached_map, FieldOperand(feedback, counter, times_half_pointer_size, + FixedArray::kHeaderSize)); + __ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset)); + __ j(not_equal, &prepare_next); + __ mov(handler, FieldOperand(feedback, counter, times_half_pointer_size, + FixedArray::kHeaderSize + kPointerSize)); + __ pop(key); + __ pop(vector); + __ pop(receiver); + __ lea(handler, FieldOperand(handler, Code::kHeaderSize)); + __ jmp(handler); + + __ bind(&prepare_next); + __ add(counter, Immediate(Smi::FromInt(2))); + __ cmp(counter, FieldOperand(feedback, FixedArray::kLengthOffset)); + __ j(less, &next_loop); + + // We exhausted our array of map handler pairs. + __ pop(key); + __ pop(vector); + __ pop(receiver); + __ jmp(miss); + + __ bind(&load_smi_map); + __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex); + __ jmp(&compare_map); +} + + +static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver, + Register key, Register vector, Register slot, + Register weak_cell, Label* miss) { + // feedback initially contains the feedback array + Label compare_smi_map; + + // Move the weak map into the weak_cell register. + Register ic_map = weak_cell; + __ mov(ic_map, FieldOperand(weak_cell, WeakCell::kValueOffset)); + + // Receiver might not be a heap object. + __ JumpIfSmi(receiver, &compare_smi_map); + __ cmp(ic_map, FieldOperand(receiver, 0)); + __ j(not_equal, miss); + Register handler = weak_cell; + __ mov(handler, FieldOperand(vector, slot, times_half_pointer_size, + FixedArray::kHeaderSize + kPointerSize)); + __ lea(handler, FieldOperand(handler, Code::kHeaderSize)); + __ jmp(handler); + + // In microbenchmarks, it made sense to unroll this code so that the call to + // the handler is duplicated for a HeapObject receiver and a Smi receiver. + __ bind(&compare_smi_map); + __ CompareRoot(ic_map, Heap::kHeapNumberMapRootIndex); + __ j(not_equal, miss); + __ mov(handler, FieldOperand(vector, slot, times_half_pointer_size, + FixedArray::kHeaderSize + kPointerSize)); + __ lea(handler, FieldOperand(handler, Code::kHeaderSize)); + __ jmp(handler); +} + + +void VectorRawLoadStub::Generate(MacroAssembler* masm) { + GenerateImpl(masm, false); +} + + +void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) { + GenerateImpl(masm, true); +} + + +void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { + Register receiver = VectorLoadICDescriptor::ReceiverRegister(); // edx + Register name = VectorLoadICDescriptor::NameRegister(); // ecx + Register vector = VectorLoadICDescriptor::VectorRegister(); // ebx + Register slot = VectorLoadICDescriptor::SlotRegister(); // eax + Register scratch = edi; + __ mov(scratch, FieldOperand(vector, slot, times_half_pointer_size, + FixedArray::kHeaderSize)); + + // Is it a weak cell? + Label try_array; + Label not_array, smi_key, key_okay, miss; + __ CompareRoot(FieldOperand(scratch, 0), Heap::kWeakCellMapRootIndex); + __ j(not_equal, &try_array); + HandleMonomorphicCase(masm, receiver, name, vector, slot, scratch, &miss); + + // Is it a fixed array? + __ bind(&try_array); + __ CompareRoot(FieldOperand(scratch, 0), Heap::kFixedArrayMapRootIndex); + __ j(not_equal, ¬_array); + HandleArrayCases(masm, receiver, name, vector, slot, scratch, true, &miss); + + __ bind(¬_array); + __ CompareRoot(scratch, Heap::kmegamorphic_symbolRootIndex); + __ j(not_equal, &miss); + __ push(slot); + __ push(vector); + Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags( + Code::ComputeHandlerFlags(Code::LOAD_IC)); + masm->isolate()->stub_cache()->GenerateProbe( + masm, Code::LOAD_IC, code_flags, false, receiver, name, vector, scratch); + __ pop(vector); + __ pop(slot); + + __ bind(&miss); + LoadIC::GenerateMiss(masm); +} + + +void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) { + GenerateImpl(masm, false); +} + + +void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) { + GenerateImpl(masm, true); +} + + +void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { + Register receiver = VectorLoadICDescriptor::ReceiverRegister(); // edx + Register key = VectorLoadICDescriptor::NameRegister(); // ecx + Register vector = VectorLoadICDescriptor::VectorRegister(); // ebx + Register slot = VectorLoadICDescriptor::SlotRegister(); // eax + Register feedback = edi; + __ mov(feedback, FieldOperand(vector, slot, times_half_pointer_size, + FixedArray::kHeaderSize)); + // Is it a weak cell? + Label try_array; + Label not_array, smi_key, key_okay, miss; + __ CompareRoot(FieldOperand(feedback, 0), Heap::kWeakCellMapRootIndex); + __ j(not_equal, &try_array); + HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, &miss); + + __ bind(&try_array); + // Is it a fixed array? + __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex); + __ j(not_equal, ¬_array); + + // We have a polymorphic element handler. + Label polymorphic, try_poly_name; + __ bind(&polymorphic); + HandleArrayCases(masm, receiver, key, vector, slot, feedback, true, &miss); + + __ bind(¬_array); + // Is it generic? + __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); + __ j(not_equal, &try_poly_name); + Handle<Code> megamorphic_stub = + KeyedLoadIC::ChooseMegamorphicStub(masm->isolate()); + __ jmp(megamorphic_stub, RelocInfo::CODE_TARGET); + + __ bind(&try_poly_name); + // We might have a name in feedback, and a fixed array in the next slot. + __ cmp(key, feedback); + __ j(not_equal, &miss); + // If the name comparison succeeded, we know we have a fixed array with + // at least one map/handler pair. + __ mov(feedback, FieldOperand(vector, slot, times_half_pointer_size, + FixedArray::kHeaderSize + kPointerSize)); + HandleArrayCases(masm, receiver, key, vector, slot, feedback, false, &miss); + + __ bind(&miss); + KeyedLoadIC::GenerateMiss(masm); } @@ -4875,7 +5119,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, __ mov(eax, return_value_operand); Label promote_scheduled_exception; - Label exception_handled; Label delete_allocated_handles; Label leave_exit_frame; @@ -4887,7 +5130,17 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, __ Assert(above_equal, kInvalidHandleScopeLevel); __ cmp(edi, Operand::StaticVariable(limit_address)); __ j(not_equal, &delete_allocated_handles); + + // Leave the API exit frame. __ bind(&leave_exit_frame); + bool restore_context = context_restore_operand != NULL; + if (restore_context) { + __ mov(esi, *context_restore_operand); + } + if (stack_space_operand != nullptr) { + __ mov(ebx, *stack_space_operand); + } + __ LeaveApiExitFrame(!restore_context); // Check if the function scheduled an exception. ExternalReference scheduled_exception_address = @@ -4895,7 +5148,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, __ cmp(Operand::StaticVariable(scheduled_exception_address), Immediate(isolate->factory()->the_hole_value())); __ j(not_equal, &promote_scheduled_exception); - __ bind(&exception_handled); #if DEBUG // Check if the function returned a valid JavaScript value. @@ -4932,14 +5184,6 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, __ bind(&ok); #endif - bool restore_context = context_restore_operand != NULL; - if (restore_context) { - __ mov(esi, *context_restore_operand); - } - if (stack_space_operand != nullptr) { - __ mov(ebx, *stack_space_operand); - } - __ LeaveApiExitFrame(!restore_context); if (stack_space_operand != nullptr) { DCHECK_EQ(0, stack_space); __ pop(ecx); @@ -4949,12 +5193,9 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm, __ ret(stack_space * kPointerSize); } + // Re-throw by promoting a scheduled exception. __ bind(&promote_scheduled_exception); - { - FrameScope frame(masm, StackFrame::INTERNAL); - __ CallRuntime(Runtime::kPromoteScheduledException, 0); - } - __ jmp(&exception_handled); + __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); // HandleScope limit has changed. Delete allocated extensions. ExternalReference delete_extensions = |