Skip to content

Commit 4acca53

Browse files
bmeurerCommit bot
authored andcommitted
[runtime] Rewrite Function.prototype.toString in C++.
There's actually no point trying to do Function.prototype.toString in JavaScript, as it always calls into C++ at least once, so it only complicates things (esp. once we start optimizing bound functions). Drive-by-fix: Rename FunctionApply and FunctionCall builtins to also reflect the fact that these are builtins in the Function.prototype and not on Function itself. TBR=hpayer@chromium.org R=yangguo@chromium.org BUG=chromium:535408 LOG=n Review URL: https://codereview.chromium.org/1540953004 Cr-Commit-Position: refs/heads/master@{#32996}
1 parent 0589e84 commit 4acca53

22 files changed

Lines changed: 438 additions & 471 deletions

src/arm/builtins-arm.cc

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,50 +1382,7 @@ void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
13821382

13831383

13841384
// static
1385-
void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
1386-
// 1. Make sure we have at least one argument.
1387-
// r0: actual number of arguments
1388-
{
1389-
Label done;
1390-
__ cmp(r0, Operand::Zero());
1391-
__ b(ne, &done);
1392-
__ PushRoot(Heap::kUndefinedValueRootIndex);
1393-
__ add(r0, r0, Operand(1));
1394-
__ bind(&done);
1395-
}
1396-
1397-
// 2. Get the callable to call (passed as receiver) from the stack.
1398-
// r0: actual number of arguments
1399-
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
1400-
1401-
// 3. Shift arguments and return address one slot down on the stack
1402-
// (overwriting the original receiver). Adjust argument count to make
1403-
// the original first argument the new receiver.
1404-
// r0: actual number of arguments
1405-
// r1: callable
1406-
{
1407-
Label loop;
1408-
// Calculate the copy start address (destination). Copy end address is sp.
1409-
__ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
1410-
1411-
__ bind(&loop);
1412-
__ ldr(ip, MemOperand(r2, -kPointerSize));
1413-
__ str(ip, MemOperand(r2));
1414-
__ sub(r2, r2, Operand(kPointerSize));
1415-
__ cmp(r2, sp);
1416-
__ b(ne, &loop);
1417-
// Adjust the actual number of arguments and remove the top element
1418-
// (which is a copy of the last argument).
1419-
__ sub(r0, r0, Operand(1));
1420-
__ pop();
1421-
}
1422-
1423-
// 4. Call the callable.
1424-
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1425-
}
1426-
1427-
1428-
void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
1385+
void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
14291386
// ----------- S t a t e -------------
14301387
// -- r0 : argc
14311388
// -- sp[0] : argArray
@@ -1490,6 +1447,50 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
14901447
}
14911448

14921449

1450+
// static
1451+
void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
1452+
// 1. Make sure we have at least one argument.
1453+
// r0: actual number of arguments
1454+
{
1455+
Label done;
1456+
__ cmp(r0, Operand::Zero());
1457+
__ b(ne, &done);
1458+
__ PushRoot(Heap::kUndefinedValueRootIndex);
1459+
__ add(r0, r0, Operand(1));
1460+
__ bind(&done);
1461+
}
1462+
1463+
// 2. Get the callable to call (passed as receiver) from the stack.
1464+
// r0: actual number of arguments
1465+
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
1466+
1467+
// 3. Shift arguments and return address one slot down on the stack
1468+
// (overwriting the original receiver). Adjust argument count to make
1469+
// the original first argument the new receiver.
1470+
// r0: actual number of arguments
1471+
// r1: callable
1472+
{
1473+
Label loop;
1474+
// Calculate the copy start address (destination). Copy end address is sp.
1475+
__ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
1476+
1477+
__ bind(&loop);
1478+
__ ldr(ip, MemOperand(r2, -kPointerSize));
1479+
__ str(ip, MemOperand(r2));
1480+
__ sub(r2, r2, Operand(kPointerSize));
1481+
__ cmp(r2, sp);
1482+
__ b(ne, &loop);
1483+
// Adjust the actual number of arguments and remove the top element
1484+
// (which is a copy of the last argument).
1485+
__ sub(r0, r0, Operand(1));
1486+
__ pop();
1487+
}
1488+
1489+
// 4. Call the callable.
1490+
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1491+
}
1492+
1493+
14931494
void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
14941495
// ----------- S t a t e -------------
14951496
// -- r0 : argc

src/arm64/builtins-arm64.cc

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,59 +1353,15 @@ void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
13531353
}
13541354

13551355

1356-
void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
1357-
Register argc = x0;
1358-
Register function = x1;
1359-
Register scratch1 = x10;
1360-
Register scratch2 = x11;
1361-
1362-
ASM_LOCATION("Builtins::Generate_FunctionCall");
1363-
// 1. Make sure we have at least one argument.
1364-
{
1365-
Label done;
1366-
__ Cbnz(argc, &done);
1367-
__ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1368-
__ Push(scratch1);
1369-
__ Mov(argc, 1);
1370-
__ Bind(&done);
1371-
}
1372-
1373-
// 2. Get the callable to call (passed as receiver) from the stack.
1374-
__ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
1375-
1376-
// 3. Shift arguments and return address one slot down on the stack
1377-
// (overwriting the original receiver). Adjust argument count to make
1378-
// the original first argument the new receiver.
1379-
{
1380-
Label loop;
1381-
// Calculate the copy start address (destination). Copy end address is jssp.
1382-
__ Add(scratch2, jssp, Operand(argc, LSL, kPointerSizeLog2));
1383-
__ Sub(scratch1, scratch2, kPointerSize);
1384-
1385-
__ Bind(&loop);
1386-
__ Ldr(x12, MemOperand(scratch1, -kPointerSize, PostIndex));
1387-
__ Str(x12, MemOperand(scratch2, -kPointerSize, PostIndex));
1388-
__ Cmp(scratch1, jssp);
1389-
__ B(ge, &loop);
1390-
// Adjust the actual number of arguments and remove the top element
1391-
// (which is a copy of the last argument).
1392-
__ Sub(argc, argc, 1);
1393-
__ Drop(1);
1394-
}
1395-
1396-
// 4. Call the callable.
1397-
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1398-
}
1399-
1400-
1401-
void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
1356+
// static
1357+
void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
14021358
// ----------- S t a t e -------------
14031359
// -- r0 : argc
14041360
// -- sp[0] : argArray
14051361
// -- sp[8] : thisArg
14061362
// -- sp[16] : receiver
14071363
// -----------------------------------
1408-
ASM_LOCATION("Builtins::Generate_FunctionApply");
1364+
ASM_LOCATION("Builtins::Generate_FunctionPrototypeApply");
14091365

14101366
// 1. Load receiver into x1, argArray into x0 (if present), remove all
14111367
// arguments from the stack (including the receiver), and push thisArg (if
@@ -1467,6 +1423,53 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
14671423
}
14681424

14691425

1426+
// static
1427+
void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
1428+
Register argc = x0;
1429+
Register function = x1;
1430+
Register scratch1 = x10;
1431+
Register scratch2 = x11;
1432+
1433+
ASM_LOCATION("Builtins::Generate_FunctionPrototypeCall");
1434+
1435+
// 1. Make sure we have at least one argument.
1436+
{
1437+
Label done;
1438+
__ Cbnz(argc, &done);
1439+
__ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
1440+
__ Push(scratch1);
1441+
__ Mov(argc, 1);
1442+
__ Bind(&done);
1443+
}
1444+
1445+
// 2. Get the callable to call (passed as receiver) from the stack.
1446+
__ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
1447+
1448+
// 3. Shift arguments and return address one slot down on the stack
1449+
// (overwriting the original receiver). Adjust argument count to make
1450+
// the original first argument the new receiver.
1451+
{
1452+
Label loop;
1453+
// Calculate the copy start address (destination). Copy end address is jssp.
1454+
__ Add(scratch2, jssp, Operand(argc, LSL, kPointerSizeLog2));
1455+
__ Sub(scratch1, scratch2, kPointerSize);
1456+
1457+
__ Bind(&loop);
1458+
__ Ldr(x12, MemOperand(scratch1, -kPointerSize, PostIndex));
1459+
__ Str(x12, MemOperand(scratch2, -kPointerSize, PostIndex));
1460+
__ Cmp(scratch1, jssp);
1461+
__ B(ge, &loop);
1462+
// Adjust the actual number of arguments and remove the top element
1463+
// (which is a copy of the last argument).
1464+
__ Sub(argc, argc, 1);
1465+
__ Drop(1);
1466+
}
1467+
1468+
// 4. Call the callable.
1469+
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1470+
}
1471+
1472+
14701473
void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
14711474
// ----------- S t a t e -------------
14721475
// -- x0 : argc

src/bootstrapper.cc

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2513,7 +2513,7 @@ bool Genesis::InstallNatives(ContextType context_type) {
25132513
// Set the lengths for the functions to satisfy ECMA-262.
25142514
concat->shared()->set_length(1);
25152515
}
2516-
// Install Function.prototype.call and apply.
2516+
// Install Function.prototype.apply, call, and toString.
25172517
{
25182518
Handle<String> key = factory()->Function_string();
25192519
Handle<JSFunction> function =
@@ -2522,24 +2522,13 @@ bool Genesis::InstallNatives(ContextType context_type) {
25222522
Handle<JSObject> proto =
25232523
Handle<JSObject>(JSObject::cast(function->instance_prototype()));
25242524

2525-
// Install the call and the apply functions.
2526-
Handle<JSFunction> call =
2527-
InstallFunction(proto, "call", JS_OBJECT_TYPE, JSObject::kHeaderSize,
2528-
MaybeHandle<JSObject>(), Builtins::kFunctionCall);
2529-
Handle<JSFunction> apply =
2530-
InstallFunction(proto, "apply", JS_OBJECT_TYPE, JSObject::kHeaderSize,
2531-
MaybeHandle<JSObject>(), Builtins::kFunctionApply);
2532-
2533-
// Make sure that Function.prototype.call appears to be compiled.
2534-
// The code will never be called, but inline caching for call will
2535-
// only work if it appears to be compiled.
2536-
apply->shared()->DontAdaptArguments();
2537-
call->shared()->DontAdaptArguments();
2538-
DCHECK(call->is_compiled());
2539-
2540-
// Set the lengths for the functions to satisfy ECMA-262.
2541-
apply->shared()->set_length(2);
2542-
call->shared()->set_length(1);
2525+
// Install the apply, call and toString functions.
2526+
SimpleInstallFunction(proto, factory()->apply_string(),
2527+
Builtins::kFunctionPrototypeApply, 2, false);
2528+
SimpleInstallFunction(proto, factory()->call_string(),
2529+
Builtins::kFunctionPrototypeCall, 1, false);
2530+
SimpleInstallFunction(proto, factory()->toString_string(),
2531+
Builtins::kFunctionPrototypeToString, 0, false);
25432532
}
25442533

25452534
// Set up the Promise constructor.

src/builtins.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,6 +1777,21 @@ BUILTIN(DateToPrimitive) {
17771777
}
17781778

17791779

1780+
// ES6 section 19.2.3.5 Function.prototype.toString ( )
1781+
BUILTIN(FunctionPrototypeToString) {
1782+
HandleScope scope(isolate);
1783+
Handle<Object> receiver = args.receiver();
1784+
1785+
if (receiver->IsJSFunction()) {
1786+
return *JSFunction::ToString(Handle<JSFunction>::cast(receiver));
1787+
}
1788+
THROW_NEW_ERROR_RETURN_FAILURE(
1789+
isolate, NewTypeError(MessageTemplate::kNotGeneric,
1790+
isolate->factory()->NewStringFromAsciiChecked(
1791+
"Function.prototype.toString")));
1792+
}
1793+
1794+
17801795
// ES6 section 19.4.1.1 Symbol ( [ description ] ) for the [[Call]] case.
17811796
BUILTIN(SymbolConstructor) {
17821797
HandleScope scope(isolate);

src/builtins.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
6767
\
6868
V(DateToPrimitive, kNone) \
6969
\
70+
V(FunctionPrototypeToString, kNone) \
71+
\
7072
V(ObjectAssign, kNone) \
7173
V(ObjectProtoToString, kNone) \
7274
\
@@ -168,8 +170,8 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
168170
V(KeyedStoreIC_Megamorphic_Strict, KEYED_STORE_IC, MEGAMORPHIC, \
169171
StoreICState::kStrictModeState) \
170172
\
171-
V(FunctionCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \
172-
V(FunctionApply, BUILTIN, UNINITIALIZED, kNoExtraICState) \
173+
V(FunctionPrototypeApply, BUILTIN, UNINITIALIZED, kNoExtraICState) \
174+
V(FunctionPrototypeCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \
173175
V(ReflectApply, BUILTIN, UNINITIALIZED, kNoExtraICState) \
174176
V(ReflectConstruct, BUILTIN, UNINITIALIZED, kNoExtraICState) \
175177
\
@@ -357,8 +359,8 @@ class Builtins {
357359

358360
static void Generate_HandleFastApiCall(MacroAssembler* masm);
359361

360-
static void Generate_FunctionCall(MacroAssembler* masm);
361-
static void Generate_FunctionApply(MacroAssembler* masm);
362+
static void Generate_FunctionPrototypeApply(MacroAssembler* masm);
363+
static void Generate_FunctionPrototypeCall(MacroAssembler* masm);
362364
static void Generate_ReflectApply(MacroAssembler* masm);
363365
static void Generate_ReflectConstruct(MacroAssembler* masm);
364366

src/debug/mirrors.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// Imports
1010

1111
var ErrorToString;
12-
var FunctionSourceString;
1312
var GlobalArray = global.Array;
1413
var IsNaN = global.isNaN;
1514
var JSONStringify = global.JSON.stringify;
@@ -25,7 +24,6 @@ var SymbolToString;
2524

2625
utils.Import(function(from) {
2726
ErrorToString = from.ErrorToString;
28-
FunctionSourceString = from.FunctionSourceString;
2927
MakeError = from.MakeError;
3028
MapEntries = from.MapEntries;
3129
MapIteratorNext = from.MapIteratorNext;
@@ -938,7 +936,7 @@ FunctionMirror.prototype.source = function() {
938936
// Return source if function is resolved. Otherwise just fall through to
939937
// return undefined.
940938
if (this.resolved()) {
941-
return FunctionSourceString(this.value_);
939+
return %FunctionToString(this.value_);
942940
}
943941
};
944942

src/elements.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,8 @@ static void TraceTopFrame(Isolate* isolate) {
428428
}
429429
StackFrame* raw_frame = it.frame();
430430
if (raw_frame->is_internal()) {
431-
Code* apply_builtin = isolate->builtins()->builtin(
432-
Builtins::kFunctionApply);
431+
Code* apply_builtin =
432+
isolate->builtins()->builtin(Builtins::kFunctionPrototypeApply);
433433
if (raw_frame->unchecked_code() == apply_builtin) {
434434
PrintF("apply from ");
435435
it.Advance();

src/heap/heap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ namespace internal {
225225
V(Boolean_string, "Boolean") \
226226
V(byte_length_string, "byteLength") \
227227
V(byte_offset_string, "byteOffset") \
228+
V(call_string, "call") \
228229
V(callee_string, "callee") \
229230
V(caller_string, "caller") \
230231
V(cell_value_string, "%cell_value") \

0 commit comments

Comments
 (0)