[builtins] Introduce a proper BUILTIN frame type.
This adds a new BUILTIN frame type, which supports variable number of arguments for builtins implemented in hand-written native code (we will extend this mechanism to TurboFan builtins at some point). Convert the Math.max and Math.min builtins to construct a BUILTIN frame if required. This does not yet work for C++ builtins, but that'll be the next step. R=bmeurer@chromium.org, jarin@chromium.org BUG=v8:4815 LOG=n Review-Url: https://codereview.chromium.org/2069423002 Cr-Commit-Position: refs/heads/master@{#37051}
This commit is contained in:
parent
9347cae998
commit
f47b9e9810
@ -140,6 +140,8 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
|
||||
void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : number of arguments
|
||||
// -- r1 : function
|
||||
// -- cp : context
|
||||
// -- lr : return address
|
||||
// -- sp[(argc - n) * 8] : arg[n] (zero-based)
|
||||
// -- sp[(argc + 1) * 8] : receiver
|
||||
@ -152,9 +154,9 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
DoubleRegister const reg = (kind == MathMaxMinKind::kMin) ? d2 : d1;
|
||||
|
||||
// Load the accumulator with the default return value (either -Infinity or
|
||||
// +Infinity), with the tagged value in r1 and the double value in d1.
|
||||
__ LoadRoot(r1, root_index);
|
||||
__ vldr(d1, FieldMemOperand(r1, HeapNumber::kValueOffset));
|
||||
// +Infinity), with the tagged value in r5 and the double value in d1.
|
||||
__ LoadRoot(r5, root_index);
|
||||
__ vldr(d1, FieldMemOperand(r5, HeapNumber::kValueOffset));
|
||||
|
||||
// Remember how many slots to drop (including the receiver).
|
||||
__ add(r4, r0, Operand(1));
|
||||
@ -178,24 +180,28 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
__ JumpIfRoot(r3, Heap::kHeapNumberMapRootIndex, &convert_number);
|
||||
{
|
||||
// Parameter is not a Number, use the ToNumber builtin to convert it.
|
||||
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
||||
DCHECK(!FLAG_enable_embedded_constant_pool);
|
||||
FrameScope scope(masm, StackFrame::MANUAL);
|
||||
__ Push(lr, fp, cp, r1);
|
||||
__ add(fp, sp, Operand(2 * kPointerSize));
|
||||
__ SmiTag(r0);
|
||||
__ SmiTag(r4);
|
||||
__ Push(r0, r1, r4);
|
||||
__ Push(r0, r4, r5);
|
||||
__ mov(r0, r2);
|
||||
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
|
||||
__ mov(r2, r0);
|
||||
__ Pop(r0, r1, r4);
|
||||
__ Pop(r0, r4, r5);
|
||||
{
|
||||
// Restore the double accumulator value (d1).
|
||||
Label done_restore;
|
||||
__ SmiToDouble(d1, r1);
|
||||
__ JumpIfSmi(r1, &done_restore);
|
||||
__ vldr(d1, FieldMemOperand(r1, HeapNumber::kValueOffset));
|
||||
__ SmiToDouble(d1, r5);
|
||||
__ JumpIfSmi(r5, &done_restore);
|
||||
__ vldr(d1, FieldMemOperand(r5, HeapNumber::kValueOffset));
|
||||
__ bind(&done_restore);
|
||||
}
|
||||
__ SmiUntag(r4);
|
||||
__ SmiUntag(r0);
|
||||
__ Pop(lr, fp, cp, r1);
|
||||
}
|
||||
__ b(&convert);
|
||||
__ bind(&convert_number);
|
||||
@ -221,18 +227,18 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
// Result is on the right hand side.
|
||||
__ bind(&compare_swap);
|
||||
__ vmov(d1, d2);
|
||||
__ mov(r1, r2);
|
||||
__ mov(r5, r2);
|
||||
__ b(&loop);
|
||||
|
||||
// At least one side is NaN, which means that the result will be NaN too.
|
||||
__ bind(&compare_nan);
|
||||
__ LoadRoot(r1, Heap::kNanValueRootIndex);
|
||||
__ vldr(d1, FieldMemOperand(r1, HeapNumber::kValueOffset));
|
||||
__ LoadRoot(r5, Heap::kNanValueRootIndex);
|
||||
__ vldr(d1, FieldMemOperand(r5, HeapNumber::kValueOffset));
|
||||
__ b(&loop);
|
||||
}
|
||||
|
||||
__ bind(&done_loop);
|
||||
__ mov(r0, r1);
|
||||
__ mov(r0, r5);
|
||||
__ Drop(r4);
|
||||
__ Ret();
|
||||
}
|
||||
|
@ -141,6 +141,8 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
|
||||
void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- x0 : number of arguments
|
||||
// -- x1 : function
|
||||
// -- cp : context
|
||||
// -- lr : return address
|
||||
// -- sp[(argc - n) * 8] : arg[n] (zero-based)
|
||||
// -- sp[(argc + 1) * 8] : receiver
|
||||
@ -152,9 +154,9 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
: Heap::kMinusInfinityValueRootIndex;
|
||||
|
||||
// Load the accumulator with the default return value (either -Infinity or
|
||||
// +Infinity), with the tagged value in x1 and the double value in d1.
|
||||
__ LoadRoot(x1, root_index);
|
||||
__ Ldr(d1, FieldMemOperand(x1, HeapNumber::kValueOffset));
|
||||
// +Infinity), with the tagged value in x5 and the double value in d5.
|
||||
__ LoadRoot(x5, root_index);
|
||||
__ Ldr(d5, FieldMemOperand(x5, HeapNumber::kValueOffset));
|
||||
|
||||
// Remember how many slots to drop (including the receiver).
|
||||
__ Add(x4, x0, 1);
|
||||
@ -176,24 +178,28 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
__ JumpIfHeapNumber(x2, &convert_number);
|
||||
{
|
||||
// Parameter is not a Number, use the ToNumber builtin to convert it.
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
FrameScope scope(masm, StackFrame::MANUAL);
|
||||
__ Push(lr, fp);
|
||||
__ Move(fp, jssp);
|
||||
__ Push(cp, x1);
|
||||
__ SmiTag(x0);
|
||||
__ SmiTag(x4);
|
||||
__ Push(x0, x1, x4);
|
||||
__ Push(x0, x5, x4);
|
||||
__ Mov(x0, x2);
|
||||
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
|
||||
__ Mov(x2, x0);
|
||||
__ Pop(x4, x1, x0);
|
||||
__ Pop(x4, x5, x0);
|
||||
{
|
||||
// Restore the double accumulator value (d1).
|
||||
// Restore the double accumulator value (d5).
|
||||
Label done_restore;
|
||||
__ SmiUntagToDouble(d1, x1, kSpeculativeUntag);
|
||||
__ JumpIfSmi(x1, &done_restore);
|
||||
__ Ldr(d1, FieldMemOperand(x1, HeapNumber::kValueOffset));
|
||||
__ SmiUntagToDouble(d5, x5, kSpeculativeUntag);
|
||||
__ JumpIfSmi(x5, &done_restore);
|
||||
__ Ldr(d5, FieldMemOperand(x5, HeapNumber::kValueOffset));
|
||||
__ Bind(&done_restore);
|
||||
}
|
||||
__ SmiUntag(x4);
|
||||
__ SmiUntag(x0);
|
||||
__ Pop(x1, cp, fp, lr);
|
||||
}
|
||||
__ AssertNumber(x2);
|
||||
__ JumpIfSmi(x2, &convert_smi);
|
||||
@ -208,22 +214,22 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
|
||||
// We can use a single fmin/fmax for the operation itself, but we then need
|
||||
// to work out which HeapNumber (or smi) the result came from.
|
||||
__ Fmov(x11, d1);
|
||||
__ Fmov(x11, d5);
|
||||
if (kind == MathMaxMinKind::kMin) {
|
||||
__ Fmin(d1, d1, d2);
|
||||
__ Fmin(d5, d5, d2);
|
||||
} else {
|
||||
DCHECK(kind == MathMaxMinKind::kMax);
|
||||
__ Fmax(d1, d1, d2);
|
||||
__ Fmax(d5, d5, d2);
|
||||
}
|
||||
__ Fmov(x10, d1);
|
||||
__ Fmov(x10, d5);
|
||||
__ Cmp(x10, x11);
|
||||
__ Csel(x1, x1, x2, eq);
|
||||
__ Csel(x5, x5, x2, eq);
|
||||
__ B(&loop);
|
||||
}
|
||||
|
||||
__ Bind(&done_loop);
|
||||
__ Mov(x0, x1);
|
||||
__ Drop(x4);
|
||||
__ Mov(x0, x5);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
@ -233,6 +233,9 @@ inline ArgumentsAdaptorFrame::ArgumentsAdaptorFrame(
|
||||
StackFrameIteratorBase* iterator) : JavaScriptFrame(iterator) {
|
||||
}
|
||||
|
||||
inline BuiltinFrame::BuiltinFrame(StackFrameIteratorBase* iterator)
|
||||
: JavaScriptFrame(iterator) {}
|
||||
|
||||
inline WasmFrame::WasmFrame(StackFrameIteratorBase* iterator)
|
||||
: StandardFrame(iterator) {}
|
||||
|
||||
|
@ -454,10 +454,14 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
|
||||
if (code_obj->is_interpreter_trampoline_builtin()) {
|
||||
return INTERPRETED;
|
||||
}
|
||||
// We treat frames for BUILTIN Code objects as OptimizedFrame for now
|
||||
// (all the builtins with JavaScript linkage are actually generated
|
||||
// with TurboFan currently, so this is sound).
|
||||
return OPTIMIZED;
|
||||
if (code_obj->is_turbofanned()) {
|
||||
// TODO(bmeurer): We treat frames for BUILTIN Code objects as
|
||||
// OptimizedFrame for now (all the builtins with JavaScript
|
||||
// linkage are actually generated with TurboFan currently, so
|
||||
// this is sound).
|
||||
return OPTIMIZED;
|
||||
}
|
||||
return BUILTIN;
|
||||
case Code::FUNCTION:
|
||||
return JAVA_SCRIPT;
|
||||
case Code::OPTIMIZED_FUNCTION:
|
||||
@ -692,6 +696,7 @@ void StandardFrame::IterateCompiledFrame(ObjectVisitor* v) const {
|
||||
case JAVA_SCRIPT:
|
||||
case OPTIMIZED:
|
||||
case INTERPRETED:
|
||||
case BUILTIN:
|
||||
// These frame types have a context, but they are actually stored
|
||||
// in the place on the stack that one finds the frame type.
|
||||
UNREACHABLE();
|
||||
@ -1289,11 +1294,6 @@ int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const {
|
||||
return Smi::cast(GetExpression(0))->value();
|
||||
}
|
||||
|
||||
|
||||
Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
|
||||
return fp() + StandardFrameConstants::kCallerSPOffset;
|
||||
}
|
||||
|
||||
int ArgumentsAdaptorFrame::GetLength(Address fp) {
|
||||
const int offset = ArgumentsAdaptorFrameConstants::kLengthOffset;
|
||||
return Smi::cast(Memory::Object_at(fp + offset))->value();
|
||||
@ -1304,6 +1304,15 @@ Code* ArgumentsAdaptorFrame::unchecked_code() const {
|
||||
Builtins::kArgumentsAdaptorTrampoline);
|
||||
}
|
||||
|
||||
void BuiltinFrame::Print(StringStream* accumulator, PrintMode mode,
|
||||
int index) const {
|
||||
// TODO(bmeurer)
|
||||
}
|
||||
|
||||
int BuiltinFrame::GetNumberOfIncomingArguments() const {
|
||||
return Smi::cast(GetExpression(0))->value();
|
||||
}
|
||||
|
||||
Address InternalFrame::GetCallerStackPointer() const {
|
||||
// Internal frames have no arguments. The stack pointer of the
|
||||
// caller is at a fixed offset from the frame pointer.
|
||||
|
37
src/frames.h
37
src/frames.h
@ -111,7 +111,8 @@ class StackHandler BASE_EMBEDDED {
|
||||
V(STUB_FAILURE_TRAMPOLINE, StubFailureTrampolineFrame) \
|
||||
V(INTERNAL, InternalFrame) \
|
||||
V(CONSTRUCT, ConstructFrame) \
|
||||
V(ARGUMENTS_ADAPTOR, ArgumentsAdaptorFrame)
|
||||
V(ARGUMENTS_ADAPTOR, ArgumentsAdaptorFrame) \
|
||||
V(BUILTIN, BuiltinFrame)
|
||||
|
||||
// Every pointer in a frame has a slot id. On 32-bit platforms, doubles consume
|
||||
// two slots.
|
||||
@ -280,6 +281,14 @@ class ArgumentsAdaptorFrameConstants : public TypedFrameConstants {
|
||||
DEFINE_TYPED_FRAME_SIZES(2);
|
||||
};
|
||||
|
||||
class BuiltinFrameConstants : public TypedFrameConstants {
|
||||
public:
|
||||
// FP-relative.
|
||||
static const int kFunctionOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0);
|
||||
static const int kLengthOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
|
||||
DEFINE_TYPED_FRAME_SIZES(2);
|
||||
};
|
||||
|
||||
class InternalFrameConstants : public TypedFrameConstants {
|
||||
public:
|
||||
// FP-relative.
|
||||
@ -411,6 +420,7 @@ class StackFrame BASE_EMBEDDED {
|
||||
bool is_wasm_to_js() const { return type() == WASM_TO_JS; }
|
||||
bool is_js_to_wasm() const { return type() == JS_TO_WASM; }
|
||||
bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; }
|
||||
bool is_builtin() const { return type() == BUILTIN; }
|
||||
bool is_internal() const { return type() == INTERNAL; }
|
||||
bool is_stub_failure_trampoline() const {
|
||||
return type() == STUB_FAILURE_TRAMPOLINE;
|
||||
@ -421,7 +431,7 @@ class StackFrame BASE_EMBEDDED {
|
||||
bool is_java_script() const {
|
||||
Type type = this->type();
|
||||
return (type == JAVA_SCRIPT) || (type == OPTIMIZED) ||
|
||||
(type == INTERPRETED);
|
||||
(type == INTERPRETED) || (type == BUILTIN);
|
||||
}
|
||||
|
||||
// Accessors.
|
||||
@ -950,7 +960,28 @@ class ArgumentsAdaptorFrame: public JavaScriptFrame {
|
||||
|
||||
int GetNumberOfIncomingArguments() const override;
|
||||
|
||||
Address GetCallerStackPointer() const override;
|
||||
private:
|
||||
friend class StackFrameIteratorBase;
|
||||
};
|
||||
|
||||
// Builtin frames are built for builtins with JavaScript linkage, such as
|
||||
// various standard library functions (i.e. Math.asin, Math.floor, etc.).
|
||||
class BuiltinFrame final : public JavaScriptFrame {
|
||||
public:
|
||||
Type type() const final { return BUILTIN; }
|
||||
|
||||
static BuiltinFrame* cast(StackFrame* frame) {
|
||||
DCHECK(frame->is_builtin());
|
||||
return static_cast<BuiltinFrame*>(frame);
|
||||
}
|
||||
|
||||
// Printing support.
|
||||
void Print(StringStream* accumulator, PrintMode mode, int index) const final;
|
||||
|
||||
protected:
|
||||
inline explicit BuiltinFrame(StackFrameIteratorBase* iterator);
|
||||
|
||||
int GetNumberOfIncomingArguments() const final;
|
||||
|
||||
private:
|
||||
friend class StackFrameIteratorBase;
|
||||
|
@ -1569,6 +1569,8 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
|
||||
void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : number of arguments
|
||||
// -- edi : function
|
||||
// -- esi : context
|
||||
// -- esp[0] : return address
|
||||
// -- esp[(argc - n) * 8] : arg[n] (zero-based)
|
||||
// -- esp[(argc + 1) * 8] : receiver
|
||||
@ -1604,7 +1606,11 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
Heap::kHeapNumberMapRootIndex, &convert_number);
|
||||
{
|
||||
// Parameter is not a Number, use the ToNumber builtin to convert it.
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
FrameScope scope(masm, StackFrame::MANUAL);
|
||||
__ Push(ebp);
|
||||
__ Move(ebp, esp);
|
||||
__ Push(esi);
|
||||
__ Push(edi);
|
||||
__ SmiTag(eax);
|
||||
__ SmiTag(ecx);
|
||||
__ Push(eax);
|
||||
@ -1616,6 +1622,8 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
__ Pop(edx);
|
||||
__ Pop(ecx);
|
||||
__ Pop(eax);
|
||||
__ Pop(edi);
|
||||
__ Pop(esi);
|
||||
{
|
||||
// Restore the double accumulator value (xmm0).
|
||||
Label restore_smi, done_restore;
|
||||
@ -1630,6 +1638,7 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
}
|
||||
__ SmiUntag(ecx);
|
||||
__ SmiUntag(eax);
|
||||
__ leave();
|
||||
}
|
||||
__ jmp(&convert);
|
||||
__ bind(&convert_number);
|
||||
|
@ -386,7 +386,8 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
|
||||
switch (frame->type()) {
|
||||
case StackFrame::JAVA_SCRIPT:
|
||||
case StackFrame::OPTIMIZED:
|
||||
case StackFrame::INTERPRETED: {
|
||||
case StackFrame::INTERPRETED:
|
||||
case StackFrame::BUILTIN: {
|
||||
JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
|
||||
// Set initial size to the maximum inlining level + 1 for the outermost
|
||||
// function.
|
||||
|
@ -145,6 +145,8 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
|
||||
void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : number of arguments
|
||||
// -- a1 : function
|
||||
// -- cp : context
|
||||
// -- ra : return address
|
||||
// -- sp[(argc - n) * 8] : arg[n] (zero-based)
|
||||
// -- sp[(argc + 1) * 8] : receiver
|
||||
@ -154,9 +156,9 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
: Heap::kMinusInfinityValueRootIndex;
|
||||
|
||||
// Load the accumulator with the default return value (either -Infinity or
|
||||
// +Infinity), with the tagged value in a1 and the double value in f0.
|
||||
__ LoadRoot(a1, root_index);
|
||||
__ ldc1(f0, FieldMemOperand(a1, HeapNumber::kValueOffset));
|
||||
// +Infinity), with the tagged value in t2 and the double value in f0.
|
||||
__ LoadRoot(t2, root_index);
|
||||
__ ldc1(f0, FieldMemOperand(t2, HeapNumber::kValueOffset));
|
||||
__ Addu(a3, a0, Operand(1));
|
||||
|
||||
Label done_loop, loop;
|
||||
@ -179,26 +181,31 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
__ JumpIfRoot(t0, Heap::kHeapNumberMapRootIndex, &convert_number);
|
||||
{
|
||||
// Parameter is not a Number, use the ToNumber builtin to convert it.
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
FrameScope scope(masm, StackFrame::MANUAL);
|
||||
__ Push(ra, fp);
|
||||
__ Move(fp, sp);
|
||||
__ Push(cp, a1);
|
||||
__ SmiTag(a0);
|
||||
__ SmiTag(a3);
|
||||
__ Push(a0, a1, a3);
|
||||
__ Push(a0, t2, a3);
|
||||
__ mov(a0, a2);
|
||||
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
|
||||
__ mov(a2, v0);
|
||||
__ Pop(a0, a1, a3);
|
||||
__ Pop(a0, t2, a3);
|
||||
{
|
||||
// Restore the double accumulator value (f0).
|
||||
Label restore_smi, done_restore;
|
||||
__ JumpIfSmi(a1, &restore_smi);
|
||||
__ ldc1(f0, FieldMemOperand(a1, HeapNumber::kValueOffset));
|
||||
__ JumpIfSmi(t2, &restore_smi);
|
||||
__ ldc1(f0, FieldMemOperand(t2, HeapNumber::kValueOffset));
|
||||
__ jmp(&done_restore);
|
||||
__ bind(&restore_smi);
|
||||
__ SmiToDoubleFPURegister(a1, f0, t0);
|
||||
__ SmiToDoubleFPURegister(t2, f0, t0);
|
||||
__ bind(&done_restore);
|
||||
}
|
||||
__ SmiUntag(a3);
|
||||
__ SmiUntag(a0);
|
||||
__ Pop(cp, a1);
|
||||
__ Pop(ra, fp);
|
||||
}
|
||||
__ jmp(&convert);
|
||||
__ bind(&convert_number);
|
||||
@ -226,20 +233,20 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
__ Branch(&set_value, ne, t1, Operand(t8));
|
||||
__ jmp(&loop);
|
||||
__ bind(&set_value);
|
||||
__ mov(a1, a2);
|
||||
__ mov(t2, a2);
|
||||
__ jmp(&loop);
|
||||
|
||||
// At least one side is NaN, which means that the result will be NaN too.
|
||||
__ bind(&compare_nan);
|
||||
__ LoadRoot(a1, Heap::kNanValueRootIndex);
|
||||
__ ldc1(f0, FieldMemOperand(a1, HeapNumber::kValueOffset));
|
||||
__ LoadRoot(t2, Heap::kNanValueRootIndex);
|
||||
__ ldc1(f0, FieldMemOperand(t2, HeapNumber::kValueOffset));
|
||||
__ jmp(&loop);
|
||||
}
|
||||
|
||||
__ bind(&done_loop);
|
||||
__ Lsa(sp, sp, a3, kPointerSizeLog2);
|
||||
__ Ret(USE_DELAY_SLOT);
|
||||
__ mov(v0, a1); // In delay slot.
|
||||
__ mov(v0, t2); // In delay slot.
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -144,6 +144,8 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
|
||||
void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : number of arguments
|
||||
// -- a1 : function
|
||||
// -- cp : context
|
||||
// -- ra : return address
|
||||
// -- sp[(argc - n) * 8] : arg[n] (zero-based)
|
||||
// -- sp[(argc + 1) * 8] : receiver
|
||||
@ -153,9 +155,9 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
: Heap::kMinusInfinityValueRootIndex;
|
||||
|
||||
// Load the accumulator with the default return value (either -Infinity or
|
||||
// +Infinity), with the tagged value in a1 and the double value in f0.
|
||||
__ LoadRoot(a1, root_index);
|
||||
__ ldc1(f0, FieldMemOperand(a1, HeapNumber::kValueOffset));
|
||||
// +Infinity), with the tagged value in t1 and the double value in f0.
|
||||
__ LoadRoot(t1, root_index);
|
||||
__ ldc1(f0, FieldMemOperand(t1, HeapNumber::kValueOffset));
|
||||
__ Addu(a3, a0, 1);
|
||||
|
||||
Label done_loop, loop;
|
||||
@ -178,26 +180,31 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
__ JumpIfRoot(a4, Heap::kHeapNumberMapRootIndex, &convert_number);
|
||||
{
|
||||
// Parameter is not a Number, use the ToNumber builtin to convert it.
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
FrameScope scope(masm, StackFrame::MANUAL);
|
||||
__ Push(ra, fp);
|
||||
__ Move(fp, sp);
|
||||
__ Push(cp, a1);
|
||||
__ SmiTag(a0);
|
||||
__ SmiTag(a3);
|
||||
__ Push(a0, a1, a3);
|
||||
__ Push(a0, t1, a3);
|
||||
__ mov(a0, a2);
|
||||
__ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
|
||||
__ mov(a2, v0);
|
||||
__ Pop(a0, a1, a3);
|
||||
__ Pop(a0, t1, a3);
|
||||
{
|
||||
// Restore the double accumulator value (f0).
|
||||
Label restore_smi, done_restore;
|
||||
__ JumpIfSmi(a1, &restore_smi);
|
||||
__ ldc1(f0, FieldMemOperand(a1, HeapNumber::kValueOffset));
|
||||
__ JumpIfSmi(t1, &restore_smi);
|
||||
__ ldc1(f0, FieldMemOperand(t1, HeapNumber::kValueOffset));
|
||||
__ jmp(&done_restore);
|
||||
__ bind(&restore_smi);
|
||||
__ SmiToDoubleFPURegister(a1, f0, a4);
|
||||
__ SmiToDoubleFPURegister(t1, f0, a4);
|
||||
__ bind(&done_restore);
|
||||
}
|
||||
__ SmiUntag(a3);
|
||||
__ SmiUntag(a0);
|
||||
__ Pop(cp, a1);
|
||||
__ Pop(ra, fp);
|
||||
}
|
||||
__ jmp(&convert);
|
||||
__ bind(&convert_number);
|
||||
@ -222,20 +229,20 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
}
|
||||
__ Move(at, f0);
|
||||
__ Branch(&loop, eq, a4, Operand(at));
|
||||
__ mov(a1, a2);
|
||||
__ mov(t1, a2);
|
||||
__ jmp(&loop);
|
||||
|
||||
// At least one side is NaN, which means that the result will be NaN too.
|
||||
__ bind(&compare_nan);
|
||||
__ LoadRoot(a1, Heap::kNanValueRootIndex);
|
||||
__ ldc1(f0, FieldMemOperand(a1, HeapNumber::kValueOffset));
|
||||
__ LoadRoot(t1, Heap::kNanValueRootIndex);
|
||||
__ ldc1(f0, FieldMemOperand(t1, HeapNumber::kValueOffset));
|
||||
__ jmp(&loop);
|
||||
}
|
||||
|
||||
__ bind(&done_loop);
|
||||
__ Dlsa(sp, sp, a3, kPointerSizeLog2);
|
||||
__ Ret(USE_DELAY_SLOT);
|
||||
__ mov(v0, a1); // In delay slot.
|
||||
__ mov(v0, t1); // In delay slot.
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -1637,6 +1637,8 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
|
||||
void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : number of arguments
|
||||
// -- rdi : function
|
||||
// -- rsi : context
|
||||
// -- rsp[0] : return address
|
||||
// -- rsp[(argc - n) * 8] : arg[n] (zero-based)
|
||||
// -- rsp[(argc + 1) * 8] : receiver
|
||||
@ -1672,7 +1674,11 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
Heap::kHeapNumberMapRootIndex, &convert_number);
|
||||
{
|
||||
// Parameter is not a Number, use the ToNumber builtin to convert it.
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
FrameScope scope(masm, StackFrame::MANUAL);
|
||||
__ Push(rbp);
|
||||
__ Move(rbp, rsp);
|
||||
__ Push(rsi);
|
||||
__ Push(rdi);
|
||||
__ Integer32ToSmi(rax, rax);
|
||||
__ Integer32ToSmi(rcx, rcx);
|
||||
__ Push(rax);
|
||||
@ -1684,6 +1690,8 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
__ Pop(rdx);
|
||||
__ Pop(rcx);
|
||||
__ Pop(rax);
|
||||
__ Pop(rdi);
|
||||
__ Pop(rsi);
|
||||
{
|
||||
// Restore the double accumulator value (xmm0).
|
||||
Label restore_smi, done_restore;
|
||||
@ -1696,6 +1704,7 @@ void Builtins::Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind) {
|
||||
}
|
||||
__ SmiToInteger32(rcx, rcx);
|
||||
__ SmiToInteger32(rax, rax);
|
||||
__ leave();
|
||||
}
|
||||
__ jmp(&convert);
|
||||
__ bind(&convert_number);
|
||||
|
20
test/mjsunit/regress/regress-4815.js
Normal file
20
test/mjsunit/regress/regress-4815.js
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
var thrower = { [Symbol.toPrimitive]: () => FAIL };
|
||||
|
||||
// Tests that a native conversion function is included in the
|
||||
// stack trace.
|
||||
function testTraceNativeConversion(nativeFunc) {
|
||||
var nativeFuncName = nativeFunc.name;
|
||||
try {
|
||||
nativeFunc(thrower);
|
||||
assertUnreachable(nativeFuncName);
|
||||
} catch (e) {
|
||||
assertTrue(e.stack.indexOf(nativeFuncName) >= 0, nativeFuncName);
|
||||
}
|
||||
}
|
||||
|
||||
testTraceNativeConversion(Math.max);
|
||||
testTraceNativeConversion(Math.min);
|
Loading…
Reference in New Issue
Block a user