Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index ab037f3a3186c1986f2e4b40c4953f7e77bcc2c3..85b4b3b55db9c4f55d123c72a19efb11fb976df5 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -2032,6 +2032,165 @@ HValue* HGraphBuilder::BuildNumberToString(HValue* object, Type* type) { |
} |
+HValue* HGraphBuilder::BuildToObject(HValue* receiver) { |
+ NoObservableSideEffectsScope scope(this); |
+ |
+ // Create a joinable continuation. |
+ HIfContinuation wrap(graph()->CreateBasicBlock(), |
+ graph()->CreateBasicBlock()); |
+ |
+ // Determine the proper global constructor function required to wrap |
+ // {receiver} into a JSValue, unless {receiver} is already a {JSReceiver}, in |
+ // which case we just return it. Deopts to Runtime::kToObject if {receiver} |
+ // is undefined or null. |
+ IfBuilder receiver_is_smi(this); |
+ receiver_is_smi.If<HIsSmiAndBranch>(receiver); |
+ receiver_is_smi.Then(); |
+ { |
+ // Load native context. |
+ HValue* native_context = BuildGetNativeContext(); |
+ |
+ // Load global Number function. |
+ HValue* constructor = Add<HLoadNamedField>( |
+ native_context, nullptr, |
+ HObjectAccess::ForContextSlot(Context::NUMBER_FUNCTION_INDEX)); |
+ Push(constructor); |
+ } |
+ receiver_is_smi.Else(); |
+ { |
+ // Determine {receiver} map and instance type. |
+ HValue* receiver_map = |
+ Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap()); |
+ HValue* receiver_instance_type = Add<HLoadNamedField>( |
+ receiver_map, nullptr, HObjectAccess::ForMapInstanceType()); |
+ |
+ // First check whether {receiver} is already a spec object (fast case). |
+ IfBuilder receiver_is_not_spec_object(this); |
+ receiver_is_not_spec_object.If<HCompareNumericAndBranch>( |
+ receiver_instance_type, Add<HConstant>(FIRST_SPEC_OBJECT_TYPE), |
+ Token::LT); |
+ receiver_is_not_spec_object.Then(); |
+ { |
+ // Load native context. |
+ HValue* native_context = BuildGetNativeContext(); |
+ |
+ IfBuilder receiver_is_heap_number(this); |
+ receiver_is_heap_number.If<HCompareNumericAndBranch>( |
+ receiver_instance_type, Add<HConstant>(HEAP_NUMBER_TYPE), Token::EQ); |
+ receiver_is_heap_number.Then(); |
+ { |
+ // Load global Number function. |
+ HValue* constructor = Add<HLoadNamedField>( |
+ native_context, nullptr, |
+ HObjectAccess::ForContextSlot(Context::NUMBER_FUNCTION_INDEX)); |
+ Push(constructor); |
+ } |
+ receiver_is_heap_number.Else(); |
+ { |
+ // Load boolean map (we cannot decide based on instance type, because |
+ // it's ODDBALL_TYPE, which would also include null and undefined). |
+ HValue* boolean_map = Add<HLoadRoot>(Heap::kBooleanMapRootIndex); |
+ |
+ IfBuilder receiver_is_boolean(this); |
+ receiver_is_boolean.If<HCompareObjectEqAndBranch>(receiver_map, |
+ boolean_map); |
+ receiver_is_boolean.Then(); |
+ { |
+ // Load global Boolean function. |
+ HValue* constructor = Add<HLoadNamedField>( |
+ native_context, nullptr, |
+ HObjectAccess::ForContextSlot(Context::BOOLEAN_FUNCTION_INDEX)); |
+ Push(constructor); |
+ } |
+ receiver_is_boolean.Else(); |
+ { |
+ IfBuilder receiver_is_string(this); |
+ receiver_is_string.If<HCompareNumericAndBranch>( |
+ receiver_instance_type, Add<HConstant>(FIRST_NONSTRING_TYPE), |
+ Token::LT); |
+ receiver_is_string.Then(); |
+ { |
+ // Load global String function. |
+ HValue* constructor = Add<HLoadNamedField>( |
+ native_context, nullptr, |
+ HObjectAccess::ForContextSlot(Context::STRING_FUNCTION_INDEX)); |
+ Push(constructor); |
+ } |
+ receiver_is_string.Else(); |
+ { |
+ IfBuilder receiver_is_symbol(this); |
+ receiver_is_symbol.If<HCompareNumericAndBranch>( |
+ receiver_instance_type, Add<HConstant>(SYMBOL_TYPE), Token::EQ); |
+ receiver_is_symbol.Then(); |
+ { |
+ // Load global Symbol function. |
+ HValue* constructor = Add<HLoadNamedField>( |
+ native_context, nullptr, HObjectAccess::ForContextSlot( |
+ Context::SYMBOL_FUNCTION_INDEX)); |
+ Push(constructor); |
+ } |
+ receiver_is_symbol.Else(); |
+ { |
+ IfBuilder receiver_is_float32x4(this); |
+ receiver_is_float32x4.If<HCompareNumericAndBranch>( |
+ receiver_instance_type, Add<HConstant>(FLOAT32X4_TYPE), |
+ Token::EQ); |
+ receiver_is_float32x4.Then(); |
+ { |
+ // Load global Float32x4 function. |
+ HValue* constructor = Add<HLoadNamedField>( |
+ native_context, nullptr, |
+ HObjectAccess::ForContextSlot( |
+ Context::FLOAT32X4_FUNCTION_INDEX)); |
+ Push(constructor); |
+ } |
+ receiver_is_float32x4.ElseDeopt( |
+ Deoptimizer::kUndefinedOrNullInToObject); |
+ receiver_is_float32x4.JoinContinuation(&wrap); |
+ } |
+ receiver_is_symbol.JoinContinuation(&wrap); |
+ } |
+ receiver_is_string.JoinContinuation(&wrap); |
+ } |
+ receiver_is_boolean.JoinContinuation(&wrap); |
+ } |
+ receiver_is_heap_number.JoinContinuation(&wrap); |
+ } |
+ receiver_is_not_spec_object.JoinContinuation(&wrap); |
+ } |
+ receiver_is_smi.JoinContinuation(&wrap); |
+ |
+ // Wrap the receiver if necessary. |
+ IfBuilder if_wrap(this, &wrap); |
+ if_wrap.Then(); |
+ { |
+ // Determine the initial map for the global constructor. |
+ HValue* constructor = Pop(); |
+ HValue* constructor_initial_map = Add<HLoadNamedField>( |
+ constructor, nullptr, HObjectAccess::ForPrototypeOrInitialMap()); |
+ // Allocate and initialize a JSValue wrapper. |
+ HValue* value = |
+ BuildAllocate(Add<HConstant>(JSValue::kSize), HType::JSObject(), |
+ JS_VALUE_TYPE, HAllocationMode()); |
+ Add<HStoreNamedField>(value, HObjectAccess::ForMap(), |
+ constructor_initial_map); |
+ HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); |
+ Add<HStoreNamedField>(value, HObjectAccess::ForPropertiesPointer(), |
+ empty_fixed_array); |
+ Add<HStoreNamedField>(value, HObjectAccess::ForElementsPointer(), |
+ empty_fixed_array); |
+ Add<HStoreNamedField>(value, HObjectAccess::ForObservableJSObjectOffset( |
+ JSValue::kValueOffset), |
+ receiver); |
+ Push(value); |
+ } |
+ if_wrap.Else(); |
+ { Push(receiver); } |
+ if_wrap.End(); |
+ return Pop(); |
+} |
+ |
+ |
HAllocate* HGraphBuilder::BuildAllocate( |
HValue* object_size, |
HType type, |