Skip to content

Commit ceade6c

Browse files
bmeurerCommit bot
authored and
Commit bot
committed
[runtime] Introduce a proper %NewArray runtime entry.
This adds a new %NewArray runtime entry, which constructs a new JSArray and does the subclassing correctly (to the same degree that %NewObject does currently), and also deals properly with the AllocationSite feedback mechanism. This runtime entry will be used by TurboFan and is also used as a fallback in the subclassing case in the stub currently. BUG=v8:3101, v8:3330 LOG=n Review URL: https://codereview.chromium.org/1456423003 Cr-Commit-Position: refs/heads/master@{#32131}
1 parent ce3d04c commit ceade6c

File tree

8 files changed

+153
-154
lines changed

8 files changed

+153
-154
lines changed

src/arm/code-stubs-arm.cc

+8-10
Original file line numberDiff line numberDiff line change
@@ -4821,25 +4821,23 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
48214821
GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
48224822

48234823
__ bind(&subclassing);
4824-
__ push(r1);
4825-
__ push(r3);
4826-
4827-
// Adjust argc.
48284824
switch (argument_count()) {
48294825
case ANY:
48304826
case MORE_THAN_ONE:
4831-
__ add(r0, r0, Operand(2));
4827+
__ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
4828+
__ add(r0, r0, Operand(3));
48324829
break;
48334830
case NONE:
4834-
__ mov(r0, Operand(2));
4831+
__ str(r1, MemOperand(sp, 0 * kPointerSize));
4832+
__ mov(r0, Operand(3));
48354833
break;
48364834
case ONE:
4837-
__ mov(r0, Operand(3));
4835+
__ str(r1, MemOperand(sp, 1 * kPointerSize));
4836+
__ mov(r0, Operand(4));
48384837
break;
48394838
}
4840-
4841-
__ JumpToExternalReference(
4842-
ExternalReference(Runtime::kArrayConstructorWithSubclassing, isolate()));
4839+
__ Push(r3, r2);
4840+
__ JumpToExternalReference(ExternalReference(Runtime::kNewArray, isolate()));
48434841
}
48444842

48454843

src/arm64/code-stubs-arm64.cc

+8-7
Original file line numberDiff line numberDiff line change
@@ -5215,22 +5215,23 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
52155215

52165216
// Subclassing support.
52175217
__ Bind(&subclassing);
5218-
__ Push(constructor, new_target);
5219-
// Adjust argc.
52205218
switch (argument_count()) {
52215219
case ANY:
52225220
case MORE_THAN_ONE:
5223-
__ add(x0, x0, Operand(2));
5221+
__ Poke(constructor, Operand(x0, LSL, kPointerSizeLog2));
5222+
__ Add(x0, x0, Operand(3));
52245223
break;
52255224
case NONE:
5226-
__ Mov(x0, Operand(2));
5225+
__ Poke(constructor, 0 * kPointerSize);
5226+
__ Mov(x0, Operand(3));
52275227
break;
52285228
case ONE:
5229-
__ Mov(x0, Operand(3));
5229+
__ Poke(constructor, 1 * kPointerSize);
5230+
__ Mov(x0, Operand(4));
52305231
break;
52315232
}
5232-
__ JumpToExternalReference(
5233-
ExternalReference(Runtime::kArrayConstructorWithSubclassing, isolate()));
5233+
__ Push(new_target, allocation_site);
5234+
__ JumpToExternalReference(ExternalReference(Runtime::kNewArray, isolate()));
52345235
}
52355236

52365237

src/ia32/code-stubs-ia32.cc

+11-12
Original file line numberDiff line numberDiff line change
@@ -5019,27 +5019,26 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
50195019

50205020
// Subclassing.
50215021
__ bind(&subclassing);
5022-
__ pop(ecx); // return address.
5023-
__ push(edi);
5024-
__ push(edx);
5025-
5026-
// Adjust argc.
50275022
switch (argument_count()) {
50285023
case ANY:
50295024
case MORE_THAN_ONE:
5030-
__ add(eax, Immediate(2));
5025+
__ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
5026+
__ add(eax, Immediate(3));
50315027
break;
50325028
case NONE:
5033-
__ mov(eax, Immediate(2));
5029+
__ mov(Operand(esp, 1 * kPointerSize), edi);
5030+
__ mov(eax, Immediate(3));
50345031
break;
50355032
case ONE:
5036-
__ mov(eax, Immediate(3));
5033+
__ mov(Operand(esp, 2 * kPointerSize), edi);
5034+
__ mov(eax, Immediate(4));
50375035
break;
50385036
}
5039-
5040-
__ push(ecx);
5041-
__ JumpToExternalReference(
5042-
ExternalReference(Runtime::kArrayConstructorWithSubclassing, isolate()));
5037+
__ PopReturnAddressTo(ecx);
5038+
__ Push(edx);
5039+
__ Push(ebx);
5040+
__ PushReturnAddressFrom(ecx);
5041+
__ JumpToExternalReference(ExternalReference(Runtime::kNewArray, isolate()));
50435042
}
50445043

50455044

src/mips/code-stubs-mips.cc

+10-10
Original file line numberDiff line numberDiff line change
@@ -5030,26 +5030,26 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
50305030

50315031
// Subclassing.
50325032
__ bind(&subclassing);
5033-
__ Push(a1);
5034-
__ Push(a3);
5035-
5036-
// Adjust argc.
50375033
switch (argument_count()) {
50385034
case ANY:
50395035
case MORE_THAN_ONE:
5040-
__ li(at, Operand(2));
5036+
__ sll(at, a0, kPointerSizeLog2);
5037+
__ addu(at, sp, at);
5038+
__ sw(a1, MemOperand(at));
5039+
__ li(at, Operand(3));
50415040
__ addu(a0, a0, at);
50425041
break;
50435042
case NONE:
5044-
__ li(a0, Operand(2));
5043+
__ sw(a1, MemOperand(sp, 0 * kPointerSize));
5044+
__ li(a0, Operand(3));
50455045
break;
50465046
case ONE:
5047-
__ li(a0, Operand(3));
5047+
__ sw(a1, MemOperand(sp, 1 * kPointerSize));
5048+
__ li(a0, Operand(4));
50485049
break;
50495050
}
5050-
5051-
__ JumpToExternalReference(
5052-
ExternalReference(Runtime::kArrayConstructorWithSubclassing, isolate()));
5051+
__ Push(a3, a2);
5052+
__ JumpToExternalReference(ExternalReference(Runtime::kNewArray, isolate()));
50535053
}
50545054

50555055

src/mips64/code-stubs-mips64.cc

+11-11
Original file line numberDiff line numberDiff line change
@@ -5055,26 +5055,26 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
50555055

50565056
// Subclassing.
50575057
__ bind(&subclassing);
5058-
__ Push(a1);
5059-
__ Push(a3);
5060-
5061-
// Adjust argc.
50625058
switch (argument_count()) {
50635059
case ANY:
50645060
case MORE_THAN_ONE:
5065-
__ li(at, Operand(2));
5066-
__ addu(a0, a0, at);
5061+
__ dsll(at, a0, kPointerSizeLog2);
5062+
__ Daddu(at, sp, at);
5063+
__ sd(a1, MemOperand(at));
5064+
__ li(at, Operand(3));
5065+
__ Daddu(a0, a0, at);
50675066
break;
50685067
case NONE:
5069-
__ li(a0, Operand(2));
5068+
__ sd(a1, MemOperand(sp, 0 * kPointerSize));
5069+
__ li(a0, Operand(3));
50705070
break;
50715071
case ONE:
5072-
__ li(a0, Operand(3));
5072+
__ sd(a1, MemOperand(sp, 1 * kPointerSize));
5073+
__ li(a0, Operand(4));
50735074
break;
50745075
}
5075-
5076-
__ JumpToExternalReference(
5077-
ExternalReference(Runtime::kArrayConstructorWithSubclassing, isolate()));
5076+
__ Push(a3, a2);
5077+
__ JumpToExternalReference(ExternalReference(Runtime::kNewArray, isolate()));
50785078
}
50795079

50805080

src/runtime/runtime-array.cc

+64-68
Original file line numberDiff line numberDiff line change
@@ -233,15 +233,24 @@ RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
233233
}
234234

235235

236-
static Object* ArrayConstructorCommon(Isolate* isolate,
237-
Handle<JSFunction> constructor,
238-
Handle<JSFunction> new_target,
239-
Handle<AllocationSite> site,
240-
Arguments* caller_args) {
236+
namespace {
237+
238+
Object* ArrayConstructorCommon(Isolate* isolate, Handle<JSFunction> constructor,
239+
Handle<JSReceiver> new_target,
240+
Handle<AllocationSite> site,
241+
Arguments* caller_args) {
241242
Factory* factory = isolate->factory();
242243

244+
// If called through new, new.target can be:
245+
// - a subclass of constructor,
246+
// - a proxy wrapper around constructor, or
247+
// - the constructor itself.
248+
// If called through Reflect.construct, it's guaranteed to be a constructor by
249+
// REFLECT_CONSTRUCT_PREPARE.
250+
DCHECK(new_target->IsConstructor());
251+
243252
bool holey = false;
244-
bool can_use_type_feedback = true;
253+
bool can_use_type_feedback = !site.is_null();
245254
bool can_inline_array_constructor = true;
246255
if (caller_args->length() == 1) {
247256
Handle<Object> argument_one = caller_args->at<Object>(0);
@@ -263,43 +272,42 @@ static Object* ArrayConstructorCommon(Isolate* isolate,
263272
}
264273
}
265274

266-
Handle<JSArray> array;
267-
if (!site.is_null() && can_use_type_feedback) {
268-
ElementsKind to_kind = site->GetElementsKind();
269-
if (holey && !IsFastHoleyElementsKind(to_kind)) {
270-
to_kind = GetHoleyElementsKind(to_kind);
271-
// Update the allocation site info to reflect the advice alteration.
272-
site->SetElementsKind(to_kind);
273-
}
275+
// TODO(verwaest): new_target could be a proxy. Read new.target.prototype in
276+
// that case.
277+
Handle<JSFunction> original_function = Handle<JSFunction>::cast(new_target);
274278

275-
// We should allocate with an initial map that reflects the allocation site
276-
// advice. Therefore we use AllocateJSObjectFromMap instead of passing
277-
// the constructor.
278-
Handle<Map> initial_map(constructor->initial_map(), isolate);
279-
if (to_kind != initial_map->elements_kind()) {
280-
initial_map = Map::AsElementsKind(initial_map, to_kind);
281-
}
279+
JSFunction::EnsureHasInitialMap(constructor);
282280

283-
// If we don't care to track arrays of to_kind ElementsKind, then
284-
// don't emit a memento for them.
285-
Handle<AllocationSite> allocation_site;
286-
if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) {
287-
allocation_site = site;
288-
}
281+
// TODO(verwaest): original_function could have non-instance-prototype
282+
// (non-JSReceiver), requiring fallback to the intrinsicDefaultProto.
283+
Handle<Map> initial_map =
284+
JSFunction::EnsureDerivedHasInitialMap(original_function, constructor);
289285

290-
array = Handle<JSArray>::cast(
291-
factory->NewJSObjectFromMap(initial_map, NOT_TENURED, allocation_site));
292-
} else {
293-
array = Handle<JSArray>::cast(factory->NewJSObject(constructor));
286+
ElementsKind to_kind = can_use_type_feedback ? site->GetElementsKind()
287+
: initial_map->elements_kind();
288+
if (holey && !IsFastHoleyElementsKind(to_kind)) {
289+
to_kind = GetHoleyElementsKind(to_kind);
290+
// Update the allocation site info to reflect the advice alteration.
291+
if (!site.is_null()) site->SetElementsKind(to_kind);
292+
}
294293

295-
// We might need to transition to holey
296-
ElementsKind kind = constructor->initial_map()->elements_kind();
297-
if (holey && !IsFastHoleyElementsKind(kind)) {
298-
kind = GetHoleyElementsKind(kind);
299-
JSObject::TransitionElementsKind(array, kind);
300-
}
294+
// We should allocate with an initial map that reflects the allocation site
295+
// advice. Therefore we use AllocateJSObjectFromMap instead of passing
296+
// the constructor.
297+
if (to_kind != initial_map->elements_kind()) {
298+
initial_map = Map::AsElementsKind(initial_map, to_kind);
299+
}
300+
301+
// If we don't care to track arrays of to_kind ElementsKind, then
302+
// don't emit a memento for them.
303+
Handle<AllocationSite> allocation_site;
304+
if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) {
305+
allocation_site = site;
301306
}
302307

308+
Handle<JSArray> array = Handle<JSArray>::cast(
309+
factory->NewJSObjectFromMap(initial_map, NOT_TENURED, allocation_site));
310+
303311
factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
304312

305313
ElementsKind old_kind = array->GetElementsKind();
@@ -314,21 +322,28 @@ static Object* ArrayConstructorCommon(Isolate* isolate,
314322
site->SetDoNotInlineCall();
315323
}
316324

317-
// Set up the prototoype using original function.
318-
// TODO(dslomov): instead of setting the __proto__,
319-
// use and cache the correct map.
320-
if (*new_target != *constructor) {
321-
if (new_target->has_instance_prototype()) {
322-
Handle<Object> prototype(new_target->instance_prototype(), isolate);
323-
MAYBE_RETURN(JSObject::SetPrototype(array, prototype, false,
324-
Object::THROW_ON_ERROR),
325-
isolate->heap()->exception());
326-
}
327-
}
328-
329325
return *array;
330326
}
331327

328+
} // namespace
329+
330+
331+
RUNTIME_FUNCTION(Runtime_NewArray) {
332+
HandleScope scope(isolate);
333+
DCHECK_LE(3, args.length());
334+
int const argc = args.length() - 3;
335+
// TODO(bmeurer): Remove this Arguments nonsense.
336+
Arguments argv(argc, args.arguments() - 1);
337+
CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
338+
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, argc + 1);
339+
CONVERT_ARG_HANDLE_CHECKED(HeapObject, type_info, argc + 2);
340+
// TODO(bmeurer): Use MaybeHandle to pass around the AllocationSite.
341+
Handle<AllocationSite> site = type_info->IsAllocationSite()
342+
? Handle<AllocationSite>::cast(type_info)
343+
: Handle<AllocationSite>::null();
344+
return ArrayConstructorCommon(isolate, constructor, new_target, site, &argv);
345+
}
346+
332347

333348
RUNTIME_FUNCTION(Runtime_ArrayConstructor) {
334349
HandleScope scope(isolate);
@@ -364,25 +379,6 @@ RUNTIME_FUNCTION(Runtime_ArrayConstructor) {
364379
}
365380

366381

367-
RUNTIME_FUNCTION(Runtime_ArrayConstructorWithSubclassing) {
368-
HandleScope scope(isolate);
369-
int args_length = args.length();
370-
CHECK(args_length >= 2);
371-
372-
// This variables and checks work around -Werror=strict-overflow.
373-
int pre_last_arg_index = args_length - 2;
374-
int last_arg_index = args_length - 1;
375-
CHECK(pre_last_arg_index >= 0);
376-
CHECK(last_arg_index >= 0);
377-
378-
CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, pre_last_arg_index);
379-
CONVERT_ARG_HANDLE_CHECKED(JSFunction, new_target, last_arg_index);
380-
Arguments caller_args(args_length - 2, args.arguments());
381-
return ArrayConstructorCommon(isolate, constructor, new_target,
382-
Handle<AllocationSite>::null(), &caller_args);
383-
}
384-
385-
386382
RUNTIME_FUNCTION(Runtime_InternalArrayConstructor) {
387383
HandleScope scope(isolate);
388384
Arguments empty_args(0, NULL);

src/runtime/runtime.h

+20-20
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,26 @@ namespace internal {
3030

3131
// Entries have the form F(name, number of arguments, number of values):
3232

33-
#define FOR_EACH_INTRINSIC_ARRAY(F) \
34-
F(FinishArrayPrototypeSetup, 1, 1) \
35-
F(SpecialArrayFunctions, 0, 1) \
36-
F(TransitionElementsKind, 2, 1) \
37-
F(PushIfAbsent, 2, 1) \
38-
F(RemoveArrayHoles, 2, 1) \
39-
F(MoveArrayContents, 2, 1) \
40-
F(EstimateNumberOfElements, 1, 1) \
41-
F(GetArrayKeys, 2, 1) \
42-
F(ArrayConstructor, -1, 1) \
43-
F(ArrayConstructorWithSubclassing, -1, 1) \
44-
F(InternalArrayConstructor, -1, 1) \
45-
F(NormalizeElements, 1, 1) \
46-
F(GrowArrayElements, 2, 1) \
47-
F(HasComplexElements, 1, 1) \
48-
F(IsArray, 1, 1) \
49-
F(HasCachedArrayIndex, 1, 1) \
50-
F(GetCachedArrayIndex, 1, 1) \
51-
F(FixedArrayGet, 2, 1) \
52-
F(FixedArraySet, 3, 1) \
33+
#define FOR_EACH_INTRINSIC_ARRAY(F) \
34+
F(FinishArrayPrototypeSetup, 1, 1) \
35+
F(SpecialArrayFunctions, 0, 1) \
36+
F(TransitionElementsKind, 2, 1) \
37+
F(PushIfAbsent, 2, 1) \
38+
F(RemoveArrayHoles, 2, 1) \
39+
F(MoveArrayContents, 2, 1) \
40+
F(EstimateNumberOfElements, 1, 1) \
41+
F(GetArrayKeys, 2, 1) \
42+
F(ArrayConstructor, -1, 1) \
43+
F(NewArray, -1 /* >= 3 */, 1) \
44+
F(InternalArrayConstructor, -1, 1) \
45+
F(NormalizeElements, 1, 1) \
46+
F(GrowArrayElements, 2, 1) \
47+
F(HasComplexElements, 1, 1) \
48+
F(IsArray, 1, 1) \
49+
F(HasCachedArrayIndex, 1, 1) \
50+
F(GetCachedArrayIndex, 1, 1) \
51+
F(FixedArrayGet, 2, 1) \
52+
F(FixedArraySet, 3, 1) \
5353
F(FastOneByteArrayJoin, 2, 1)
5454

5555

0 commit comments

Comments
 (0)