Chromium Code Reviews| Index: src/builtins/builtins.cc |
| diff --git a/src/builtins/builtins.cc b/src/builtins/builtins.cc |
| index 0545c85d6b7cc66339186bb2e839594fdb340d55..d3b4f0a0f723c4929881c70db3cc1d1742be9382 100644 |
| --- a/src/builtins/builtins.cc |
| +++ b/src/builtins/builtins.cc |
| @@ -5801,6 +5801,30 @@ Handle<Code> Builtins::CallBoundFunction(TailCallMode tail_call_mode) { |
| return Handle<Code>::null(); |
| } |
| +Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) { |
| + switch (hint) { |
| + case ToPrimitiveHint::kDefault: |
| + return NonPrimitiveToPrimitive_Default(); |
| + case ToPrimitiveHint::kNumber: |
| + return NonPrimitiveToPrimitive_Number(); |
| + case ToPrimitiveHint::kString: |
| + return NonPrimitiveToPrimitive_String(); |
| + } |
| + UNREACHABLE(); |
| + return Handle<Code>::null(); |
| +} |
| + |
| +Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) { |
| + switch (hint) { |
| + case OrdinaryToPrimitiveHint::kNumber: |
| + return OrdinaryToPrimitive_Number(); |
| + case OrdinaryToPrimitiveHint::kString: |
| + return OrdinaryToPrimitive_String(); |
| + } |
| + UNREACHABLE(); |
| + return Handle<Code>::null(); |
| +} |
| + |
| Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode, |
| CallableType function_type) { |
| switch (tail_call_mode) { |
| @@ -6087,6 +6111,164 @@ void Generate_StoreIC_SlowStrict(CodeStubAssembler* assembler) { |
| Generate_StoreIC_Slow(assembler, STRICT); |
| } |
| +// 7.1.1.1 OrdinaryToPrimitive ( O, hint ) |
| +void Generate_OrdinaryToPrimitive(CodeStubAssembler* assembler, |
| + OrdinaryToPrimitiveHint hint) { |
| + typedef CodeStubAssembler::Label Label; |
| + typedef compiler::Node Node; |
| + typedef CodeStubAssembler::Variable Variable; |
| + |
| + Node* input = assembler->Parameter(0); |
| + Node* context = assembler->Parameter(1); |
| + |
| + Variable var_result(assembler, MachineRepresentation::kTagged); |
| + Label return_result(assembler, &var_result); |
| + |
| + Handle<String> method_names[2]; |
| + switch (hint) { |
| + case OrdinaryToPrimitiveHint::kNumber: |
| + method_names[0] = assembler->factory()->valueOf_string(); |
| + method_names[1] = assembler->factory()->toString_string(); |
| + break; |
| + case OrdinaryToPrimitiveHint::kString: |
| + method_names[0] = assembler->factory()->toString_string(); |
| + method_names[1] = assembler->factory()->valueOf_string(); |
| + break; |
| + } |
| + for (Handle<String> name : method_names) { |
| + // Lookup the {name} on the {input}. |
| + Callable callable = CodeFactory::GetProperty(assembler->isolate()); |
| + Node* name_string = assembler->HeapConstant(name); |
| + Node* method = assembler->CallStub(callable, context, input, name_string); |
| + |
| + // Check if the {method} is callable. |
| + Label if_methodiscallable(assembler), |
| + if_methodisnotcallable(assembler, Label::kDeferred); |
| + assembler->GotoIf(assembler->WordIsSmi(method), &if_methodisnotcallable); |
| + Node* method_map = assembler->LoadMap(method); |
| + Node* method_bit_field = assembler->LoadMapBitField(method_map); |
| + assembler->Branch( |
| + assembler->Word32Equal( |
| + assembler->Word32And(method_bit_field, assembler->Int32Constant( |
| + 1 << Map::kIsCallable)), |
| + assembler->Int32Constant(0)), |
| + &if_methodisnotcallable, &if_methodiscallable); |
| + |
| + assembler->Bind(&if_methodiscallable); |
| + { |
| + // Call the {method} on the {input}. |
| + Callable callable = CodeFactory::Call(assembler->isolate()); |
| + Node* result = assembler->CallJS(callable, context, method, input); |
| + var_result.Bind(result); |
| + |
| + // Return the {result} if it is a primitive. |
| + assembler->GotoIf(assembler->WordIsSmi(result), &return_result); |
| + Node* result_instance_type = assembler->LoadInstanceType(result); |
|
Igor Sheludko
2016/07/14 09:53:47
Same here: STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == F
Benedikt Meurer
2016/07/14 09:56:09
Hm, that would have to materialize a bit because o
|
| + assembler->GotoIf(assembler->Int32LessThanOrEqual( |
| + result_instance_type, |
| + assembler->Int32Constant(LAST_PRIMITIVE_TYPE)), |
| + &return_result); |
| + } |
| + |
| + // Just continue with the next {name} if the {method} is not callable. |
| + assembler->Goto(&if_methodisnotcallable); |
| + assembler->Bind(&if_methodisnotcallable); |
| + } |
| + |
| + assembler->TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context); |
| + |
| + assembler->Bind(&return_result); |
| + assembler->Return(var_result.value()); |
| +} |
| + |
| +void Generate_OrdinaryToPrimitive_Number(CodeStubAssembler* assembler) { |
| + Generate_OrdinaryToPrimitive(assembler, OrdinaryToPrimitiveHint::kNumber); |
| +} |
| + |
| +void Generate_OrdinaryToPrimitive_String(CodeStubAssembler* assembler) { |
| + Generate_OrdinaryToPrimitive(assembler, OrdinaryToPrimitiveHint::kString); |
| +} |
| + |
| +// ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] ) |
| +void Generate_NonPrimitiveToPrimitive(CodeStubAssembler* assembler, |
| + ToPrimitiveHint hint) { |
| + typedef CodeStubAssembler::Label Label; |
| + typedef compiler::Node Node; |
| + |
| + Node* input = assembler->Parameter(0); |
| + Node* context = assembler->Parameter(1); |
| + |
| + // Lookup the @@toPrimitive property on the {input}. |
| + Callable callable = CodeFactory::GetProperty(assembler->isolate()); |
| + Node* to_primitive_symbol = |
| + assembler->HeapConstant(assembler->factory()->to_primitive_symbol()); |
| + Node* exotic_to_prim = |
| + assembler->CallStub(callable, context, input, to_primitive_symbol); |
| + |
| + // Check if {exotic_to_prim} is neither null nor undefined. |
| + Label ordinary_to_primitive(assembler); |
| + assembler->GotoIf( |
| + assembler->WordEqual(exotic_to_prim, assembler->NullConstant()), |
| + &ordinary_to_primitive); |
| + assembler->GotoIf( |
| + assembler->WordEqual(exotic_to_prim, assembler->UndefinedConstant()), |
| + &ordinary_to_primitive); |
| + { |
| + // Invoke the {exotic_to_prim} method on the {input} with a string |
| + // representation of the {hint}. |
| + Callable callable = CodeFactory::Call(assembler->isolate()); |
| + Node* hint_string = assembler->HeapConstant( |
| + assembler->factory()->ToPrimitiveHintString(hint)); |
| + Node* result = assembler->CallJS(callable, context, exotic_to_prim, input, |
| + hint_string); |
| + |
| + // Verify that the {result} is actually a primitive. |
| + Label if_resultisprimitive(assembler), |
| + if_resultisnotprimitive(assembler, Label::kDeferred); |
| + assembler->GotoIf(assembler->WordIsSmi(result), &if_resultisprimitive); |
| + Node* result_instance_type = assembler->LoadInstanceType(result); |
|
Igor Sheludko
2016/07/14 09:41:25
STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
Benedikt Meurer
2016/07/14 09:56:09
Done.
|
| + assembler->Branch(assembler->Int32LessThanOrEqual( |
| + result_instance_type, |
| + assembler->Int32Constant(LAST_PRIMITIVE_TYPE)), |
| + &if_resultisprimitive, &if_resultisnotprimitive); |
| + |
| + assembler->Bind(&if_resultisprimitive); |
| + { |
| + // Just return the {result}. |
| + assembler->Return(result); |
| + } |
| + |
| + assembler->Bind(&if_resultisnotprimitive); |
| + { |
| + // Somehow the @@toPrimitive method on {input} didn't yield a primitive. |
| + assembler->TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, |
| + context); |
| + } |
| + } |
| + |
| + // Convert using the OrdinaryToPrimitive algorithm instead. |
| + assembler->Bind(&ordinary_to_primitive); |
| + { |
| + Callable callable = CodeFactory::OrdinaryToPrimitive( |
| + assembler->isolate(), (hint == ToPrimitiveHint::kString) |
| + ? OrdinaryToPrimitiveHint::kString |
| + : OrdinaryToPrimitiveHint::kNumber); |
| + assembler->TailCallStub(callable, context, input); |
| + } |
| +} |
| + |
| +void Generate_NonPrimitiveToPrimitive_Default(CodeStubAssembler* assembler) { |
| + Generate_NonPrimitiveToPrimitive(assembler, ToPrimitiveHint::kDefault); |
| +} |
| + |
| +void Generate_NonPrimitiveToPrimitive_Number(CodeStubAssembler* assembler) { |
| + Generate_NonPrimitiveToPrimitive(assembler, ToPrimitiveHint::kNumber); |
| +} |
| + |
| +void Generate_NonPrimitiveToPrimitive_String(CodeStubAssembler* assembler) { |
| + Generate_NonPrimitiveToPrimitive(assembler, ToPrimitiveHint::kString); |
| +} |
| + |
| void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) { |
| ElementHandlerCompiler::GenerateStoreSlow(masm); |
| } |