[stubs] Unify (and optimize) implementation of ToObject.
This is the initial (big) step towards a more uniform implementation of the ToObject abstract operation (ES6 7.1.13), where we have a fallback implementation in JSReceiver::ToObject() and a fast (hydrogen) CodeStub to deal with the fast case (we should be able to do more cleanup on this in a followup CL). For natives we expose the abstract operation via a %_ToObject intrinsic, also exposed via a macro TO_OBJECT, that unifies the previous confusion with TO_OBJECT_INLINE, ToObject, TO_OBJECT, $toObject and %$toObject. Now the whole implementation of the abstract operation is context independent, meaning we don't need any magic in the builtins object nor the native context. R=mvstanton@chromium.org,yangguo@chromium.org Review URL: https://codereview.chromium.org/1266013006 Cr-Commit-Position: refs/heads/master@{#29953}
This commit is contained in:
parent
f8a4afa7bd
commit
4fc6f54724
@ -6913,7 +6913,7 @@ class Internals {
|
||||
static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
|
||||
static const int kFixedArrayHeaderSize = 2 * kApiPointerSize;
|
||||
static const int kContextHeaderSize = 2 * kApiPointerSize;
|
||||
static const int kContextEmbedderDataIndex = 82;
|
||||
static const int kContextEmbedderDataIndex = 81;
|
||||
static const int kFullStringRepresentationMask = 0x07;
|
||||
static const int kStringEncodingMask = 0x4;
|
||||
static const int kExternalTwoByteRepresentationTag = 0x02;
|
||||
|
@ -1319,8 +1319,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
__ SmiTag(r0);
|
||||
__ push(r0);
|
||||
|
||||
__ push(r2);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ mov(r0, r2);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ mov(r2, r0);
|
||||
|
||||
__ pop(r0);
|
||||
@ -1556,8 +1557,8 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
|
||||
// Convert the receiver to a regular object.
|
||||
// r0: receiver
|
||||
__ bind(&call_to_object);
|
||||
__ push(r0);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ b(&push_receiver);
|
||||
|
||||
__ bind(&use_global_proxy);
|
||||
|
@ -2547,8 +2547,10 @@ static void EmitSlowCase(MacroAssembler* masm,
|
||||
static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
|
||||
// Wrap the receiver and patch it back onto the stack.
|
||||
{ FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL);
|
||||
__ Push(r1, r3);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ push(r1);
|
||||
__ mov(r0, r3);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ pop(r1);
|
||||
}
|
||||
__ str(r0, MemOperand(sp, argc * kPointerSize));
|
||||
|
@ -95,6 +95,10 @@ void ToNumberDescriptor::InitializePlatformSpecific(
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
const Register ToObjectDescriptor::ReceiverRegister() { return r0; }
|
||||
|
||||
|
||||
void NumberToStringDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {r0};
|
||||
|
@ -1355,8 +1355,10 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
__ SmiTag(argc);
|
||||
|
||||
__ Push(argc, receiver);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ Push(argc);
|
||||
__ Mov(x0, receiver);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ Mov(receiver, x0);
|
||||
|
||||
__ Pop(argc);
|
||||
@ -1582,8 +1584,9 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
|
||||
|
||||
// Call a builtin to convert the receiver to a regular object.
|
||||
__ Bind(&convert_receiver_to_object);
|
||||
__ Push(receiver);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ Mov(x0, receiver);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ Mov(receiver, x0);
|
||||
__ B(&push_receiver);
|
||||
|
||||
|
@ -2921,8 +2921,10 @@ static void EmitSlowCase(MacroAssembler* masm,
|
||||
static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
|
||||
// Wrap the receiver and patch it back onto the stack.
|
||||
{ FrameScope frame_scope(masm, StackFrame::INTERNAL);
|
||||
__ Push(x1, x3);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ Push(x1);
|
||||
__ Mov(x0, x3);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ Pop(x1);
|
||||
}
|
||||
__ Poke(x0, argc * kPointerSize);
|
||||
|
@ -104,6 +104,10 @@ void ToNumberDescriptor::InitializePlatformSpecific(
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
const Register ToObjectDescriptor::ReceiverRegister() { return x0; }
|
||||
|
||||
|
||||
void NumberToStringDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
// x0: value
|
||||
|
@ -45,7 +45,7 @@ function ArrayIterator() {}
|
||||
|
||||
// 15.4.5.1 CreateArrayIterator Abstract Operation
|
||||
function CreateArrayIterator(array, kind) {
|
||||
var object = $toObject(array);
|
||||
var object = TO_OBJECT(array);
|
||||
var iterator = new ArrayIterator;
|
||||
SET_PRIVATE(iterator, arrayIteratorObjectSymbol, object);
|
||||
SET_PRIVATE(iterator, arrayIteratorNextIndexSymbol, 0);
|
||||
@ -68,7 +68,7 @@ function ArrayIteratorIterator() {
|
||||
|
||||
// 15.4.5.2.2 ArrayIterator.prototype.next( )
|
||||
function ArrayIteratorNext() {
|
||||
var iterator = $toObject(this);
|
||||
var iterator = TO_OBJECT(this);
|
||||
|
||||
if (!HAS_DEFINED_PRIVATE(iterator, arrayIteratorNextIndexSymbol)) {
|
||||
throw MakeTypeError(kIncompatibleMethodReceiver,
|
||||
|
50
src/array.js
50
src/array.js
@ -227,7 +227,7 @@ function ConvertToLocaleString(e) {
|
||||
// According to ES5, section 15.4.4.3, the toLocaleString conversion
|
||||
// must throw a TypeError if ToObject(e).toLocaleString isn't
|
||||
// callable.
|
||||
var e_obj = $toObject(e);
|
||||
var e_obj = TO_OBJECT(e);
|
||||
return $toString(e_obj.toLocaleString());
|
||||
}
|
||||
}
|
||||
@ -388,7 +388,7 @@ function ArrayToString() {
|
||||
}
|
||||
array = this;
|
||||
} else {
|
||||
array = $toObject(this);
|
||||
array = TO_OBJECT(this);
|
||||
func = array.join;
|
||||
}
|
||||
if (!IS_SPEC_FUNCTION(func)) {
|
||||
@ -406,7 +406,7 @@ function InnerArrayToLocaleString(array, length) {
|
||||
|
||||
|
||||
function ArrayToLocaleString() {
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var arrayLen = array.length;
|
||||
return InnerArrayToLocaleString(array, arrayLen);
|
||||
}
|
||||
@ -437,7 +437,7 @@ function InnerArrayJoin(separator, array, length) {
|
||||
function ArrayJoin(separator) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.join");
|
||||
|
||||
var array = TO_OBJECT_INLINE(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = TO_UINT32(array.length);
|
||||
|
||||
return InnerArrayJoin(separator, array, length);
|
||||
@ -466,7 +466,7 @@ function ObservedArrayPop(n) {
|
||||
function ArrayPop() {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.pop");
|
||||
|
||||
var array = TO_OBJECT_INLINE(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var n = TO_UINT32(array.length);
|
||||
if (n == 0) {
|
||||
array.length = n;
|
||||
@ -512,7 +512,7 @@ function ArrayPush() {
|
||||
if (%IsObserved(this))
|
||||
return ObservedArrayPush.apply(this, arguments);
|
||||
|
||||
var array = TO_OBJECT_INLINE(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var n = TO_UINT32(array.length);
|
||||
var m = %_ArgumentsLength();
|
||||
|
||||
@ -532,7 +532,7 @@ function ArrayPush() {
|
||||
function ArrayConcatJS(arg1) { // length == 1
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.concat");
|
||||
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var arg_count = %_ArgumentsLength();
|
||||
var arrays = new InternalArray(1 + arg_count);
|
||||
arrays[0] = array;
|
||||
@ -627,7 +627,7 @@ function GenericArrayReverse(array, len) {
|
||||
function ArrayReverse() {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reverse");
|
||||
|
||||
var array = TO_OBJECT_INLINE(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var len = TO_UINT32(array.length);
|
||||
var isArray = IS_ARRAY(array);
|
||||
|
||||
@ -662,7 +662,7 @@ function ObservedArrayShift(len) {
|
||||
function ArrayShift() {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.shift");
|
||||
|
||||
var array = TO_OBJECT_INLINE(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var len = TO_UINT32(array.length);
|
||||
|
||||
if (len === 0) {
|
||||
@ -716,7 +716,7 @@ function ArrayUnshift(arg1) { // length == 1
|
||||
if (%IsObserved(this))
|
||||
return ObservedArrayUnshift.apply(this, arguments);
|
||||
|
||||
var array = TO_OBJECT_INLINE(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var len = TO_UINT32(array.length);
|
||||
var num_arguments = %_ArgumentsLength();
|
||||
|
||||
@ -740,7 +740,7 @@ function ArrayUnshift(arg1) { // length == 1
|
||||
function ArraySlice(start, end) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.slice");
|
||||
|
||||
var array = TO_OBJECT_INLINE(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var len = TO_UINT32(array.length);
|
||||
var start_i = TO_INTEGER(start);
|
||||
var end_i = len;
|
||||
@ -858,7 +858,7 @@ function ArraySplice(start, delete_count) {
|
||||
return ObservedArraySplice.apply(this, arguments);
|
||||
|
||||
var num_arguments = %_ArgumentsLength();
|
||||
var array = TO_OBJECT_INLINE(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var len = TO_UINT32(array.length);
|
||||
var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len);
|
||||
var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len,
|
||||
@ -1190,7 +1190,7 @@ function InnerArraySort(length, comparefn) {
|
||||
function ArraySort(comparefn) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.sort");
|
||||
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = TO_UINT32(array.length);
|
||||
return %_CallFunction(array, length, comparefn, InnerArraySort);
|
||||
}
|
||||
@ -1217,7 +1217,7 @@ function InnerArrayFilter(f, receiver, array, length) {
|
||||
var element = array[i];
|
||||
// Prepare break slots for debugger step in.
|
||||
if (stepping) %DebugPrepareStepInIfStepping(f);
|
||||
var new_receiver = needs_wrapper ? $toObject(receiver) : receiver;
|
||||
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
|
||||
if (%_CallFunction(new_receiver, element, i, array, f)) {
|
||||
accumulator[accumulator_length++] = element;
|
||||
}
|
||||
@ -1231,7 +1231,7 @@ function ArrayFilter(f, receiver) {
|
||||
|
||||
// Pull out the length so that modifications to the length in the
|
||||
// loop will not affect the looping and side effects are visible.
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = $toUint32(array.length);
|
||||
var accumulator = InnerArrayFilter(f, receiver, array, length);
|
||||
var result = new GlobalArray();
|
||||
@ -1255,7 +1255,7 @@ function InnerArrayForEach(f, receiver, array, length) {
|
||||
var element = array[i];
|
||||
// Prepare break slots for debugger step in.
|
||||
if (stepping) %DebugPrepareStepInIfStepping(f);
|
||||
var new_receiver = needs_wrapper ? $toObject(receiver) : receiver;
|
||||
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
|
||||
%_CallFunction(new_receiver, element, i, array, f);
|
||||
}
|
||||
}
|
||||
@ -1266,7 +1266,7 @@ function ArrayForEach(f, receiver) {
|
||||
|
||||
// Pull out the length so that modifications to the length in the
|
||||
// loop will not affect the looping and side effects are visible.
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = TO_UINT32(array.length);
|
||||
InnerArrayForEach(f, receiver, array, length);
|
||||
}
|
||||
@ -1288,7 +1288,7 @@ function InnerArraySome(f, receiver, array, length) {
|
||||
var element = array[i];
|
||||
// Prepare break slots for debugger step in.
|
||||
if (stepping) %DebugPrepareStepInIfStepping(f);
|
||||
var new_receiver = needs_wrapper ? $toObject(receiver) : receiver;
|
||||
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
|
||||
if (%_CallFunction(new_receiver, element, i, array, f)) return true;
|
||||
}
|
||||
}
|
||||
@ -1303,7 +1303,7 @@ function ArraySome(f, receiver) {
|
||||
|
||||
// Pull out the length so that modifications to the length in the
|
||||
// loop will not affect the looping and side effects are visible.
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = TO_UINT32(array.length);
|
||||
return InnerArraySome(f, receiver, array, length);
|
||||
}
|
||||
@ -1325,7 +1325,7 @@ function InnerArrayEvery(f, receiver, array, length) {
|
||||
var element = array[i];
|
||||
// Prepare break slots for debugger step in.
|
||||
if (stepping) %DebugPrepareStepInIfStepping(f);
|
||||
var new_receiver = needs_wrapper ? $toObject(receiver) : receiver;
|
||||
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
|
||||
if (!%_CallFunction(new_receiver, element, i, array, f)) return false;
|
||||
}
|
||||
}
|
||||
@ -1337,7 +1337,7 @@ function ArrayEvery(f, receiver) {
|
||||
|
||||
// Pull out the length so that modifications to the length in the
|
||||
// loop will not affect the looping and side effects are visible.
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = TO_UINT32(array.length);
|
||||
return InnerArrayEvery(f, receiver, array, length);
|
||||
}
|
||||
@ -1360,7 +1360,7 @@ function InnerArrayMap(f, receiver, array, length) {
|
||||
var element = array[i];
|
||||
// Prepare break slots for debugger step in.
|
||||
if (stepping) %DebugPrepareStepInIfStepping(f);
|
||||
var new_receiver = needs_wrapper ? $toObject(receiver) : receiver;
|
||||
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
|
||||
accumulator[i] = %_CallFunction(new_receiver, element, i, array, f);
|
||||
}
|
||||
}
|
||||
@ -1373,7 +1373,7 @@ function ArrayMap(f, receiver) {
|
||||
|
||||
// Pull out the length so that modifications to the length in the
|
||||
// loop will not affect the looping and side effects are visible.
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = TO_UINT32(array.length);
|
||||
var accumulator = InnerArrayMap(f, receiver, array, length);
|
||||
var result = new GlobalArray();
|
||||
@ -1542,7 +1542,7 @@ function ArrayReduce(callback, current) {
|
||||
|
||||
// Pull out the length so that modifications to the length in the
|
||||
// loop will not affect the looping and side effects are visible.
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = $toUint32(array.length);
|
||||
return InnerArrayReduce(callback, current, array, length,
|
||||
%_ArgumentsLength());
|
||||
@ -1585,7 +1585,7 @@ function ArrayReduceRight(callback, current) {
|
||||
|
||||
// Pull out the length so that side effects are visible before the
|
||||
// callback function is checked.
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = $toUint32(array.length);
|
||||
return InnerArrayReduceRight(callback, current, array, length,
|
||||
%_ArgumentsLength());
|
||||
|
@ -1724,7 +1724,6 @@ void Genesis::InstallNativeFunctions() {
|
||||
INSTALL_NATIVE(JSFunction, "$toNumber", to_number_fun);
|
||||
INSTALL_NATIVE(JSFunction, "$toString", to_string_fun);
|
||||
INSTALL_NATIVE(JSFunction, "$toDetailString", to_detail_string_fun);
|
||||
INSTALL_NATIVE(JSFunction, "$toObject", to_object_fun);
|
||||
INSTALL_NATIVE(JSFunction, "$toInteger", to_integer_fun);
|
||||
INSTALL_NATIVE(JSFunction, "$toUint32", to_uint32_fun);
|
||||
INSTALL_NATIVE(JSFunction, "$toInt32", to_int32_fun);
|
||||
|
@ -182,7 +182,6 @@ enum BuiltinExtraArguments {
|
||||
V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \
|
||||
V(CALL_FUNCTION_PROXY, 1) \
|
||||
V(CALL_FUNCTION_PROXY_AS_CONSTRUCTOR, 1) \
|
||||
V(TO_OBJECT, 0) \
|
||||
V(TO_NUMBER, 0) \
|
||||
V(TO_STRING, 0) \
|
||||
V(TO_NAME, 0) \
|
||||
|
@ -177,6 +177,13 @@ Callable CodeFactory::ToNumber(Isolate* isolate) {
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
Callable CodeFactory::ToObject(Isolate* isolate) {
|
||||
ToObjectStub stub(isolate);
|
||||
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
Callable CodeFactory::StringAdd(Isolate* isolate, StringAddFlags flags,
|
||||
PretenureFlag pretenure_flag) {
|
||||
|
@ -73,6 +73,7 @@ class CodeFactory final {
|
||||
ToBooleanStub::Types types = ToBooleanStub::Types());
|
||||
|
||||
static Callable ToNumber(Isolate* isolate);
|
||||
static Callable ToObject(Isolate* isolate);
|
||||
|
||||
static Callable StringAdd(Isolate* isolate, StringAddFlags flags,
|
||||
PretenureFlag pretenure_flag);
|
||||
|
@ -1657,6 +1657,16 @@ Handle<Code> ElementsTransitionAndStoreStub::GenerateCode() {
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
HValue* CodeStubGraphBuilder<ToObjectStub>::BuildCodeStub() {
|
||||
HValue* receiver = GetParameter(ToObjectDescriptor::kReceiverIndex);
|
||||
return BuildToObject(receiver);
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> ToObjectStub::GenerateCode() { return DoGenerateCode(this); }
|
||||
|
||||
|
||||
void CodeStubGraphBuilderBase::BuildCheckAndInstallOptimizedCode(
|
||||
HValue* js_function,
|
||||
HValue* native_context,
|
||||
|
@ -672,6 +672,11 @@ void ElementsTransitionAndStoreStub::InitializeDescriptor(
|
||||
}
|
||||
|
||||
|
||||
void ToObjectStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
|
||||
descriptor->Initialize(Runtime::FunctionForId(Runtime::kToObject)->entry);
|
||||
}
|
||||
|
||||
|
||||
CallInterfaceDescriptor StoreTransitionStub::GetCallInterfaceDescriptor()
|
||||
const {
|
||||
return StoreTransitionDescriptor(isolate());
|
||||
|
@ -54,6 +54,7 @@ namespace internal {
|
||||
V(StubFailureTrampoline) \
|
||||
V(SubString) \
|
||||
V(ToNumber) \
|
||||
V(ToObject) \
|
||||
V(VectorStoreICTrampoline) \
|
||||
V(VectorKeyedStoreICTrampoline) \
|
||||
V(VectorStoreIC) \
|
||||
@ -3050,6 +3051,15 @@ class ToNumberStub final : public PlatformCodeStub {
|
||||
};
|
||||
|
||||
|
||||
class ToObjectStub final : public HydrogenCodeStub {
|
||||
public:
|
||||
explicit ToObjectStub(Isolate* isolate) : HydrogenCodeStub(isolate) {}
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(ToObject);
|
||||
DEFINE_HYDROGEN_CODE_STUB(ToObject, HydrogenCodeStub);
|
||||
};
|
||||
|
||||
|
||||
class StringCompareStub : public PlatformCodeStub {
|
||||
public:
|
||||
explicit StringCompareStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
|
||||
|
@ -268,7 +268,7 @@ function SetForEach(f, receiver) {
|
||||
while (%SetIteratorNext(iterator, value_array)) {
|
||||
if (stepping) %DebugPrepareStepInIfStepping(f);
|
||||
key = value_array[0];
|
||||
var new_receiver = needs_wrapper ? $toObject(receiver) : receiver;
|
||||
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
|
||||
%_CallFunction(new_receiver, key, key, this, f);
|
||||
}
|
||||
}
|
||||
@ -457,7 +457,7 @@ function MapForEach(f, receiver) {
|
||||
var value_array = [UNDEFINED, UNDEFINED];
|
||||
while (%MapIteratorNext(iterator, value_array)) {
|
||||
if (stepping) %DebugPrepareStepInIfStepping(f);
|
||||
var new_receiver = needs_wrapper ? $toObject(receiver) : receiver;
|
||||
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
|
||||
%_CallFunction(new_receiver, value_array[1], value_array[0], this, f);
|
||||
}
|
||||
}
|
||||
|
@ -307,7 +307,9 @@ void JSGenericLowering::LowerJSToName(Node* node) {
|
||||
|
||||
|
||||
void JSGenericLowering::LowerJSToObject(Node* node) {
|
||||
ReplaceWithBuiltinCall(node, Builtins::TO_OBJECT, 1);
|
||||
CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
|
||||
Callable callable = CodeFactory::ToObject(isolate());
|
||||
ReplaceWithStubCall(node, callable, flags);
|
||||
}
|
||||
|
||||
|
||||
|
@ -94,6 +94,8 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
|
||||
return ReduceGetTypeFeedbackVector(node);
|
||||
case Runtime::kInlineGetCallerJSFunction:
|
||||
return ReduceGetCallerJSFunction(node);
|
||||
case Runtime::kInlineToObject:
|
||||
return ReduceToObject(node);
|
||||
case Runtime::kInlineThrowNotDateError:
|
||||
return ReduceThrowNotDateError(node);
|
||||
case Runtime::kInlineCallFunction:
|
||||
@ -528,6 +530,12 @@ Reduction JSIntrinsicLowering::ReduceThrowNotDateError(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
|
||||
node->set_op(javascript()->ToObject());
|
||||
return Changed(node);
|
||||
}
|
||||
|
||||
|
||||
Reduction JSIntrinsicLowering::ReduceCallFunction(Node* node) {
|
||||
CallRuntimeParameters params = OpParameter<CallRuntimeParameters>(node->op());
|
||||
size_t arity = params.arity();
|
||||
|
@ -58,6 +58,7 @@ class JSIntrinsicLowering final : public AdvancedReducer {
|
||||
Reduction ReduceGetTypeFeedbackVector(Node* node);
|
||||
Reduction ReduceGetCallerJSFunction(Node* node);
|
||||
Reduction ReduceThrowNotDateError(Node* node);
|
||||
Reduction ReduceToObject(Node* node);
|
||||
Reduction ReduceCallFunction(Node* node);
|
||||
|
||||
Reduction Change(Node* node, const Operator* op);
|
||||
|
@ -219,6 +219,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
|
||||
case Runtime::kInlineGetCallerJSFunction:
|
||||
case Runtime::kInlineGetPrototype:
|
||||
case Runtime::kInlineRegExpExec:
|
||||
case Runtime::kInlineToObject:
|
||||
return 1;
|
||||
case Runtime::kInlineDeoptimizeNow:
|
||||
case Runtime::kInlineThrowNotDateError:
|
||||
|
@ -1559,6 +1559,8 @@ Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) {
|
||||
return Bounds(Type::None(), Type::Range(0, 32, zone()));
|
||||
case Runtime::kInlineStringGetLength:
|
||||
return Bounds(Type::None(), Type::Range(0, String::kMaxLength, zone()));
|
||||
case Runtime::kInlineToObject:
|
||||
return Bounds(Type::None(), Type::Receiver());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -97,7 +97,6 @@ enum BindingFlags {
|
||||
V(TO_NUMBER_FUN_INDEX, JSFunction, to_number_fun) \
|
||||
V(TO_STRING_FUN_INDEX, JSFunction, to_string_fun) \
|
||||
V(TO_DETAIL_STRING_FUN_INDEX, JSFunction, to_detail_string_fun) \
|
||||
V(TO_OBJECT_FUN_INDEX, JSFunction, to_object_fun) \
|
||||
V(TO_INTEGER_FUN_INDEX, JSFunction, to_integer_fun) \
|
||||
V(TO_UINT32_FUN_INDEX, JSFunction, to_uint32_fun) \
|
||||
V(TO_INT32_FUN_INDEX, JSFunction, to_int32_fun) \
|
||||
@ -363,7 +362,6 @@ class Context: public FixedArray {
|
||||
TO_NUMBER_FUN_INDEX,
|
||||
TO_STRING_FUN_INDEX,
|
||||
TO_DETAIL_STRING_FUN_INDEX,
|
||||
TO_OBJECT_FUN_INDEX,
|
||||
TO_INTEGER_FUN_INDEX,
|
||||
TO_UINT32_FUN_INDEX,
|
||||
TO_INT32_FUN_INDEX,
|
||||
|
@ -775,7 +775,7 @@ function DateToISOString() {
|
||||
|
||||
|
||||
function DateToJSON(key) {
|
||||
var o = $toObject(this);
|
||||
var o = TO_OBJECT(this);
|
||||
var tv = $defaultNumber(o);
|
||||
if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) {
|
||||
return null;
|
||||
|
@ -385,7 +385,8 @@ class OptimizedFunctionVisitor BASE_EMBEDDED {
|
||||
V(kValueMismatch, "value mismatch") \
|
||||
V(kWrongInstanceType, "wrong instance type") \
|
||||
V(kWrongMap, "wrong map") \
|
||||
V(kUndefinedOrNullInForIn, "null or undefined in for-in")
|
||||
V(kUndefinedOrNullInForIn, "null or undefined in for-in") \
|
||||
V(kUndefinedOrNullInToObject, "null or undefined in ToObject")
|
||||
|
||||
|
||||
class Deoptimizer : public Malloced {
|
||||
|
@ -548,14 +548,6 @@ MaybeHandle<Object> Execution::ToDetailString(
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Object> Execution::ToObject(
|
||||
Isolate* isolate, Handle<Object> obj) {
|
||||
if (obj->IsSpecObject()) return obj;
|
||||
// TODO(verwaest): Use Object::ToObject but throw an exception on failure.
|
||||
RETURN_NATIVE_CALL(to_object, { obj });
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Object> Execution::ToInteger(
|
||||
Isolate* isolate, Handle<Object> obj) {
|
||||
RETURN_NATIVE_CALL(to_integer, { obj });
|
||||
@ -589,6 +581,16 @@ MaybeHandle<Object> Execution::NewDate(Isolate* isolate, double time) {
|
||||
#undef RETURN_NATIVE_CALL
|
||||
|
||||
|
||||
MaybeHandle<Object> Execution::ToObject(Isolate* isolate, Handle<Object> obj) {
|
||||
Handle<JSReceiver> receiver;
|
||||
if (JSReceiver::ToObject(isolate, obj).ToHandle(&receiver)) {
|
||||
return receiver;
|
||||
}
|
||||
THROW_NEW_ERROR(
|
||||
isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject), Object);
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<JSRegExp> Execution::NewJSRegExp(Handle<String> pattern,
|
||||
Handle<String> flags) {
|
||||
Isolate* isolate = pattern->GetIsolate();
|
||||
|
@ -1083,8 +1083,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
__ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE);
|
||||
__ b(ge, &done_convert);
|
||||
__ bind(&convert);
|
||||
__ push(r0);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
__ bind(&done_convert);
|
||||
PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
|
||||
__ push(r0);
|
||||
@ -4018,6 +4018,19 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitToObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(1, args->length());
|
||||
|
||||
// Load the argument into r0 and convert it.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(r0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -1085,8 +1085,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
__ JumpIfSmi(x0, &convert);
|
||||
__ JumpIfObjectType(x0, x10, x11, FIRST_SPEC_OBJECT_TYPE, &done_convert, ge);
|
||||
__ Bind(&convert);
|
||||
__ Push(x0);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
__ Bind(&done_convert);
|
||||
PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
|
||||
__ Push(x0);
|
||||
@ -3726,6 +3726,19 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitToObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(1, args->length());
|
||||
|
||||
// Load the argument into x0 and convert it.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(x0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -531,6 +531,7 @@ class FullCodeGenerator: public AstVisitor {
|
||||
F(RegExpConstructResult) \
|
||||
F(GetFromCache) \
|
||||
F(NumberToString) \
|
||||
F(ToObject) \
|
||||
F(DebugIsActive)
|
||||
|
||||
#define GENERATOR_DECLARATION(Name) void Emit##Name(CallRuntime* call);
|
||||
|
@ -1025,8 +1025,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
||||
__ j(above_equal, &done_convert, Label::kNear);
|
||||
__ bind(&convert);
|
||||
__ push(eax);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
__ bind(&done_convert);
|
||||
PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
|
||||
__ push(eax);
|
||||
@ -3921,6 +3921,19 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitToObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(1, args->length());
|
||||
|
||||
// Load the argument into eax and convert it.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(eax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -1085,8 +1085,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
__ GetObjectType(a0, a1, a1);
|
||||
__ Branch(&done_convert, ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||
__ bind(&convert);
|
||||
__ push(a0);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
__ mov(a0, v0);
|
||||
__ bind(&done_convert);
|
||||
PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
|
||||
@ -4028,6 +4028,20 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitToObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(1, args->length());
|
||||
|
||||
// Load the argument into a0 and convert it.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
__ mov(a0, result_register());
|
||||
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(v0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -1082,8 +1082,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
__ GetObjectType(a0, a1, a1);
|
||||
__ Branch(&done_convert, ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||
__ bind(&convert);
|
||||
__ push(a0);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
__ mov(a0, v0);
|
||||
__ bind(&done_convert);
|
||||
PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
|
||||
@ -4031,6 +4031,20 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitToObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(1, args->length());
|
||||
|
||||
// Load the argument into a0 and convert it.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
__ mov(a0, result_register());
|
||||
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(v0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -1046,8 +1046,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
__ CompareObjectType(r3, r4, r4, FIRST_SPEC_OBJECT_TYPE);
|
||||
__ bge(&done_convert);
|
||||
__ bind(&convert);
|
||||
__ push(r3);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
__ bind(&done_convert);
|
||||
PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
|
||||
__ push(r3);
|
||||
@ -4029,6 +4029,18 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitToObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(1, args->length());
|
||||
// Load the argument into r3 and convert it.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(r3);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -1039,12 +1039,12 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
|
||||
// Convert the object to a JS object.
|
||||
Label convert, done_convert;
|
||||
__ JumpIfSmi(rax, &convert);
|
||||
__ JumpIfSmi(rax, &convert, Label::kNear);
|
||||
__ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
|
||||
__ j(above_equal, &done_convert);
|
||||
__ j(above_equal, &done_convert, Label::kNear);
|
||||
__ bind(&convert);
|
||||
__ Push(rax);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
__ bind(&done_convert);
|
||||
PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
|
||||
__ Push(rax);
|
||||
@ -3912,6 +3912,19 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitToObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(1, args->length());
|
||||
|
||||
// Load the argument into rax and convert it.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(rax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -1018,8 +1018,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
||||
__ j(above_equal, &done_convert, Label::kNear);
|
||||
__ bind(&convert);
|
||||
__ push(eax);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
__ bind(&done_convert);
|
||||
PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
|
||||
__ push(eax);
|
||||
@ -3912,6 +3912,19 @@ void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitToObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK_EQ(1, args->length());
|
||||
|
||||
// Load the argument into eax and convert it.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
ToObjectStub stub(isolate());
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(eax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -16,7 +16,7 @@ var GlobalArray = global.Array;
|
||||
// https://github.com/tc39/Array.prototype.includes
|
||||
// 6e3b78c927aeda20b9d40e81303f9d44596cd904
|
||||
function ArrayIncludes(searchElement, fromIndex) {
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var len = $toLength(array.length);
|
||||
|
||||
if (len === 0) {
|
||||
|
@ -83,7 +83,7 @@ function InnerArrayCopyWithin(target, start, end, array, length) {
|
||||
function ArrayCopyWithin(target, start, end) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.copyWithin");
|
||||
|
||||
var array = TO_OBJECT_INLINE(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = $toLength(array.length);
|
||||
|
||||
return InnerArrayCopyWithin(target, start, end, array, length);
|
||||
@ -103,7 +103,7 @@ function InnerArrayFind(predicate, thisArg, array, length) {
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
var element = array[i];
|
||||
var newThisArg = needs_wrapper ? $toObject(thisArg) : thisArg;
|
||||
var newThisArg = needs_wrapper ? TO_OBJECT(thisArg) : thisArg;
|
||||
if (%_CallFunction(newThisArg, element, i, array, predicate)) {
|
||||
return element;
|
||||
}
|
||||
@ -116,7 +116,7 @@ function InnerArrayFind(predicate, thisArg, array, length) {
|
||||
function ArrayFind(predicate, thisArg) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.find");
|
||||
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = $toInteger(array.length);
|
||||
|
||||
return InnerArrayFind(predicate, thisArg, array, length);
|
||||
@ -136,7 +136,7 @@ function InnerArrayFindIndex(predicate, thisArg, array, length) {
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
var element = array[i];
|
||||
var newThisArg = needs_wrapper ? $toObject(thisArg) : thisArg;
|
||||
var newThisArg = needs_wrapper ? TO_OBJECT(thisArg) : thisArg;
|
||||
if (%_CallFunction(newThisArg, element, i, array, predicate)) {
|
||||
return i;
|
||||
}
|
||||
@ -149,7 +149,7 @@ function InnerArrayFindIndex(predicate, thisArg, array, length) {
|
||||
function ArrayFindIndex(predicate, thisArg) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.findIndex");
|
||||
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = $toInteger(array.length);
|
||||
|
||||
return InnerArrayFindIndex(predicate, thisArg, array, length);
|
||||
@ -187,7 +187,7 @@ function InnerArrayFill(value, start, end, array, length) {
|
||||
function ArrayFill(value, start, end) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.fill");
|
||||
|
||||
var array = $toObject(this);
|
||||
var array = TO_OBJECT(this);
|
||||
var length = TO_UINT32(array.length);
|
||||
|
||||
return InnerArrayFill(value, start, end, array, length);
|
||||
@ -205,7 +205,7 @@ function AddArrayElement(constructor, array, i, value) {
|
||||
|
||||
// ES6, draft 10-14-14, section 22.1.2.1
|
||||
function ArrayFrom(arrayLike, mapfn, receiver) {
|
||||
var items = $toObject(arrayLike);
|
||||
var items = TO_OBJECT(arrayLike);
|
||||
var mapping = !IS_UNDEFINED(mapfn);
|
||||
|
||||
if (mapping) {
|
||||
@ -215,7 +215,7 @@ function ArrayFrom(arrayLike, mapfn, receiver) {
|
||||
if (IS_NULL(receiver)) {
|
||||
receiver = UNDEFINED;
|
||||
} else if (!IS_UNDEFINED(receiver)) {
|
||||
receiver = TO_OBJECT_INLINE(receiver);
|
||||
receiver = TO_OBJECT(receiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ utils.Import(function(from) {
|
||||
|
||||
// ES6, draft 04-03-15, section 19.1.2.1
|
||||
function ObjectAssign(target, sources) {
|
||||
var to = TO_OBJECT_INLINE(target);
|
||||
var to = TO_OBJECT(target);
|
||||
var argsLen = %_ArgumentsLength();
|
||||
if (argsLen < 2) return to;
|
||||
|
||||
@ -34,7 +34,7 @@ function ObjectAssign(target, sources) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var from = TO_OBJECT_INLINE(nextSource);
|
||||
var from = TO_OBJECT(nextSource);
|
||||
var keys = OwnPropertyKeys(from);
|
||||
var len = keys.length;
|
||||
|
||||
|
159
src/hydrogen.cc
159
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,
|
||||
|
@ -1329,6 +1329,7 @@ class HGraphBuilder {
|
||||
bool is_jsarray);
|
||||
|
||||
HValue* BuildNumberToString(HValue* object, Type* type);
|
||||
HValue* BuildToObject(HValue* receiver);
|
||||
|
||||
void BuildJSObjectCheck(HValue* receiver,
|
||||
int bit_field_mask);
|
||||
|
14
src/i18n.js
14
src/i18n.js
@ -251,7 +251,7 @@ function supportedLocalesOf(service, locales, options) {
|
||||
if (IS_UNDEFINED(options)) {
|
||||
options = {};
|
||||
} else {
|
||||
options = $toObject(options);
|
||||
options = TO_OBJECT(options);
|
||||
}
|
||||
|
||||
var matcher = options.localeMatcher;
|
||||
@ -717,7 +717,7 @@ function initializeLocaleList(locales) {
|
||||
return freezeArray(seen);
|
||||
}
|
||||
|
||||
var o = $toObject(locales);
|
||||
var o = TO_OBJECT(locales);
|
||||
var len = TO_UINT32(o.length);
|
||||
|
||||
for (var k = 0; k < len; k++) {
|
||||
@ -951,7 +951,7 @@ function initializeCollator(collator, locales, options) {
|
||||
return new Intl.Collator(locales, options);
|
||||
}
|
||||
|
||||
return initializeCollator($toObject(this), locales, options);
|
||||
return initializeCollator(TO_OBJECT(this), locales, options);
|
||||
},
|
||||
DONT_ENUM
|
||||
);
|
||||
@ -1192,7 +1192,7 @@ function initializeNumberFormat(numberFormat, locales, options) {
|
||||
return new Intl.NumberFormat(locales, options);
|
||||
}
|
||||
|
||||
return initializeNumberFormat($toObject(this), locales, options);
|
||||
return initializeNumberFormat(TO_OBJECT(this), locales, options);
|
||||
},
|
||||
DONT_ENUM
|
||||
);
|
||||
@ -1444,7 +1444,7 @@ function toDateTimeOptions(options, required, defaults) {
|
||||
if (IS_UNDEFINED(options)) {
|
||||
options = {};
|
||||
} else {
|
||||
options = TO_OBJECT_INLINE(options);
|
||||
options = TO_OBJECT(options);
|
||||
}
|
||||
|
||||
var needsDefault = true;
|
||||
@ -1594,7 +1594,7 @@ function initializeDateTimeFormat(dateFormat, locales, options) {
|
||||
return new Intl.DateTimeFormat(locales, options);
|
||||
}
|
||||
|
||||
return initializeDateTimeFormat($toObject(this), locales, options);
|
||||
return initializeDateTimeFormat(TO_OBJECT(this), locales, options);
|
||||
},
|
||||
DONT_ENUM
|
||||
);
|
||||
@ -1814,7 +1814,7 @@ function initializeBreakIterator(iterator, locales, options) {
|
||||
return new Intl.v8BreakIterator(locales, options);
|
||||
}
|
||||
|
||||
return initializeBreakIterator($toObject(this), locales, options);
|
||||
return initializeBreakIterator(TO_OBJECT(this), locales, options);
|
||||
},
|
||||
DONT_ENUM
|
||||
);
|
||||
|
@ -994,8 +994,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
__ SmiTag(eax);
|
||||
__ push(eax);
|
||||
|
||||
__ push(ebx);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ mov(eax, ebx);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ mov(ebx, eax);
|
||||
__ Move(edx, Immediate(0)); // restore
|
||||
|
||||
@ -1215,8 +1216,9 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
|
||||
__ j(above_equal, &push_receiver);
|
||||
|
||||
__ bind(&call_to_object);
|
||||
__ push(ebx);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ mov(eax, ebx);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ mov(ebx, eax);
|
||||
__ jmp(&push_receiver);
|
||||
|
||||
|
@ -2093,8 +2093,8 @@ static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
|
||||
// Wrap the receiver and patch it back onto the stack.
|
||||
{ FrameScope frame_scope(masm, StackFrame::INTERNAL);
|
||||
__ push(edi);
|
||||
__ push(eax);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ pop(edi);
|
||||
}
|
||||
__ mov(Operand(esp, (argc + 1) * kPointerSize), eax);
|
||||
|
@ -103,6 +103,10 @@ void ToNumberDescriptor::InitializePlatformSpecific(
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
const Register ToObjectDescriptor::ReceiverRegister() { return eax; }
|
||||
|
||||
|
||||
void NumberToStringDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {eax};
|
||||
|
@ -155,6 +155,13 @@ void InstanceofDescriptor::InitializePlatformSpecific(
|
||||
}
|
||||
|
||||
|
||||
void ToObjectDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {ReceiverRegister()};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
|
||||
void MathPowTaggedDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {exponent()};
|
||||
|
@ -24,6 +24,7 @@ class PlatformInterfaceDescriptor;
|
||||
V(FastNewClosure) \
|
||||
V(FastNewContext) \
|
||||
V(ToNumber) \
|
||||
V(ToObject) \
|
||||
V(NumberToString) \
|
||||
V(Typeof) \
|
||||
V(FastCloneShallowArray) \
|
||||
@ -339,6 +340,16 @@ class ToNumberDescriptor : public CallInterfaceDescriptor {
|
||||
};
|
||||
|
||||
|
||||
class ToObjectDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
enum ParameterIndices { kReceiverIndex };
|
||||
|
||||
DECLARE_DESCRIPTOR(ToObjectDescriptor, CallInterfaceDescriptor)
|
||||
|
||||
static const Register ReceiverRegister();
|
||||
};
|
||||
|
||||
|
||||
class NumberToStringDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DECLARE_DESCRIPTOR(NumberToStringDescriptor, CallInterfaceDescriptor)
|
||||
|
@ -154,7 +154,7 @@ macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
|
||||
macro TO_UINT32(arg) = (arg >>> 0);
|
||||
macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : $nonStringToString(arg));
|
||||
macro TO_NUMBER_INLINE(arg) = (IS_NUMBER(%IS_VAR(arg)) ? arg : $nonNumberToNumber(arg));
|
||||
macro TO_OBJECT_INLINE(arg) = (IS_SPEC_OBJECT(%IS_VAR(arg)) ? arg : $toObject(arg));
|
||||
macro TO_OBJECT(arg) = (%_ToObject(arg));
|
||||
macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null");
|
||||
macro HAS_OWN_PROPERTY(arg, index) = (%_CallFunction(arg, index, ObjectHasOwnProperty));
|
||||
macro SHOULD_CREATE_WRAPPER(functionName, receiver) = (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(functionName));
|
||||
|
@ -67,7 +67,7 @@ var GlobalEvalError;
|
||||
function NoSideEffectsObjectToString() {
|
||||
if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
|
||||
if (IS_NULL(this)) return "[object Null]";
|
||||
return "[object " + %_ClassOf(TO_OBJECT_INLINE(this)) + "]";
|
||||
return "[object " + %_ClassOf(TO_OBJECT(this)) + "]";
|
||||
}
|
||||
|
||||
|
||||
|
@ -1313,8 +1313,10 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
__ sll(a0, a0, kSmiTagSize); // Smi tagged.
|
||||
__ Push(a0, a2);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ push(a0);
|
||||
__ mov(a0, a2);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ mov(a2, v0);
|
||||
|
||||
__ pop(a0);
|
||||
@ -1548,8 +1550,8 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
|
||||
// Convert the receiver to a regular object.
|
||||
// a0: receiver
|
||||
__ bind(&call_to_object);
|
||||
__ push(a0);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ mov(a0, v0); // Put object in a0 to match other paths to push_receiver.
|
||||
__ Branch(&push_receiver);
|
||||
|
||||
|
@ -2675,8 +2675,10 @@ static void EmitSlowCase(MacroAssembler* masm,
|
||||
static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
|
||||
// Wrap the receiver and patch it back onto the stack.
|
||||
{ FrameScope frame_scope(masm, StackFrame::INTERNAL);
|
||||
__ Push(a1, a3);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ Push(a1);
|
||||
__ mov(a0, a3);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ pop(a1);
|
||||
}
|
||||
__ Branch(USE_DELAY_SLOT, cont);
|
||||
|
@ -95,6 +95,10 @@ void ToNumberDescriptor::InitializePlatformSpecific(
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
const Register ToObjectDescriptor::ReceiverRegister() { return a0; }
|
||||
|
||||
|
||||
void NumberToStringDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {a0};
|
||||
|
@ -1309,8 +1309,10 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
__ SmiTag(a0);
|
||||
__ Push(a0, a2);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ Push(a0);
|
||||
__ mov(a0, a2);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ mov(a2, v0);
|
||||
|
||||
__ pop(a0);
|
||||
@ -1545,8 +1547,8 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
|
||||
// Convert the receiver to a regular object.
|
||||
// a0: receiver
|
||||
__ bind(&call_to_object);
|
||||
__ push(a0);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ mov(a0, v0); // Put object in a0 to match other paths to push_receiver.
|
||||
__ Branch(&push_receiver);
|
||||
|
||||
|
@ -2714,8 +2714,10 @@ static void EmitSlowCase(MacroAssembler* masm,
|
||||
static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
|
||||
// Wrap the receiver and patch it back onto the stack.
|
||||
{ FrameScope frame_scope(masm, StackFrame::INTERNAL);
|
||||
__ Push(a1, a3);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ Push(a1);
|
||||
__ mov(a0, a3);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ pop(a1);
|
||||
}
|
||||
__ Branch(USE_DELAY_SLOT, cont);
|
||||
|
@ -95,6 +95,10 @@ void ToNumberDescriptor::InitializePlatformSpecific(
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
const Register ToObjectDescriptor::ReceiverRegister() { return a0; }
|
||||
|
||||
|
||||
void NumberToStringDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {a0};
|
||||
|
@ -1338,8 +1338,10 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
// Enter an internal frame in order to preserve argument count.
|
||||
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
||||
__ SmiTag(r3);
|
||||
__ Push(r3, r5);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ Push(r3);
|
||||
__ mr(r3, r5);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ mr(r5, r3);
|
||||
|
||||
__ pop(r3);
|
||||
@ -1592,8 +1594,8 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
|
||||
// Convert the receiver to a regular object.
|
||||
// r3: receiver
|
||||
__ bind(&call_to_object);
|
||||
__ push(r3);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ b(&push_receiver);
|
||||
|
||||
__ bind(&use_global_proxy);
|
||||
|
@ -2726,8 +2726,10 @@ static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
|
||||
// Wrap the receiver and patch it back onto the stack.
|
||||
{
|
||||
FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL);
|
||||
__ Push(r4, r6);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ push(r4);
|
||||
__ mr(r3, r6);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ pop(r4);
|
||||
}
|
||||
__ StoreP(r3, MemOperand(sp, argc * kPointerSize), r0);
|
||||
|
@ -95,6 +95,10 @@ void ToNumberDescriptor::InitializePlatformSpecific(
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
const Register ToObjectDescriptor::ReceiverRegister() { return r3; }
|
||||
|
||||
|
||||
void NumberToStringDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {r3};
|
||||
|
@ -58,7 +58,6 @@ var APPLY_PREPARE;
|
||||
var REFLECT_APPLY_PREPARE;
|
||||
var REFLECT_CONSTRUCT_PREPARE;
|
||||
var STACK_OVERFLOW;
|
||||
var TO_OBJECT;
|
||||
var TO_NUMBER;
|
||||
var TO_STRING;
|
||||
var TO_NAME;
|
||||
@ -76,7 +75,6 @@ var $toInteger;
|
||||
var $toLength;
|
||||
var $toName;
|
||||
var $toNumber;
|
||||
var $toObject;
|
||||
var $toPositiveInteger;
|
||||
var $toPrimitive;
|
||||
var $toString;
|
||||
@ -512,7 +510,7 @@ SHR_STRONG = function SHR_STRONG(y) {
|
||||
|
||||
// ECMA-262, section 11.4.1, page 46.
|
||||
DELETE = function DELETE(key, language_mode) {
|
||||
return %DeleteProperty(%$toObject(this), key, language_mode);
|
||||
return %DeleteProperty(TO_OBJECT(this), key, language_mode);
|
||||
}
|
||||
|
||||
|
||||
@ -730,12 +728,6 @@ STACK_OVERFLOW = function STACK_OVERFLOW(length) {
|
||||
}
|
||||
|
||||
|
||||
// Convert the receiver to an object - forward to ToObject.
|
||||
TO_OBJECT = function TO_OBJECT() {
|
||||
return %$toObject(this);
|
||||
}
|
||||
|
||||
|
||||
// Convert the receiver to a number - forward to ToNumber.
|
||||
TO_NUMBER = function TO_NUMBER() {
|
||||
return %$toNumber(this);
|
||||
@ -832,20 +824,6 @@ function ToName(x) {
|
||||
}
|
||||
|
||||
|
||||
// ECMA-262, section 9.9, page 36.
|
||||
function ToObject(x) {
|
||||
if (IS_STRING(x)) return new GlobalString(x);
|
||||
if (IS_NUMBER(x)) return new GlobalNumber(x);
|
||||
if (IS_BOOLEAN(x)) return new GlobalBoolean(x);
|
||||
if (IS_SYMBOL(x)) return %NewSymbolWrapper(x);
|
||||
if (IS_FLOAT32X4(x)) return %NewFloat32x4Wrapper(x);
|
||||
if (IS_NULL_OR_UNDEFINED(x) && !IS_UNDETECTABLE(x)) {
|
||||
throw MakeTypeError(kUndefinedOrNullToObject);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
// ECMA-262, section 9.4, page 34.
|
||||
function ToInteger(x) {
|
||||
if (%_IsSmi(x)) return x;
|
||||
@ -1006,7 +984,6 @@ $toInteger = ToInteger;
|
||||
$toLength = ToLength;
|
||||
$toName = ToName;
|
||||
$toNumber = ToNumber;
|
||||
$toObject = ToObject;
|
||||
$toPositiveInteger = ToPositiveInteger;
|
||||
$toPrimitive = ToPrimitive;
|
||||
$toString = ToString;
|
||||
|
@ -1461,5 +1461,19 @@ RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) {
|
||||
setter, attrs));
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ToObject) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
||||
Handle<JSReceiver> receiver;
|
||||
if (JSReceiver::ToObject(isolate, object).ToHandle(&receiver)) {
|
||||
return *receiver;
|
||||
}
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -33,14 +33,6 @@
|
||||
NumberTo##type##Component(*y), NumberTo##type##Component(*z)); \
|
||||
}
|
||||
|
||||
#define SIMD_CREATE_WRAPPER_FUNCTION(type) \
|
||||
RUNTIME_FUNCTION(Runtime_New##type##Wrapper) { \
|
||||
HandleScope scope(isolate); \
|
||||
DCHECK(args.length() == 1); \
|
||||
CONVERT_ARG_HANDLE_CHECKED(type, value, 0); \
|
||||
return *Object::ToObject(isolate, value).ToHandleChecked(); \
|
||||
}
|
||||
|
||||
#define SIMD_CHECK_FUNCTION(type) \
|
||||
RUNTIME_FUNCTION(Runtime_##type##Check) { \
|
||||
HandleScope scope(isolate); \
|
||||
@ -101,7 +93,6 @@
|
||||
|
||||
#define SIMD4_FUNCTIONS(type) \
|
||||
SIMD4_CREATE_FUNCTION(type) \
|
||||
SIMD_CREATE_WRAPPER_FUNCTION(type) \
|
||||
SIMD_CHECK_FUNCTION(type) \
|
||||
SIMD4_EXTRACT_LANE_FUNCTION(type) \
|
||||
SIMD4_EQUALS_FUNCTION(type) \
|
||||
@ -125,5 +116,6 @@ inline bool Equals(float x, float y) { return x == y; }
|
||||
} // namespace
|
||||
|
||||
SIMD4_FUNCTIONS(Float32x4)
|
||||
}
|
||||
} // namespace v8::internal
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -51,14 +51,6 @@ RUNTIME_FUNCTION(Runtime_CreateGlobalPrivateSymbol) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_NewSymbolWrapper) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0);
|
||||
return *Object::ToObject(isolate, symbol).ToHandleChecked();
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_SymbolDescription) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
|
@ -497,7 +497,8 @@ namespace internal {
|
||||
F(IsStrong, 1, 1) \
|
||||
F(ClassOf, 1, 1) \
|
||||
F(DefineGetterPropertyUnchecked, 4, 1) \
|
||||
F(DefineSetterPropertyUnchecked, 4, 1)
|
||||
F(DefineSetterPropertyUnchecked, 4, 1) \
|
||||
F(ToObject, 1, 1)
|
||||
|
||||
|
||||
#define FOR_EACH_INTRINSIC_OBSERVE(F) \
|
||||
@ -570,7 +571,6 @@ namespace internal {
|
||||
|
||||
#define FOR_EACH_INTRINSIC_SIMD(F) \
|
||||
F(CreateFloat32x4, 4, 1) \
|
||||
F(NewFloat32x4Wrapper, 1, 1) \
|
||||
F(Float32x4Check, 1, 1) \
|
||||
F(Float32x4ExtractLane, 2, 1) \
|
||||
F(Float32x4Equals, 2, 1) \
|
||||
@ -620,7 +620,6 @@ namespace internal {
|
||||
F(CreateSymbol, 1, 1) \
|
||||
F(CreatePrivateSymbol, 1, 1) \
|
||||
F(CreateGlobalPrivateSymbol, 1, 1) \
|
||||
F(NewSymbolWrapper, 1, 1) \
|
||||
F(SymbolDescription, 1, 1) \
|
||||
F(SymbolRegistry, 0, 1) \
|
||||
F(SymbolIsPrivate, 1, 1)
|
||||
|
@ -41,7 +41,7 @@ function CreateStringIterator(string) {
|
||||
|
||||
// 21.1.5.2.1 %StringIteratorPrototype%.next( )
|
||||
function StringIteratorNext() {
|
||||
var iterator = $toObject(this);
|
||||
var iterator = TO_OBJECT(this);
|
||||
|
||||
if (!HAS_DEFINED_PRIVATE(iterator, stringIteratorNextIndexSymbol)) {
|
||||
throw MakeTypeError(kIncompatibleMethodReceiver,
|
||||
|
@ -1112,8 +1112,8 @@ function StringFromCodePoint(_) { // length = 1
|
||||
function StringRaw(callSite) {
|
||||
// TODO(caitp): Use rest parameters when implemented
|
||||
var numberOfSubstitutions = %_ArgumentsLength();
|
||||
var cooked = $toObject(callSite);
|
||||
var raw = $toObject(cooked.raw);
|
||||
var cooked = TO_OBJECT(callSite);
|
||||
var raw = TO_OBJECT(cooked.raw);
|
||||
var literalSegments = $toLength(raw.length);
|
||||
if (literalSegments <= 0) return "";
|
||||
|
||||
|
@ -78,7 +78,7 @@ function SymbolKeyFor(symbol) {
|
||||
|
||||
// ES6 19.1.2.8
|
||||
function ObjectGetOwnPropertySymbols(obj) {
|
||||
obj = $toObject(obj);
|
||||
obj = TO_OBJECT(obj);
|
||||
|
||||
// TODO(arv): Proxies use a shared trap for String and Symbol keys.
|
||||
|
||||
|
@ -141,7 +141,7 @@ utils.InstallFunctions(global, DONT_ENUM, [
|
||||
function ObjectToString() {
|
||||
if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
|
||||
if (IS_NULL(this)) return "[object Null]";
|
||||
var O = TO_OBJECT_INLINE(this);
|
||||
var O = TO_OBJECT(this);
|
||||
var builtinTag = %_ClassOf(O);
|
||||
var tag;
|
||||
|
||||
@ -168,14 +168,14 @@ function ObjectToLocaleString() {
|
||||
|
||||
// ECMA-262 - 15.2.4.4
|
||||
function ObjectValueOf() {
|
||||
return TO_OBJECT_INLINE(this);
|
||||
return TO_OBJECT(this);
|
||||
}
|
||||
|
||||
|
||||
// ECMA-262 - 15.2.4.5
|
||||
function ObjectHasOwnProperty(value) {
|
||||
var name = $toName(value);
|
||||
var object = TO_OBJECT_INLINE(this);
|
||||
var object = TO_OBJECT(this);
|
||||
|
||||
if (%_IsJSProxy(object)) {
|
||||
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
|
||||
@ -206,7 +206,7 @@ function ObjectPropertyIsEnumerable(V) {
|
||||
var desc = GetOwnPropertyJS(this, P);
|
||||
return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
|
||||
}
|
||||
return %IsPropertyEnumerable(TO_OBJECT_INLINE(this), P);
|
||||
return %IsPropertyEnumerable(TO_OBJECT(this), P);
|
||||
}
|
||||
|
||||
|
||||
@ -223,7 +223,7 @@ function ObjectDefineGetter(name, fun) {
|
||||
desc.setGet(fun);
|
||||
desc.setEnumerable(true);
|
||||
desc.setConfigurable(true);
|
||||
DefineOwnProperty(TO_OBJECT_INLINE(receiver), $toName(name), desc, false);
|
||||
DefineOwnProperty(TO_OBJECT(receiver), $toName(name), desc, false);
|
||||
}
|
||||
|
||||
|
||||
@ -232,7 +232,7 @@ function ObjectLookupGetter(name) {
|
||||
if (receiver == null && !IS_UNDETECTABLE(receiver)) {
|
||||
receiver = %GlobalProxy(ObjectLookupGetter);
|
||||
}
|
||||
return %LookupAccessor(TO_OBJECT_INLINE(receiver), $toName(name), GETTER);
|
||||
return %LookupAccessor(TO_OBJECT(receiver), $toName(name), GETTER);
|
||||
}
|
||||
|
||||
|
||||
@ -248,7 +248,7 @@ function ObjectDefineSetter(name, fun) {
|
||||
desc.setSet(fun);
|
||||
desc.setEnumerable(true);
|
||||
desc.setConfigurable(true);
|
||||
DefineOwnProperty(TO_OBJECT_INLINE(receiver), $toName(name), desc, false);
|
||||
DefineOwnProperty(TO_OBJECT(receiver), $toName(name), desc, false);
|
||||
}
|
||||
|
||||
|
||||
@ -257,12 +257,12 @@ function ObjectLookupSetter(name) {
|
||||
if (receiver == null && !IS_UNDETECTABLE(receiver)) {
|
||||
receiver = %GlobalProxy(ObjectLookupSetter);
|
||||
}
|
||||
return %LookupAccessor(TO_OBJECT_INLINE(receiver), $toName(name), SETTER);
|
||||
return %LookupAccessor(TO_OBJECT(receiver), $toName(name), SETTER);
|
||||
}
|
||||
|
||||
|
||||
function ObjectKeys(obj) {
|
||||
obj = TO_OBJECT_INLINE(obj);
|
||||
obj = TO_OBJECT(obj);
|
||||
if (%_IsJSProxy(obj)) {
|
||||
var handler = %GetHandler(obj);
|
||||
var names = CallTrap0(handler, "keys", ProxyDerivedKeysTrap);
|
||||
@ -579,7 +579,7 @@ function GetOwnPropertyJS(obj, v) {
|
||||
// GetOwnProperty returns an array indexed by the constants
|
||||
// defined in macros.py.
|
||||
// If p is not a property on obj undefined is returned.
|
||||
var props = %GetOwnProperty(TO_OBJECT_INLINE(obj), p);
|
||||
var props = %GetOwnProperty(TO_OBJECT(obj), p);
|
||||
|
||||
return ConvertDescriptorArrayToDescriptor(props);
|
||||
}
|
||||
@ -868,7 +868,7 @@ function DefineOwnPropertyFromAPI(obj, p, value, desc) {
|
||||
|
||||
// ES6 section 19.1.2.9
|
||||
function ObjectGetPrototypeOf(obj) {
|
||||
return %_GetPrototype(TO_OBJECT_INLINE(obj));
|
||||
return %_GetPrototype(TO_OBJECT(obj));
|
||||
}
|
||||
|
||||
// ES6 section 19.1.2.19.
|
||||
@ -889,7 +889,7 @@ function ObjectSetPrototypeOf(obj, proto) {
|
||||
|
||||
// ES6 section 19.1.2.6
|
||||
function ObjectGetOwnPropertyDescriptor(obj, p) {
|
||||
var desc = GetOwnPropertyJS(TO_OBJECT_INLINE(obj), p);
|
||||
var desc = GetOwnPropertyJS(TO_OBJECT(obj), p);
|
||||
return FromPropertyDescriptor(desc);
|
||||
}
|
||||
|
||||
@ -1001,7 +1001,7 @@ function OwnPropertyKeys(obj) {
|
||||
|
||||
// ES5 section 15.2.3.4.
|
||||
function ObjectGetOwnPropertyNames(obj) {
|
||||
obj = TO_OBJECT_INLINE(obj);
|
||||
obj = TO_OBJECT(obj);
|
||||
// Special handling for proxies.
|
||||
if (%_IsJSProxy(obj)) {
|
||||
var handler = %GetHandler(obj);
|
||||
@ -1093,7 +1093,7 @@ function ObjectDefineProperties(obj, properties) {
|
||||
if (!IS_SPEC_OBJECT(obj)) {
|
||||
throw MakeTypeError(kCalledOnNonObject, "Object.defineProperties");
|
||||
}
|
||||
var props = TO_OBJECT_INLINE(properties);
|
||||
var props = TO_OBJECT(properties);
|
||||
var names = GetOwnEnumerablePropertyNames(props);
|
||||
var descriptors = new InternalArray();
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
@ -1263,7 +1263,7 @@ function ObjectIs(obj1, obj2) {
|
||||
|
||||
// ECMA-262, Edition 6, section B.2.2.1.1
|
||||
function ObjectGetProto() {
|
||||
return %_GetPrototype(TO_OBJECT_INLINE(this));
|
||||
return %_GetPrototype(TO_OBJECT(this));
|
||||
}
|
||||
|
||||
|
||||
@ -1280,10 +1280,10 @@ function ObjectSetProto(proto) {
|
||||
function ObjectConstructor(x) {
|
||||
if (%_IsConstructCall()) {
|
||||
if (x == null) return this;
|
||||
return TO_OBJECT_INLINE(x);
|
||||
return TO_OBJECT(x);
|
||||
} else {
|
||||
if (x == null) return { };
|
||||
return TO_OBJECT_INLINE(x);
|
||||
return TO_OBJECT(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1053,8 +1053,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
__ Integer32ToSmi(rax, rax);
|
||||
__ Push(rax);
|
||||
|
||||
__ Push(rbx);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ movp(rax, rbx);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ movp(rbx, rax);
|
||||
__ Set(rdx, 0); // indicate regular JS_FUNCTION
|
||||
|
||||
@ -1274,8 +1275,9 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
|
||||
|
||||
// Convert the receiver to an object.
|
||||
__ bind(&call_to_object);
|
||||
__ Push(rbx);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ movp(rax, rbx);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ movp(rbx, rax);
|
||||
__ jmp(&push_receiver, Label::kNear);
|
||||
|
||||
|
@ -1964,8 +1964,8 @@ static void EmitWrapCase(MacroAssembler* masm,
|
||||
// Wrap the receiver and patch it back onto the stack.
|
||||
{ FrameScope frame_scope(masm, StackFrame::INTERNAL);
|
||||
__ Push(rdi);
|
||||
__ Push(rax);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ Pop(rdi);
|
||||
}
|
||||
__ movp(args->GetReceiverOperand(), rax);
|
||||
|
@ -103,6 +103,10 @@ void ToNumberDescriptor::InitializePlatformSpecific(
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
const Register ToObjectDescriptor::ReceiverRegister() { return rax; }
|
||||
|
||||
|
||||
void NumberToStringDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {rax};
|
||||
|
@ -994,8 +994,9 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
||||
__ SmiTag(eax);
|
||||
__ push(eax);
|
||||
|
||||
__ push(ebx);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ mov(eax, ebx);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ mov(ebx, eax);
|
||||
__ Move(edx, Immediate(0)); // restore
|
||||
|
||||
@ -1215,8 +1216,9 @@ static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
|
||||
__ j(above_equal, &push_receiver);
|
||||
|
||||
__ bind(&call_to_object);
|
||||
__ push(ebx);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
__ mov(eax, ebx);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ mov(ebx, eax);
|
||||
__ jmp(&push_receiver);
|
||||
|
||||
|
@ -1800,8 +1800,8 @@ static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
|
||||
// Wrap the receiver and patch it back onto the stack.
|
||||
{ FrameScope frame_scope(masm, StackFrame::INTERNAL);
|
||||
__ push(edi);
|
||||
__ push(eax);
|
||||
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
||||
ToObjectStub stub(masm->isolate());
|
||||
__ CallStub(&stub);
|
||||
__ pop(edi);
|
||||
}
|
||||
__ mov(Operand(esp, (argc + 1) * kPointerSize), eax);
|
||||
|
@ -103,6 +103,10 @@ void ToNumberDescriptor::InitializePlatformSpecific(
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
const Register ToObjectDescriptor::ReceiverRegister() { return eax; }
|
||||
|
||||
|
||||
void NumberToStringDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {eax};
|
||||
|
Loading…
Reference in New Issue
Block a user