From 7798548a8f2ef14e8320cc42effa86f0eb8e4294 Mon Sep 17 00:00:00 2001 From: mvstanton Date: Wed, 6 May 2015 06:31:00 -0700 Subject: [PATCH] Optimize the typeof operator. typeof was implemented as a runtime function. Calling it in optimized code with a non-constant input becomes burdensome. BUG= Review URL: https://codereview.chromium.org/1114563003 Cr-Commit-Position: refs/heads/master@{#28260} --- src/arm/code-stubs-arm.cc | 1 + src/arm/full-codegen-arm.cc | 7 +- src/arm/interface-descriptors-arm.cc | 6 ++ src/arm/lithium-arm.cc | 3 +- src/arm/lithium-codegen-arm.cc | 14 +++- src/arm64/code-stubs-arm64.cc | 1 + src/arm64/full-codegen-arm64.cc | 6 +- src/arm64/interface-descriptors-arm64.cc | 6 ++ src/arm64/lithium-arm64.cc | 8 +-- src/arm64/lithium-codegen-arm64.cc | 14 +++- src/code-factory.cc | 7 ++ src/code-factory.h | 2 + src/code-stubs-hydrogen.cc | 111 +++++++++++++++++++++++++++++ src/code-stubs.cc | 9 +++ src/code-stubs.h | 15 ++++ src/compiler/js-generic-lowering.cc | 7 +- src/compiler/linkage.cc | 1 - src/ia32/code-stubs-ia32.cc | 1 + src/ia32/full-codegen-ia32.cc | 7 +- src/ia32/interface-descriptors-ia32.cc | 6 ++ src/ia32/lithium-codegen-ia32.cc | 13 +++- src/ia32/lithium-ia32.cc | 2 +- src/interface-descriptors.h | 7 ++ src/mips/code-stubs-mips.cc | 1 + src/mips/full-codegen-mips.cc | 7 +- src/mips/interface-descriptors-mips.cc | 6 ++ src/mips/lithium-codegen-mips.cc | 13 +++- src/mips/lithium-mips.cc | 3 +- src/mips64/code-stubs-mips64.cc | 1 + src/mips64/full-codegen-mips64.cc | 7 +- src/mips64/interface-descriptors-mips64.cc | 6 ++ src/mips64/lithium-codegen-mips64.cc | 13 +++- src/mips64/lithium-mips64.cc | 3 +- src/runtime/runtime-object.cc | 42 ----------- src/runtime/runtime.h | 1 - src/x64/code-stubs-x64.cc | 1 + src/x64/full-codegen-x64.cc | 7 +- src/x64/interface-descriptors-x64.cc | 6 ++ src/x64/lithium-codegen-x64.cc | 13 +++- src/x64/lithium-x64.cc | 2 +- 40 files changed, 300 insertions(+), 86 deletions(-) diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 6ec8145..c69b382 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -923,6 +923,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { BinaryOpICStub::GenerateAheadOfTime(isolate); BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); StoreFastElementStub::GenerateAheadOfTime(isolate); + TypeofStub::GenerateAheadOfTime(isolate); } diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 2522b09..6f43d17 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -4799,10 +4799,13 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { case Token::TYPEOF: { Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); - { StackValueContext context(this); + { + AccumulatorValueContext context(this); VisitForTypeofValue(expr->expression()); } - __ CallRuntime(Runtime::kTypeof, 1); + __ mov(r3, r0); + TypeofStub typeof_stub(isolate()); + __ CallStub(&typeof_stub); context()->Plug(r0); break; } diff --git a/src/arm/interface-descriptors-arm.cc b/src/arm/interface-descriptors-arm.cc index caff56d..11613d1 100644 --- a/src/arm/interface-descriptors-arm.cc +++ b/src/arm/interface-descriptors-arm.cc @@ -83,6 +83,12 @@ void NumberToStringDescriptor::Initialize(CallInterfaceDescriptorData* data) { } +void TypeofDescriptor::Initialize(CallInterfaceDescriptorData* data) { + Register registers[] = {cp, r3}; + data->Initialize(arraysize(registers), registers, NULL); +} + + void FastCloneShallowArrayDescriptor::Initialize( CallInterfaceDescriptorData* data) { Register registers[] = {cp, r3, r2, r1}; diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 7d600db..ccd962c 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -2550,7 +2550,8 @@ LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) { LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) { LOperand* context = UseFixed(instr->context(), cp); - LTypeof* result = new(zone()) LTypeof(context, UseFixed(instr->value(), r0)); + LOperand* value = UseFixed(instr->value(), r3); + LTypeof* result = new (zone()) LTypeof(context, value); return MarkAsCall(DefineFixed(result, r0), instr); } diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 394c6bd..e91fddf 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -5550,9 +5550,17 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { - Register input = ToRegister(instr->value()); - __ push(input); - CallRuntime(Runtime::kTypeof, 1, instr); + DCHECK(ToRegister(instr->value()).is(r3)); + DCHECK(ToRegister(instr->result()).is(r0)); + Label end, do_call; + Register value_register = ToRegister(instr->value()); + __ JumpIfNotSmi(value_register, &do_call); + __ mov(r0, Operand(isolate()->factory()->number_string())); + __ jmp(&end); + __ bind(&do_call); + TypeofStub stub(isolate()); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + __ bind(&end); } diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc index b9dd63f..f71822e 100644 --- a/src/arm64/code-stubs-arm64.cc +++ b/src/arm64/code-stubs-arm64.cc @@ -981,6 +981,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { RestoreRegistersStateStub::GenerateAheadOfTime(isolate); BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); StoreFastElementStub::GenerateAheadOfTime(isolate); + TypeofStub::GenerateAheadOfTime(isolate); } diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index af4a6d6..aee9ddf 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -4482,10 +4482,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { case Token::TYPEOF: { Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); { - StackValueContext context(this); + AccumulatorValueContext context(this); VisitForTypeofValue(expr->expression()); } - __ CallRuntime(Runtime::kTypeof, 1); + __ Mov(x3, x0); + TypeofStub typeof_stub(isolate()); + __ CallStub(&typeof_stub); context()->Plug(x0); break; } diff --git a/src/arm64/interface-descriptors-arm64.cc b/src/arm64/interface-descriptors-arm64.cc index 7dff69c..7787224 100644 --- a/src/arm64/interface-descriptors-arm64.cc +++ b/src/arm64/interface-descriptors-arm64.cc @@ -97,6 +97,12 @@ void NumberToStringDescriptor::Initialize(CallInterfaceDescriptorData* data) { } +void TypeofDescriptor::Initialize(CallInterfaceDescriptorData* data) { + Register registers[] = {cp, x3}; + data->Initialize(arraysize(registers), registers, NULL); +} + + void FastCloneShallowArrayDescriptor::Initialize( CallInterfaceDescriptorData* data) { // cp: context diff --git a/src/arm64/lithium-arm64.cc b/src/arm64/lithium-arm64.cc index a9daec4..a4a36bf 100644 --- a/src/arm64/lithium-arm64.cc +++ b/src/arm64/lithium-arm64.cc @@ -2569,12 +2569,8 @@ LInstruction* LChunkBuilder::DoTrapAllocationMemento( LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) { LOperand* context = UseFixed(instr->context(), cp); - // TODO(jbramley): In ARM, this uses UseFixed to force the input to x0. - // However, LCodeGen::DoTypeof just pushes it to the stack (for CallRuntime) - // anyway, so the input doesn't have to be in x0. We might be able to improve - // the ARM back-end a little by relaxing this restriction. - LTypeof* result = - new(zone()) LTypeof(context, UseRegisterAtStart(instr->value())); + LOperand* value = UseFixed(instr->value(), x3); + LTypeof* result = new (zone()) LTypeof(context, value); return MarkAsCall(DefineFixed(result, x0), instr); } diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index 7834833..c2a2ff3 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc @@ -5795,9 +5795,17 @@ void LCodeGen::DoTruncateDoubleToIntOrSmi(LTruncateDoubleToIntOrSmi* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { - Register input = ToRegister(instr->value()); - __ Push(input); - CallRuntime(Runtime::kTypeof, 1, instr); + DCHECK(ToRegister(instr->value()).is(x3)); + DCHECK(ToRegister(instr->result()).is(x0)); + Label end, do_call; + Register value_register = ToRegister(instr->value()); + __ JumpIfNotSmi(value_register, &do_call); + __ Mov(x0, Immediate(isolate()->factory()->number_string())); + __ B(&end); + __ Bind(&do_call); + TypeofStub stub(isolate()); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + __ Bind(&end); } diff --git a/src/code-factory.cc b/src/code-factory.cc index 7277448..30448d8 100644 --- a/src/code-factory.cc +++ b/src/code-factory.cc @@ -144,6 +144,13 @@ Callable CodeFactory::StringAdd(Isolate* isolate, StringAddFlags flags, // static +Callable CodeFactory::Typeof(Isolate* isolate) { + TypeofStub stub(isolate); + return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor()); +} + + +// static Callable CodeFactory::FastCloneShallowArray(Isolate* isolate) { // TODO(mstarzinger): Thread through AllocationSiteMode at some point. FastCloneShallowArrayStub stub(isolate, DONT_TRACK_ALLOCATION_SITE); diff --git a/src/code-factory.h b/src/code-factory.h index 16ef6d5..1007be8 100644 --- a/src/code-factory.h +++ b/src/code-factory.h @@ -66,6 +66,8 @@ class CodeFactory final { static Callable StringAdd(Isolate* isolate, StringAddFlags flags, PretenureFlag pretenure_flag); + static Callable Typeof(Isolate* isolate); + static Callable FastCloneShallowArray(Isolate* isolate); static Callable FastCloneShallowObject(Isolate* isolate, int length); diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index d841ea0..70f6e61 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -299,6 +299,117 @@ Handle NumberToStringStub::GenerateCode() { } +// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47). +// Possible optimizations: put the type string into the oddballs. +template <> +HValue* CodeStubGraphBuilder::BuildCodeStub() { + Factory* factory = isolate()->factory(); + HConstant* number_string = Add(factory->number_string()); + HValue* object = GetParameter(TypeofStub::kObject); + + IfBuilder is_smi(this); + HValue* smi_check = is_smi.If(object); + is_smi.Then(); + { Push(number_string); } + is_smi.Else(); + { + IfBuilder is_number(this); + is_number.If(object, isolate()->factory()->heap_number_map()); + is_number.Then(); + { Push(number_string); } + is_number.Else(); + { + HConstant* undefined_string = Add(factory->undefined_string()); + HValue* map = AddLoadMap(object, smi_check); + HValue* instance_type = Add( + map, nullptr, HObjectAccess::ForMapInstanceType()); + IfBuilder is_string(this); + is_string.If( + instance_type, Add(FIRST_NONSTRING_TYPE), Token::LT); + is_string.Then(); + { Push(Add(factory->string_string())); } + is_string.Else(); + { + HConstant* object_string = Add(factory->object_string()); + IfBuilder is_oddball(this); + is_oddball.If( + instance_type, Add(ODDBALL_TYPE), Token::EQ); + is_oddball.Then(); + { + IfBuilder is_true_or_false(this); + is_true_or_false.If( + object, graph()->GetConstantTrue()); + is_true_or_false.OrIf( + object, graph()->GetConstantFalse()); + is_true_or_false.Then(); + { Push(Add(factory->boolean_string())); } + is_true_or_false.Else(); + { + IfBuilder is_null(this); + is_null.If(object, + graph()->GetConstantNull()); + is_null.Then(); + { Push(object_string); } + is_null.Else(); + { Push(undefined_string); } + } + is_true_or_false.End(); + } + is_oddball.Else(); + { + IfBuilder is_symbol(this); + is_symbol.If( + instance_type, Add(SYMBOL_TYPE), Token::EQ); + is_symbol.Then(); + { Push(Add(factory->symbol_string())); } + is_symbol.Else(); + { + IfBuilder is_function(this); + HConstant* js_function = Add(JS_FUNCTION_TYPE); + HConstant* js_function_proxy = + Add(JS_FUNCTION_PROXY_TYPE); + is_function.If(instance_type, js_function, + Token::EQ); + is_function.OrIf( + instance_type, js_function_proxy, Token::EQ); + is_function.Then(); + { Push(Add(factory->function_string())); } + is_function.Else(); + { + // Is it an undetectable object? + IfBuilder is_undetectable(this); + is_undetectable.If(object); + is_undetectable.Then(); + { + // typeof an undetectable object is 'undefined'. + Push(undefined_string); + } + is_undetectable.Else(); + { + // For any kind of object not handled above, the spec rule for + // host objects gives that it is okay to return "object". + Push(object_string); + } + } + is_function.End(); + } + is_symbol.End(); + } + is_oddball.End(); + } + is_string.End(); + } + is_number.End(); + } + is_smi.End(); + + return environment()->Pop(); +} + + +Handle TypeofStub::GenerateCode() { return DoGenerateCode(this); } + + template <> HValue* CodeStubGraphBuilder::BuildCodeStub() { Factory* factory = isolate()->factory(); diff --git a/src/code-stubs.cc b/src/code-stubs.cc index 46d8342..21d11a9 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -633,6 +633,9 @@ void FastNewClosureStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { void FastNewContextStub::InitializeDescriptor(CodeStubDescriptor* d) {} +void TypeofStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {} + + void NumberToStringStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { NumberToStringDescriptor call_descriptor(isolate()); descriptor->Initialize( @@ -722,6 +725,12 @@ void GrowArrayElementsStub::InitializeDescriptor( } +void TypeofStub::GenerateAheadOfTime(Isolate* isolate) { + TypeofStub stub(isolate); + stub.GetCode(); +} + + void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) { CreateAllocationSiteStub stub(isolate); stub.GetCode(); diff --git a/src/code-stubs.h b/src/code-stubs.h index c6767e9..040bf10 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -80,6 +80,7 @@ namespace internal { V(MegamorphicLoad) \ V(NameDictionaryLookup) \ V(NumberToString) \ + V(Typeof) \ V(RegExpConstructResult) \ V(StoreFastElement) \ V(StoreScriptContextField) \ @@ -595,6 +596,20 @@ class NumberToStringStub final : public HydrogenCodeStub { }; +class TypeofStub final : public HydrogenCodeStub { + public: + explicit TypeofStub(Isolate* isolate) : HydrogenCodeStub(isolate) {} + + // Parameters accessed via CodeStubGraphBuilder::GetParameter() + static const int kObject = 0; + + static void GenerateAheadOfTime(Isolate* isolate); + + DEFINE_CALL_INTERFACE_DESCRIPTOR(Typeof); + DEFINE_HYDROGEN_CODE_STUB(Typeof, HydrogenCodeStub); +}; + + class FastNewClosureStub : public HydrogenCodeStub { public: FastNewClosureStub(Isolate* isolate, LanguageMode language_mode, diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index 92a91e9..c60af1d 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -91,7 +91,6 @@ REPLACE_COMPARE_IC_CALL(JSGreaterThanOrEqual, Token::GTE) void JSGenericLowering::Lower##op(Node* node) { \ ReplaceWithRuntimeCall(node, fun); \ } -REPLACE_RUNTIME_CALL(JSTypeOf, Runtime::kTypeof) REPLACE_RUNTIME_CALL(JSCreate, Runtime::kAbort) REPLACE_RUNTIME_CALL(JSCreateFunctionContext, Runtime::kNewFunctionContext) REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext) @@ -272,6 +271,12 @@ void JSGenericLowering::LowerJSUnaryNot(Node* node) { } +void JSGenericLowering::LowerJSTypeOf(Node* node) { + Callable callable = CodeFactory::Typeof(isolate()); + ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags); +} + + void JSGenericLowering::LowerJSToBoolean(Node* node) { Callable callable = CodeFactory::ToBoolean(isolate(), ToBooleanStub::RESULT_AS_ODDBALL); diff --git a/src/compiler/linkage.cc b/src/compiler/linkage.cc index 08fef67..2f22d9a 100644 --- a/src/compiler/linkage.cc +++ b/src/compiler/linkage.cc @@ -130,7 +130,6 @@ bool Linkage::NeedsFrameState(Runtime::FunctionId function) { case Runtime::kToFastProperties: // TODO(jarin): Is it safe? case Runtime::kTraceEnter: case Runtime::kTraceExit: - case Runtime::kTypeof: return false; case Runtime::kInlineArguments: case Runtime::kInlineCallFunction: diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 15e7110..4d0a295 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -2457,6 +2457,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { BinaryOpICStub::GenerateAheadOfTime(isolate); BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); StoreFastElementStub::GenerateAheadOfTime(isolate); + TypeofStub::GenerateAheadOfTime(isolate); } diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 7033301..6ef215e 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -4723,10 +4723,13 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { case Token::TYPEOF: { Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); - { StackValueContext context(this); + { + AccumulatorValueContext context(this); VisitForTypeofValue(expr->expression()); } - __ CallRuntime(Runtime::kTypeof, 1); + __ mov(ebx, eax); + TypeofStub typeof_stub(isolate()); + __ CallStub(&typeof_stub); context()->Plug(eax); break; } diff --git a/src/ia32/interface-descriptors-ia32.cc b/src/ia32/interface-descriptors-ia32.cc index fc5c5c3..2c7c0dd 100644 --- a/src/ia32/interface-descriptors-ia32.cc +++ b/src/ia32/interface-descriptors-ia32.cc @@ -86,6 +86,12 @@ void NumberToStringDescriptor::Initialize(CallInterfaceDescriptorData* data) { } +void TypeofDescriptor::Initialize(CallInterfaceDescriptorData* data) { + Register registers[] = {esi, ebx}; + data->Initialize(arraysize(registers), registers, NULL); +} + + void FastCloneShallowArrayDescriptor::Initialize( CallInterfaceDescriptorData* data) { Register registers[] = {esi, eax, ebx, ecx}; diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 4dedbec..3f1bab7 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -5386,9 +5386,16 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { DCHECK(ToRegister(instr->context()).is(esi)); - LOperand* input = instr->value(); - EmitPushTaggedOperand(input); - CallRuntime(Runtime::kTypeof, 1, instr); + DCHECK(ToRegister(instr->value()).is(ebx)); + Label end, do_call; + Register value_register = ToRegister(instr->value()); + __ JumpIfNotSmi(value_register, &do_call); + __ mov(eax, Immediate(isolate()->factory()->number_string())); + __ jmp(&end); + __ bind(&do_call); + TypeofStub stub(isolate()); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + __ bind(&end); } diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index d9cef76..b085555 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -2611,7 +2611,7 @@ LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) { LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) { LOperand* context = UseFixed(instr->context(), esi); - LOperand* value = UseAtStart(instr->value()); + LOperand* value = UseFixed(instr->value(), ebx); LTypeof* result = new(zone()) LTypeof(context, value); return MarkAsCall(DefineFixed(result, eax), instr); } diff --git a/src/interface-descriptors.h b/src/interface-descriptors.h index 6ce5faa..ab1517e 100644 --- a/src/interface-descriptors.h +++ b/src/interface-descriptors.h @@ -25,6 +25,7 @@ class PlatformInterfaceDescriptor; V(FastNewContext) \ V(ToNumber) \ V(NumberToString) \ + V(Typeof) \ V(FastCloneShallowArray) \ V(FastCloneShallowObject) \ V(CreateAllocationSite) \ @@ -303,6 +304,12 @@ class NumberToStringDescriptor : public CallInterfaceDescriptor { }; +class TypeofDescriptor : public CallInterfaceDescriptor { + public: + DECLARE_DESCRIPTOR(TypeofDescriptor, CallInterfaceDescriptor) +}; + + class FastCloneShallowArrayDescriptor : public CallInterfaceDescriptor { public: DECLARE_DESCRIPTOR(FastCloneShallowArrayDescriptor, CallInterfaceDescriptor) diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index 0f7700a..484c81a 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -1009,6 +1009,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { RestoreRegistersStateStub::GenerateAheadOfTime(isolate); BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); StoreFastElementStub::GenerateAheadOfTime(isolate); + TypeofStub::GenerateAheadOfTime(isolate); } diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 0756b09..5ac885a 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -4802,10 +4802,13 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { case Token::TYPEOF: { Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); - { StackValueContext context(this); + { + AccumulatorValueContext context(this); VisitForTypeofValue(expr->expression()); } - __ CallRuntime(Runtime::kTypeof, 1); + __ mov(a3, v0); + TypeofStub typeof_stub(isolate()); + __ CallStub(&typeof_stub); context()->Plug(v0); break; } diff --git a/src/mips/interface-descriptors-mips.cc b/src/mips/interface-descriptors-mips.cc index 96bb2af..01db516 100644 --- a/src/mips/interface-descriptors-mips.cc +++ b/src/mips/interface-descriptors-mips.cc @@ -83,6 +83,12 @@ void NumberToStringDescriptor::Initialize(CallInterfaceDescriptorData* data) { } +void TypeofDescriptor::Initialize(CallInterfaceDescriptorData* data) { + Register registers[] = {cp, a3}; + data->Initialize(arraysize(registers), registers, NULL); +} + + void FastCloneShallowArrayDescriptor::Initialize( CallInterfaceDescriptorData* data) { Register registers[] = {cp, a3, a2, a1}; diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 09026cd..b173e30 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -5565,10 +5565,17 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { + DCHECK(ToRegister(instr->value()).is(a3)); DCHECK(ToRegister(instr->result()).is(v0)); - Register input = ToRegister(instr->value()); - __ push(input); - CallRuntime(Runtime::kTypeof, 1, instr); + Label end, do_call; + Register value_register = ToRegister(instr->value()); + __ JumpIfNotSmi(value_register, &do_call); + __ li(v0, Operand(isolate()->factory()->number_string())); + __ jmp(&end); + __ bind(&do_call); + TypeofStub stub(isolate()); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + __ bind(&end); } diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index c2d22ea..06b8d51 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -2497,7 +2497,8 @@ LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) { LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) { LOperand* context = UseFixed(instr->context(), cp); - LTypeof* result = new(zone()) LTypeof(context, UseFixed(instr->value(), a0)); + LOperand* value = UseFixed(instr->value(), a3); + LTypeof* result = new (zone()) LTypeof(context, value); return MarkAsCall(DefineFixed(result, v0), instr); } diff --git a/src/mips64/code-stubs-mips64.cc b/src/mips64/code-stubs-mips64.cc index 4d2400f..0a872c1 100644 --- a/src/mips64/code-stubs-mips64.cc +++ b/src/mips64/code-stubs-mips64.cc @@ -1005,6 +1005,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { RestoreRegistersStateStub::GenerateAheadOfTime(isolate); BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); StoreFastElementStub::GenerateAheadOfTime(isolate); + TypeofStub::GenerateAheadOfTime(isolate); } diff --git a/src/mips64/full-codegen-mips64.cc b/src/mips64/full-codegen-mips64.cc index 0e3f072..d2eb9dc 100644 --- a/src/mips64/full-codegen-mips64.cc +++ b/src/mips64/full-codegen-mips64.cc @@ -4805,10 +4805,13 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { case Token::TYPEOF: { Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); - { StackValueContext context(this); + { + AccumulatorValueContext context(this); VisitForTypeofValue(expr->expression()); } - __ CallRuntime(Runtime::kTypeof, 1); + __ mov(a3, v0); + TypeofStub typeof_stub(isolate()); + __ CallStub(&typeof_stub); context()->Plug(v0); break; } diff --git a/src/mips64/interface-descriptors-mips64.cc b/src/mips64/interface-descriptors-mips64.cc index 50ad745..2d6cabe 100644 --- a/src/mips64/interface-descriptors-mips64.cc +++ b/src/mips64/interface-descriptors-mips64.cc @@ -83,6 +83,12 @@ void NumberToStringDescriptor::Initialize(CallInterfaceDescriptorData* data) { } +void TypeofDescriptor::Initialize(CallInterfaceDescriptorData* data) { + Register registers[] = {cp, a3}; + data->Initialize(arraysize(registers), registers, NULL); +} + + void FastCloneShallowArrayDescriptor::Initialize( CallInterfaceDescriptorData* data) { Register registers[] = {cp, a3, a2, a1}; diff --git a/src/mips64/lithium-codegen-mips64.cc b/src/mips64/lithium-codegen-mips64.cc index fa75afd..223370f 100644 --- a/src/mips64/lithium-codegen-mips64.cc +++ b/src/mips64/lithium-codegen-mips64.cc @@ -5627,10 +5627,17 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { + DCHECK(ToRegister(instr->value()).is(a3)); DCHECK(ToRegister(instr->result()).is(v0)); - Register input = ToRegister(instr->value()); - __ push(input); - CallRuntime(Runtime::kTypeof, 1, instr); + Label end, do_call; + Register value_register = ToRegister(instr->value()); + __ JumpIfNotSmi(value_register, &do_call); + __ li(v0, Operand(isolate()->factory()->number_string())); + __ jmp(&end); + __ bind(&do_call); + TypeofStub stub(isolate()); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + __ bind(&end); } diff --git a/src/mips64/lithium-mips64.cc b/src/mips64/lithium-mips64.cc index 7495b74..1f518d3 100644 --- a/src/mips64/lithium-mips64.cc +++ b/src/mips64/lithium-mips64.cc @@ -2497,7 +2497,8 @@ LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) { LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) { LOperand* context = UseFixed(instr->context(), cp); - LTypeof* result = new(zone()) LTypeof(context, UseFixed(instr->value(), a0)); + LOperand* value = UseFixed(instr->value(), a3); + LTypeof* result = new (zone()) LTypeof(context, value); return MarkAsCall(DefineFixed(result, v0), instr); } diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc index d3e3313..462e024 100644 --- a/src/runtime/runtime-object.cc +++ b/src/runtime/runtime-object.cc @@ -1146,48 +1146,6 @@ RUNTIME_FUNCTION(Runtime_ToBool) { } -// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47). -// Possible optimizations: put the type string into the oddballs. -RUNTIME_FUNCTION(Runtime_Typeof) { - SealHandleScope shs(isolate); - DCHECK(args.length() == 1); - CONVERT_ARG_CHECKED(Object, obj, 0); - if (obj->IsNumber()) return isolate->heap()->number_string(); - HeapObject* heap_obj = HeapObject::cast(obj); - - // typeof an undetectable object is 'undefined' - if (heap_obj->map()->is_undetectable()) { - return isolate->heap()->undefined_string(); - } - - InstanceType instance_type = heap_obj->map()->instance_type(); - if (instance_type < FIRST_NONSTRING_TYPE) { - return isolate->heap()->string_string(); - } - - switch (instance_type) { - case ODDBALL_TYPE: - if (heap_obj->IsTrue() || heap_obj->IsFalse()) { - return isolate->heap()->boolean_string(); - } - if (heap_obj->IsNull()) { - return isolate->heap()->object_string(); - } - DCHECK(heap_obj->IsUndefined()); - return isolate->heap()->undefined_string(); - case SYMBOL_TYPE: - return isolate->heap()->symbol_string(); - case JS_FUNCTION_TYPE: - case JS_FUNCTION_PROXY_TYPE: - return isolate->heap()->function_string(); - default: - // For any kind of object not handled above, the spec rule for - // host objects gives that it is okay to return "object" - return isolate->heap()->object_string(); - } -} - - RUNTIME_FUNCTION(Runtime_NewStringWrapper) { HandleScope scope(isolate); DCHECK(args.length() == 1); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 4a8e468..f87e993 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -426,7 +426,6 @@ namespace internal { F(OwnKeys, 1, 1) \ F(ToFastProperties, 1, 1) \ F(ToBool, 1, 1) \ - F(Typeof, 1, 1) \ F(NewStringWrapper, 1, 1) \ F(AllocateHeapNumber, 0, 1) \ F(NewObject, 2, 1) \ diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 11cceb7..92b186e 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -2338,6 +2338,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { BinaryOpICStub::GenerateAheadOfTime(isolate); BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); StoreFastElementStub::GenerateAheadOfTime(isolate); + TypeofStub::GenerateAheadOfTime(isolate); } diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 7f0f66d..cdd5707 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -4746,10 +4746,13 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { case Token::TYPEOF: { Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); - { StackValueContext context(this); + { + AccumulatorValueContext context(this); VisitForTypeofValue(expr->expression()); } - __ CallRuntime(Runtime::kTypeof, 1); + __ movp(rbx, rax); + TypeofStub typeof_stub(isolate()); + __ CallStub(&typeof_stub); context()->Plug(rax); break; } diff --git a/src/x64/interface-descriptors-x64.cc b/src/x64/interface-descriptors-x64.cc index fe7789b..bb31cbd 100644 --- a/src/x64/interface-descriptors-x64.cc +++ b/src/x64/interface-descriptors-x64.cc @@ -73,6 +73,12 @@ void FastNewContextDescriptor::Initialize(CallInterfaceDescriptorData* data) { } +void TypeofDescriptor::Initialize(CallInterfaceDescriptorData* data) { + Register registers[] = {rsi, rbx}; + data->Initialize(arraysize(registers), registers, NULL); +} + + void ToNumberDescriptor::Initialize(CallInterfaceDescriptorData* data) { // ToNumberStub invokes a function, and therefore needs a context. Register registers[] = {rsi, rax}; diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index a5c4c7c..eb8274b 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -5549,9 +5549,16 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { DCHECK(ToRegister(instr->context()).is(rsi)); - LOperand* input = instr->value(); - EmitPushTaggedOperand(input); - CallRuntime(Runtime::kTypeof, 1, instr); + DCHECK(ToRegister(instr->value()).is(rbx)); + Label end, do_call; + Register value_register = ToRegister(instr->value()); + __ JumpIfNotSmi(value_register, &do_call); + __ Move(rax, isolate()->factory()->number_string()); + __ jmp(&end); + __ bind(&do_call); + TypeofStub stub(isolate()); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + __ bind(&end); } diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index 80f9f0b..54aed57 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -2582,7 +2582,7 @@ LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) { LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) { LOperand* context = UseFixed(instr->context(), rsi); - LOperand* value = UseAtStart(instr->value()); + LOperand* value = UseFixed(instr->value(), rbx); LTypeof* result = new(zone()) LTypeof(context, value); return MarkAsCall(DefineFixed(result, rax), instr); } -- 2.7.4