Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(746)

Side by Side Diff: src/runtime/runtime-array.cc

Issue 1456423003: [runtime] Introduce a proper %NewArray runtime entry. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/runtime/runtime.h ('k') | src/x64/code-stubs-x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/runtime/runtime-utils.h" 5 #include "src/runtime/runtime-utils.h"
6 6
7 #include "src/arguments.h" 7 #include "src/arguments.h"
8 #include "src/conversions-inl.h" 8 #include "src/conversions-inl.h"
9 #include "src/elements.h" 9 #include "src/elements.h"
10 #include "src/factory.h" 10 #include "src/factory.h"
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 // TODO(adamk): Remove this step when the contract of %GetArrayKeys 226 // TODO(adamk): Remove this step when the contract of %GetArrayKeys
227 // is changed to let this happen on the JS side. 227 // is changed to let this happen on the JS side.
228 Handle<FixedArray> keys = accumulator.GetKeys(KEEP_NUMBERS); 228 Handle<FixedArray> keys = accumulator.GetKeys(KEEP_NUMBERS);
229 for (int i = 0; i < keys->length(); i++) { 229 for (int i = 0; i < keys->length(); i++) {
230 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i); 230 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i);
231 } 231 }
232 return *isolate->factory()->NewJSArrayWithElements(keys); 232 return *isolate->factory()->NewJSArrayWithElements(keys);
233 } 233 }
234 234
235 235
236 static Object* ArrayConstructorCommon(Isolate* isolate, 236 namespace {
237 Handle<JSFunction> constructor, 237
238 Handle<JSFunction> new_target, 238 Object* ArrayConstructorCommon(Isolate* isolate, Handle<JSFunction> constructor,
239 Handle<AllocationSite> site, 239 Handle<JSReceiver> new_target,
240 Arguments* caller_args) { 240 Handle<AllocationSite> site,
241 Arguments* caller_args) {
241 Factory* factory = isolate->factory(); 242 Factory* factory = isolate->factory();
242 243
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
243 bool holey = false; 252 bool holey = false;
244 bool can_use_type_feedback = true; 253 bool can_use_type_feedback = !site.is_null();
245 bool can_inline_array_constructor = true; 254 bool can_inline_array_constructor = true;
246 if (caller_args->length() == 1) { 255 if (caller_args->length() == 1) {
247 Handle<Object> argument_one = caller_args->at<Object>(0); 256 Handle<Object> argument_one = caller_args->at<Object>(0);
248 if (argument_one->IsSmi()) { 257 if (argument_one->IsSmi()) {
249 int value = Handle<Smi>::cast(argument_one)->value(); 258 int value = Handle<Smi>::cast(argument_one)->value();
250 if (value < 0 || 259 if (value < 0 ||
251 JSArray::SetLengthWouldNormalize(isolate->heap(), value)) { 260 JSArray::SetLengthWouldNormalize(isolate->heap(), value)) {
252 // the array is a dictionary in this case. 261 // the array is a dictionary in this case.
253 can_use_type_feedback = false; 262 can_use_type_feedback = false;
254 } else if (value != 0) { 263 } else if (value != 0) {
255 holey = true; 264 holey = true;
256 if (value >= JSArray::kInitialMaxFastElementArray) { 265 if (value >= JSArray::kInitialMaxFastElementArray) {
257 can_inline_array_constructor = false; 266 can_inline_array_constructor = false;
258 } 267 }
259 } 268 }
260 } else { 269 } else {
261 // Non-smi length argument produces a dictionary 270 // Non-smi length argument produces a dictionary
262 can_use_type_feedback = false; 271 can_use_type_feedback = false;
263 } 272 }
264 } 273 }
265 274
266 Handle<JSArray> array; 275 // TODO(verwaest): new_target could be a proxy. Read new.target.prototype in
267 if (!site.is_null() && can_use_type_feedback) { 276 // that case.
268 ElementsKind to_kind = site->GetElementsKind(); 277 Handle<JSFunction> original_function = Handle<JSFunction>::cast(new_target);
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 }
274 278
275 // We should allocate with an initial map that reflects the allocation site 279 JSFunction::EnsureHasInitialMap(constructor);
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 }
282 280
283 // If we don't care to track arrays of to_kind ElementsKind, then 281 // TODO(verwaest): original_function could have non-instance-prototype
284 // don't emit a memento for them. 282 // (non-JSReceiver), requiring fallback to the intrinsicDefaultProto.
285 Handle<AllocationSite> allocation_site; 283 Handle<Map> initial_map =
286 if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) { 284 JSFunction::EnsureDerivedHasInitialMap(original_function, constructor);
287 allocation_site = site;
288 }
289 285
290 array = Handle<JSArray>::cast( 286 ElementsKind to_kind = can_use_type_feedback ? site->GetElementsKind()
291 factory->NewJSObjectFromMap(initial_map, NOT_TENURED, allocation_site)); 287 : initial_map->elements_kind();
292 } else { 288 if (holey && !IsFastHoleyElementsKind(to_kind)) {
293 array = Handle<JSArray>::cast(factory->NewJSObject(constructor)); 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 }
294 293
295 // We might need to transition to holey 294 // We should allocate with an initial map that reflects the allocation site
296 ElementsKind kind = constructor->initial_map()->elements_kind(); 295 // advice. Therefore we use AllocateJSObjectFromMap instead of passing
297 if (holey && !IsFastHoleyElementsKind(kind)) { 296 // the constructor.
298 kind = GetHoleyElementsKind(kind); 297 if (to_kind != initial_map->elements_kind()) {
299 JSObject::TransitionElementsKind(array, kind); 298 initial_map = Map::AsElementsKind(initial_map, to_kind);
300 }
301 } 299 }
302 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;
306 }
307
308 Handle<JSArray> array = Handle<JSArray>::cast(
309 factory->NewJSObjectFromMap(initial_map, NOT_TENURED, allocation_site));
310
303 factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS); 311 factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
304 312
305 ElementsKind old_kind = array->GetElementsKind(); 313 ElementsKind old_kind = array->GetElementsKind();
306 RETURN_FAILURE_ON_EXCEPTION( 314 RETURN_FAILURE_ON_EXCEPTION(
307 isolate, ArrayConstructInitializeElements(array, caller_args)); 315 isolate, ArrayConstructInitializeElements(array, caller_args));
308 if (!site.is_null() && 316 if (!site.is_null() &&
309 (old_kind != array->GetElementsKind() || !can_use_type_feedback || 317 (old_kind != array->GetElementsKind() || !can_use_type_feedback ||
310 !can_inline_array_constructor)) { 318 !can_inline_array_constructor)) {
311 // The arguments passed in caused a transition. This kind of complexity 319 // The arguments passed in caused a transition. This kind of complexity
312 // can't be dealt with in the inlined hydrogen array constructor case. 320 // can't be dealt with in the inlined hydrogen array constructor case.
313 // We must mark the allocationsite as un-inlinable. 321 // We must mark the allocationsite as un-inlinable.
314 site->SetDoNotInlineCall(); 322 site->SetDoNotInlineCall();
315 } 323 }
316 324
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
329 return *array; 325 return *array;
330 } 326 }
331 327
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
332 347
333 RUNTIME_FUNCTION(Runtime_ArrayConstructor) { 348 RUNTIME_FUNCTION(Runtime_ArrayConstructor) {
334 HandleScope scope(isolate); 349 HandleScope scope(isolate);
335 // If we get 2 arguments then they are the stub parameters (constructor, type 350 // If we get 2 arguments then they are the stub parameters (constructor, type
336 // info). If we get 4, then the first one is a pointer to the arguments 351 // info). If we get 4, then the first one is a pointer to the arguments
337 // passed by the caller, and the last one is the length of the arguments 352 // passed by the caller, and the last one is the length of the arguments
338 // passed to the caller (redundant, but useful to check on the deoptimizer 353 // passed to the caller (redundant, but useful to check on the deoptimizer
339 // with an assert). 354 // with an assert).
340 Arguments empty_args(0, NULL); 355 Arguments empty_args(0, NULL);
341 bool no_caller_args = args.length() == 2; 356 bool no_caller_args = args.length() == 2;
(...skipping 15 matching lines...) Expand all
357 *type_info != isolate->heap()->undefined_value()) { 372 *type_info != isolate->heap()->undefined_value()) {
358 site = Handle<AllocationSite>::cast(type_info); 373 site = Handle<AllocationSite>::cast(type_info);
359 DCHECK(!site->SitePointsToLiteral()); 374 DCHECK(!site->SitePointsToLiteral());
360 } 375 }
361 376
362 return ArrayConstructorCommon(isolate, constructor, constructor, site, 377 return ArrayConstructorCommon(isolate, constructor, constructor, site,
363 caller_args); 378 caller_args);
364 } 379 }
365 380
366 381
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
386 RUNTIME_FUNCTION(Runtime_InternalArrayConstructor) { 382 RUNTIME_FUNCTION(Runtime_InternalArrayConstructor) {
387 HandleScope scope(isolate); 383 HandleScope scope(isolate);
388 Arguments empty_args(0, NULL); 384 Arguments empty_args(0, NULL);
389 bool no_caller_args = args.length() == 1; 385 bool no_caller_args = args.length() == 1;
390 DCHECK(no_caller_args || args.length() == 3); 386 DCHECK(no_caller_args || args.length() == 3);
391 int parameters_start = no_caller_args ? 0 : 1; 387 int parameters_start = no_caller_args ? 0 : 1;
392 Arguments* caller_args = 388 Arguments* caller_args =
393 no_caller_args ? &empty_args : reinterpret_cast<Arguments*>(args[0]); 389 no_caller_args ? &empty_args : reinterpret_cast<Arguments*>(args[0]);
394 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start); 390 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
395 #ifdef DEBUG 391 #ifdef DEBUG
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 488
493 RUNTIME_FUNCTION(Runtime_FastOneByteArrayJoin) { 489 RUNTIME_FUNCTION(Runtime_FastOneByteArrayJoin) {
494 SealHandleScope shs(isolate); 490 SealHandleScope shs(isolate);
495 DCHECK(args.length() == 2); 491 DCHECK(args.length() == 2);
496 // Returning undefined means that this fast path fails and one has to resort 492 // Returning undefined means that this fast path fails and one has to resort
497 // to a slow path. 493 // to a slow path.
498 return isolate->heap()->undefined_value(); 494 return isolate->heap()->undefined_value();
499 } 495 }
500 } // namespace internal 496 } // namespace internal
501 } // namespace v8 497 } // namespace v8
OLDNEW
« no previous file with comments | « src/runtime/runtime.h ('k') | src/x64/code-stubs-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698