LCOV - code coverage report
Current view: top level - src/builtins - builtins-conversion-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 175 175 100.0 %
Date: 2017-10-20 Functions: 38 38 100.0 %

          Line data    Source code
       1             : // Copyright 2016 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/builtins/builtins-utils-gen.h"
       6             : #include "src/builtins/builtins.h"
       7             : #include "src/code-factory.h"
       8             : #include "src/code-stub-assembler.h"
       9             : #include "src/objects-inl.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : 
      14             : class ConversionBuiltinsAssembler : public CodeStubAssembler {
      15             :  public:
      16             :   explicit ConversionBuiltinsAssembler(compiler::CodeAssemblerState* state)
      17         155 :       : CodeStubAssembler(state) {}
      18             : 
      19             :  protected:
      20             :   void Generate_NonPrimitiveToPrimitive(Node* context, Node* input,
      21             :                                         ToPrimitiveHint hint);
      22             : 
      23             :   void Generate_OrdinaryToPrimitive(Node* context, Node* input,
      24             :                                     OrdinaryToPrimitiveHint hint);
      25             : };
      26             : 
      27             : // ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] )
      28          93 : void ConversionBuiltinsAssembler::Generate_NonPrimitiveToPrimitive(
      29             :     Node* context, Node* input, ToPrimitiveHint hint) {
      30             :   // Lookup the @@toPrimitive property on the {input}.
      31             :   Node* exotic_to_prim =
      32         186 :       GetProperty(context, input, factory()->to_primitive_symbol());
      33             : 
      34             :   // Check if {exotic_to_prim} is neither null nor undefined.
      35             :   Label ordinary_to_primitive(this);
      36         186 :   GotoIf(WordEqual(exotic_to_prim, NullConstant()), &ordinary_to_primitive);
      37         186 :   GotoIf(WordEqual(exotic_to_prim, UndefinedConstant()),
      38          93 :          &ordinary_to_primitive);
      39             :   {
      40             :     // Invoke the {exotic_to_prim} method on the {input} with a string
      41             :     // representation of the {hint}.
      42             :     Callable callable =
      43          93 :         CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined);
      44          93 :     Node* hint_string = HeapConstant(factory()->ToPrimitiveHintString(hint));
      45             :     Node* result =
      46          93 :         CallJS(callable, context, exotic_to_prim, input, hint_string);
      47             : 
      48             :     // Verify that the {result} is actually a primitive.
      49          93 :     Label if_resultisprimitive(this),
      50          93 :         if_resultisnotprimitive(this, Label::kDeferred);
      51         186 :     GotoIf(TaggedIsSmi(result), &if_resultisprimitive);
      52         186 :     Node* result_instance_type = LoadInstanceType(result);
      53             :     STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
      54             :     Branch(Int32LessThanOrEqual(result_instance_type,
      55         186 :                                 Int32Constant(LAST_PRIMITIVE_TYPE)),
      56         186 :            &if_resultisprimitive, &if_resultisnotprimitive);
      57             : 
      58          93 :     BIND(&if_resultisprimitive);
      59             :     {
      60             :       // Just return the {result}.
      61          93 :       Return(result);
      62             :     }
      63             : 
      64          93 :     BIND(&if_resultisnotprimitive);
      65             :     {
      66             :       // Somehow the @@toPrimitive method on {input} didn't yield a primitive.
      67             :       TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context);
      68             :     }
      69             :   }
      70             : 
      71             :   // Convert using the OrdinaryToPrimitive algorithm instead.
      72          93 :   BIND(&ordinary_to_primitive);
      73             :   {
      74             :     Callable callable = CodeFactory::OrdinaryToPrimitive(
      75             :         isolate(), (hint == ToPrimitiveHint::kString)
      76             :                        ? OrdinaryToPrimitiveHint::kString
      77          93 :                        : OrdinaryToPrimitiveHint::kNumber);
      78          93 :     TailCallStub(callable, context, input);
      79          93 :   }
      80          93 : }
      81             : 
      82         124 : TF_BUILTIN(NonPrimitiveToPrimitive_Default, ConversionBuiltinsAssembler) {
      83             :   Node* context = Parameter(Descriptor::kContext);
      84             :   Node* input = Parameter(Descriptor::kArgument);
      85             : 
      86          31 :   Generate_NonPrimitiveToPrimitive(context, input, ToPrimitiveHint::kDefault);
      87          31 : }
      88             : 
      89         124 : TF_BUILTIN(NonPrimitiveToPrimitive_Number, ConversionBuiltinsAssembler) {
      90             :   Node* context = Parameter(Descriptor::kContext);
      91             :   Node* input = Parameter(Descriptor::kArgument);
      92             : 
      93          31 :   Generate_NonPrimitiveToPrimitive(context, input, ToPrimitiveHint::kNumber);
      94          31 : }
      95             : 
      96         124 : TF_BUILTIN(NonPrimitiveToPrimitive_String, ConversionBuiltinsAssembler) {
      97             :   Node* context = Parameter(Descriptor::kContext);
      98             :   Node* input = Parameter(Descriptor::kArgument);
      99             : 
     100          31 :   Generate_NonPrimitiveToPrimitive(context, input, ToPrimitiveHint::kString);
     101          31 : }
     102             : 
     103          93 : TF_BUILTIN(StringToNumber, CodeStubAssembler) {
     104             :   Node* context = Parameter(Descriptor::kContext);
     105             :   Node* input = Parameter(Descriptor::kArgument);
     106             : 
     107          62 :   Return(StringToNumber(context, input));
     108          31 : }
     109             : 
     110          93 : TF_BUILTIN(ToName, CodeStubAssembler) {
     111             :   Node* context = Parameter(Descriptor::kContext);
     112             :   Node* input = Parameter(Descriptor::kArgument);
     113             : 
     114          62 :   Return(ToName(context, input));
     115          31 : }
     116             : 
     117          93 : TF_BUILTIN(NonNumberToNumber, CodeStubAssembler) {
     118             :   Node* context = Parameter(Descriptor::kContext);
     119             :   Node* input = Parameter(Descriptor::kArgument);
     120             : 
     121          62 :   Return(NonNumberToNumber(context, input));
     122          31 : }
     123             : 
     124          93 : TF_BUILTIN(NonNumberToNumeric, CodeStubAssembler) {
     125             :   Node* context = Parameter(Descriptor::kContext);
     126             :   Node* input = Parameter(Descriptor::kArgument);
     127             : 
     128          62 :   Return(NonNumberToNumeric(context, input));
     129          31 : }
     130             : 
     131             : // ES6 section 7.1.3 ToNumber ( argument )
     132          93 : TF_BUILTIN(ToNumber, CodeStubAssembler) {
     133             :   Node* context = Parameter(Descriptor::kContext);
     134             :   Node* input = Parameter(Descriptor::kArgument);
     135             : 
     136          62 :   Return(ToNumber(context, input));
     137          31 : }
     138             : 
     139          93 : TF_BUILTIN(ToString, CodeStubAssembler) {
     140             :   Node* context = Parameter(Descriptor::kContext);
     141             :   Node* input = Parameter(Descriptor::kArgument);
     142             : 
     143          62 :   Return(ToString(context, input));
     144          31 : }
     145             : 
     146             : // 7.1.1.1 OrdinaryToPrimitive ( O, hint )
     147          62 : void ConversionBuiltinsAssembler::Generate_OrdinaryToPrimitive(
     148             :     Node* context, Node* input, OrdinaryToPrimitiveHint hint) {
     149          62 :   VARIABLE(var_result, MachineRepresentation::kTagged);
     150          62 :   Label return_result(this, &var_result);
     151             : 
     152         186 :   Handle<String> method_names[2];
     153          62 :   switch (hint) {
     154             :     case OrdinaryToPrimitiveHint::kNumber:
     155          62 :       method_names[0] = factory()->valueOf_string();
     156          62 :       method_names[1] = factory()->toString_string();
     157          31 :       break;
     158             :     case OrdinaryToPrimitiveHint::kString:
     159          62 :       method_names[0] = factory()->toString_string();
     160          62 :       method_names[1] = factory()->valueOf_string();
     161          31 :       break;
     162             :   }
     163         248 :   for (Handle<String> name : method_names) {
     164             :     // Lookup the {name} on the {input}.
     165         124 :     Node* method = GetProperty(context, input, name);
     166             : 
     167             :     // Check if the {method} is callable.
     168             :     Label if_methodiscallable(this),
     169         124 :         if_methodisnotcallable(this, Label::kDeferred);
     170         248 :     GotoIf(TaggedIsSmi(method), &if_methodisnotcallable);
     171         248 :     Node* method_map = LoadMap(method);
     172             :     Branch(IsCallableMap(method_map), &if_methodiscallable,
     173         248 :            &if_methodisnotcallable);
     174             : 
     175         124 :     BIND(&if_methodiscallable);
     176             :     {
     177             :       // Call the {method} on the {input}.
     178             :       Callable callable = CodeFactory::Call(
     179         124 :           isolate(), ConvertReceiverMode::kNotNullOrUndefined);
     180         124 :       Node* result = CallJS(callable, context, method, input);
     181         124 :       var_result.Bind(result);
     182             : 
     183             :       // Return the {result} if it is a primitive.
     184         248 :       GotoIf(TaggedIsSmi(result), &return_result);
     185         248 :       Node* result_instance_type = LoadInstanceType(result);
     186             :       STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
     187             :       GotoIf(Int32LessThanOrEqual(result_instance_type,
     188         248 :                                   Int32Constant(LAST_PRIMITIVE_TYPE)),
     189         248 :              &return_result);
     190             :     }
     191             : 
     192             :     // Just continue with the next {name} if the {method} is not callable.
     193         124 :     Goto(&if_methodisnotcallable);
     194         124 :     BIND(&if_methodisnotcallable);
     195         124 :   }
     196             : 
     197             :   TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context);
     198             : 
     199          62 :   BIND(&return_result);
     200         186 :   Return(var_result.value());
     201          62 : }
     202             : 
     203         124 : TF_BUILTIN(OrdinaryToPrimitive_Number, ConversionBuiltinsAssembler) {
     204             :   Node* context = Parameter(Descriptor::kContext);
     205             :   Node* input = Parameter(Descriptor::kArgument);
     206             :   Generate_OrdinaryToPrimitive(context, input,
     207          31 :                                OrdinaryToPrimitiveHint::kNumber);
     208          31 : }
     209             : 
     210         124 : TF_BUILTIN(OrdinaryToPrimitive_String, ConversionBuiltinsAssembler) {
     211             :   Node* context = Parameter(Descriptor::kContext);
     212             :   Node* input = Parameter(Descriptor::kArgument);
     213             :   Generate_OrdinaryToPrimitive(context, input,
     214          31 :                                OrdinaryToPrimitiveHint::kString);
     215          31 : }
     216             : 
     217             : // ES6 section 7.1.2 ToBoolean ( argument )
     218          93 : TF_BUILTIN(ToBoolean, CodeStubAssembler) {
     219             :   Node* value = Parameter(Descriptor::kArgument);
     220             : 
     221          31 :   Label return_true(this), return_false(this);
     222          31 :   BranchIfToBooleanIsTrue(value, &return_true, &return_false);
     223             : 
     224          31 :   BIND(&return_true);
     225          62 :   Return(BooleanConstant(true));
     226             : 
     227          31 :   BIND(&return_false);
     228          93 :   Return(BooleanConstant(false));
     229          31 : }
     230             : 
     231             : // ES6 section 7.1.2 ToBoolean ( argument )
     232             : // Requires parameter on stack so that it can be used as a continuation from a
     233             : // LAZY deopt.
     234          93 : TF_BUILTIN(ToBooleanLazyDeoptContinuation, CodeStubAssembler) {
     235             :   Node* value = Parameter(Descriptor::kArgument);
     236             : 
     237          31 :   Label return_true(this), return_false(this);
     238          31 :   BranchIfToBooleanIsTrue(value, &return_true, &return_false);
     239             : 
     240          31 :   BIND(&return_true);
     241          62 :   Return(BooleanConstant(true));
     242             : 
     243          31 :   BIND(&return_false);
     244          93 :   Return(BooleanConstant(false));
     245          31 : }
     246             : 
     247          93 : TF_BUILTIN(ToLength, CodeStubAssembler) {
     248             :   Node* context = Parameter(Descriptor::kContext);
     249             : 
     250             :   // We might need to loop once for ToNumber conversion.
     251          31 :   VARIABLE(var_len, MachineRepresentation::kTagged,
     252             :            Parameter(Descriptor::kArgument));
     253          31 :   Label loop(this, &var_len);
     254          31 :   Goto(&loop);
     255          31 :   BIND(&loop);
     256             :   {
     257             :     // Shared entry points.
     258          31 :     Label return_len(this), return_two53minus1(this, Label::kDeferred),
     259          31 :         return_zero(this, Label::kDeferred);
     260             : 
     261             :     // Load the current {len} value.
     262          31 :     Node* len = var_len.value();
     263             : 
     264             :     // Check if {len} is a positive Smi.
     265          62 :     GotoIf(TaggedIsPositiveSmi(len), &return_len);
     266             : 
     267             :     // Check if {len} is a (negative) Smi.
     268          62 :     GotoIf(TaggedIsSmi(len), &return_zero);
     269             : 
     270             :     // Check if {len} is a HeapNumber.
     271          31 :     Label if_lenisheapnumber(this),
     272          31 :         if_lenisnotheapnumber(this, Label::kDeferred);
     273          62 :     Branch(IsHeapNumber(len), &if_lenisheapnumber, &if_lenisnotheapnumber);
     274             : 
     275          31 :     BIND(&if_lenisheapnumber);
     276             :     {
     277             :       // Load the floating-point value of {len}.
     278          62 :       Node* len_value = LoadHeapNumberValue(len);
     279             : 
     280             :       // Check if {len} is not greater than zero.
     281          62 :       GotoIfNot(Float64GreaterThan(len_value, Float64Constant(0.0)),
     282          62 :                 &return_zero);
     283             : 
     284             :       // Check if {len} is greater than or equal to 2^53-1.
     285             :       GotoIf(Float64GreaterThanOrEqual(len_value,
     286          62 :                                        Float64Constant(kMaxSafeInteger)),
     287          62 :              &return_two53minus1);
     288             : 
     289             :       // Round the {len} towards -Infinity.
     290          62 :       Node* value = Float64Floor(len_value);
     291          62 :       Node* result = ChangeFloat64ToTagged(value);
     292          31 :       Return(result);
     293             :     }
     294             : 
     295          31 :     BIND(&if_lenisnotheapnumber);
     296             :     {
     297             :       // Need to convert {len} to a Number first.
     298          31 :       var_len.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, len));
     299          31 :       Goto(&loop);
     300             :     }
     301             : 
     302          31 :     BIND(&return_len);
     303          62 :     Return(var_len.value());
     304             : 
     305          31 :     BIND(&return_two53minus1);
     306          62 :     Return(NumberConstant(kMaxSafeInteger));
     307             : 
     308          31 :     BIND(&return_zero);
     309          93 :     Return(SmiConstant(0));
     310          31 :   }
     311          31 : }
     312             : 
     313          93 : TF_BUILTIN(ToInteger, CodeStubAssembler) {
     314             :   Node* context = Parameter(Descriptor::kContext);
     315             :   Node* input = Parameter(Descriptor::kArgument);
     316             : 
     317          62 :   Return(ToInteger(context, input));
     318          31 : }
     319             : 
     320             : // ES6 section 7.1.13 ToObject (argument)
     321         124 : TF_BUILTIN(ToObject, CodeStubAssembler) {
     322          62 :   Label if_smi(this, Label::kDeferred), if_jsreceiver(this),
     323          31 :       if_noconstructor(this, Label::kDeferred), if_wrapjsvalue(this);
     324             : 
     325             :   Node* context = Parameter(Descriptor::kContext);
     326             :   Node* object = Parameter(Descriptor::kArgument);
     327             : 
     328          62 :   VARIABLE(constructor_function_index_var,
     329             :            MachineType::PointerRepresentation());
     330             : 
     331          62 :   GotoIf(TaggedIsSmi(object), &if_smi);
     332             : 
     333          62 :   Node* map = LoadMap(object);
     334          62 :   Node* instance_type = LoadMapInstanceType(map);
     335          62 :   GotoIf(IsJSReceiverInstanceType(instance_type), &if_jsreceiver);
     336             : 
     337          62 :   Node* constructor_function_index = LoadMapConstructorFunctionIndex(map);
     338             :   GotoIf(WordEqual(constructor_function_index,
     339          62 :                    IntPtrConstant(Map::kNoConstructorFunctionIndex)),
     340          62 :          &if_noconstructor);
     341          31 :   constructor_function_index_var.Bind(constructor_function_index);
     342          31 :   Goto(&if_wrapjsvalue);
     343             : 
     344          31 :   BIND(&if_smi);
     345             :   constructor_function_index_var.Bind(
     346          62 :       IntPtrConstant(Context::NUMBER_FUNCTION_INDEX));
     347          31 :   Goto(&if_wrapjsvalue);
     348             : 
     349          31 :   BIND(&if_wrapjsvalue);
     350          31 :   Node* native_context = LoadNativeContext(context);
     351             :   Node* constructor = LoadFixedArrayElement(
     352          31 :       native_context, constructor_function_index_var.value());
     353             :   Node* initial_map =
     354             :       LoadObjectField(constructor, JSFunction::kPrototypeOrInitialMapOffset);
     355          31 :   Node* js_value = Allocate(JSValue::kSize);
     356          31 :   StoreMapNoWriteBarrier(js_value, initial_map);
     357             :   StoreObjectFieldRoot(js_value, JSValue::kPropertiesOrHashOffset,
     358          31 :                        Heap::kEmptyFixedArrayRootIndex);
     359             :   StoreObjectFieldRoot(js_value, JSObject::kElementsOffset,
     360          31 :                        Heap::kEmptyFixedArrayRootIndex);
     361          31 :   StoreObjectField(js_value, JSValue::kValueOffset, object);
     362          31 :   Return(js_value);
     363             : 
     364          31 :   BIND(&if_noconstructor);
     365             :   TailCallRuntime(Runtime::kThrowUndefinedOrNullToObject, context,
     366          31 :                   StringConstant("ToObject"));
     367             : 
     368          31 :   BIND(&if_jsreceiver);
     369          62 :   Return(object);
     370          31 : }
     371             : 
     372             : // Deprecated ES5 [[Class]] internal property (used to implement %_ClassOf).
     373          93 : TF_BUILTIN(ClassOf, CodeStubAssembler) {
     374             :   Node* object = Parameter(TypeofDescriptor::kObject);
     375             : 
     376          62 :   Return(ClassOf(object));
     377          31 : }
     378             : 
     379             : // ES6 section 12.5.5 typeof operator
     380          93 : TF_BUILTIN(Typeof, CodeStubAssembler) {
     381             :   Node* object = Parameter(TypeofDescriptor::kObject);
     382             : 
     383          62 :   Return(Typeof(object));
     384          31 : }
     385             : 
     386             : }  // namespace internal
     387             : }  // namespace v8

Generated by: LCOV version 1.10