Commit f47b9e98 authored by jgruber's avatar jgruber Committed by Commit bot

[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}
parent 9347cae9
......@@ -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.
......
......@@ -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);
......
// 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);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment