diff options
Diffstat (limited to 'deps/v8/src/ia32/code-stubs-ia32.cc')
-rw-r--r-- | deps/v8/src/ia32/code-stubs-ia32.cc | 286 |
1 files changed, 264 insertions, 22 deletions
diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index 84fe688f72..96d2411865 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -101,16 +101,21 @@ void TransitionElementsKindStub::InitializeInterfaceDescriptor( } -static void InitializeArrayConstructorDescriptor(Isolate* isolate, - CodeStubInterfaceDescriptor* descriptor) { +static void InitializeArrayConstructorDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor, + int constant_stack_parameter_count) { // register state - // edi -- constructor function + // eax -- number of arguments // ebx -- type info cell with elements kind - // eax -- number of arguments to the constructor function - static Register registers[] = { edi, ebx }; - descriptor->register_param_count_ = 2; - // stack param count needs (constructor pointer, and single argument) - descriptor->stack_parameter_count_ = &eax; + static Register registers[] = { ebx }; + descriptor->register_param_count_ = 1; + + if (constant_stack_parameter_count != 0) { + // stack param count needs (constructor pointer, and single argument) + descriptor->stack_parameter_count_ = &eax; + } + descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count; descriptor->register_params_ = registers; descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; descriptor->deoptimization_handler_ = @@ -121,26 +126,64 @@ static void InitializeArrayConstructorDescriptor(Isolate* isolate, void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { - InitializeArrayConstructorDescriptor(isolate, descriptor); + InitializeArrayConstructorDescriptor(isolate, descriptor, 0); } void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { - InitializeArrayConstructorDescriptor(isolate, descriptor); + InitializeArrayConstructorDescriptor(isolate, descriptor, 1); } void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { - InitializeArrayConstructorDescriptor(isolate, descriptor); + InitializeArrayConstructorDescriptor(isolate, descriptor, -1); +} + + +void CompareNilICStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + static Register registers[] = { eax }; + descriptor->register_param_count_ = 1; + descriptor->register_params_ = registers; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(CompareNilIC_Miss); + descriptor->miss_handler_ = + ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate); } #define __ ACCESS_MASM(masm) + +void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { + // Update the static counter each time a new code stub is generated. + Isolate* isolate = masm->isolate(); + isolate->counters()->code_stubs()->Increment(); + + CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate); + int param_count = descriptor->register_param_count_; + { + // Call the runtime system in a fresh internal frame. + FrameScope scope(masm, StackFrame::INTERNAL); + ASSERT(descriptor->register_param_count_ == 0 || + eax.is(descriptor->register_params_[param_count - 1])); + // Push arguments + for (int i = 0; i < param_count; ++i) { + __ push(descriptor->register_params_[i]); + } + ExternalReference miss = descriptor->miss_handler_; + __ CallExternalReference(miss, descriptor->register_param_count_); + } + + __ ret(0); +} + + void ToNumberStub::Generate(MacroAssembler* masm) { // The ToNumber stub takes one argument in eax. Label check_heap_number, call_builtin; @@ -531,7 +574,7 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { AllowExternalCallThatCantCauseGC scope(masm); __ PrepareCallCFunction(argument_count, ecx); __ mov(Operand(esp, 0 * kPointerSize), - Immediate(ExternalReference::isolate_address())); + Immediate(ExternalReference::isolate_address(masm->isolate()))); __ CallCFunction( ExternalReference::store_buffer_overflow_function(masm->isolate()), argument_count); @@ -3851,7 +3894,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Argument 9: Pass current isolate address. __ mov(Operand(esp, 8 * kPointerSize), - Immediate(ExternalReference::isolate_address())); + Immediate(ExternalReference::isolate_address(masm->isolate()))); // Argument 8: Indicate that this is a direct call from JavaScript. __ mov(Operand(esp, 7 * kPointerSize), Immediate(1)); @@ -4927,6 +4970,9 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { StubFailureTrampolineStub::GenerateAheadOfTime(isolate); // It is important that the store buffer overflow stubs are generated first. RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); + if (FLAG_optimize_constructed_arrays) { + ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); + } } @@ -5005,7 +5051,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, __ mov(Operand(esp, 0 * kPointerSize), edi); // argc. __ mov(Operand(esp, 1 * kPointerSize), esi); // argv. __ mov(Operand(esp, 2 * kPointerSize), - Immediate(ExternalReference::isolate_address())); + Immediate(ExternalReference::isolate_address(masm->isolate()))); __ call(ebx); // Result is in eax or edx:eax - do not destroy these registers! @@ -5013,12 +5059,17 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, __ dec(Operand::StaticVariable(scope_depth)); } - // Make sure we're not trying to return 'the hole' from the runtime - // call as this may lead to crashes in the IC code later. + // Runtime functions should not return 'the hole'. Allowing it to escape may + // lead to crashes in the IC code later. if (FLAG_debug_code) { Label okay; __ cmp(eax, masm->isolate()->factory()->the_hole_value()); __ j(not_equal, &okay, Label::kNear); + // TODO(wingo): Currently SuspendJSGeneratorObject returns the hole. Change + // to return another sentinel like a harmony symbol. + __ cmp(ebx, Immediate(ExternalReference( + Runtime::kSuspendJSGeneratorObject, masm->isolate()))); + __ j(equal, &okay, Label::kNear); __ int3(); __ bind(&okay); } @@ -5777,17 +5828,17 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ ret(2 * kPointerSize); __ bind(&non_ascii); // At least one of the strings is two-byte. Check whether it happens - // to contain only ASCII characters. + // to contain only one byte characters. // ecx: first instance type AND second instance type. // edi: second instance type. - __ test(ecx, Immediate(kAsciiDataHintMask)); + __ test(ecx, Immediate(kOneByteDataHintMask)); __ j(not_zero, &ascii_data); __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); __ xor_(edi, ecx); - STATIC_ASSERT(kOneByteStringTag != 0 && kAsciiDataHintTag != 0); - __ and_(edi, kOneByteStringTag | kAsciiDataHintTag); - __ cmp(edi, kOneByteStringTag | kAsciiDataHintTag); + STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0); + __ and_(edi, kOneByteStringTag | kOneByteDataHintTag); + __ cmp(edi, kOneByteStringTag | kOneByteDataHintTag); __ j(equal, &ascii_data); // Allocate a two byte cons string. __ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime); @@ -7446,7 +7497,7 @@ void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) { __ mov(Operand(esp, 0 * kPointerSize), regs_.object()); __ mov(Operand(esp, 1 * kPointerSize), regs_.address()); // Slot. __ mov(Operand(esp, 2 * kPointerSize), - Immediate(ExternalReference::isolate_address())); + Immediate(ExternalReference::isolate_address(masm->isolate()))); AllowExternalCallThatCantCauseGC scope(masm); if (mode == INCREMENTAL_COMPACTION) { @@ -7686,6 +7737,197 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) { __ ret(0); } + +template<class T> +static void CreateArrayDispatch(MacroAssembler* masm) { + int last_index = GetSequenceIndexFromFastElementsKind( + TERMINAL_FAST_ELEMENTS_KIND); + for (int i = 0; i <= last_index; ++i) { + Label next; + ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); + __ cmp(edx, kind); + __ j(not_equal, &next); + T stub(kind); + __ TailCallStub(&stub); + __ bind(&next); + } + + // If we reached this point there is a problem. + __ Abort("Unexpected ElementsKind in array constructor"); +} + + +static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { + // ebx - type info cell + // edx - kind + // eax - number of arguments + // edi - constructor? + // esp[0] - return address + // esp[4] - last argument + ASSERT(FAST_SMI_ELEMENTS == 0); + ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); + ASSERT(FAST_ELEMENTS == 2); + ASSERT(FAST_HOLEY_ELEMENTS == 3); + ASSERT(FAST_DOUBLE_ELEMENTS == 4); + ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5); + + Handle<Object> undefined_sentinel( + masm->isolate()->heap()->undefined_value(), + masm->isolate()); + + // is the low bit set? If so, we are holey and that is good. + __ test_b(edx, 1); + Label normal_sequence; + __ j(not_zero, &normal_sequence); + + // look at the first argument + __ mov(ecx, Operand(esp, kPointerSize)); + __ test(ecx, ecx); + __ j(zero, &normal_sequence); + + // We are going to create a holey array, but our kind is non-holey. + // Fix kind and retry + __ inc(edx); + __ cmp(ebx, Immediate(undefined_sentinel)); + __ j(equal, &normal_sequence); + + // Save the resulting elements kind in type info + __ SmiTag(edx); + __ mov(FieldOperand(ebx, kPointerSize), edx); + __ SmiUntag(edx); + + __ bind(&normal_sequence); + int last_index = GetSequenceIndexFromFastElementsKind( + TERMINAL_FAST_ELEMENTS_KIND); + for (int i = 0; i <= last_index; ++i) { + Label next; + ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); + __ cmp(edx, kind); + __ j(not_equal, &next); + ArraySingleArgumentConstructorStub stub(kind); + __ TailCallStub(&stub); + __ bind(&next); + } + + // If we reached this point there is a problem. + __ Abort("Unexpected ElementsKind in array constructor"); +} + + +template<class T> +static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { + int to_index = GetSequenceIndexFromFastElementsKind( + TERMINAL_FAST_ELEMENTS_KIND); + for (int i = 0; i <= to_index; ++i) { + ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); + T stub(kind); + stub.GetCode(isolate)->set_is_pregenerated(true); + } +} + + +void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) { + ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>( + isolate); + ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>( + isolate); + ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>( + isolate); +} + + +void ArrayConstructorStub::Generate(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- eax : argc (only if argument_count_ == ANY) + // -- ebx : type info cell + // -- edi : constructor + // -- esp[0] : return address + // -- esp[4] : last argument + // ----------------------------------- + Handle<Object> undefined_sentinel( + masm->isolate()->heap()->undefined_value(), + masm->isolate()); + + if (FLAG_debug_code) { + // The array construct code is only set for the global and natives + // builtin Array functions which always have maps. + + // Initial map for the builtin Array function should be a map. + __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); + // Will both indicate a NULL and a Smi. + __ test(ecx, Immediate(kSmiTagMask)); + __ Assert(not_zero, "Unexpected initial map for Array function"); + __ CmpObjectType(ecx, MAP_TYPE, ecx); + __ Assert(equal, "Unexpected initial map for Array function"); + + // We should either have undefined in ebx or a valid jsglobalpropertycell + Label okay_here; + Handle<Map> global_property_cell_map( + masm->isolate()->heap()->global_property_cell_map()); + __ cmp(ebx, Immediate(undefined_sentinel)); + __ j(equal, &okay_here); + __ cmp(FieldOperand(ebx, 0), Immediate(global_property_cell_map)); + __ Assert(equal, "Expected property cell in register ebx"); + __ bind(&okay_here); + } + + if (FLAG_optimize_constructed_arrays) { + Label no_info, switch_ready; + // Get the elements kind and case on that. + __ cmp(ebx, Immediate(undefined_sentinel)); + __ j(equal, &no_info); + __ mov(edx, FieldOperand(ebx, kPointerSize)); + + // There is no info if the call site went megamorphic either + + // TODO(mvstanton): Really? I thought if it was the array function that + // the cell wouldn't get stamped as megamorphic. + __ cmp(edx, Immediate(TypeFeedbackCells::MegamorphicSentinel( + masm->isolate()))); + __ j(equal, &no_info); + __ SmiUntag(edx); + __ jmp(&switch_ready); + __ bind(&no_info); + __ mov(edx, Immediate(GetInitialFastElementsKind())); + __ bind(&switch_ready); + + if (argument_count_ == ANY) { + Label not_zero_case, not_one_case; + __ test(eax, eax); + __ j(not_zero, ¬_zero_case); + CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); + + __ bind(¬_zero_case); + __ cmp(eax, 1); + __ j(greater, ¬_one_case); + CreateArrayDispatchOneArgument(masm); + + __ bind(¬_one_case); + CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); + } else if (argument_count_ == NONE) { + CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); + } else if (argument_count_ == ONE) { + CreateArrayDispatchOneArgument(masm); + } else if (argument_count_ == MORE_THAN_ONE) { + CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); + } else { + UNREACHABLE(); + } + } else { + Label generic_constructor; + // Run the native code for the Array function called as constructor. + ArrayNativeCode(masm, true, &generic_constructor); + + // Jump to the generic construct code in case the specialized code cannot + // handle the construction. + __ bind(&generic_constructor); + Handle<Code> generic_construct_stub = + masm->isolate()->builtins()->JSConstructStubGeneric(); + __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); + } +} + + #undef __ } } // namespace v8::internal |