1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "accessors.h"
34 #include "allocation-site-scopes.h"
36 #include "arguments.h"
37 #include "bootstrapper.h"
39 #include "compilation-cache.h"
42 #include "cpu-profiler.h"
43 #include "dateparser-inl.h"
45 #include "deoptimizer.h"
47 #include "execution.h"
48 #include "full-codegen.h"
49 #include "global-handles.h"
50 #include "isolate-inl.h"
52 #include "jsregexp-inl.h"
53 #include "json-parser.h"
54 #include "json-stringifier.h"
56 #include "misc-intrinsics.h"
59 #include "runtime-profiler.h"
61 #include "scopeinfo.h"
62 #include "smart-pointers.h"
63 #include "string-search.h"
64 #include "stub-cache.h"
66 #include "v8conversions.h"
67 #include "v8threads.h"
68 #include "vm-state-inl.h"
70 #ifdef V8_I18N_SUPPORT
72 #include "unicode/brkiter.h"
73 #include "unicode/calendar.h"
74 #include "unicode/coll.h"
75 #include "unicode/curramt.h"
76 #include "unicode/datefmt.h"
77 #include "unicode/dcfmtsym.h"
78 #include "unicode/decimfmt.h"
79 #include "unicode/dtfmtsym.h"
80 #include "unicode/dtptngen.h"
81 #include "unicode/locid.h"
82 #include "unicode/numfmt.h"
83 #include "unicode/numsys.h"
84 #include "unicode/rbbi.h"
85 #include "unicode/smpdtfmt.h"
86 #include "unicode/timezone.h"
87 #include "unicode/uchar.h"
88 #include "unicode/ucol.h"
89 #include "unicode/ucurr.h"
90 #include "unicode/uloc.h"
91 #include "unicode/unum.h"
92 #include "unicode/uversion.h"
95 #ifndef _STLP_VENDOR_CSTD
96 // STLPort doesn't import fpclassify and isless into the std namespace.
97 using std::fpclassify;
105 #define RUNTIME_ASSERT(value) \
106 if (!(value)) return isolate->ThrowIllegalOperation();
108 // Cast the given object to a value of the specified type and store
109 // it in a variable with the given name. If the object is not of the
110 // expected type call IllegalOperation and return.
111 #define CONVERT_ARG_CHECKED(Type, name, index) \
112 RUNTIME_ASSERT(args[index]->Is##Type()); \
113 Type* name = Type::cast(args[index]);
115 #define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
116 RUNTIME_ASSERT(args[index]->Is##Type()); \
117 Handle<Type> name = args.at<Type>(index);
119 // Cast the given object to a boolean and store it in a variable with
120 // the given name. If the object is not a boolean call IllegalOperation
122 #define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
123 RUNTIME_ASSERT(args[index]->IsBoolean()); \
124 bool name = args[index]->IsTrue();
126 // Cast the given argument to a Smi and store its value in an int variable
127 // with the given name. If the argument is not a Smi call IllegalOperation
129 #define CONVERT_SMI_ARG_CHECKED(name, index) \
130 RUNTIME_ASSERT(args[index]->IsSmi()); \
131 int name = args.smi_at(index);
133 // Cast the given argument to a double and store it in a variable with
134 // the given name. If the argument is not a number (as opposed to
135 // the number not-a-number) call IllegalOperation and return.
136 #define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
137 RUNTIME_ASSERT(args[index]->IsNumber()); \
138 double name = args.number_at(index);
140 // Call the specified converter on the object *comand store the result in
141 // a variable of the specified type with the given name. If the
142 // object is not a Number call IllegalOperation and return.
143 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
144 RUNTIME_ASSERT(obj->IsNumber()); \
145 type name = NumberTo##Type(obj);
148 // Cast the given argument to PropertyDetails and store its value in a
149 // variable with the given name. If the argument is not a Smi call
150 // IllegalOperation and return.
151 #define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
152 RUNTIME_ASSERT(args[index]->IsSmi()); \
153 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
156 // Assert that the given argument has a valid value for a StrictMode
157 // and store it in a StrictMode variable with the given name.
158 #define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
159 RUNTIME_ASSERT(args[index]->IsSmi()); \
160 RUNTIME_ASSERT(args.smi_at(index) == STRICT || \
161 args.smi_at(index) == SLOPPY); \
162 StrictMode name = static_cast<StrictMode>(args.smi_at(index));
165 static Handle<Map> ComputeObjectLiteralMap(
166 Handle<Context> context,
167 Handle<FixedArray> constant_properties,
168 bool* is_result_from_cache) {
169 Isolate* isolate = context->GetIsolate();
170 int properties_length = constant_properties->length();
171 int number_of_properties = properties_length / 2;
172 // Check that there are only internal strings and array indices among keys.
173 int number_of_string_keys = 0;
174 for (int p = 0; p != properties_length; p += 2) {
175 Object* key = constant_properties->get(p);
176 uint32_t element_index = 0;
177 if (key->IsInternalizedString()) {
178 number_of_string_keys++;
179 } else if (key->ToArrayIndex(&element_index)) {
180 // An index key does not require space in the property backing store.
181 number_of_properties--;
183 // Bail out as a non-internalized-string non-index key makes caching
185 // ASSERT to make sure that the if condition after the loop is false.
186 ASSERT(number_of_string_keys != number_of_properties);
190 // If we only have internalized strings and array indices among keys then we
191 // can use the map cache in the native context.
192 const int kMaxKeys = 10;
193 if ((number_of_string_keys == number_of_properties) &&
194 (number_of_string_keys < kMaxKeys)) {
195 // Create the fixed array with the key.
196 Handle<FixedArray> keys =
197 isolate->factory()->NewFixedArray(number_of_string_keys);
198 if (number_of_string_keys > 0) {
200 for (int p = 0; p < properties_length; p += 2) {
201 Object* key = constant_properties->get(p);
202 if (key->IsInternalizedString()) {
203 keys->set(index++, key);
206 ASSERT(index == number_of_string_keys);
208 *is_result_from_cache = true;
209 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
211 *is_result_from_cache = false;
212 return isolate->factory()->CopyMap(
213 Handle<Map>(context->object_function()->initial_map()),
214 number_of_properties);
218 static Handle<Object> CreateLiteralBoilerplate(
220 Handle<FixedArray> literals,
221 Handle<FixedArray> constant_properties);
224 static Handle<Object> CreateObjectLiteralBoilerplate(
226 Handle<FixedArray> literals,
227 Handle<FixedArray> constant_properties,
228 bool should_have_fast_elements,
229 bool has_function_literal) {
230 // Get the native context from the literals array. This is the
231 // context in which the function was created and we use the object
232 // function from this context to create the object literal. We do
233 // not use the object function from the current native context
234 // because this might be the object function from another context
235 // which we should not have access to.
236 Handle<Context> context =
237 Handle<Context>(JSFunction::NativeContextFromLiterals(*literals));
239 // In case we have function literals, we want the object to be in
240 // slow properties mode for now. We don't go in the map cache because
241 // maps with constant functions can't be shared if the functions are
242 // not the same (which is the common case).
243 bool is_result_from_cache = false;
244 Handle<Map> map = has_function_literal
245 ? Handle<Map>(context->object_function()->initial_map())
246 : ComputeObjectLiteralMap(context,
248 &is_result_from_cache);
250 PretenureFlag pretenure_flag =
251 isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
253 Handle<JSObject> boilerplate =
254 isolate->factory()->NewJSObjectFromMap(map, pretenure_flag);
256 // Normalize the elements of the boilerplate to save space if needed.
257 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
259 // Add the constant properties to the boilerplate.
260 int length = constant_properties->length();
261 bool should_transform =
262 !is_result_from_cache && boilerplate->HasFastProperties();
263 if (should_transform || has_function_literal) {
264 // Normalize the properties of object to avoid n^2 behavior
265 // when extending the object multiple properties. Indicate the number of
266 // properties to be added.
267 JSObject::NormalizeProperties(
268 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
271 // TODO(verwaest): Support tracking representations in the boilerplate.
272 for (int index = 0; index < length; index +=2) {
273 Handle<Object> key(constant_properties->get(index+0), isolate);
274 Handle<Object> value(constant_properties->get(index+1), isolate);
275 if (value->IsFixedArray()) {
276 // The value contains the constant_properties of a
277 // simple object or array literal.
278 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
279 value = CreateLiteralBoilerplate(isolate, literals, array);
280 if (value.is_null()) return value;
282 Handle<Object> result;
283 uint32_t element_index = 0;
284 StoreMode mode = value->IsJSObject() ? FORCE_FIELD : ALLOW_AS_CONSTANT;
285 if (key->IsInternalizedString()) {
286 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
287 // Array index as string (uint32).
288 result = JSObject::SetOwnElement(
289 boilerplate, element_index, value, SLOPPY);
291 Handle<String> name(String::cast(*key));
292 ASSERT(!name->AsArrayIndex(&element_index));
293 result = JSObject::SetLocalPropertyIgnoreAttributes(
294 boilerplate, name, value, NONE,
295 Object::OPTIMAL_REPRESENTATION, mode);
297 } else if (key->ToArrayIndex(&element_index)) {
298 // Array index (uint32).
299 result = JSObject::SetOwnElement(
300 boilerplate, element_index, value, SLOPPY);
302 // Non-uint32 number.
303 ASSERT(key->IsNumber());
304 double num = key->Number();
306 Vector<char> buffer(arr, ARRAY_SIZE(arr));
307 const char* str = DoubleToCString(num, buffer);
308 Handle<String> name =
309 isolate->factory()->NewStringFromAscii(CStrVector(str));
310 result = JSObject::SetLocalPropertyIgnoreAttributes(
311 boilerplate, name, value, NONE,
312 Object::OPTIMAL_REPRESENTATION, mode);
314 // If setting the property on the boilerplate throws an
315 // exception, the exception is converted to an empty handle in
316 // the handle based operations. In that case, we need to
317 // convert back to an exception.
318 if (result.is_null()) return result;
321 // Transform to fast properties if necessary. For object literals with
322 // containing function literals we defer this operation until after all
323 // computed properties have been assigned so that we can generate
324 // constant function properties.
325 if (should_transform && !has_function_literal) {
326 JSObject::TransformToFastProperties(
327 boilerplate, boilerplate->map()->unused_property_fields());
334 MaybeObject* TransitionElements(Handle<Object> object,
335 ElementsKind to_kind,
337 HandleScope scope(isolate);
338 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
339 ElementsKind from_kind =
340 Handle<JSObject>::cast(object)->map()->elements_kind();
341 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
342 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
345 return isolate->ThrowIllegalOperation();
349 static const int kSmiLiteralMinimumLength = 1024;
352 Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
354 Handle<FixedArray> literals,
355 Handle<FixedArray> elements) {
356 // Create the JSArray.
357 Handle<JSFunction> constructor(
358 JSFunction::NativeContextFromLiterals(*literals)->array_function());
360 PretenureFlag pretenure_flag =
361 isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
363 Handle<JSArray> object = Handle<JSArray>::cast(
364 isolate->factory()->NewJSObject(constructor, pretenure_flag));
366 ElementsKind constant_elements_kind =
367 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
368 Handle<FixedArrayBase> constant_elements_values(
369 FixedArrayBase::cast(elements->get(1)));
371 ASSERT(IsFastElementsKind(constant_elements_kind));
372 Context* native_context = isolate->context()->native_context();
373 Object* maybe_maps_array = native_context->js_array_maps();
374 ASSERT(!maybe_maps_array->IsUndefined());
375 Object* maybe_map = FixedArray::cast(maybe_maps_array)->get(
376 constant_elements_kind);
377 ASSERT(maybe_map->IsMap());
378 object->set_map(Map::cast(maybe_map));
380 Handle<FixedArrayBase> copied_elements_values;
381 if (IsFastDoubleElementsKind(constant_elements_kind)) {
382 ASSERT(FLAG_smi_only_arrays);
383 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
384 Handle<FixedDoubleArray>::cast(constant_elements_values));
386 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind));
388 (constant_elements_values->map() ==
389 isolate->heap()->fixed_cow_array_map());
391 copied_elements_values = constant_elements_values;
393 Handle<FixedArray> fixed_array_values =
394 Handle<FixedArray>::cast(copied_elements_values);
395 for (int i = 0; i < fixed_array_values->length(); i++) {
396 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
400 Handle<FixedArray> fixed_array_values =
401 Handle<FixedArray>::cast(constant_elements_values);
402 Handle<FixedArray> fixed_array_values_copy =
403 isolate->factory()->CopyFixedArray(fixed_array_values);
404 copied_elements_values = fixed_array_values_copy;
405 for (int i = 0; i < fixed_array_values->length(); i++) {
406 Object* current = fixed_array_values->get(i);
407 if (current->IsFixedArray()) {
408 // The value contains the constant_properties of a
409 // simple object or array literal.
410 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
411 Handle<Object> result =
412 CreateLiteralBoilerplate(isolate, literals, fa);
413 if (result.is_null()) return result;
414 fixed_array_values_copy->set(i, *result);
419 object->set_elements(*copied_elements_values);
420 object->set_length(Smi::FromInt(copied_elements_values->length()));
422 // Ensure that the boilerplate object has FAST_*_ELEMENTS, unless the flag is
423 // on or the object is larger than the threshold.
424 if (!FLAG_smi_only_arrays &&
425 constant_elements_values->length() < kSmiLiteralMinimumLength) {
426 ElementsKind elements_kind = object->GetElementsKind();
427 if (!IsFastObjectElementsKind(elements_kind)) {
428 if (IsFastHoleyElementsKind(elements_kind)) {
429 CHECK(!TransitionElements(object, FAST_HOLEY_ELEMENTS,
430 isolate)->IsFailure());
432 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
437 object->ValidateElements();
442 static Handle<Object> CreateLiteralBoilerplate(
444 Handle<FixedArray> literals,
445 Handle<FixedArray> array) {
446 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
447 const bool kHasNoFunctionLiteral = false;
448 switch (CompileTimeValue::GetLiteralType(array)) {
449 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
450 return CreateObjectLiteralBoilerplate(isolate,
454 kHasNoFunctionLiteral);
455 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
456 return CreateObjectLiteralBoilerplate(isolate,
460 kHasNoFunctionLiteral);
461 case CompileTimeValue::ARRAY_LITERAL:
462 return Runtime::CreateArrayLiteralBoilerplate(
463 isolate, literals, elements);
466 return Handle<Object>::null();
471 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_CreateObjectLiteral) {
472 HandleScope scope(isolate);
473 ASSERT(args.length() == 4);
474 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
475 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
476 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
477 CONVERT_SMI_ARG_CHECKED(flags, 3);
478 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
479 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
481 // Check if boilerplate exists. If not, create it first.
482 Handle<Object> literal_site(literals->get(literals_index), isolate);
483 Handle<AllocationSite> site;
484 Handle<JSObject> boilerplate;
485 if (*literal_site == isolate->heap()->undefined_value()) {
486 Handle<Object> raw_boilerplate = CreateObjectLiteralBoilerplate(
490 should_have_fast_elements,
491 has_function_literal);
492 RETURN_IF_EMPTY_HANDLE(isolate, raw_boilerplate);
493 boilerplate = Handle<JSObject>::cast(raw_boilerplate);
495 AllocationSiteCreationContext creation_context(isolate);
496 site = creation_context.EnterNewScope();
497 RETURN_IF_EMPTY_HANDLE(isolate,
498 JSObject::DeepWalk(boilerplate, &creation_context));
499 creation_context.ExitScope(site, boilerplate);
501 // Update the functions literal and return the boilerplate.
502 literals->set(literals_index, *site);
504 site = Handle<AllocationSite>::cast(literal_site);
505 boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
509 AllocationSiteUsageContext usage_context(isolate, site, true);
510 usage_context.EnterNewScope();
511 Handle<Object> copy = JSObject::DeepCopy(boilerplate, &usage_context);
512 usage_context.ExitScope(site, boilerplate);
513 RETURN_IF_EMPTY_HANDLE(isolate, copy);
518 static Handle<AllocationSite> GetLiteralAllocationSite(
520 Handle<FixedArray> literals,
522 Handle<FixedArray> elements) {
523 // Check if boilerplate exists. If not, create it first.
524 Handle<Object> literal_site(literals->get(literals_index), isolate);
525 Handle<AllocationSite> site;
526 if (*literal_site == isolate->heap()->undefined_value()) {
527 ASSERT(*elements != isolate->heap()->empty_fixed_array());
528 Handle<Object> boilerplate =
529 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
530 if (boilerplate.is_null()) return Handle<AllocationSite>::null();
532 AllocationSiteCreationContext creation_context(isolate);
533 site = creation_context.EnterNewScope();
534 if (JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate),
535 &creation_context).is_null()) {
536 return Handle<AllocationSite>::null();
538 creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate));
540 literals->set(literals_index, *site);
542 site = Handle<AllocationSite>::cast(literal_site);
549 static MaybeObject* CreateArrayLiteralImpl(Isolate* isolate,
550 Handle<FixedArray> literals,
552 Handle<FixedArray> elements,
554 Handle<AllocationSite> site = GetLiteralAllocationSite(isolate, literals,
555 literals_index, elements);
556 RETURN_IF_EMPTY_HANDLE(isolate, site);
558 bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0;
559 Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
560 AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
561 usage_context.EnterNewScope();
562 JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0
564 : JSObject::kObjectIsShallowArray;
565 Handle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context,
567 usage_context.ExitScope(site, boilerplate);
568 RETURN_IF_EMPTY_HANDLE(isolate, copy);
573 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_CreateArrayLiteral) {
574 HandleScope scope(isolate);
575 ASSERT(args.length() == 4);
576 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
577 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
578 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
579 CONVERT_SMI_ARG_CHECKED(flags, 3);
581 return CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
586 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_CreateArrayLiteralStubBailout) {
587 HandleScope scope(isolate);
588 ASSERT(args.length() == 3);
589 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
590 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
591 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
593 return CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
594 ArrayLiteral::kShallowElements);
598 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) {
599 HandleScope scope(isolate);
600 ASSERT(args.length() == 1);
601 Handle<Object> name(args[0], isolate);
602 RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
604 MaybeObject* maybe = isolate->heap()->AllocateSymbol();
605 if (!maybe->To(&symbol)) return maybe;
606 if (name->IsString()) symbol->set_name(*name);
611 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreatePrivateSymbol) {
612 HandleScope scope(isolate);
613 ASSERT(args.length() == 1);
614 Handle<Object> name(args[0], isolate);
615 RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
617 MaybeObject* maybe = isolate->heap()->AllocatePrivateSymbol();
618 if (!maybe->To(&symbol)) return maybe;
619 if (name->IsString()) symbol->set_name(*name);
624 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateGlobalPrivateSymbol) {
625 HandleScope scope(isolate);
626 ASSERT(args.length() == 1);
627 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
628 Handle<JSObject> registry = isolate->GetSymbolRegistry();
629 Handle<String> part = isolate->factory()->private_intern_string();
630 Handle<JSObject> privates =
631 Handle<JSObject>::cast(JSObject::GetProperty(registry, part));
632 Handle<Object> symbol = JSObject::GetProperty(privates, name);
633 if (!symbol->IsSymbol()) {
634 ASSERT(symbol->IsUndefined());
635 symbol = isolate->factory()->NewPrivateSymbol();
636 Handle<Symbol>::cast(symbol)->set_name(*name);
637 JSObject::SetProperty(privates, name, symbol, NONE, STRICT);
643 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewSymbolWrapper) {
644 ASSERT(args.length() == 1);
645 CONVERT_ARG_CHECKED(Symbol, symbol, 0);
646 return symbol->ToObject(isolate);
650 RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolDescription) {
651 SealHandleScope shs(isolate);
652 ASSERT(args.length() == 1);
653 CONVERT_ARG_CHECKED(Symbol, symbol, 0);
654 return symbol->name();
658 RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolRegistry) {
659 HandleScope scope(isolate);
660 ASSERT(args.length() == 0);
661 return *isolate->GetSymbolRegistry();
665 RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolIsPrivate) {
666 SealHandleScope shs(isolate);
667 ASSERT(args.length() == 1);
668 CONVERT_ARG_CHECKED(Symbol, symbol, 0);
669 return isolate->heap()->ToBoolean(symbol->is_private());
673 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
674 SealHandleScope shs(isolate);
675 ASSERT(args.length() == 2);
676 CONVERT_ARG_CHECKED(JSReceiver, handler, 0);
677 Object* prototype = args[1];
678 Object* used_prototype =
679 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
680 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
684 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
685 SealHandleScope shs(isolate);
686 ASSERT(args.length() == 4);
687 CONVERT_ARG_CHECKED(JSReceiver, handler, 0);
688 Object* call_trap = args[1];
689 RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy());
690 CONVERT_ARG_CHECKED(JSFunction, construct_trap, 2);
691 Object* prototype = args[3];
692 Object* used_prototype =
693 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
694 return isolate->heap()->AllocateJSFunctionProxy(
695 handler, call_trap, construct_trap, used_prototype);
699 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
700 SealHandleScope shs(isolate);
701 ASSERT(args.length() == 1);
702 Object* obj = args[0];
703 return isolate->heap()->ToBoolean(obj->IsJSProxy());
707 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
708 SealHandleScope shs(isolate);
709 ASSERT(args.length() == 1);
710 Object* obj = args[0];
711 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
715 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
716 SealHandleScope shs(isolate);
717 ASSERT(args.length() == 1);
718 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
719 return proxy->handler();
723 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
724 SealHandleScope shs(isolate);
725 ASSERT(args.length() == 1);
726 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
727 return proxy->call_trap();
731 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
732 SealHandleScope shs(isolate);
733 ASSERT(args.length() == 1);
734 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
735 return proxy->construct_trap();
739 RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
740 HandleScope scope(isolate);
741 ASSERT(args.length() == 1);
742 CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0);
744 return isolate->heap()->undefined_value();
748 void Runtime::FreeArrayBuffer(Isolate* isolate,
749 JSArrayBuffer* phantom_array_buffer) {
750 if (phantom_array_buffer->should_be_freed()) {
751 ASSERT(phantom_array_buffer->is_external());
752 free(phantom_array_buffer->backing_store());
754 if (phantom_array_buffer->is_external()) return;
756 size_t allocated_length = NumberToSize(
757 isolate, phantom_array_buffer->byte_length());
759 isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
760 -static_cast<int64_t>(allocated_length));
761 CHECK(V8::ArrayBufferAllocator() != NULL);
762 V8::ArrayBufferAllocator()->Free(
763 phantom_array_buffer->backing_store(),
768 void Runtime::SetupArrayBuffer(Isolate* isolate,
769 Handle<JSArrayBuffer> array_buffer,
772 size_t allocated_length) {
773 ASSERT(array_buffer->GetInternalFieldCount() ==
774 v8::ArrayBuffer::kInternalFieldCount);
775 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
776 array_buffer->SetInternalField(i, Smi::FromInt(0));
778 array_buffer->set_backing_store(data);
779 array_buffer->set_flag(Smi::FromInt(0));
780 array_buffer->set_is_external(is_external);
782 Handle<Object> byte_length =
783 isolate->factory()->NewNumberFromSize(allocated_length);
784 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
785 array_buffer->set_byte_length(*byte_length);
787 array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
788 isolate->heap()->set_array_buffers_list(*array_buffer);
789 array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
793 bool Runtime::SetupArrayBufferAllocatingData(
795 Handle<JSArrayBuffer> array_buffer,
796 size_t allocated_length,
799 CHECK(V8::ArrayBufferAllocator() != NULL);
800 if (allocated_length != 0) {
802 data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
805 V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
807 if (data == NULL) return false;
812 SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
814 isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length);
820 void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) {
821 Isolate* isolate = array_buffer->GetIsolate();
822 for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate);
823 !view_obj->IsUndefined();) {
824 Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
825 if (view->IsJSTypedArray()) {
826 JSTypedArray::cast(*view)->Neuter();
827 } else if (view->IsJSDataView()) {
828 JSDataView::cast(*view)->Neuter();
832 view_obj = handle(view->weak_next(), isolate);
834 array_buffer->Neuter();
838 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) {
839 HandleScope scope(isolate);
840 ASSERT(args.length() == 2);
841 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
842 CONVERT_ARG_HANDLE_CHECKED(Object, byteLength, 1);
843 size_t allocated_length;
844 if (byteLength->IsSmi()) {
845 allocated_length = Smi::cast(*byteLength)->value();
847 ASSERT(byteLength->IsHeapNumber());
848 double value = HeapNumber::cast(*byteLength)->value();
852 if (value > std::numeric_limits<size_t>::max()) {
853 return isolate->Throw(
854 *isolate->factory()->NewRangeError("invalid_array_buffer_length",
855 HandleVector<Object>(NULL, 0)));
858 allocated_length = static_cast<size_t>(value);
861 if (!Runtime::SetupArrayBufferAllocatingData(isolate,
862 holder, allocated_length)) {
863 return isolate->Throw(*isolate->factory()->
864 NewRangeError("invalid_array_buffer_length",
865 HandleVector<Object>(NULL, 0)));
872 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) {
873 SealHandleScope shs(isolate);
874 ASSERT(args.length() == 1);
875 CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
876 return holder->byte_length();
880 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
881 HandleScope scope(isolate);
882 ASSERT(args.length() == 3);
883 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
884 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
885 CONVERT_DOUBLE_ARG_CHECKED(first, 2);
886 size_t start = static_cast<size_t>(first);
887 size_t target_length = NumberToSize(isolate, target->byte_length());
889 if (target_length == 0) return isolate->heap()->undefined_value();
891 size_t source_byte_length = NumberToSize(isolate, source->byte_length());
892 CHECK(start <= source_byte_length);
893 CHECK(source_byte_length - start >= target_length);
894 uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
895 uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
896 CopyBytes(target_data, source_data + start, target_length);
897 return isolate->heap()->undefined_value();
901 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferIsView) {
902 HandleScope scope(isolate);
903 ASSERT(args.length() == 1);
904 CONVERT_ARG_CHECKED(Object, object, 0);
905 return object->IsJSArrayBufferView()
906 ? isolate->heap()->true_value()
907 : isolate->heap()->false_value();
911 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferNeuter) {
912 HandleScope scope(isolate);
913 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0);
914 if (array_buffer->backing_store() == NULL) {
915 CHECK(Smi::FromInt(0) == array_buffer->byte_length());
916 return isolate->heap()->undefined_value();
918 ASSERT(!array_buffer->is_external());
919 void* backing_store = array_buffer->backing_store();
920 size_t byte_length = NumberToSize(isolate, array_buffer->byte_length());
921 array_buffer->set_is_external(true);
922 Runtime::NeuterArrayBuffer(array_buffer);
923 V8::ArrayBufferAllocator()->Free(backing_store, byte_length);
924 return isolate->heap()->undefined_value();
928 void Runtime::ArrayIdToTypeAndSize(
930 ExternalArrayType* array_type,
931 ElementsKind* external_elements_kind,
932 ElementsKind* fixed_elements_kind,
933 size_t* element_size) {
935 #define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \
936 case ARRAY_ID_##TYPE: \
937 *array_type = kExternal##Type##Array; \
938 *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \
939 *fixed_elements_kind = TYPE##_ELEMENTS; \
940 *element_size = size; \
943 TYPED_ARRAYS(ARRAY_ID_CASE)
952 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
953 HandleScope scope(isolate);
954 ASSERT(args.length() == 5);
955 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
956 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
957 CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2);
958 CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
959 CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
961 ASSERT(holder->GetInternalFieldCount() ==
962 v8::ArrayBufferView::kInternalFieldCount);
963 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
964 holder->SetInternalField(i, Smi::FromInt(0));
967 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
968 size_t element_size = 1; // Bogus initialization.
969 ElementsKind external_elements_kind = EXTERNAL_INT8_ELEMENTS;
970 ElementsKind fixed_elements_kind = INT8_ELEMENTS;
971 Runtime::ArrayIdToTypeAndSize(arrayId,
973 &external_elements_kind,
974 &fixed_elements_kind,
977 holder->set_byte_offset(*byte_offset_object);
978 holder->set_byte_length(*byte_length_object);
980 size_t byte_offset = NumberToSize(isolate, *byte_offset_object);
981 size_t byte_length = NumberToSize(isolate, *byte_length_object);
983 CHECK_EQ(0, static_cast<int>(byte_length % element_size));
984 size_t length = byte_length / element_size;
986 if (length > static_cast<unsigned>(Smi::kMaxValue)) {
987 return isolate->Throw(*isolate->factory()->
988 NewRangeError("invalid_typed_array_length",
989 HandleVector<Object>(NULL, 0)));
992 Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
993 holder->set_length(*length_obj);
994 if (!maybe_buffer->IsNull()) {
995 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(*maybe_buffer));
997 size_t array_buffer_byte_length =
998 NumberToSize(isolate, buffer->byte_length());
999 CHECK(byte_offset <= array_buffer_byte_length);
1000 CHECK(array_buffer_byte_length - byte_offset >= byte_length);
1002 holder->set_buffer(*buffer);
1003 holder->set_weak_next(buffer->weak_first_view());
1004 buffer->set_weak_first_view(*holder);
1006 Handle<ExternalArray> elements =
1007 isolate->factory()->NewExternalArray(
1008 static_cast<int>(length), array_type,
1009 static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
1011 JSObject::GetElementsTransitionMap(holder, external_elements_kind);
1012 holder->set_map_and_elements(*map, *elements);
1013 ASSERT(IsExternalArrayElementsKind(holder->map()->elements_kind()));
1015 holder->set_buffer(Smi::FromInt(0));
1016 holder->set_weak_next(isolate->heap()->undefined_value());
1017 Handle<FixedTypedArrayBase> elements =
1018 isolate->factory()->NewFixedTypedArray(
1019 static_cast<int>(length), array_type);
1020 holder->set_elements(*elements);
1022 return isolate->heap()->undefined_value();
1026 // Initializes a typed array from an array-like object.
1027 // If an array-like object happens to be a typed array of the same type,
1028 // initializes backing store using memove.
1030 // Returns true if backing store was initialized or false otherwise.
1031 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
1032 HandleScope scope(isolate);
1033 ASSERT(args.length() == 4);
1034 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
1035 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
1036 CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
1037 CONVERT_ARG_HANDLE_CHECKED(Object, length_obj, 3);
1039 ASSERT(holder->GetInternalFieldCount() ==
1040 v8::ArrayBufferView::kInternalFieldCount);
1041 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
1042 holder->SetInternalField(i, Smi::FromInt(0));
1045 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
1046 size_t element_size = 1; // Bogus initialization.
1047 ElementsKind external_elements_kind;
1048 ElementsKind fixed_elements_kind;
1049 Runtime::ArrayIdToTypeAndSize(arrayId,
1051 &external_elements_kind,
1052 &fixed_elements_kind,
1055 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
1056 if (source->IsJSTypedArray() &&
1057 JSTypedArray::cast(*source)->type() == array_type) {
1058 length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate);
1060 size_t length = NumberToSize(isolate, *length_obj);
1062 if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
1063 (length > (kMaxInt / element_size))) {
1064 return isolate->Throw(*isolate->factory()->
1065 NewRangeError("invalid_typed_array_length",
1066 HandleVector<Object>(NULL, 0)));
1068 size_t byte_length = length * element_size;
1070 // NOTE: not initializing backing store.
1071 // We assume that the caller of this function will initialize holder
1073 // for(i = 0; i < length; i++) { holder[i] = source[i]; }
1074 // We assume that the caller of this function is always a typed array
1076 // If source is a typed array, this loop will always run to completion,
1077 // so we are sure that the backing store will be initialized.
1078 // Otherwise, the indexing operation might throw, so the loop will not
1079 // run to completion and the typed array might remain partly initialized.
1080 // However we further assume that the caller of this function is a typed array
1081 // constructor, and the exception will propagate out of the constructor,
1082 // therefore uninitialized memory will not be accessible by a user program.
1084 // TODO(dslomov): revise this once we support subclassing.
1086 if (!Runtime::SetupArrayBufferAllocatingData(
1087 isolate, buffer, byte_length, false)) {
1088 return isolate->Throw(*isolate->factory()->
1089 NewRangeError("invalid_array_buffer_length",
1090 HandleVector<Object>(NULL, 0)));
1093 holder->set_buffer(*buffer);
1094 holder->set_byte_offset(Smi::FromInt(0));
1095 Handle<Object> byte_length_obj(
1096 isolate->factory()->NewNumberFromSize(byte_length));
1097 holder->set_byte_length(*byte_length_obj);
1098 holder->set_length(*length_obj);
1099 holder->set_weak_next(buffer->weak_first_view());
1100 buffer->set_weak_first_view(*holder);
1102 Handle<ExternalArray> elements =
1103 isolate->factory()->NewExternalArray(
1104 static_cast<int>(length), array_type,
1105 static_cast<uint8_t*>(buffer->backing_store()));
1106 Handle<Map> map = JSObject::GetElementsTransitionMap(
1107 holder, external_elements_kind);
1108 holder->set_map_and_elements(*map, *elements);
1110 if (source->IsJSTypedArray()) {
1111 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
1113 if (typed_array->type() == holder->type()) {
1114 uint8_t* backing_store =
1115 static_cast<uint8_t*>(
1116 typed_array->GetBuffer()->backing_store());
1117 size_t source_byte_offset =
1118 NumberToSize(isolate, typed_array->byte_offset());
1120 buffer->backing_store(),
1121 backing_store + source_byte_offset,
1123 return *isolate->factory()->true_value();
1125 return *isolate->factory()->false_value();
1129 return *isolate->factory()->false_value();
1133 #define TYPED_ARRAY_GETTER(getter, accessor) \
1134 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \
1135 HandleScope scope(isolate); \
1136 ASSERT(args.length() == 1); \
1137 CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0); \
1138 if (!holder->IsJSTypedArray()) \
1139 return isolate->Throw(*isolate->factory()->NewTypeError( \
1140 "not_typed_array", HandleVector<Object>(NULL, 0))); \
1141 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*holder)); \
1142 return typed_array->accessor(); \
1145 TYPED_ARRAY_GETTER(ByteLength, byte_length)
1146 TYPED_ARRAY_GETTER(ByteOffset, byte_offset)
1147 TYPED_ARRAY_GETTER(Length, length)
1149 #undef TYPED_ARRAY_GETTER
1151 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGetBuffer) {
1152 HandleScope scope(isolate);
1153 ASSERT(args.length() == 1);
1154 CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0);
1155 if (!holder->IsJSTypedArray())
1156 return isolate->Throw(*isolate->factory()->NewTypeError(
1157 "not_typed_array", HandleVector<Object>(NULL, 0)));
1158 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*holder));
1159 return *typed_array->GetBuffer();
1163 // Return codes for Runtime_TypedArraySetFastCases.
1164 // Should be synchronized with typedarray.js natives.
1165 enum TypedArraySetResultCodes {
1166 // Set from typed array of the same type.
1167 // This is processed by TypedArraySetFastCases
1168 TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
1169 // Set from typed array of the different type, overlapping in memory.
1170 TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
1171 // Set from typed array of the different type, non-overlapping.
1172 TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
1173 // Set from non-typed array.
1174 TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
1178 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) {
1179 HandleScope scope(isolate);
1180 CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0);
1181 CONVERT_ARG_HANDLE_CHECKED(Object, source_obj, 1);
1182 CONVERT_ARG_HANDLE_CHECKED(Object, offset_obj, 2);
1184 if (!target_obj->IsJSTypedArray())
1185 return isolate->Throw(*isolate->factory()->NewTypeError(
1186 "not_typed_array", HandleVector<Object>(NULL, 0)));
1188 if (!source_obj->IsJSTypedArray())
1189 return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
1191 Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
1192 Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
1193 size_t offset = NumberToSize(isolate, *offset_obj);
1194 size_t target_length = NumberToSize(isolate, target->length());
1195 size_t source_length = NumberToSize(isolate, source->length());
1196 size_t target_byte_length = NumberToSize(isolate, target->byte_length());
1197 size_t source_byte_length = NumberToSize(isolate, source->byte_length());
1198 if (offset > target_length ||
1199 offset + source_length > target_length ||
1200 offset + source_length < offset) // overflow
1201 return isolate->Throw(*isolate->factory()->NewRangeError(
1202 "typed_array_set_source_too_large", HandleVector<Object>(NULL, 0)));
1204 size_t target_offset = NumberToSize(isolate, target->byte_offset());
1205 size_t source_offset = NumberToSize(isolate, source->byte_offset());
1206 uint8_t* target_base =
1207 static_cast<uint8_t*>(
1208 target->GetBuffer()->backing_store()) + target_offset;
1209 uint8_t* source_base =
1210 static_cast<uint8_t*>(
1211 source->GetBuffer()->backing_store()) + source_offset;
1213 // Typed arrays of the same type: use memmove.
1214 if (target->type() == source->type()) {
1215 memmove(target_base + offset * target->element_size(),
1216 source_base, source_byte_length);
1217 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
1220 // Typed arrays of different types over the same backing store
1221 if ((source_base <= target_base &&
1222 source_base + source_byte_length > target_base) ||
1223 (target_base <= source_base &&
1224 target_base + target_byte_length > source_base)) {
1225 // We do not support overlapping ArrayBuffers
1227 target->GetBuffer()->backing_store() ==
1228 source->GetBuffer()->backing_store());
1229 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
1230 } else { // Non-overlapping typed arrays
1231 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
1236 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayMaxSizeInHeap) {
1237 ASSERT_OBJECT_SIZE(FLAG_typed_array_max_size_in_heap);
1238 return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
1242 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewInitialize) {
1243 HandleScope scope(isolate);
1244 ASSERT(args.length() == 4);
1245 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
1246 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
1247 CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset, 2);
1248 CONVERT_ARG_HANDLE_CHECKED(Object, byte_length, 3);
1250 ASSERT(holder->GetInternalFieldCount() ==
1251 v8::ArrayBufferView::kInternalFieldCount);
1252 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
1253 holder->SetInternalField(i, Smi::FromInt(0));
1256 holder->set_buffer(*buffer);
1257 ASSERT(byte_offset->IsNumber());
1259 NumberToSize(isolate, buffer->byte_length()) >=
1260 NumberToSize(isolate, *byte_offset)
1261 + NumberToSize(isolate, *byte_length));
1262 holder->set_byte_offset(*byte_offset);
1263 ASSERT(byte_length->IsNumber());
1264 holder->set_byte_length(*byte_length);
1266 holder->set_weak_next(buffer->weak_first_view());
1267 buffer->set_weak_first_view(*holder);
1269 return isolate->heap()->undefined_value();
1273 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetBuffer) {
1274 HandleScope scope(isolate);
1275 ASSERT(args.length() == 1);
1276 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
1277 return data_view->buffer();
1281 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteOffset) {
1282 HandleScope scope(isolate);
1283 ASSERT(args.length() == 1);
1284 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
1285 return data_view->byte_offset();
1289 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteLength) {
1290 HandleScope scope(isolate);
1291 ASSERT(args.length() == 1);
1292 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
1293 return data_view->byte_length();
1297 inline static bool NeedToFlipBytes(bool is_little_endian) {
1298 #ifdef V8_TARGET_LITTLE_ENDIAN
1299 return !is_little_endian;
1301 return is_little_endian;
1307 inline void CopyBytes(uint8_t* target, uint8_t* source) {
1308 for (int i = 0; i < n; i++) {
1309 *(target++) = *(source++);
1315 inline void FlipBytes(uint8_t* target, uint8_t* source) {
1316 source = source + (n-1);
1317 for (int i = 0; i < n; i++) {
1318 *(target++) = *(source--);
1323 template<typename T>
1324 inline static bool DataViewGetValue(
1326 Handle<JSDataView> data_view,
1327 Handle<Object> byte_offset_obj,
1328 bool is_little_endian,
1330 size_t byte_offset = 0;
1331 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
1334 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
1336 size_t data_view_byte_offset =
1337 NumberToSize(isolate, data_view->byte_offset());
1338 size_t data_view_byte_length =
1339 NumberToSize(isolate, data_view->byte_length());
1340 if (byte_offset + sizeof(T) > data_view_byte_length ||
1341 byte_offset + sizeof(T) < byte_offset) { // overflow
1347 uint8_t bytes[sizeof(T)];
1351 size_t buffer_offset = data_view_byte_offset + byte_offset;
1353 NumberToSize(isolate, buffer->byte_length())
1354 >= buffer_offset + sizeof(T));
1356 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
1357 if (NeedToFlipBytes(is_little_endian)) {
1358 FlipBytes<sizeof(T)>(value.bytes, source);
1360 CopyBytes<sizeof(T)>(value.bytes, source);
1362 *result = value.data;
1367 template<typename T>
1368 static bool DataViewSetValue(
1370 Handle<JSDataView> data_view,
1371 Handle<Object> byte_offset_obj,
1372 bool is_little_endian,
1374 size_t byte_offset = 0;
1375 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
1378 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
1380 size_t data_view_byte_offset =
1381 NumberToSize(isolate, data_view->byte_offset());
1382 size_t data_view_byte_length =
1383 NumberToSize(isolate, data_view->byte_length());
1384 if (byte_offset + sizeof(T) > data_view_byte_length ||
1385 byte_offset + sizeof(T) < byte_offset) { // overflow
1391 uint8_t bytes[sizeof(T)];
1396 size_t buffer_offset = data_view_byte_offset + byte_offset;
1398 NumberToSize(isolate, buffer->byte_length())
1399 >= buffer_offset + sizeof(T));
1401 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
1402 if (NeedToFlipBytes(is_little_endian)) {
1403 FlipBytes<sizeof(T)>(target, value.bytes);
1405 CopyBytes<sizeof(T)>(target, value.bytes);
1411 #define DATA_VIEW_GETTER(TypeName, Type, Converter) \
1412 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGet##TypeName) { \
1413 HandleScope scope(isolate); \
1414 ASSERT(args.length() == 3); \
1415 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
1416 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \
1417 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \
1419 if (DataViewGetValue( \
1420 isolate, holder, offset, is_little_endian, &result)) { \
1421 return isolate->heap()->Converter(result); \
1423 return isolate->Throw(*isolate->factory()->NewRangeError( \
1424 "invalid_data_view_accessor_offset", \
1425 HandleVector<Object>(NULL, 0))); \
1429 DATA_VIEW_GETTER(Uint8, uint8_t, NumberFromUint32)
1430 DATA_VIEW_GETTER(Int8, int8_t, NumberFromInt32)
1431 DATA_VIEW_GETTER(Uint16, uint16_t, NumberFromUint32)
1432 DATA_VIEW_GETTER(Int16, int16_t, NumberFromInt32)
1433 DATA_VIEW_GETTER(Uint32, uint32_t, NumberFromUint32)
1434 DATA_VIEW_GETTER(Int32, int32_t, NumberFromInt32)
1435 DATA_VIEW_GETTER(Float32, float, NumberFromDouble)
1436 DATA_VIEW_GETTER(Float64, double, NumberFromDouble)
1438 #undef DATA_VIEW_GETTER
1441 template <typename T>
1442 static T DataViewConvertValue(double value);
1446 int8_t DataViewConvertValue<int8_t>(double value) {
1447 return static_cast<int8_t>(DoubleToInt32(value));
1452 int16_t DataViewConvertValue<int16_t>(double value) {
1453 return static_cast<int16_t>(DoubleToInt32(value));
1458 int32_t DataViewConvertValue<int32_t>(double value) {
1459 return DoubleToInt32(value);
1464 uint8_t DataViewConvertValue<uint8_t>(double value) {
1465 return static_cast<uint8_t>(DoubleToUint32(value));
1470 uint16_t DataViewConvertValue<uint16_t>(double value) {
1471 return static_cast<uint16_t>(DoubleToUint32(value));
1476 uint32_t DataViewConvertValue<uint32_t>(double value) {
1477 return DoubleToUint32(value);
1482 float DataViewConvertValue<float>(double value) {
1483 return static_cast<float>(value);
1488 double DataViewConvertValue<double>(double value) {
1493 #define DATA_VIEW_SETTER(TypeName, Type) \
1494 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewSet##TypeName) { \
1495 HandleScope scope(isolate); \
1496 ASSERT(args.length() == 4); \
1497 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
1498 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \
1499 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); \
1500 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \
1501 Type v = DataViewConvertValue<Type>(value->Number()); \
1502 if (DataViewSetValue( \
1503 isolate, holder, offset, is_little_endian, v)) { \
1504 return isolate->heap()->undefined_value(); \
1506 return isolate->Throw(*isolate->factory()->NewRangeError( \
1507 "invalid_data_view_accessor_offset", \
1508 HandleVector<Object>(NULL, 0))); \
1512 DATA_VIEW_SETTER(Uint8, uint8_t)
1513 DATA_VIEW_SETTER(Int8, int8_t)
1514 DATA_VIEW_SETTER(Uint16, uint16_t)
1515 DATA_VIEW_SETTER(Int16, int16_t)
1516 DATA_VIEW_SETTER(Uint32, uint32_t)
1517 DATA_VIEW_SETTER(Int32, int32_t)
1518 DATA_VIEW_SETTER(Float32, float)
1519 DATA_VIEW_SETTER(Float64, double)
1521 #undef DATA_VIEW_SETTER
1524 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
1525 HandleScope scope(isolate);
1526 ASSERT(args.length() == 1);
1527 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1528 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
1529 holder->set_table(*table);
1534 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
1535 HandleScope scope(isolate);
1536 ASSERT(args.length() == 2);
1537 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1538 Handle<Object> key(args[1], isolate);
1539 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1540 table = ObjectHashSet::Add(table, key);
1541 holder->set_table(*table);
1542 return isolate->heap()->undefined_value();
1546 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
1547 HandleScope scope(isolate);
1548 ASSERT(args.length() == 2);
1549 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1550 Handle<Object> key(args[1], isolate);
1551 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1552 return isolate->heap()->ToBoolean(table->Contains(*key));
1556 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
1557 HandleScope scope(isolate);
1558 ASSERT(args.length() == 2);
1559 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1560 Handle<Object> key(args[1], isolate);
1561 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1562 table = ObjectHashSet::Remove(table, key);
1563 holder->set_table(*table);
1564 return isolate->heap()->undefined_value();
1568 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetGetSize) {
1569 HandleScope scope(isolate);
1570 ASSERT(args.length() == 1);
1571 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1572 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1573 return Smi::FromInt(table->NumberOfElements());
1577 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
1578 HandleScope scope(isolate);
1579 ASSERT(args.length() == 1);
1580 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1581 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
1582 holder->set_table(*table);
1587 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
1588 HandleScope scope(isolate);
1589 ASSERT(args.length() == 2);
1590 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1591 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1592 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1593 Handle<Object> lookup(table->Lookup(*key), isolate);
1594 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
1598 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapHas) {
1599 HandleScope scope(isolate);
1600 ASSERT(args.length() == 2);
1601 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1602 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1603 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1604 Handle<Object> lookup(table->Lookup(*key), isolate);
1605 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1609 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapDelete) {
1610 HandleScope scope(isolate);
1611 ASSERT(args.length() == 2);
1612 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1613 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1614 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1615 Handle<Object> lookup(table->Lookup(*key), isolate);
1616 Handle<ObjectHashTable> new_table =
1617 ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value());
1618 holder->set_table(*new_table);
1619 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1623 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
1624 HandleScope scope(isolate);
1625 ASSERT(args.length() == 3);
1626 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1627 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1628 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
1629 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1630 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value);
1631 holder->set_table(*new_table);
1632 return isolate->heap()->undefined_value();
1636 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGetSize) {
1637 HandleScope scope(isolate);
1638 ASSERT(args.length() == 1);
1639 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1640 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1641 return Smi::FromInt(table->NumberOfElements());
1645 static JSWeakCollection* WeakCollectionInitialize(Isolate* isolate,
1646 Handle<JSWeakCollection> weak_collection) {
1647 ASSERT(weak_collection->map()->inobject_properties() == 0);
1648 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
1649 weak_collection->set_table(*table);
1650 weak_collection->set_next(Smi::FromInt(0));
1651 return *weak_collection;
1655 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionInitialize) {
1656 HandleScope scope(isolate);
1657 ASSERT(args.length() == 1);
1658 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1659 return WeakCollectionInitialize(isolate, weak_collection);
1663 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionGet) {
1664 HandleScope scope(isolate);
1665 ASSERT(args.length() == 2);
1666 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1667 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1668 Handle<ObjectHashTable> table(
1669 ObjectHashTable::cast(weak_collection->table()));
1670 Handle<Object> lookup(table->Lookup(*key), isolate);
1671 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
1675 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionHas) {
1676 HandleScope scope(isolate);
1677 ASSERT(args.length() == 2);
1678 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1679 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1680 Handle<ObjectHashTable> table(
1681 ObjectHashTable::cast(weak_collection->table()));
1682 Handle<Object> lookup(table->Lookup(*key), isolate);
1683 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1687 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionDelete) {
1688 HandleScope scope(isolate);
1689 ASSERT(args.length() == 2);
1690 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1691 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1692 Handle<ObjectHashTable> table(ObjectHashTable::cast(
1693 weak_collection->table()));
1694 Handle<Object> lookup(table->Lookup(*key), isolate);
1695 Handle<ObjectHashTable> new_table =
1696 ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value());
1697 weak_collection->set_table(*new_table);
1698 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1702 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionSet) {
1703 HandleScope scope(isolate);
1704 ASSERT(args.length() == 3);
1705 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1706 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1707 Handle<Object> value(args[2], isolate);
1708 Handle<ObjectHashTable> table(
1709 ObjectHashTable::cast(weak_collection->table()));
1710 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value);
1711 weak_collection->set_table(*new_table);
1712 return isolate->heap()->undefined_value();
1716 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
1717 SealHandleScope shs(isolate);
1718 ASSERT(args.length() == 1);
1719 Object* obj = args[0];
1720 if (!obj->IsJSObject()) return isolate->heap()->null_value();
1721 return JSObject::cast(obj)->class_name();
1725 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
1726 HandleScope scope(isolate);
1727 ASSERT(args.length() == 1);
1728 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
1729 // We don't expect access checks to be needed on JSProxy objects.
1730 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
1732 if (obj->IsAccessCheckNeeded() &&
1733 !isolate->MayNamedAccessWrapper(Handle<JSObject>::cast(obj),
1734 isolate->factory()->proto_string(),
1736 isolate->ReportFailedAccessCheckWrapper(Handle<JSObject>::cast(obj),
1738 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1739 return isolate->heap()->undefined_value();
1741 obj = handle(obj->GetPrototype(isolate), isolate);
1742 } while (obj->IsJSObject() &&
1743 JSObject::cast(*obj)->map()->is_hidden_prototype());
1748 static inline Object* GetPrototypeSkipHiddenPrototypes(Isolate* isolate,
1750 Object* current = receiver->GetPrototype(isolate);
1751 while (current->IsJSObject() &&
1752 JSObject::cast(current)->map()->is_hidden_prototype()) {
1753 current = current->GetPrototype(isolate);
1759 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) {
1760 HandleScope scope(isolate);
1761 ASSERT(args.length() == 2);
1762 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1763 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
1764 if (obj->IsAccessCheckNeeded() &&
1765 !isolate->MayNamedAccessWrapper(obj,
1766 isolate->factory()->proto_string(),
1768 isolate->ReportFailedAccessCheckWrapper(obj, v8::ACCESS_SET);
1769 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1770 return isolate->heap()->undefined_value();
1772 if (obj->map()->is_observed()) {
1773 Handle<Object> old_value(
1774 GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
1776 Handle<Object> result = JSObject::SetPrototype(obj, prototype, true);
1777 RETURN_IF_EMPTY_HANDLE(isolate, result);
1779 Handle<Object> new_value(
1780 GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
1781 if (!new_value->SameValue(*old_value)) {
1782 JSObject::EnqueueChangeRecord(obj, "setPrototype",
1783 isolate->factory()->proto_string(),
1788 Handle<Object> result = JSObject::SetPrototype(obj, prototype, true);
1789 RETURN_IF_EMPTY_HANDLE(isolate, result);
1794 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
1795 SealHandleScope shs(isolate);
1796 ASSERT(args.length() == 2);
1797 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
1798 Object* O = args[0];
1799 Object* V = args[1];
1801 Object* prototype = V->GetPrototype(isolate);
1802 if (prototype->IsNull()) return isolate->heap()->false_value();
1803 if (O == prototype) return isolate->heap()->true_value();
1809 static bool CheckAccessException(Object* callback,
1810 v8::AccessType access_type) {
1811 DisallowHeapAllocation no_gc;
1812 if (callback->IsAccessorInfo()) {
1813 AccessorInfo* info = AccessorInfo::cast(callback);
1815 (access_type == v8::ACCESS_HAS &&
1816 (info->all_can_read() || info->all_can_write())) ||
1817 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
1818 (access_type == v8::ACCESS_SET && info->all_can_write());
1820 if (callback->IsAccessorPair()) {
1821 AccessorPair* info = AccessorPair::cast(callback);
1823 (access_type == v8::ACCESS_HAS &&
1824 (info->all_can_read() || info->all_can_write())) ||
1825 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
1826 (access_type == v8::ACCESS_SET && info->all_can_write());
1833 static bool CheckGenericAccess(
1834 Handle<JSObject> receiver,
1835 Handle<JSObject> holder,
1837 v8::AccessType access_type,
1838 bool (Isolate::*mayAccess)(Handle<JSObject>, Key, v8::AccessType)) {
1839 Isolate* isolate = receiver->GetIsolate();
1840 for (Handle<JSObject> current = receiver;
1842 current = handle(JSObject::cast(current->GetPrototype()), isolate)) {
1843 if (current->IsAccessCheckNeeded() &&
1844 !(isolate->*mayAccess)(current, key, access_type)) {
1847 if (current.is_identical_to(holder)) break;
1853 enum AccessCheckResult {
1860 static AccessCheckResult CheckPropertyAccess(Handle<JSObject> obj,
1862 v8::AccessType access_type) {
1864 if (name->AsArrayIndex(&index)) {
1865 // TODO(1095): we should traverse hidden prototype hierachy as well.
1866 if (CheckGenericAccess(
1867 obj, obj, index, access_type, &Isolate::MayIndexedAccessWrapper)) {
1868 return ACCESS_ALLOWED;
1871 obj->GetIsolate()->ReportFailedAccessCheckWrapper(obj, access_type);
1872 return ACCESS_FORBIDDEN;
1875 Isolate* isolate = obj->GetIsolate();
1876 LookupResult lookup(isolate);
1877 obj->LocalLookup(*name, &lookup, true);
1879 if (!lookup.IsProperty()) return ACCESS_ABSENT;
1880 Handle<JSObject> holder(lookup.holder(), isolate);
1881 if (CheckGenericAccess<Handle<Object> >(
1882 obj, holder, name, access_type, &Isolate::MayNamedAccessWrapper)) {
1883 return ACCESS_ALLOWED;
1886 // Access check callback denied the access, but some properties
1887 // can have a special permissions which override callbacks descision
1888 // (currently see v8::AccessControl).
1889 // API callbacks can have per callback access exceptions.
1890 switch (lookup.type()) {
1892 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1893 return ACCESS_ALLOWED;
1897 // If the object has an interceptor, try real named properties.
1898 // Overwrite the result to fetch the correct property later.
1899 holder->LookupRealNamedProperty(*name, &lookup);
1900 if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) {
1901 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1902 return ACCESS_ALLOWED;
1910 isolate->ReportFailedAccessCheckWrapper(obj, access_type);
1911 return ACCESS_FORBIDDEN;
1915 // Enumerator used as indices into the array returned from GetOwnProperty
1916 enum PropertyDescriptorIndices {
1928 static Handle<Object> GetOwnProperty(Isolate* isolate,
1929 Handle<JSObject> obj,
1930 Handle<Name> name) {
1931 Heap* heap = isolate->heap();
1932 Factory* factory = isolate->factory();
1933 // Due to some WebKit tests, we want to make sure that we do not log
1934 // more than one access failure here.
1935 AccessCheckResult access_check_result =
1936 CheckPropertyAccess(obj, name, v8::ACCESS_HAS);
1937 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
1938 switch (access_check_result) {
1939 case ACCESS_FORBIDDEN: return factory->false_value();
1940 case ACCESS_ALLOWED: break;
1941 case ACCESS_ABSENT: return factory->undefined_value();
1944 PropertyAttributes attrs = JSReceiver::GetLocalPropertyAttribute(obj, name);
1945 if (attrs == ABSENT) {
1946 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
1947 return factory->undefined_value();
1949 ASSERT(!isolate->has_scheduled_exception());
1950 AccessorPair* raw_accessors = obj->GetLocalPropertyAccessorPair(*name);
1951 Handle<AccessorPair> accessors(raw_accessors, isolate);
1952 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1953 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0));
1954 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0));
1955 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(raw_accessors != NULL));
1957 if (raw_accessors == NULL) {
1958 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
1959 // GetProperty does access check.
1960 Handle<Object> value = GetProperty(isolate, obj, name);
1961 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<Object>::null());
1962 elms->set(VALUE_INDEX, *value);
1964 // Access checks are performed for both accessors separately.
1965 // When they fail, the respective field is not set in the descriptor.
1966 Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate);
1967 Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate);
1969 if (!getter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_GET)) {
1970 ASSERT(!isolate->has_scheduled_exception());
1971 elms->set(GETTER_INDEX, *getter);
1973 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
1976 if (!setter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_SET)) {
1977 ASSERT(!isolate->has_scheduled_exception());
1978 elms->set(SETTER_INDEX, *setter);
1980 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
1984 return isolate->factory()->NewJSArrayWithElements(elms);
1988 // Returns an array with the property description:
1989 // if args[1] is not a property on args[0]
1990 // returns undefined
1991 // if args[1] is a data property on args[0]
1992 // [false, value, Writeable, Enumerable, Configurable]
1993 // if args[1] is an accessor on args[0]
1994 // [true, GetFunction, SetFunction, Enumerable, Configurable]
1995 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1996 HandleScope scope(isolate);
1997 ASSERT(args.length() == 2);
1998 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1999 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
2000 Handle<Object> result = GetOwnProperty(isolate, obj, name);
2001 RETURN_IF_EMPTY_HANDLE(isolate, result);
2006 RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
2007 HandleScope scope(isolate);
2008 ASSERT(args.length() == 1);
2009 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
2010 Handle<Object> result = JSObject::PreventExtensions(obj);
2011 RETURN_IF_EMPTY_HANDLE(isolate, result);
2016 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
2017 SealHandleScope shs(isolate);
2018 ASSERT(args.length() == 1);
2019 CONVERT_ARG_CHECKED(JSObject, obj, 0);
2020 if (obj->IsJSGlobalProxy()) {
2021 Object* proto = obj->GetPrototype();
2022 if (proto->IsNull()) return isolate->heap()->false_value();
2023 ASSERT(proto->IsJSGlobalObject());
2024 obj = JSObject::cast(proto);
2026 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
2030 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
2031 HandleScope scope(isolate);
2032 ASSERT(args.length() == 3);
2033 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
2034 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
2035 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
2036 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
2037 RETURN_IF_EMPTY_HANDLE(isolate, result);
2042 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
2043 HandleScope scope(isolate);
2044 ASSERT(args.length() == 1);
2045 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
2046 return *isolate->factory()->CreateApiFunction(data);
2050 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
2051 SealHandleScope shs(isolate);
2052 ASSERT(args.length() == 1);
2053 Object* arg = args[0];
2054 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
2055 return isolate->heap()->ToBoolean(result);
2059 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
2060 SealHandleScope shs(isolate);
2061 ASSERT(args.length() == 2);
2062 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
2063 CONVERT_SMI_ARG_CHECKED(index, 1)
2064 int offset = index * kPointerSize + HeapObject::kHeaderSize;
2065 InstanceType type = templ->map()->instance_type();
2066 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
2067 type == OBJECT_TEMPLATE_INFO_TYPE);
2068 RUNTIME_ASSERT(offset > 0);
2069 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
2070 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
2072 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
2074 return *HeapObject::RawField(templ, offset);
2078 RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
2079 SealHandleScope shs(isolate);
2080 ASSERT(args.length() == 1);
2081 CONVERT_ARG_CHECKED(HeapObject, object, 0);
2082 Map* old_map = object->map();
2083 bool needs_access_checks = old_map->is_access_check_needed();
2084 if (needs_access_checks) {
2085 // Copy map so it won't interfere constructor's initial map.
2087 MaybeObject* maybe_new_map = old_map->Copy();
2088 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
2090 new_map->set_is_access_check_needed(false);
2091 object->set_map(new_map);
2093 return isolate->heap()->ToBoolean(needs_access_checks);
2097 RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
2098 SealHandleScope shs(isolate);
2099 ASSERT(args.length() == 1);
2100 CONVERT_ARG_CHECKED(HeapObject, object, 0);
2101 Map* old_map = object->map();
2102 if (!old_map->is_access_check_needed()) {
2103 // Copy map so it won't interfere constructor's initial map.
2105 MaybeObject* maybe_new_map = old_map->Copy();
2106 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
2108 new_map->set_is_access_check_needed(true);
2109 object->set_map(new_map);
2111 return isolate->heap()->undefined_value();
2115 // Transform getter or setter into something DefineAccessor can handle.
2116 static Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
2117 Handle<Object> component) {
2118 if (component->IsUndefined()) return isolate->factory()->null_value();
2119 Handle<FunctionTemplateInfo> info =
2120 Handle<FunctionTemplateInfo>::cast(component);
2121 return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
2125 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAccessorProperty) {
2126 HandleScope scope(isolate);
2127 ASSERT(args.length() == 6);
2128 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
2129 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
2130 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
2131 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
2132 CONVERT_SMI_ARG_CHECKED(attribute, 4);
2133 CONVERT_SMI_ARG_CHECKED(access_control, 5);
2134 RUNTIME_ASSERT(getter->IsUndefined() || getter->IsFunctionTemplateInfo());
2135 RUNTIME_ASSERT(setter->IsUndefined() || setter->IsFunctionTemplateInfo());
2136 JSObject::DefineAccessor(object,
2138 InstantiateAccessorComponent(isolate, getter),
2139 InstantiateAccessorComponent(isolate, setter),
2140 static_cast<PropertyAttributes>(attribute),
2141 static_cast<v8::AccessControl>(access_control));
2142 return isolate->heap()->undefined_value();
2146 static Failure* ThrowRedeclarationError(Isolate* isolate,
2148 Handle<String> name) {
2149 HandleScope scope(isolate);
2150 Handle<Object> type_handle =
2151 isolate->factory()->NewStringFromAscii(CStrVector(type));
2152 Handle<Object> args[2] = { type_handle, name };
2153 Handle<Object> error =
2154 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
2155 return isolate->Throw(*error);
2159 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_DeclareGlobals) {
2160 HandleScope scope(isolate);
2161 ASSERT(args.length() == 3);
2162 Handle<GlobalObject> global = Handle<GlobalObject>(
2163 isolate->context()->global_object());
2165 Handle<Context> context = args.at<Context>(0);
2166 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
2167 CONVERT_SMI_ARG_CHECKED(flags, 2);
2169 // Traverse the name/value pairs and set the properties.
2170 int length = pairs->length();
2171 for (int i = 0; i < length; i += 2) {
2172 HandleScope scope(isolate);
2173 Handle<String> name(String::cast(pairs->get(i)));
2174 Handle<Object> value(pairs->get(i + 1), isolate);
2176 // We have to declare a global const property. To capture we only
2177 // assign to it when evaluating the assignment for "const x =
2178 // <expr>" the initial value is the hole.
2179 bool is_var = value->IsUndefined();
2180 bool is_const = value->IsTheHole();
2181 bool is_function = value->IsSharedFunctionInfo();
2182 ASSERT(is_var + is_const + is_function == 1);
2184 if (is_var || is_const) {
2185 // Lookup the property in the global object, and don't set the
2186 // value of the variable if the property is already there.
2187 // Do the lookup locally only, see ES5 erratum.
2188 LookupResult lookup(isolate);
2189 global->LocalLookup(*name, &lookup, true);
2190 if (lookup.IsFound()) {
2191 // We found an existing property. Unless it was an interceptor
2192 // that claims the property is absent, skip this declaration.
2193 if (!lookup.IsInterceptor()) continue;
2194 if (JSReceiver::GetPropertyAttribute(global, name) != ABSENT) continue;
2195 // Fall-through and introduce the absent property by using
2198 } else if (is_function) {
2199 // Copy the function and update its context. Use it as value.
2200 Handle<SharedFunctionInfo> shared =
2201 Handle<SharedFunctionInfo>::cast(value);
2202 Handle<JSFunction> function =
2203 isolate->factory()->NewFunctionFromSharedFunctionInfo(
2204 shared, context, TENURED);
2208 LookupResult lookup(isolate);
2209 global->LocalLookup(*name, &lookup, true);
2211 // Compute the property attributes. According to ECMA-262,
2212 // the property must be non-configurable except in eval.
2214 bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
2216 attr |= DONT_DELETE;
2218 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
2219 if (is_const || (is_native && is_function)) {
2223 StrictMode strict_mode = DeclareGlobalsStrictMode::decode(flags);
2225 if (!lookup.IsFound() || is_function) {
2226 // If the local property exists, check that we can reconfigure it
2227 // as required for function declarations.
2228 if (lookup.IsFound() && lookup.IsDontDelete()) {
2229 if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
2230 lookup.IsPropertyCallbacks()) {
2231 return ThrowRedeclarationError(isolate, "function", name);
2233 // If the existing property is not configurable, keep its attributes.
2234 attr = lookup.GetAttributes();
2236 // Define or redefine own property.
2237 RETURN_IF_EMPTY_HANDLE(isolate,
2238 JSObject::SetLocalPropertyIgnoreAttributes(
2239 global, name, value, static_cast<PropertyAttributes>(attr)));
2241 // Do a [[Put]] on the existing (own) property.
2242 RETURN_IF_EMPTY_HANDLE(isolate,
2243 JSObject::SetProperty(
2244 global, name, value, static_cast<PropertyAttributes>(attr),
2249 ASSERT(!isolate->has_pending_exception());
2250 return isolate->heap()->undefined_value();
2254 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_DeclareContextSlot) {
2255 HandleScope scope(isolate);
2256 ASSERT(args.length() == 4);
2258 // Declarations are always made in a function or native context. In the
2259 // case of eval code, the context passed is the context of the caller,
2260 // which may be some nested context and not the declaration context.
2261 RUNTIME_ASSERT(args[0]->IsContext());
2262 Handle<Context> context(Context::cast(args[0])->declaration_context());
2264 Handle<String> name(String::cast(args[1]));
2265 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
2266 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
2267 Handle<Object> initial_value(args[3], isolate);
2270 PropertyAttributes attributes;
2271 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
2272 BindingFlags binding_flags;
2273 Handle<Object> holder =
2274 context->Lookup(name, flags, &index, &attributes, &binding_flags);
2276 if (attributes != ABSENT) {
2277 // The name was declared before; check for conflicting re-declarations.
2278 // Note: this is actually inconsistent with what happens for globals (where
2279 // we silently ignore such declarations).
2280 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
2281 // Functions are not read-only.
2282 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
2283 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
2284 return ThrowRedeclarationError(isolate, type, name);
2287 // Initialize it if necessary.
2288 if (*initial_value != NULL) {
2290 ASSERT(holder.is_identical_to(context));
2291 if (((attributes & READ_ONLY) == 0) ||
2292 context->get(index)->IsTheHole()) {
2293 context->set(index, *initial_value);
2296 // Slow case: The property is in the context extension object of a
2297 // function context or the global object of a native context.
2298 Handle<JSObject> object = Handle<JSObject>::cast(holder);
2299 RETURN_IF_EMPTY_HANDLE(
2301 JSReceiver::SetProperty(object, name, initial_value, mode, SLOPPY));
2306 // The property is not in the function context. It needs to be
2307 // "declared" in the function context's extension context or as a
2308 // property of the the global object.
2309 Handle<JSObject> object;
2310 if (context->has_extension()) {
2311 object = Handle<JSObject>(JSObject::cast(context->extension()));
2313 // Context extension objects are allocated lazily.
2314 ASSERT(context->IsFunctionContext());
2315 object = isolate->factory()->NewJSObject(
2316 isolate->context_extension_function());
2317 context->set_extension(*object);
2319 ASSERT(*object != NULL);
2321 // Declare the property by setting it to the initial value if provided,
2322 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
2323 // constant declarations).
2324 ASSERT(!JSReceiver::HasLocalProperty(object, name));
2325 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
2326 if (*initial_value != NULL) value = initial_value;
2327 // Declaring a const context slot is a conflicting declaration if
2328 // there is a callback with that name in a prototype. It is
2329 // allowed to introduce const variables in
2330 // JSContextExtensionObjects. They are treated specially in
2331 // SetProperty and no setters are invoked for those since they are
2332 // not real JSObjects.
2333 if (initial_value->IsTheHole() &&
2334 !object->IsJSContextExtensionObject()) {
2335 LookupResult lookup(isolate);
2336 object->Lookup(*name, &lookup);
2337 if (lookup.IsPropertyCallbacks()) {
2338 return ThrowRedeclarationError(isolate, "const", name);
2341 if (object->IsJSGlobalObject()) {
2342 // Define own property on the global object.
2343 RETURN_IF_EMPTY_HANDLE(isolate,
2344 JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode));
2346 RETURN_IF_EMPTY_HANDLE(isolate,
2347 JSReceiver::SetProperty(object, name, value, mode, SLOPPY));
2351 return isolate->heap()->undefined_value();
2355 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
2356 HandleScope scope(isolate);
2358 // args[1] == language_mode
2359 // args[2] == value (optional)
2361 // Determine if we need to assign to the variable if it already
2362 // exists (based on the number of arguments).
2363 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
2364 bool assign = args.length() == 3;
2366 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2367 RUNTIME_ASSERT(args[1]->IsSmi());
2368 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 1);
2370 // According to ECMA-262, section 12.2, page 62, the property must
2371 // not be deletable.
2372 PropertyAttributes attributes = DONT_DELETE;
2374 // Lookup the property locally in the global object. If it isn't
2375 // there, there is a property with this name in the prototype chain.
2376 // We follow Safari and Firefox behavior and only set the property
2377 // locally if there is an explicit initialization value that we have
2378 // to assign to the property.
2379 // Note that objects can have hidden prototypes, so we need to traverse
2380 // the whole chain of hidden prototypes to do a 'local' lookup.
2381 LookupResult lookup(isolate);
2382 isolate->context()->global_object()->LocalLookup(*name, &lookup, true);
2383 if (lookup.IsInterceptor()) {
2384 Handle<JSObject> holder(lookup.holder());
2385 PropertyAttributes intercepted =
2386 JSReceiver::GetPropertyAttribute(holder, name);
2387 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
2388 // Found an interceptor that's not read only.
2390 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
2391 Handle<Object> result = JSObject::SetPropertyForResult(
2392 holder, &lookup, name, value, attributes, strict_mode);
2393 RETURN_IF_EMPTY_HANDLE(isolate, result);
2396 return isolate->heap()->undefined_value();
2402 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
2403 Handle<GlobalObject> global(isolate->context()->global_object());
2404 Handle<Object> result = JSReceiver::SetProperty(
2405 global, name, value, attributes, strict_mode);
2406 RETURN_IF_EMPTY_HANDLE(isolate, result);
2409 return isolate->heap()->undefined_value();
2413 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_InitializeConstGlobal) {
2414 SealHandleScope shs(isolate);
2415 // All constants are declared with an initial value. The name
2416 // of the constant is the first argument and the initial value
2418 RUNTIME_ASSERT(args.length() == 2);
2419 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
2420 Handle<Object> value = args.at<Object>(1);
2422 // Get the current global object from top.
2423 GlobalObject* global = isolate->context()->global_object();
2425 // According to ECMA-262, section 12.2, page 62, the property must
2426 // not be deletable. Since it's a const, it must be READ_ONLY too.
2427 PropertyAttributes attributes =
2428 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
2430 // Lookup the property locally in the global object. If it isn't
2431 // there, we add the property and take special precautions to always
2432 // add it as a local property even in case of callbacks in the
2433 // prototype chain (this rules out using SetProperty).
2434 // We use SetLocalPropertyIgnoreAttributes instead
2435 LookupResult lookup(isolate);
2436 global->LocalLookup(*name, &lookup);
2437 if (!lookup.IsFound()) {
2438 HandleScope handle_scope(isolate);
2439 Handle<GlobalObject> global(isolate->context()->global_object());
2440 RETURN_IF_EMPTY_HANDLE(
2442 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
2447 if (!lookup.IsReadOnly()) {
2448 // Restore global object from context (in case of GC) and continue
2449 // with setting the value.
2450 HandleScope handle_scope(isolate);
2451 Handle<GlobalObject> global(isolate->context()->global_object());
2453 // BUG 1213575: Handle the case where we have to set a read-only
2454 // property through an interceptor and only do it if it's
2455 // uninitialized, e.g. the hole. Nirk...
2456 // Passing sloppy mode because the property is writable.
2457 RETURN_IF_EMPTY_HANDLE(
2459 JSReceiver::SetProperty(global, name, value, attributes, SLOPPY));
2463 // Set the value, but only if we're assigning the initial value to a
2464 // constant. For now, we determine this by checking if the
2465 // current value is the hole.
2466 // Strict mode handling not needed (const is disallowed in strict mode).
2467 if (lookup.IsField()) {
2468 FixedArray* properties = global->properties();
2469 int index = lookup.GetFieldIndex().field_index();
2470 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
2471 properties->set(index, *value);
2473 } else if (lookup.IsNormal()) {
2474 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
2475 !lookup.IsReadOnly()) {
2476 HandleScope scope(isolate);
2477 JSObject::SetNormalizedProperty(Handle<JSObject>(global), &lookup, value);
2480 // Ignore re-initialization of constants that have already been
2481 // assigned a constant value.
2482 ASSERT(lookup.IsReadOnly() && lookup.IsConstant());
2485 // Use the set value as the result of the operation.
2490 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_InitializeConstContextSlot) {
2491 HandleScope scope(isolate);
2492 ASSERT(args.length() == 3);
2494 Handle<Object> value(args[0], isolate);
2495 ASSERT(!value->IsTheHole());
2497 // Initializations are always done in a function or native context.
2498 RUNTIME_ASSERT(args[1]->IsContext());
2499 Handle<Context> context(Context::cast(args[1])->declaration_context());
2501 Handle<String> name(String::cast(args[2]));
2504 PropertyAttributes attributes;
2505 ContextLookupFlags flags = FOLLOW_CHAINS;
2506 BindingFlags binding_flags;
2507 Handle<Object> holder =
2508 context->Lookup(name, flags, &index, &attributes, &binding_flags);
2511 ASSERT(holder->IsContext());
2512 // Property was found in a context. Perform the assignment if we
2513 // found some non-constant or an uninitialized constant.
2514 Handle<Context> context = Handle<Context>::cast(holder);
2515 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
2516 context->set(index, *value);
2521 // The property could not be found, we introduce it as a property of the
2523 if (attributes == ABSENT) {
2524 Handle<JSObject> global = Handle<JSObject>(
2525 isolate->context()->global_object());
2526 // Strict mode not needed (const disallowed in strict mode).
2527 RETURN_IF_EMPTY_HANDLE(
2529 JSReceiver::SetProperty(global, name, value, NONE, SLOPPY));
2533 // The property was present in some function's context extension object,
2534 // as a property on the subject of a with, or as a property of the global
2537 // In most situations, eval-introduced consts should still be present in
2538 // the context extension object. However, because declaration and
2539 // initialization are separate, the property might have been deleted
2540 // before we reach the initialization point.
2544 // function f() { eval("delete x; const x;"); }
2546 // In that case, the initialization behaves like a normal assignment.
2547 Handle<JSObject> object = Handle<JSObject>::cast(holder);
2549 if (*object == context->extension()) {
2550 // This is the property that was introduced by the const declaration.
2551 // Set it if it hasn't been set before. NOTE: We cannot use
2552 // GetProperty() to get the current value as it 'unholes' the value.
2553 LookupResult lookup(isolate);
2554 object->LocalLookupRealNamedProperty(*name, &lookup);
2555 ASSERT(lookup.IsFound()); // the property was declared
2556 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
2558 if (lookup.IsField()) {
2559 FixedArray* properties = object->properties();
2560 int index = lookup.GetFieldIndex().field_index();
2561 if (properties->get(index)->IsTheHole()) {
2562 properties->set(index, *value);
2564 } else if (lookup.IsNormal()) {
2565 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
2566 JSObject::SetNormalizedProperty(object, &lookup, value);
2569 // We should not reach here. Any real, named property should be
2570 // either a field or a dictionary slot.
2574 // The property was found on some other object. Set it if it is not a
2575 // read-only property.
2576 if ((attributes & READ_ONLY) == 0) {
2577 // Strict mode not needed (const disallowed in strict mode).
2578 RETURN_IF_EMPTY_HANDLE(
2580 JSReceiver::SetProperty(object, name, value, attributes, SLOPPY));
2588 RUNTIME_FUNCTION(MaybeObject*,
2589 Runtime_OptimizeObjectForAddingMultipleProperties) {
2590 HandleScope scope(isolate);
2591 ASSERT(args.length() == 2);
2592 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
2593 CONVERT_SMI_ARG_CHECKED(properties, 1);
2594 if (object->HasFastProperties() && !object->IsJSGlobalProxy()) {
2595 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
2601 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_RegExpExec) {
2602 HandleScope scope(isolate);
2603 ASSERT(args.length() == 4);
2604 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
2605 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
2606 // Due to the way the JS calls are constructed this must be less than the
2607 // length of a string, i.e. it is always a Smi. We check anyway for security.
2608 CONVERT_SMI_ARG_CHECKED(index, 2);
2609 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
2610 RUNTIME_ASSERT(index >= 0);
2611 RUNTIME_ASSERT(index <= subject->length());
2612 isolate->counters()->regexp_entry_runtime()->Increment();
2613 Handle<Object> result = RegExpImpl::Exec(regexp,
2617 RETURN_IF_EMPTY_HANDLE(isolate, result);
2622 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_RegExpConstructResult) {
2623 SealHandleScope shs(isolate);
2624 ASSERT(args.length() == 3);
2625 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
2626 if (elements_count < 0 ||
2627 elements_count > FixedArray::kMaxLength ||
2628 !Smi::IsValid(elements_count)) {
2629 return isolate->ThrowIllegalOperation();
2632 { MaybeObject* maybe_new_object =
2633 isolate->heap()->AllocateFixedArray(elements_count);
2634 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
2636 FixedArray* elements = FixedArray::cast(new_object);
2637 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
2638 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
2639 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
2642 DisallowHeapAllocation no_gc;
2643 HandleScope scope(isolate);
2644 reinterpret_cast<HeapObject*>(new_object)->
2645 set_map(isolate->native_context()->regexp_result_map());
2647 JSArray* array = JSArray::cast(new_object);
2648 array->set_properties(isolate->heap()->empty_fixed_array());
2649 array->set_elements(elements);
2650 array->set_length(Smi::FromInt(elements_count));
2651 // Write in-object properties after the length of the array.
2652 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
2653 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
2658 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
2659 HandleScope scope(isolate);
2660 ASSERT(args.length() == 5);
2661 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
2662 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
2663 // If source is the empty string we set it to "(?:)" instead as
2664 // suggested by ECMA-262, 5th, section 15.10.4.1.
2665 if (source->length() == 0) source = isolate->factory()->query_colon_string();
2667 CONVERT_ARG_HANDLE_CHECKED(Object, global, 2);
2668 if (!global->IsTrue()) global = isolate->factory()->false_value();
2670 CONVERT_ARG_HANDLE_CHECKED(Object, ignoreCase, 3);
2671 if (!ignoreCase->IsTrue()) ignoreCase = isolate->factory()->false_value();
2673 CONVERT_ARG_HANDLE_CHECKED(Object, multiline, 4);
2674 if (!multiline->IsTrue()) multiline = isolate->factory()->false_value();
2676 Map* map = regexp->map();
2677 Object* constructor = map->constructor();
2678 if (constructor->IsJSFunction() &&
2679 JSFunction::cast(constructor)->initial_map() == map) {
2680 // If we still have the original map, set in-object properties directly.
2681 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *source);
2682 // Both true and false are immovable immortal objects so no need for write
2684 regexp->InObjectPropertyAtPut(
2685 JSRegExp::kGlobalFieldIndex, *global, SKIP_WRITE_BARRIER);
2686 regexp->InObjectPropertyAtPut(
2687 JSRegExp::kIgnoreCaseFieldIndex, *ignoreCase, SKIP_WRITE_BARRIER);
2688 regexp->InObjectPropertyAtPut(
2689 JSRegExp::kMultilineFieldIndex, *multiline, SKIP_WRITE_BARRIER);
2690 regexp->InObjectPropertyAtPut(
2691 JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER);
2695 // Map has changed, so use generic, but slower, method.
2696 PropertyAttributes final =
2697 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
2698 PropertyAttributes writable =
2699 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
2700 Handle<Object> zero(Smi::FromInt(0), isolate);
2701 Factory* factory = isolate->factory();
2702 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2703 regexp, factory->source_string(), source, final));
2704 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2705 regexp, factory->global_string(), global, final));
2706 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2707 regexp, factory->ignore_case_string(), ignoreCase, final));
2708 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2709 regexp, factory->multiline_string(), multiline, final));
2710 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2711 regexp, factory->last_index_string(), zero, writable));
2716 RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
2717 HandleScope scope(isolate);
2718 ASSERT(args.length() == 1);
2719 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
2720 // This is necessary to enable fast checks for absence of elements
2721 // on Array.prototype and below.
2722 prototype->set_elements(isolate->heap()->empty_fixed_array());
2723 return Smi::FromInt(0);
2727 static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
2728 Handle<JSObject> holder,
2730 Builtins::Name builtin_name) {
2731 Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
2732 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
2733 Handle<JSFunction> optimized =
2734 isolate->factory()->NewFunction(key,
2736 JSObject::kHeaderSize,
2739 optimized->shared()->DontAdaptArguments();
2740 JSReceiver::SetProperty(holder, key, optimized, NONE, STRICT);
2745 RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
2746 HandleScope scope(isolate);
2747 ASSERT(args.length() == 1);
2748 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
2750 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
2751 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
2752 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
2753 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
2754 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
2755 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
2756 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
2762 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsSloppyModeFunction) {
2763 SealHandleScope shs(isolate);
2764 ASSERT(args.length() == 1);
2765 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
2766 if (!callable->IsJSFunction()) {
2767 HandleScope scope(isolate);
2769 Handle<Object> delegate = Execution::TryGetFunctionDelegate(
2770 isolate, Handle<JSReceiver>(callable), &threw);
2771 if (threw) return Failure::Exception();
2772 callable = JSFunction::cast(*delegate);
2774 JSFunction* function = JSFunction::cast(callable);
2775 SharedFunctionInfo* shared = function->shared();
2776 return isolate->heap()->ToBoolean(shared->strict_mode() == SLOPPY);
2780 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
2781 SealHandleScope shs(isolate);
2782 ASSERT(args.length() == 1);
2783 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
2785 if (!callable->IsJSFunction()) {
2786 HandleScope scope(isolate);
2788 Handle<Object> delegate = Execution::TryGetFunctionDelegate(
2789 isolate, Handle<JSReceiver>(callable), &threw);
2790 if (threw) return Failure::Exception();
2791 callable = JSFunction::cast(*delegate);
2793 JSFunction* function = JSFunction::cast(callable);
2795 SharedFunctionInfo* shared = function->shared();
2796 if (shared->native() || shared->strict_mode() == STRICT) {
2797 return isolate->heap()->undefined_value();
2799 // Returns undefined for strict or native functions, or
2800 // the associated global receiver for "normal" functions.
2802 Context* native_context =
2803 function->context()->global_object()->native_context();
2804 return native_context->global_object()->global_receiver();
2808 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_MaterializeRegExpLiteral) {
2809 HandleScope scope(isolate);
2810 ASSERT(args.length() == 4);
2811 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
2812 int index = args.smi_at(1);
2813 Handle<String> pattern = args.at<String>(2);
2814 Handle<String> flags = args.at<String>(3);
2816 // Get the RegExp function from the context in the literals array.
2817 // This is the RegExp function from the context in which the
2818 // function was created. We do not use the RegExp function from the
2819 // current native context because this might be the RegExp function
2820 // from another context which we should not have access to.
2821 Handle<JSFunction> constructor =
2823 JSFunction::NativeContextFromLiterals(*literals)->regexp_function());
2824 // Compute the regular expression literal.
2825 bool has_pending_exception;
2826 Handle<Object> regexp =
2827 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
2828 &has_pending_exception);
2829 if (has_pending_exception) {
2830 ASSERT(isolate->has_pending_exception());
2831 return Failure::Exception();
2833 literals->set(index, *regexp);
2838 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
2839 SealHandleScope shs(isolate);
2840 ASSERT(args.length() == 1);
2842 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2843 return f->shared()->name();
2847 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
2848 SealHandleScope shs(isolate);
2849 ASSERT(args.length() == 2);
2851 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2852 CONVERT_ARG_CHECKED(String, name, 1);
2853 f->shared()->set_name(name);
2854 return isolate->heap()->undefined_value();
2858 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
2859 SealHandleScope shs(isolate);
2860 ASSERT(args.length() == 1);
2861 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2862 return isolate->heap()->ToBoolean(
2863 f->shared()->name_should_print_as_anonymous());
2867 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
2868 SealHandleScope shs(isolate);
2869 ASSERT(args.length() == 1);
2870 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2871 f->shared()->set_name_should_print_as_anonymous(true);
2872 return isolate->heap()->undefined_value();
2876 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsGenerator) {
2877 SealHandleScope shs(isolate);
2878 ASSERT(args.length() == 1);
2879 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2880 return isolate->heap()->ToBoolean(f->shared()->is_generator());
2884 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
2885 SealHandleScope shs(isolate);
2886 ASSERT(args.length() == 1);
2888 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2889 f->RemovePrototype();
2891 return isolate->heap()->undefined_value();
2895 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
2896 HandleScope scope(isolate);
2897 ASSERT(args.length() == 1);
2899 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2900 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2901 if (!script->IsScript()) return isolate->heap()->undefined_value();
2903 return *GetScriptWrapper(Handle<Script>::cast(script));
2907 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
2908 HandleScope scope(isolate);
2909 ASSERT(args.length() == 1);
2911 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
2912 Handle<SharedFunctionInfo> shared(f->shared());
2913 return *shared->GetSourceCode();
2917 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
2918 SealHandleScope shs(isolate);
2919 ASSERT(args.length() == 1);
2921 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2922 int pos = fun->shared()->start_position();
2923 return Smi::FromInt(pos);
2927 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
2928 SealHandleScope shs(isolate);
2929 ASSERT(args.length() == 2);
2931 CONVERT_ARG_CHECKED(Code, code, 0);
2932 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2934 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2936 Address pc = code->address() + offset;
2937 return Smi::FromInt(code->SourcePosition(pc));
2941 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
2942 SealHandleScope shs(isolate);
2943 ASSERT(args.length() == 2);
2945 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2946 CONVERT_ARG_CHECKED(String, name, 1);
2947 fun->SetInstanceClassName(name);
2948 return isolate->heap()->undefined_value();
2952 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
2953 SealHandleScope shs(isolate);
2954 ASSERT(args.length() == 2);
2956 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2957 CONVERT_SMI_ARG_CHECKED(length, 1);
2958 fun->shared()->set_length(length);
2959 return isolate->heap()->undefined_value();
2963 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
2964 HandleScope scope(isolate);
2965 ASSERT(args.length() == 2);
2967 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
2968 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
2969 ASSERT(fun->should_have_prototype());
2970 Accessors::FunctionSetPrototype(fun, value);
2971 return args[0]; // return TOS
2975 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2976 SealHandleScope shs(isolate);
2977 RUNTIME_ASSERT(args.length() == 1);
2978 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2980 String* name = isolate->heap()->prototype_string();
2982 if (function->HasFastProperties()) {
2983 // Construct a new field descriptor with updated attributes.
2984 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2986 int index = instance_desc->SearchWithCache(name, function->map());
2987 ASSERT(index != DescriptorArray::kNotFound);
2988 PropertyDetails details = instance_desc->GetDetails(index);
2990 CallbacksDescriptor new_desc(name,
2991 instance_desc->GetValue(index),
2992 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY));
2994 // Create a new map featuring the new field descriptors array.
2996 MaybeObject* maybe_map =
2997 function->map()->CopyReplaceDescriptor(
2998 instance_desc, &new_desc, index, OMIT_TRANSITION);
2999 if (!maybe_map->To(&new_map)) return maybe_map;
3001 function->set_map(new_map);
3002 } else { // Dictionary properties.
3003 // Directly manipulate the property details.
3004 int entry = function->property_dictionary()->FindEntry(name);
3005 ASSERT(entry != NameDictionary::kNotFound);
3006 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
3007 PropertyDetails new_details(
3008 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
3010 details.dictionary_index());
3011 function->property_dictionary()->DetailsAtPut(entry, new_details);
3017 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
3018 SealHandleScope shs(isolate);
3019 ASSERT(args.length() == 1);
3021 CONVERT_ARG_CHECKED(JSFunction, f, 0);
3022 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
3026 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
3027 SealHandleScope shs(isolate);
3028 ASSERT(args.length() == 1);
3030 CONVERT_ARG_CHECKED(JSFunction, f, 0);
3031 return isolate->heap()->ToBoolean(f->IsBuiltin());
3035 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
3036 HandleScope scope(isolate);
3037 ASSERT(args.length() == 2);
3039 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
3040 Handle<Object> code = args.at<Object>(1);
3042 if (code->IsNull()) return *target;
3043 RUNTIME_ASSERT(code->IsJSFunction());
3044 Handle<JSFunction> source = Handle<JSFunction>::cast(code);
3045 Handle<SharedFunctionInfo> target_shared(target->shared());
3046 Handle<SharedFunctionInfo> source_shared(source->shared());
3048 if (!Compiler::EnsureCompiled(source, KEEP_EXCEPTION)) {
3049 return Failure::Exception();
3052 // Mark both, the source and the target, as un-flushable because the
3053 // shared unoptimized code makes them impossible to enqueue in a list.
3054 ASSERT(target_shared->code()->gc_metadata() == NULL);
3055 ASSERT(source_shared->code()->gc_metadata() == NULL);
3056 target_shared->set_dont_flush(true);
3057 source_shared->set_dont_flush(true);
3059 // Set the code, scope info, formal parameter count, and the length
3060 // of the target shared function info.
3061 target_shared->ReplaceCode(source_shared->code());
3062 target_shared->set_scope_info(source_shared->scope_info());
3063 target_shared->set_length(source_shared->length());
3064 target_shared->set_formal_parameter_count(
3065 source_shared->formal_parameter_count());
3066 target_shared->set_script(source_shared->script());
3067 target_shared->set_start_position_and_type(
3068 source_shared->start_position_and_type());
3069 target_shared->set_end_position(source_shared->end_position());
3070 bool was_native = target_shared->native();
3071 target_shared->set_compiler_hints(source_shared->compiler_hints());
3072 target_shared->set_native(was_native);
3074 // Set the code of the target function.
3075 target->ReplaceCode(source_shared->code());
3076 ASSERT(target->next_function_link()->IsUndefined());
3078 // Make sure we get a fresh copy of the literal vector to avoid cross
3079 // context contamination.
3080 Handle<Context> context(source->context());
3081 int number_of_literals = source->NumberOfLiterals();
3082 Handle<FixedArray> literals =
3083 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
3084 if (number_of_literals > 0) {
3085 literals->set(JSFunction::kLiteralNativeContextIndex,
3086 context->native_context());
3088 target->set_context(*context);
3089 target->set_literals(*literals);
3091 if (isolate->logger()->is_logging_code_events() ||
3092 isolate->cpu_profiler()->is_profiling()) {
3093 isolate->logger()->LogExistingFunction(
3094 source_shared, Handle<Code>(source_shared->code()));
3101 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
3102 HandleScope scope(isolate);
3103 ASSERT(args.length() == 2);
3104 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
3105 CONVERT_SMI_ARG_CHECKED(num, 1);
3106 RUNTIME_ASSERT(num >= 0);
3107 // If objects constructed from this function exist then changing
3108 // 'estimated_nof_properties' is dangerous since the previous value might
3109 // have been compiled into the fast construct stub. Moreover, the inobject
3110 // slack tracking logic might have adjusted the previous value, so even
3111 // passing the same value is risky.
3112 if (!func->shared()->live_objects_may_exist()) {
3113 func->shared()->set_expected_nof_properties(num);
3114 if (func->has_initial_map()) {
3115 Handle<Map> new_initial_map =
3116 func->GetIsolate()->factory()->CopyMap(
3117 Handle<Map>(func->initial_map()));
3118 new_initial_map->set_unused_property_fields(num);
3119 func->set_initial_map(*new_initial_map);
3122 return isolate->heap()->undefined_value();
3126 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_CreateJSGeneratorObject) {
3127 HandleScope scope(isolate);
3128 ASSERT(args.length() == 0);
3130 JavaScriptFrameIterator it(isolate);
3131 JavaScriptFrame* frame = it.frame();
3132 Handle<JSFunction> function(frame->function());
3133 RUNTIME_ASSERT(function->shared()->is_generator());
3135 Handle<JSGeneratorObject> generator;
3136 if (frame->IsConstructor()) {
3137 generator = handle(JSGeneratorObject::cast(frame->receiver()));
3139 generator = isolate->factory()->NewJSGeneratorObject(function);
3141 generator->set_function(*function);
3142 generator->set_context(Context::cast(frame->context()));
3143 generator->set_receiver(frame->receiver());
3144 generator->set_continuation(0);
3145 generator->set_operand_stack(isolate->heap()->empty_fixed_array());
3146 generator->set_stack_handler_index(-1);
3152 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_SuspendJSGeneratorObject) {
3153 SealHandleScope shs(isolate);
3154 ASSERT(args.length() == 1);
3155 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
3157 JavaScriptFrameIterator stack_iterator(isolate);
3158 JavaScriptFrame* frame = stack_iterator.frame();
3159 RUNTIME_ASSERT(frame->function()->shared()->is_generator());
3160 ASSERT_EQ(frame->function(), generator_object->function());
3162 // The caller should have saved the context and continuation already.
3163 ASSERT_EQ(generator_object->context(), Context::cast(frame->context()));
3164 ASSERT_LT(0, generator_object->continuation());
3166 // We expect there to be at least two values on the operand stack: the return
3167 // value of the yield expression, and the argument to this runtime call.
3168 // Neither of those should be saved.
3169 int operands_count = frame->ComputeOperandsCount();
3170 ASSERT_GE(operands_count, 2);
3171 operands_count -= 2;
3173 if (operands_count == 0) {
3174 // Although it's semantically harmless to call this function with an
3175 // operands_count of zero, it is also unnecessary.
3176 ASSERT_EQ(generator_object->operand_stack(),
3177 isolate->heap()->empty_fixed_array());
3178 ASSERT_EQ(generator_object->stack_handler_index(), -1);
3179 // If there are no operands on the stack, there shouldn't be a handler
3181 ASSERT(!frame->HasHandler());
3183 int stack_handler_index = -1;
3184 MaybeObject* alloc = isolate->heap()->AllocateFixedArray(operands_count);
3185 FixedArray* operand_stack;
3186 if (!alloc->To(&operand_stack)) return alloc;
3187 frame->SaveOperandStack(operand_stack, &stack_handler_index);
3188 generator_object->set_operand_stack(operand_stack);
3189 generator_object->set_stack_handler_index(stack_handler_index);
3192 return isolate->heap()->undefined_value();
3196 // Note that this function is the slow path for resuming generators. It is only
3197 // called if the suspended activation had operands on the stack, stack handlers
3198 // needing rewinding, or if the resume should throw an exception. The fast path
3199 // is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
3200 // inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is
3201 // called in any case, as it needs to reconstruct the stack frame and make space
3202 // for arguments and operands.
3203 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_ResumeJSGeneratorObject) {
3204 SealHandleScope shs(isolate);
3205 ASSERT(args.length() == 3);
3206 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
3207 CONVERT_ARG_CHECKED(Object, value, 1);
3208 CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2);
3209 JavaScriptFrameIterator stack_iterator(isolate);
3210 JavaScriptFrame* frame = stack_iterator.frame();
3212 ASSERT_EQ(frame->function(), generator_object->function());
3213 ASSERT(frame->function()->is_compiled());
3215 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
3216 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
3218 Address pc = generator_object->function()->code()->instruction_start();
3219 int offset = generator_object->continuation();
3221 frame->set_pc(pc + offset);
3222 if (FLAG_enable_ool_constant_pool) {
3223 frame->set_constant_pool(
3224 generator_object->function()->code()->constant_pool());
3226 generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
3228 FixedArray* operand_stack = generator_object->operand_stack();
3229 int operands_count = operand_stack->length();
3230 if (operands_count != 0) {
3231 frame->RestoreOperandStack(operand_stack,
3232 generator_object->stack_handler_index());
3233 generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
3234 generator_object->set_stack_handler_index(-1);
3237 JSGeneratorObject::ResumeMode resume_mode =
3238 static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
3239 switch (resume_mode) {
3240 case JSGeneratorObject::NEXT:
3242 case JSGeneratorObject::THROW:
3243 return isolate->Throw(value);
3247 return isolate->ThrowIllegalOperation();
3251 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_ThrowGeneratorStateError) {
3252 HandleScope scope(isolate);
3253 ASSERT(args.length() == 1);
3254 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
3255 int continuation = generator->continuation();
3256 const char* message = continuation == JSGeneratorObject::kGeneratorClosed ?
3257 "generator_finished" : "generator_running";
3258 Vector< Handle<Object> > argv = HandleVector<Object>(NULL, 0);
3259 Handle<Object> error = isolate->factory()->NewError(message, argv);
3260 return isolate->Throw(*error);
3264 RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectFreeze) {
3265 HandleScope scope(isolate);
3266 ASSERT(args.length() == 1);
3267 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
3268 Handle<Object> result = JSObject::Freeze(object);
3269 RETURN_IF_EMPTY_HANDLE(isolate, result);
3274 MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
3275 Object* char_code) {
3276 if (char_code->IsNumber()) {
3277 return isolate->heap()->LookupSingleCharacterStringFromCode(
3278 NumberToUint32(char_code) & 0xffff);
3280 return isolate->heap()->empty_string();
3284 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_StringCharCodeAt) {
3285 SealHandleScope shs(isolate);
3286 ASSERT(args.length() == 2);
3288 CONVERT_ARG_CHECKED(String, subject, 0);
3289 CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]);
3291 // Flatten the string. If someone wants to get a char at an index
3292 // in a cons string, it is likely that more indices will be
3295 { MaybeObject* maybe_flat = subject->TryFlatten();
3296 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
3298 subject = String::cast(flat);
3300 if (i >= static_cast<uint32_t>(subject->length())) {
3301 return isolate->heap()->nan_value();
3304 return Smi::FromInt(subject->Get(i));
3308 RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
3309 SealHandleScope shs(isolate);
3310 ASSERT(args.length() == 1);
3311 return CharFromCode(isolate, args[0]);
3315 class FixedArrayBuilder {
3317 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
3318 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
3320 has_non_smi_elements_(false) {
3321 // Require a non-zero initial size. Ensures that doubling the size to
3322 // extend the array will work.
3323 ASSERT(initial_capacity > 0);
3326 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
3327 : array_(backing_store),
3329 has_non_smi_elements_(false) {
3330 // Require a non-zero initial size. Ensures that doubling the size to
3331 // extend the array will work.
3332 ASSERT(backing_store->length() > 0);
3335 bool HasCapacity(int elements) {
3336 int length = array_->length();
3337 int required_length = length_ + elements;
3338 return (length >= required_length);
3341 void EnsureCapacity(int elements) {
3342 int length = array_->length();
3343 int required_length = length_ + elements;
3344 if (length < required_length) {
3345 int new_length = length;
3348 } while (new_length < required_length);
3349 Handle<FixedArray> extended_array =
3350 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
3351 array_->CopyTo(0, *extended_array, 0, length_);
3352 array_ = extended_array;
3356 void Add(Object* value) {
3357 ASSERT(!value->IsSmi());
3358 ASSERT(length_ < capacity());
3359 array_->set(length_, value);
3361 has_non_smi_elements_ = true;
3364 void Add(Smi* value) {
3365 ASSERT(value->IsSmi());
3366 ASSERT(length_ < capacity());
3367 array_->set(length_, value);
3371 Handle<FixedArray> array() {
3380 return array_->length();
3383 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
3384 JSArray::SetContent(target_array, array_);
3385 target_array->set_length(Smi::FromInt(length_));
3386 return target_array;
3391 Handle<FixedArray> array_;
3393 bool has_non_smi_elements_;
3397 // Forward declarations.
3398 const int kStringBuilderConcatHelperLengthBits = 11;
3399 const int kStringBuilderConcatHelperPositionBits = 19;
3401 template <typename schar>
3402 static inline void StringBuilderConcatHelper(String*,
3407 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
3408 StringBuilderSubstringLength;
3409 typedef BitField<int,
3410 kStringBuilderConcatHelperLengthBits,
3411 kStringBuilderConcatHelperPositionBits>
3412 StringBuilderSubstringPosition;
3415 class ReplacementStringBuilder {
3417 ReplacementStringBuilder(Heap* heap,
3418 Handle<String> subject,
3419 int estimated_part_count)
3421 array_builder_(heap->isolate(), estimated_part_count),
3423 character_count_(0),
3424 is_ascii_(subject->IsOneByteRepresentation()) {
3425 // Require a non-zero initial size. Ensures that doubling the size to
3426 // extend the array will work.
3427 ASSERT(estimated_part_count > 0);
3430 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
3434 int length = to - from;
3436 if (StringBuilderSubstringLength::is_valid(length) &&
3437 StringBuilderSubstringPosition::is_valid(from)) {
3438 int encoded_slice = StringBuilderSubstringLength::encode(length) |
3439 StringBuilderSubstringPosition::encode(from);
3440 builder->Add(Smi::FromInt(encoded_slice));
3442 // Otherwise encode as two smis.
3443 builder->Add(Smi::FromInt(-length));
3444 builder->Add(Smi::FromInt(from));
3449 void EnsureCapacity(int elements) {
3450 array_builder_.EnsureCapacity(elements);
3454 void AddSubjectSlice(int from, int to) {
3455 AddSubjectSlice(&array_builder_, from, to);
3456 IncrementCharacterCount(to - from);
3460 void AddString(Handle<String> string) {
3461 int length = string->length();
3463 AddElement(*string);
3464 if (!string->IsOneByteRepresentation()) {
3467 IncrementCharacterCount(length);
3471 Handle<String> ToString() {
3472 if (array_builder_.length() == 0) {
3473 return heap_->isolate()->factory()->empty_string();
3476 Handle<String> joined_string;
3478 Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_);
3479 RETURN_IF_EMPTY_HANDLE_VALUE(heap_->isolate(), seq, Handle<String>());
3480 DisallowHeapAllocation no_gc;
3481 uint8_t* char_buffer = seq->GetChars();
3482 StringBuilderConcatHelper(*subject_,
3484 *array_builder_.array(),
3485 array_builder_.length());
3486 joined_string = Handle<String>::cast(seq);
3489 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
3490 RETURN_IF_EMPTY_HANDLE_VALUE(heap_->isolate(), seq, Handle<String>());
3491 DisallowHeapAllocation no_gc;
3492 uc16* char_buffer = seq->GetChars();
3493 StringBuilderConcatHelper(*subject_,
3495 *array_builder_.array(),
3496 array_builder_.length());
3497 joined_string = Handle<String>::cast(seq);
3499 return joined_string;
3503 void IncrementCharacterCount(int by) {
3504 if (character_count_ > String::kMaxLength - by) {
3505 STATIC_ASSERT(String::kMaxLength < kMaxInt);
3506 character_count_ = kMaxInt;
3508 character_count_ += by;
3513 Handle<SeqOneByteString> NewRawOneByteString(int length) {
3514 return heap_->isolate()->factory()->NewRawOneByteString(length);
3518 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
3519 return heap_->isolate()->factory()->NewRawTwoByteString(length);
3523 void AddElement(Object* element) {
3524 ASSERT(element->IsSmi() || element->IsString());
3525 ASSERT(array_builder_.capacity() > array_builder_.length());
3526 array_builder_.Add(element);
3530 FixedArrayBuilder array_builder_;
3531 Handle<String> subject_;
3532 int character_count_;
3537 class CompiledReplacement {
3539 explicit CompiledReplacement(Zone* zone)
3540 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {}
3542 // Return whether the replacement is simple.
3543 bool Compile(Handle<String> replacement,
3545 int subject_length);
3547 // Use Apply only if Compile returned false.
3548 void Apply(ReplacementStringBuilder* builder,
3553 // Number of distinct parts of the replacement pattern.
3555 return parts_.length();
3558 Zone* zone() const { return zone_; }
3565 REPLACEMENT_SUBSTRING,
3568 NUMBER_OF_PART_TYPES
3571 struct ReplacementPart {
3572 static inline ReplacementPart SubjectMatch() {
3573 return ReplacementPart(SUBJECT_CAPTURE, 0);
3575 static inline ReplacementPart SubjectCapture(int capture_index) {
3576 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
3578 static inline ReplacementPart SubjectPrefix() {
3579 return ReplacementPart(SUBJECT_PREFIX, 0);
3581 static inline ReplacementPart SubjectSuffix(int subject_length) {
3582 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
3584 static inline ReplacementPart ReplacementString() {
3585 return ReplacementPart(REPLACEMENT_STRING, 0);
3587 static inline ReplacementPart ReplacementSubString(int from, int to) {
3590 return ReplacementPart(-from, to);
3593 // If tag <= 0 then it is the negation of a start index of a substring of
3594 // the replacement pattern, otherwise it's a value from PartType.
3595 ReplacementPart(int tag, int data)
3596 : tag(tag), data(data) {
3597 // Must be non-positive or a PartType value.
3598 ASSERT(tag < NUMBER_OF_PART_TYPES);
3600 // Either a value of PartType or a non-positive number that is
3601 // the negation of an index into the replacement string.
3603 // The data value's interpretation depends on the value of tag:
3604 // tag == SUBJECT_PREFIX ||
3605 // tag == SUBJECT_SUFFIX: data is unused.
3606 // tag == SUBJECT_CAPTURE: data is the number of the capture.
3607 // tag == REPLACEMENT_SUBSTRING ||
3608 // tag == REPLACEMENT_STRING: data is index into array of substrings
3609 // of the replacement string.
3610 // tag <= 0: Temporary representation of the substring of the replacement
3611 // string ranging over -tag .. data.
3612 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
3613 // substring objects.
3617 template<typename Char>
3618 bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
3619 Vector<Char> characters,
3623 int length = characters.length();
3625 for (int i = 0; i < length; i++) {
3626 Char c = characters[i];
3628 int next_index = i + 1;
3629 if (next_index == length) { // No next character!
3632 Char c2 = characters[next_index];
3636 // There is a substring before. Include the first "$".
3637 parts->Add(ReplacementPart::ReplacementSubString(last, next_index),
3639 last = next_index + 1; // Continue after the second "$".
3641 // Let the next substring start with the second "$".
3648 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3650 parts->Add(ReplacementPart::SubjectPrefix(), zone);
3656 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3658 parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone);
3664 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3666 parts->Add(ReplacementPart::SubjectMatch(), zone);
3680 int capture_ref = c2 - '0';
3681 if (capture_ref > capture_count) {
3685 int second_digit_index = next_index + 1;
3686 if (second_digit_index < length) {
3687 // Peek ahead to see if we have two digits.
3688 Char c3 = characters[second_digit_index];
3689 if ('0' <= c3 && c3 <= '9') { // Double digits.
3690 int double_digit_ref = capture_ref * 10 + c3 - '0';
3691 if (double_digit_ref <= capture_count) {
3692 next_index = second_digit_index;
3693 capture_ref = double_digit_ref;
3697 if (capture_ref > 0) {
3699 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
3701 ASSERT(capture_ref <= capture_count);
3702 parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone);
3703 last = next_index + 1;
3714 if (length > last) {
3716 // Replacement is simple. Do not use Apply to do the replacement.
3719 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone);
3725 ZoneList<ReplacementPart> parts_;
3726 ZoneList<Handle<String> > replacement_substrings_;
3731 bool CompiledReplacement::Compile(Handle<String> replacement,
3733 int subject_length) {
3735 DisallowHeapAllocation no_gc;
3736 String::FlatContent content = replacement->GetFlatContent();
3737 ASSERT(content.IsFlat());
3738 bool simple = false;
3739 if (content.IsAscii()) {
3740 simple = ParseReplacementPattern(&parts_,
3741 content.ToOneByteVector(),
3746 ASSERT(content.IsTwoByte());
3747 simple = ParseReplacementPattern(&parts_,
3748 content.ToUC16Vector(),
3753 if (simple) return true;
3756 Isolate* isolate = replacement->GetIsolate();
3757 // Find substrings of replacement string and create them as String objects.
3758 int substring_index = 0;
3759 for (int i = 0, n = parts_.length(); i < n; i++) {
3760 int tag = parts_[i].tag;
3761 if (tag <= 0) { // A replacement string slice.
3763 int to = parts_[i].data;
3764 replacement_substrings_.Add(
3765 isolate->factory()->NewSubString(replacement, from, to), zone());
3766 parts_[i].tag = REPLACEMENT_SUBSTRING;
3767 parts_[i].data = substring_index;
3769 } else if (tag == REPLACEMENT_STRING) {
3770 replacement_substrings_.Add(replacement, zone());
3771 parts_[i].data = substring_index;
3779 void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
3783 ASSERT_LT(0, parts_.length());
3784 for (int i = 0, n = parts_.length(); i < n; i++) {
3785 ReplacementPart part = parts_[i];
3787 case SUBJECT_PREFIX:
3788 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
3790 case SUBJECT_SUFFIX: {
3791 int subject_length = part.data;
3792 if (match_to < subject_length) {
3793 builder->AddSubjectSlice(match_to, subject_length);
3797 case SUBJECT_CAPTURE: {
3798 int capture = part.data;
3799 int from = match[capture * 2];
3800 int to = match[capture * 2 + 1];
3801 if (from >= 0 && to > from) {
3802 builder->AddSubjectSlice(from, to);
3806 case REPLACEMENT_SUBSTRING:
3807 case REPLACEMENT_STRING:
3808 builder->AddString(replacement_substrings_[part.data]);
3817 void FindAsciiStringIndices(Vector<const uint8_t> subject,
3819 ZoneList<int>* indices,
3823 // Collect indices of pattern in subject using memchr.
3824 // Stop after finding at most limit values.
3825 const uint8_t* subject_start = subject.start();
3826 const uint8_t* subject_end = subject_start + subject.length();
3827 const uint8_t* pos = subject_start;
3829 pos = reinterpret_cast<const uint8_t*>(
3830 memchr(pos, pattern, subject_end - pos));
3831 if (pos == NULL) return;
3832 indices->Add(static_cast<int>(pos - subject_start), zone);
3839 void FindTwoByteStringIndices(const Vector<const uc16> subject,
3841 ZoneList<int>* indices,
3845 const uc16* subject_start = subject.start();
3846 const uc16* subject_end = subject_start + subject.length();
3847 for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) {
3848 if (*pos == pattern) {
3849 indices->Add(static_cast<int>(pos - subject_start), zone);
3856 template <typename SubjectChar, typename PatternChar>
3857 void FindStringIndices(Isolate* isolate,
3858 Vector<const SubjectChar> subject,
3859 Vector<const PatternChar> pattern,
3860 ZoneList<int>* indices,
3864 // Collect indices of pattern in subject.
3865 // Stop after finding at most limit values.
3866 int pattern_length = pattern.length();
3868 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
3870 index = search.Search(subject, index);
3871 if (index < 0) return;
3872 indices->Add(index, zone);
3873 index += pattern_length;
3879 void FindStringIndicesDispatch(Isolate* isolate,
3882 ZoneList<int>* indices,
3886 DisallowHeapAllocation no_gc;
3887 String::FlatContent subject_content = subject->GetFlatContent();
3888 String::FlatContent pattern_content = pattern->GetFlatContent();
3889 ASSERT(subject_content.IsFlat());
3890 ASSERT(pattern_content.IsFlat());
3891 if (subject_content.IsAscii()) {
3892 Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
3893 if (pattern_content.IsAscii()) {
3894 Vector<const uint8_t> pattern_vector =
3895 pattern_content.ToOneByteVector();
3896 if (pattern_vector.length() == 1) {
3897 FindAsciiStringIndices(subject_vector,
3903 FindStringIndices(isolate,
3911 FindStringIndices(isolate,
3913 pattern_content.ToUC16Vector(),
3919 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3920 if (pattern_content.IsAscii()) {
3921 Vector<const uint8_t> pattern_vector =
3922 pattern_content.ToOneByteVector();
3923 if (pattern_vector.length() == 1) {
3924 FindTwoByteStringIndices(subject_vector,
3930 FindStringIndices(isolate,
3938 Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector();
3939 if (pattern_vector.length() == 1) {
3940 FindTwoByteStringIndices(subject_vector,
3946 FindStringIndices(isolate,
3959 template<typename ResultSeqString>
3960 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString(
3962 Handle<String> subject,
3963 Handle<JSRegExp> pattern_regexp,
3964 Handle<String> replacement,
3965 Handle<JSArray> last_match_info) {
3966 ASSERT(subject->IsFlat());
3967 ASSERT(replacement->IsFlat());
3969 ZoneScope zone_scope(isolate->runtime_zone());
3970 ZoneList<int> indices(8, zone_scope.zone());
3971 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
3973 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
3974 int subject_len = subject->length();
3975 int pattern_len = pattern->length();
3976 int replacement_len = replacement->length();
3978 FindStringIndicesDispatch(
3979 isolate, *subject, pattern, &indices, 0xffffffff, zone_scope.zone());
3981 int matches = indices.length();
3982 if (matches == 0) return *subject;
3984 // Detect integer overflow.
3985 int64_t result_len_64 =
3986 (static_cast<int64_t>(replacement_len) -
3987 static_cast<int64_t>(pattern_len)) *
3988 static_cast<int64_t>(matches) +
3989 static_cast<int64_t>(subject_len);
3991 if (result_len_64 > static_cast<int64_t>(String::kMaxLength)) {
3992 STATIC_ASSERT(String::kMaxLength < kMaxInt);
3993 result_len = kMaxInt; // Provoke exception.
3995 result_len = static_cast<int>(result_len_64);
3998 int subject_pos = 0;
4001 Handle<String> result_seq;
4002 if (ResultSeqString::kHasAsciiEncoding) {
4003 result_seq = isolate->factory()->NewRawOneByteString(result_len);
4005 result_seq = isolate->factory()->NewRawTwoByteString(result_len);
4007 RETURN_IF_EMPTY_HANDLE(isolate, result_seq);
4008 Handle<ResultSeqString> result = Handle<ResultSeqString>::cast(result_seq);
4010 for (int i = 0; i < matches; i++) {
4011 // Copy non-matched subject content.
4012 if (subject_pos < indices.at(i)) {
4013 String::WriteToFlat(*subject,
4014 result->GetChars() + result_pos,
4017 result_pos += indices.at(i) - subject_pos;
4021 if (replacement_len > 0) {
4022 String::WriteToFlat(*replacement,
4023 result->GetChars() + result_pos,
4026 result_pos += replacement_len;
4029 subject_pos = indices.at(i) + pattern_len;
4031 // Add remaining subject content at the end.
4032 if (subject_pos < subject_len) {
4033 String::WriteToFlat(*subject,
4034 result->GetChars() + result_pos,
4039 int32_t match_indices[] = { indices.at(matches - 1),
4040 indices.at(matches - 1) + pattern_len };
4041 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices);
4047 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString(
4049 Handle<String> subject,
4050 Handle<JSRegExp> regexp,
4051 Handle<String> replacement,
4052 Handle<JSArray> last_match_info) {
4053 ASSERT(subject->IsFlat());
4054 ASSERT(replacement->IsFlat());
4056 int capture_count = regexp->CaptureCount();
4057 int subject_length = subject->length();
4059 // CompiledReplacement uses zone allocation.
4060 ZoneScope zone_scope(isolate->runtime_zone());
4061 CompiledReplacement compiled_replacement(zone_scope.zone());
4062 bool simple_replace = compiled_replacement.Compile(replacement,
4066 // Shortcut for simple non-regexp global replacements
4067 if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) {
4068 if (subject->HasOnlyOneByteChars() &&
4069 replacement->HasOnlyOneByteChars()) {
4070 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
4071 isolate, subject, regexp, replacement, last_match_info);
4073 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
4074 isolate, subject, regexp, replacement, last_match_info);
4078 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4079 if (global_cache.HasException()) return Failure::Exception();
4081 int32_t* current_match = global_cache.FetchNext();
4082 if (current_match == NULL) {
4083 if (global_cache.HasException()) return Failure::Exception();
4087 // Guessing the number of parts that the final result string is built
4088 // from. Global regexps can match any number of times, so we guess
4090 int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1;
4091 ReplacementStringBuilder builder(isolate->heap(),
4095 // Number of parts added by compiled replacement plus preceeding
4096 // string and possibly suffix after last match. It is possible for
4097 // all components to use two elements when encoded as two smis.
4098 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
4103 builder.EnsureCapacity(parts_added_per_loop);
4105 int start = current_match[0];
4106 int end = current_match[1];
4109 builder.AddSubjectSlice(prev, start);
4112 if (simple_replace) {
4113 builder.AddString(replacement);
4115 compiled_replacement.Apply(&builder,
4122 current_match = global_cache.FetchNext();
4123 } while (current_match != NULL);
4125 if (global_cache.HasException()) return Failure::Exception();
4127 if (prev < subject_length) {
4128 builder.EnsureCapacity(2);
4129 builder.AddSubjectSlice(prev, subject_length);
4132 RegExpImpl::SetLastMatchInfo(last_match_info,
4135 global_cache.LastSuccessfulMatch());
4137 Handle<String> result = builder.ToString();
4138 RETURN_IF_EMPTY_HANDLE(isolate, result);
4143 template <typename ResultSeqString>
4144 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString(
4146 Handle<String> subject,
4147 Handle<JSRegExp> regexp,
4148 Handle<JSArray> last_match_info) {
4149 ASSERT(subject->IsFlat());
4151 // Shortcut for simple non-regexp global replacements
4152 if (regexp->TypeTag() == JSRegExp::ATOM) {
4153 Handle<String> empty_string = isolate->factory()->empty_string();
4154 if (subject->IsOneByteRepresentation()) {
4155 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
4156 isolate, subject, regexp, empty_string, last_match_info);
4158 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
4159 isolate, subject, regexp, empty_string, last_match_info);
4163 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4164 if (global_cache.HasException()) return Failure::Exception();
4166 int32_t* current_match = global_cache.FetchNext();
4167 if (current_match == NULL) {
4168 if (global_cache.HasException()) return Failure::Exception();
4172 int start = current_match[0];
4173 int end = current_match[1];
4174 int capture_count = regexp->CaptureCount();
4175 int subject_length = subject->length();
4177 int new_length = subject_length - (end - start);
4178 if (new_length == 0) return isolate->heap()->empty_string();
4180 Handle<ResultSeqString> answer;
4181 if (ResultSeqString::kHasAsciiEncoding) {
4182 answer = Handle<ResultSeqString>::cast(
4183 isolate->factory()->NewRawOneByteString(new_length));
4185 answer = Handle<ResultSeqString>::cast(
4186 isolate->factory()->NewRawTwoByteString(new_length));
4188 ASSERT(!answer.is_null());
4194 start = current_match[0];
4195 end = current_match[1];
4197 // Add substring subject[prev;start] to answer string.
4198 String::WriteToFlat(*subject, answer->GetChars() + position, prev, start);
4199 position += start - prev;
4203 current_match = global_cache.FetchNext();
4204 } while (current_match != NULL);
4206 if (global_cache.HasException()) return Failure::Exception();
4208 RegExpImpl::SetLastMatchInfo(last_match_info,
4211 global_cache.LastSuccessfulMatch());
4213 if (prev < subject_length) {
4214 // Add substring subject[prev;length] to answer string.
4215 String::WriteToFlat(
4216 *subject, answer->GetChars() + position, prev, subject_length);
4217 position += subject_length - prev;
4220 if (position == 0) return isolate->heap()->empty_string();
4222 // Shorten string and fill
4223 int string_size = ResultSeqString::SizeFor(position);
4224 int allocated_string_size = ResultSeqString::SizeFor(new_length);
4225 int delta = allocated_string_size - string_size;
4227 answer->set_length(position);
4228 if (delta == 0) return *answer;
4230 Address end_of_string = answer->address() + string_size;
4231 Heap* heap = isolate->heap();
4232 heap->CreateFillerObjectAt(end_of_string, delta);
4233 heap->AdjustLiveBytes(answer->address(), -delta, Heap::FROM_MUTATOR);
4238 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceGlobalRegExpWithString) {
4239 HandleScope scope(isolate);
4240 ASSERT(args.length() == 4);
4242 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4243 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
4244 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
4245 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
4247 ASSERT(regexp->GetFlags().is_global());
4249 if (!subject->IsFlat()) subject = FlattenGetString(subject);
4251 if (replacement->length() == 0) {
4252 if (subject->HasOnlyOneByteChars()) {
4253 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>(
4254 isolate, subject, regexp, last_match_info);
4256 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>(
4257 isolate, subject, regexp, last_match_info);
4261 if (!replacement->IsFlat()) replacement = FlattenGetString(replacement);
4263 return StringReplaceGlobalRegExpWithString(
4264 isolate, subject, regexp, replacement, last_match_info);
4268 Handle<String> StringReplaceOneCharWithString(Isolate* isolate,
4269 Handle<String> subject,
4270 Handle<String> search,
4271 Handle<String> replace,
4273 int recursion_limit) {
4274 if (recursion_limit == 0) return Handle<String>::null();
4275 if (subject->IsConsString()) {
4276 ConsString* cons = ConsString::cast(*subject);
4277 Handle<String> first = Handle<String>(cons->first());
4278 Handle<String> second = Handle<String>(cons->second());
4279 Handle<String> new_first =
4280 StringReplaceOneCharWithString(isolate,
4285 recursion_limit - 1);
4286 if (new_first.is_null()) return new_first;
4287 if (*found) return isolate->factory()->NewConsString(new_first, second);
4289 Handle<String> new_second =
4290 StringReplaceOneCharWithString(isolate,
4295 recursion_limit - 1);
4296 if (new_second.is_null()) return new_second;
4297 if (*found) return isolate->factory()->NewConsString(first, new_second);
4301 int index = Runtime::StringMatch(isolate, subject, search, 0);
4302 if (index == -1) return subject;
4304 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
4305 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
4306 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, cons1, Handle<String>());
4307 Handle<String> second =
4308 isolate->factory()->NewSubString(subject, index + 1, subject->length());
4309 return isolate->factory()->NewConsString(cons1, second);
4314 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
4315 HandleScope scope(isolate);
4316 ASSERT(args.length() == 3);
4317 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4318 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
4319 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
4321 // If the cons string tree is too deep, we simply abort the recursion and
4322 // retry with a flattened subject string.
4323 const int kRecursionLimit = 0x1000;
4325 Handle<String> result = StringReplaceOneCharWithString(isolate,
4331 if (!result.is_null()) return *result;
4332 if (isolate->has_pending_exception()) return Failure::Exception();
4333 return *StringReplaceOneCharWithString(isolate,
4334 FlattenGetString(subject),
4342 // Perform string match of pattern on subject, starting at start index.
4343 // Caller must ensure that 0 <= start_index <= sub->length(),
4344 // and should check that pat->length() + start_index <= sub->length().
4345 int Runtime::StringMatch(Isolate* isolate,
4349 ASSERT(0 <= start_index);
4350 ASSERT(start_index <= sub->length());
4352 int pattern_length = pat->length();
4353 if (pattern_length == 0) return start_index;
4355 int subject_length = sub->length();
4356 if (start_index + pattern_length > subject_length) return -1;
4358 if (!sub->IsFlat()) FlattenString(sub);
4359 if (!pat->IsFlat()) FlattenString(pat);
4361 DisallowHeapAllocation no_gc; // ensure vectors stay valid
4362 // Extract flattened substrings of cons strings before determining asciiness.
4363 String::FlatContent seq_sub = sub->GetFlatContent();
4364 String::FlatContent seq_pat = pat->GetFlatContent();
4366 // dispatch on type of strings
4367 if (seq_pat.IsAscii()) {
4368 Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector();
4369 if (seq_sub.IsAscii()) {
4370 return SearchString(isolate,
4371 seq_sub.ToOneByteVector(),
4375 return SearchString(isolate,
4376 seq_sub.ToUC16Vector(),
4380 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
4381 if (seq_sub.IsAscii()) {
4382 return SearchString(isolate,
4383 seq_sub.ToOneByteVector(),
4387 return SearchString(isolate,
4388 seq_sub.ToUC16Vector(),
4394 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
4395 HandleScope scope(isolate);
4396 ASSERT(args.length() == 3);
4398 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
4399 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
4401 Object* index = args[2];
4402 uint32_t start_index;
4403 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
4405 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
4407 Runtime::StringMatch(isolate, sub, pat, start_index);
4408 return Smi::FromInt(position);
4412 template <typename schar, typename pchar>
4413 static int StringMatchBackwards(Vector<const schar> subject,
4414 Vector<const pchar> pattern,
4416 int pattern_length = pattern.length();
4417 ASSERT(pattern_length >= 1);
4418 ASSERT(idx + pattern_length <= subject.length());
4420 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
4421 for (int i = 0; i < pattern_length; i++) {
4422 uc16 c = pattern[i];
4423 if (c > String::kMaxOneByteCharCode) {
4429 pchar pattern_first_char = pattern[0];
4430 for (int i = idx; i >= 0; i--) {
4431 if (subject[i] != pattern_first_char) continue;
4433 while (j < pattern_length) {
4434 if (pattern[j] != subject[i+j]) {
4439 if (j == pattern_length) {
4447 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
4448 HandleScope scope(isolate);
4449 ASSERT(args.length() == 3);
4451 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
4452 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
4454 Object* index = args[2];
4455 uint32_t start_index;
4456 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
4458 uint32_t pat_length = pat->length();
4459 uint32_t sub_length = sub->length();
4461 if (start_index + pat_length > sub_length) {
4462 start_index = sub_length - pat_length;
4465 if (pat_length == 0) {
4466 return Smi::FromInt(start_index);
4469 if (!sub->IsFlat()) FlattenString(sub);
4470 if (!pat->IsFlat()) FlattenString(pat);
4473 DisallowHeapAllocation no_gc; // ensure vectors stay valid
4475 String::FlatContent sub_content = sub->GetFlatContent();
4476 String::FlatContent pat_content = pat->GetFlatContent();
4478 if (pat_content.IsAscii()) {
4479 Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector();
4480 if (sub_content.IsAscii()) {
4481 position = StringMatchBackwards(sub_content.ToOneByteVector(),
4485 position = StringMatchBackwards(sub_content.ToUC16Vector(),
4490 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
4491 if (sub_content.IsAscii()) {
4492 position = StringMatchBackwards(sub_content.ToOneByteVector(),
4496 position = StringMatchBackwards(sub_content.ToUC16Vector(),
4502 return Smi::FromInt(position);
4506 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
4507 SealHandleScope shs(isolate);
4508 ASSERT(args.length() == 2);
4510 CONVERT_ARG_CHECKED(String, str1, 0);
4511 CONVERT_ARG_CHECKED(String, str2, 1);
4513 if (str1 == str2) return Smi::FromInt(0); // Equal.
4514 int str1_length = str1->length();
4515 int str2_length = str2->length();
4517 // Decide trivial cases without flattening.
4518 if (str1_length == 0) {
4519 if (str2_length == 0) return Smi::FromInt(0); // Equal.
4520 return Smi::FromInt(-str2_length);
4522 if (str2_length == 0) return Smi::FromInt(str1_length);
4525 int end = str1_length < str2_length ? str1_length : str2_length;
4527 // No need to flatten if we are going to find the answer on the first
4528 // character. At this point we know there is at least one character
4529 // in each string, due to the trivial case handling above.
4530 int d = str1->Get(0) - str2->Get(0);
4531 if (d != 0) return Smi::FromInt(d);
4536 ConsStringIteratorOp* op1 =
4537 isolate->runtime_state()->string_locale_compare_it1();
4538 ConsStringIteratorOp* op2 =
4539 isolate->runtime_state()->string_locale_compare_it2();
4540 // TODO(dcarney) Can do array compares here more efficiently.
4541 StringCharacterStream stream1(str1, op1);
4542 StringCharacterStream stream2(str2, op2);
4544 for (int i = 0; i < end; i++) {
4545 uint16_t char1 = stream1.GetNext();
4546 uint16_t char2 = stream2.GetNext();
4547 if (char1 != char2) return Smi::FromInt(char1 - char2);
4550 return Smi::FromInt(str1_length - str2_length);
4554 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_SubString) {
4555 HandleScope scope(isolate);
4556 ASSERT(args.length() == 3);
4558 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
4560 // We have a fast integer-only case here to avoid a conversion to double in
4561 // the common case where from and to are Smis.
4562 if (args[1]->IsSmi() && args[2]->IsSmi()) {
4563 CONVERT_SMI_ARG_CHECKED(from_number, 1);
4564 CONVERT_SMI_ARG_CHECKED(to_number, 2);
4565 start = from_number;
4568 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
4569 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
4570 start = FastD2IChecked(from_number);
4571 end = FastD2IChecked(to_number);
4573 RUNTIME_ASSERT(end >= start);
4574 RUNTIME_ASSERT(start >= 0);
4575 RUNTIME_ASSERT(end <= string->length());
4576 isolate->counters()->sub_string_runtime()->Increment();
4578 return *isolate->factory()->NewSubString(string, start, end);
4582 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
4583 HandleScope handles(isolate);
4584 ASSERT_EQ(3, args.length());
4586 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4587 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
4588 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
4590 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4591 if (global_cache.HasException()) return Failure::Exception();
4593 int capture_count = regexp->CaptureCount();
4595 ZoneScope zone_scope(isolate->runtime_zone());
4596 ZoneList<int> offsets(8, zone_scope.zone());
4599 int32_t* match = global_cache.FetchNext();
4600 if (match == NULL) break;
4601 offsets.Add(match[0], zone_scope.zone()); // start
4602 offsets.Add(match[1], zone_scope.zone()); // end
4605 if (global_cache.HasException()) return Failure::Exception();
4607 if (offsets.length() == 0) {
4608 // Not a single match.
4609 return isolate->heap()->null_value();
4612 RegExpImpl::SetLastMatchInfo(regexp_info,
4615 global_cache.LastSuccessfulMatch());
4617 int matches = offsets.length() / 2;
4618 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
4619 Handle<String> substring =
4620 isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1));
4621 elements->set(0, *substring);
4622 for (int i = 1; i < matches; i++) {
4623 HandleScope temp_scope(isolate);
4624 int from = offsets.at(i * 2);
4625 int to = offsets.at(i * 2 + 1);
4626 Handle<String> substring =
4627 isolate->factory()->NewProperSubString(subject, from, to);
4628 elements->set(i, *substring);
4630 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
4631 result->set_length(Smi::FromInt(matches));
4636 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
4637 // separate last match info. See comment on that function.
4638 template<bool has_capture>
4639 static MaybeObject* SearchRegExpMultiple(
4641 Handle<String> subject,
4642 Handle<JSRegExp> regexp,
4643 Handle<JSArray> last_match_array,
4644 Handle<JSArray> result_array) {
4645 ASSERT(subject->IsFlat());
4646 ASSERT_NE(has_capture, regexp->CaptureCount() == 0);
4648 int capture_count = regexp->CaptureCount();
4649 int subject_length = subject->length();
4651 static const int kMinLengthToCache = 0x1000;
4653 if (subject_length > kMinLengthToCache) {
4654 Handle<Object> cached_answer(RegExpResultsCache::Lookup(
4658 RegExpResultsCache::REGEXP_MULTIPLE_INDICES), isolate);
4659 if (*cached_answer != Smi::FromInt(0)) {
4660 Handle<FixedArray> cached_fixed_array =
4661 Handle<FixedArray>(FixedArray::cast(*cached_answer));
4662 // The cache FixedArray is a COW-array and can therefore be reused.
4663 JSArray::SetContent(result_array, cached_fixed_array);
4664 // The actual length of the result array is stored in the last element of
4665 // the backing store (the backing FixedArray may have a larger capacity).
4666 Object* cached_fixed_array_last_element =
4667 cached_fixed_array->get(cached_fixed_array->length() - 1);
4668 Smi* js_array_length = Smi::cast(cached_fixed_array_last_element);
4669 result_array->set_length(js_array_length);
4670 RegExpImpl::SetLastMatchInfo(
4671 last_match_array, subject, capture_count, NULL);
4672 return *result_array;
4676 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4677 if (global_cache.HasException()) return Failure::Exception();
4679 Handle<FixedArray> result_elements;
4680 if (result_array->HasFastObjectElements()) {
4682 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
4684 if (result_elements.is_null() || result_elements->length() < 16) {
4685 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
4688 FixedArrayBuilder builder(result_elements);
4690 // Position to search from.
4691 int match_start = -1;
4695 // Two smis before and after the match, for very long strings.
4696 static const int kMaxBuilderEntriesPerRegExpMatch = 5;
4699 int32_t* current_match = global_cache.FetchNext();
4700 if (current_match == NULL) break;
4701 match_start = current_match[0];
4702 builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
4703 if (match_end < match_start) {
4704 ReplacementStringBuilder::AddSubjectSlice(&builder,
4708 match_end = current_match[1];
4710 // Avoid accumulating new handles inside loop.
4711 HandleScope temp_scope(isolate);
4712 Handle<String> match;
4714 match = isolate->factory()->NewProperSubString(subject,
4718 match = isolate->factory()->NewSubString(subject,
4725 // Arguments array to replace function is match, captures, index and
4726 // subject, i.e., 3 + capture count in total.
4727 Handle<FixedArray> elements =
4728 isolate->factory()->NewFixedArray(3 + capture_count);
4730 elements->set(0, *match);
4731 for (int i = 1; i <= capture_count; i++) {
4732 int start = current_match[i * 2];
4734 int end = current_match[i * 2 + 1];
4735 ASSERT(start <= end);
4736 Handle<String> substring =
4737 isolate->factory()->NewSubString(subject, start, end);
4738 elements->set(i, *substring);
4740 ASSERT(current_match[i * 2 + 1] < 0);
4741 elements->set(i, isolate->heap()->undefined_value());
4744 elements->set(capture_count + 1, Smi::FromInt(match_start));
4745 elements->set(capture_count + 2, *subject);
4746 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
4748 builder.Add(*match);
4753 if (global_cache.HasException()) return Failure::Exception();
4755 if (match_start >= 0) {
4756 // Finished matching, with at least one match.
4757 if (match_end < subject_length) {
4758 ReplacementStringBuilder::AddSubjectSlice(&builder,
4763 RegExpImpl::SetLastMatchInfo(
4764 last_match_array, subject, capture_count, NULL);
4766 if (subject_length > kMinLengthToCache) {
4767 // Store the length of the result array into the last element of the
4768 // backing FixedArray.
4769 builder.EnsureCapacity(1);
4770 Handle<FixedArray> fixed_array = builder.array();
4771 fixed_array->set(fixed_array->length() - 1,
4772 Smi::FromInt(builder.length()));
4773 // Cache the result and turn the FixedArray into a COW array.
4774 RegExpResultsCache::Enter(isolate->heap(),
4778 RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
4780 return *builder.ToJSArray(result_array);
4782 return isolate->heap()->null_value(); // No matches at all.
4787 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets
4788 // lastMatchInfoOverride to maintain the last match info, so we don't need to
4789 // set any other last match array info.
4790 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
4791 HandleScope handles(isolate);
4792 ASSERT(args.length() == 4);
4794 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
4795 if (!subject->IsFlat()) FlattenString(subject);
4796 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
4797 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
4798 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
4800 ASSERT(regexp->GetFlags().is_global());
4802 if (regexp->CaptureCount() == 0) {
4803 return SearchRegExpMultiple<false>(
4804 isolate, subject, regexp, last_match_info, result_array);
4806 return SearchRegExpMultiple<true>(
4807 isolate, subject, regexp, last_match_info, result_array);
4812 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
4813 SealHandleScope shs(isolate);
4814 ASSERT(args.length() == 2);
4815 CONVERT_SMI_ARG_CHECKED(radix, 1);
4816 RUNTIME_ASSERT(2 <= radix && radix <= 36);
4818 // Fast case where the result is a one character string.
4819 if (args[0]->IsSmi()) {
4820 int value = args.smi_at(0);
4821 if (value >= 0 && value < radix) {
4822 // Character array used for conversion.
4823 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
4824 return isolate->heap()->
4825 LookupSingleCharacterStringFromCode(kCharTable[value]);
4830 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4831 if (std::isnan(value)) {
4832 return *isolate->factory()->nan_string();
4834 if (std::isinf(value)) {
4836 return *isolate->factory()->minus_infinity_string();
4838 return *isolate->factory()->infinity_string();
4840 char* str = DoubleToRadixCString(value, radix);
4841 MaybeObject* result =
4842 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
4848 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
4849 SealHandleScope shs(isolate);
4850 ASSERT(args.length() == 2);
4852 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4853 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4854 int f = FastD2IChecked(f_number);
4855 RUNTIME_ASSERT(f >= 0);
4856 char* str = DoubleToFixedCString(value, f);
4858 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
4864 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
4865 SealHandleScope shs(isolate);
4866 ASSERT(args.length() == 2);
4868 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4869 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4870 int f = FastD2IChecked(f_number);
4871 RUNTIME_ASSERT(f >= -1 && f <= 20);
4872 char* str = DoubleToExponentialCString(value, f);
4874 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
4880 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
4881 SealHandleScope shs(isolate);
4882 ASSERT(args.length() == 2);
4884 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4885 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4886 int f = FastD2IChecked(f_number);
4887 RUNTIME_ASSERT(f >= 1 && f <= 21);
4888 char* str = DoubleToPrecisionCString(value, f);
4890 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
4896 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsValidSmi) {
4897 HandleScope shs(isolate);
4898 ASSERT(args.length() == 1);
4900 CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
4901 if (Smi::IsValid(number)) {
4902 return isolate->heap()->true_value();
4904 return isolate->heap()->false_value();
4909 // Returns a single character string where first character equals
4910 // string->Get(index).
4911 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
4912 if (index < static_cast<uint32_t>(string->length())) {
4913 string->TryFlatten();
4914 return LookupSingleCharacterStringFromCode(
4915 string->GetIsolate(),
4916 string->Get(index));
4918 return Execution::CharAt(string, index);
4922 Handle<Object> Runtime::GetElementOrCharAt(Isolate* isolate,
4923 Handle<Object> object,
4925 // Handle [] indexing on Strings
4926 if (object->IsString()) {
4927 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4928 if (!result->IsUndefined()) return result;
4931 // Handle [] indexing on String objects
4932 if (object->IsStringObjectWithCharacterAt(index)) {
4933 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4934 Handle<Object> result =
4935 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4936 if (!result->IsUndefined()) return result;
4939 Handle<Object> result;
4940 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
4941 Handle<Object> proto(object->GetPrototype(isolate), isolate);
4942 return Object::GetElement(isolate, proto, index);
4944 return Object::GetElement(isolate, object, index);
4949 static Handle<Name> ToName(Isolate* isolate, Handle<Object> key) {
4950 if (key->IsName()) {
4951 return Handle<Name>::cast(key);
4953 bool has_pending_exception = false;
4954 Handle<Object> converted =
4955 Execution::ToString(isolate, key, &has_pending_exception);
4956 if (has_pending_exception) return Handle<Name>();
4957 return Handle<Name>::cast(converted);
4962 MaybeObject* Runtime::HasObjectProperty(Isolate* isolate,
4963 Handle<JSReceiver> object,
4964 Handle<Object> key) {
4965 HandleScope scope(isolate);
4967 // Check if the given key is an array index.
4969 if (key->ToArrayIndex(&index)) {
4970 return isolate->heap()->ToBoolean(JSReceiver::HasElement(object, index));
4973 // Convert the key to a name - possibly by calling back into JavaScript.
4974 Handle<Name> name = ToName(isolate, key);
4975 RETURN_IF_EMPTY_HANDLE(isolate, name);
4977 return isolate->heap()->ToBoolean(JSReceiver::HasProperty(object, name));
4980 MaybeObject* Runtime::GetObjectPropertyOrFail(
4982 Handle<Object> object,
4983 Handle<Object> key) {
4984 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate,
4985 GetObjectProperty(isolate, object, key));
4988 MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4989 Handle<Object> object,
4990 Handle<Object> key) {
4991 HandleScope scope(isolate);
4993 if (object->IsUndefined() || object->IsNull()) {
4994 Handle<Object> args[2] = { key, object };
4995 Handle<Object> error =
4996 isolate->factory()->NewTypeError("non_object_property_load",
4997 HandleVector(args, 2));
4998 return isolate->Throw(*error);
5001 // Check if the given key is an array index.
5003 if (key->ToArrayIndex(&index)) {
5004 Handle<Object> result = GetElementOrCharAt(isolate, object, index);
5005 RETURN_IF_EMPTY_HANDLE(isolate, result);
5009 // Convert the key to a name - possibly by calling back into JavaScript.
5010 Handle<Name> name = ToName(isolate, key);
5011 RETURN_IF_EMPTY_HANDLE(isolate, name);
5013 // Check if the name is trivially convertible to an index and get
5014 // the element if so.
5015 if (name->AsArrayIndex(&index)) {
5016 Handle<Object> result = GetElementOrCharAt(isolate, object, index);
5017 RETURN_IF_EMPTY_HANDLE(isolate, result);
5020 return object->GetProperty(*name);
5025 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
5026 SealHandleScope shs(isolate);
5027 ASSERT(args.length() == 2);
5029 Handle<Object> object = args.at<Object>(0);
5030 Handle<Object> key = args.at<Object>(1);
5032 return Runtime::GetObjectProperty(isolate, object, key);
5036 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
5037 RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
5038 SealHandleScope shs(isolate);
5039 ASSERT(args.length() == 2);
5041 // Fast cases for getting named properties of the receiver JSObject
5044 // The global proxy objects has to be excluded since LocalLookup on
5045 // the global proxy object can return a valid result even though the
5046 // global proxy object never has properties. This is the case
5047 // because the global proxy object forwards everything to its hidden
5048 // prototype including local lookups.
5050 // Additionally, we need to make sure that we do not cache results
5051 // for objects that require access checks.
5052 if (args[0]->IsJSObject()) {
5053 if (!args[0]->IsJSGlobalProxy() &&
5054 !args[0]->IsAccessCheckNeeded() &&
5055 args[1]->IsName()) {
5056 JSObject* receiver = JSObject::cast(args[0]);
5057 Name* key = Name::cast(args[1]);
5058 if (receiver->HasFastProperties()) {
5059 // Attempt to use lookup cache.
5060 Map* receiver_map = receiver->map();
5061 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
5062 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
5064 // Doubles are not cached, so raw read the value.
5065 Object* value = receiver->RawFastPropertyAt(offset);
5066 return value->IsTheHole()
5067 ? isolate->heap()->undefined_value()
5070 // Lookup cache miss. Perform lookup and update the cache if
5072 LookupResult result(isolate);
5073 receiver->LocalLookup(key, &result);
5074 if (result.IsField()) {
5075 int offset = result.GetFieldIndex().field_index();
5076 // Do not track double fields in the keyed lookup cache. Reading
5077 // double values requires boxing.
5078 if (!result.representation().IsDouble()) {
5079 keyed_lookup_cache->Update(receiver_map, key, offset);
5081 return receiver->FastPropertyAt(result.representation(), offset);
5084 // Attempt dictionary lookup.
5085 NameDictionary* dictionary = receiver->property_dictionary();
5086 int entry = dictionary->FindEntry(key);
5087 if ((entry != NameDictionary::kNotFound) &&
5088 (dictionary->DetailsAt(entry).type() == NORMAL)) {
5089 Object* value = dictionary->ValueAt(entry);
5090 if (!receiver->IsGlobalObject()) return value;
5091 value = PropertyCell::cast(value)->value();
5092 if (!value->IsTheHole()) return value;
5093 // If value is the hole do the general lookup.
5096 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
5097 // JSObject without a name key. If the key is a Smi, check for a
5098 // definite out-of-bounds access to elements, which is a strong indicator
5099 // that subsequent accesses will also call the runtime. Proactively
5100 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
5101 // doubles for those future calls in the case that the elements would
5102 // become FAST_DOUBLE_ELEMENTS.
5103 Handle<JSObject> js_object(args.at<JSObject>(0));
5104 ElementsKind elements_kind = js_object->GetElementsKind();
5105 if (IsFastDoubleElementsKind(elements_kind)) {
5106 FixedArrayBase* elements = js_object->elements();
5107 if (args.at<Smi>(1)->value() >= elements->length()) {
5108 if (IsFastHoleyElementsKind(elements_kind)) {
5109 elements_kind = FAST_HOLEY_ELEMENTS;
5111 elements_kind = FAST_ELEMENTS;
5113 MaybeObject* maybe_object = TransitionElements(js_object,
5116 if (maybe_object->IsFailure()) return maybe_object;
5119 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) ||
5120 !IsFastElementsKind(elements_kind));
5123 } else if (args[0]->IsString() && args[1]->IsSmi()) {
5124 // Fast case for string indexing using [] with a smi index.
5125 HandleScope scope(isolate);
5126 Handle<String> str = args.at<String>(0);
5127 int index = args.smi_at(1);
5128 if (index >= 0 && index < str->length()) {
5129 Handle<Object> result = GetCharAt(str, index);
5134 // Fall back to GetObjectProperty.
5135 return Runtime::GetObjectProperty(isolate,
5137 args.at<Object>(1));
5141 static bool IsValidAccessor(Handle<Object> obj) {
5142 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
5146 // Implements part of 8.12.9 DefineOwnProperty.
5147 // There are 3 cases that lead here:
5148 // Step 4b - define a new accessor property.
5149 // Steps 9c & 12 - replace an existing data property with an accessor property.
5150 // Step 12 - update an existing accessor property with an accessor or generic
5152 RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
5153 HandleScope scope(isolate);
5154 ASSERT(args.length() == 5);
5155 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5156 RUNTIME_ASSERT(!obj->IsNull());
5157 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
5158 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
5159 RUNTIME_ASSERT(IsValidAccessor(getter));
5160 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
5161 RUNTIME_ASSERT(IsValidAccessor(setter));
5162 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
5163 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5164 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
5166 bool fast = obj->HasFastProperties();
5167 JSObject::DefineAccessor(obj, name, getter, setter, attr);
5168 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5169 if (fast) JSObject::TransformToFastProperties(obj, 0);
5170 return isolate->heap()->undefined_value();
5174 // Implements part of 8.12.9 DefineOwnProperty.
5175 // There are 3 cases that lead here:
5176 // Step 4a - define a new data property.
5177 // Steps 9b & 12 - replace an existing accessor property with a data property.
5178 // Step 12 - update an existing data property with a data or generic
5180 RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
5181 HandleScope scope(isolate);
5182 ASSERT(args.length() == 4);
5183 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
5184 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
5185 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
5186 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
5187 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5188 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
5190 LookupResult lookup(isolate);
5191 js_object->LocalLookupRealNamedProperty(*name, &lookup);
5193 // Special case for callback properties.
5194 if (lookup.IsPropertyCallbacks()) {
5195 Handle<Object> callback(lookup.GetCallbackObject(), isolate);
5196 // To be compatible with Safari we do not change the value on API objects
5197 // in Object.defineProperty(). Firefox disagrees here, and actually changes
5199 if (callback->IsAccessorInfo()) {
5200 return isolate->heap()->undefined_value();
5202 // Avoid redefining foreign callback as data property, just use the stored
5203 // setter to update the value instead.
5204 // TODO(mstarzinger): So far this only works if property attributes don't
5205 // change, this should be fixed once we cleanup the underlying code.
5206 if (callback->IsForeign() && lookup.GetAttributes() == attr) {
5207 Handle<Object> result_object =
5208 JSObject::SetPropertyWithCallback(js_object,
5212 handle(lookup.holder()),
5214 RETURN_IF_EMPTY_HANDLE(isolate, result_object);
5215 return *result_object;
5219 // Take special care when attributes are different and there is already
5220 // a property. For simplicity we normalize the property which enables us
5221 // to not worry about changing the instance_descriptor and creating a new
5222 // map. The current version of SetObjectProperty does not handle attributes
5223 // correctly in the case where a property is a field and is reset with
5225 if (lookup.IsFound() &&
5226 (attr != lookup.GetAttributes() || lookup.IsPropertyCallbacks())) {
5227 // New attributes - normalize to avoid writing to instance descriptor
5228 if (js_object->IsJSGlobalProxy()) {
5229 // Since the result is a property, the prototype will exist so
5230 // we don't have to check for null.
5231 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
5233 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
5234 // Use IgnoreAttributes version since a readonly property may be
5235 // overridden and SetProperty does not allow this.
5236 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
5237 js_object, name, obj_value, attr);
5238 RETURN_IF_EMPTY_HANDLE(isolate, result);
5242 Handle<Object> result = Runtime::ForceSetObjectProperty(isolate, js_object,
5246 RETURN_IF_EMPTY_HANDLE(isolate, result);
5251 // Return property without being observable by accessors or interceptors.
5252 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDataProperty) {
5253 SealHandleScope shs(isolate);
5254 ASSERT(args.length() == 2);
5255 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5256 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5257 LookupResult lookup(isolate);
5258 object->LookupRealNamedProperty(*key, &lookup);
5259 if (!lookup.IsFound()) return isolate->heap()->undefined_value();
5260 switch (lookup.type()) {
5262 return lookup.holder()->GetNormalizedProperty(&lookup);
5264 return lookup.holder()->FastPropertyAt(
5265 lookup.representation(),
5266 lookup.GetFieldIndex().field_index());
5268 return lookup.GetConstant();
5273 return isolate->heap()->undefined_value();
5277 return isolate->heap()->undefined_value();
5281 Handle<Object> Runtime::SetObjectProperty(Isolate* isolate,
5282 Handle<Object> object,
5284 Handle<Object> value,
5285 PropertyAttributes attr,
5286 StrictMode strict_mode) {
5287 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
5289 if (object->IsUndefined() || object->IsNull()) {
5290 Handle<Object> args[2] = { key, object };
5291 Handle<Object> error =
5292 isolate->factory()->NewTypeError("non_object_property_store",
5293 HandleVector(args, 2));
5294 isolate->Throw(*error);
5295 return Handle<Object>();
5298 if (object->IsJSProxy()) {
5299 bool has_pending_exception = false;
5300 Handle<Object> name_object = key->IsSymbol()
5301 ? key : Execution::ToString(isolate, key, &has_pending_exception);
5302 if (has_pending_exception) return Handle<Object>(); // exception
5303 Handle<Name> name = Handle<Name>::cast(name_object);
5304 return JSReceiver::SetProperty(Handle<JSProxy>::cast(object), name, value,
5309 // If the object isn't a JavaScript object, we ignore the store.
5310 if (!object->IsJSObject()) return value;
5312 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
5314 // Check if the given key is an array index.
5316 if (key->ToArrayIndex(&index)) {
5317 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
5318 // of a string using [] notation. We need to support this too in
5320 // In the case of a String object we just need to redirect the assignment to
5321 // the underlying string if the index is in range. Since the underlying
5322 // string does nothing with the assignment then we can ignore such
5324 if (js_object->IsStringObjectWithCharacterAt(index)) {
5328 js_object->ValidateElements();
5329 if (js_object->HasExternalArrayElements() ||
5330 js_object->HasFixedTypedArrayElements()) {
5331 // TODO(ningxin): Throw an error if setting a Float32x4Array element
5332 // while the value is not Float32x4Object.
5333 if (!value->IsNumber() && !value->IsFloat32x4() &&
5334 !value->IsInt32x4() && !value->IsUndefined()) {
5336 Handle<Object> number =
5337 Execution::ToNumber(isolate, value, &has_exception);
5338 if (has_exception) return Handle<Object>(); // exception
5342 Handle<Object> result = JSObject::SetElement(js_object, index, value, attr,
5346 js_object->ValidateElements();
5347 return result.is_null() ? result : value;
5350 if (key->IsName()) {
5351 Handle<Name> name = Handle<Name>::cast(key);
5352 if (name->AsArrayIndex(&index)) {
5353 if (js_object->HasExternalArrayElements()) {
5354 // TODO(ningxin): Throw an error if setting a Float32x4Array element
5355 // while the value is not Float32x4Object.
5356 if (!value->IsNumber() && !value->IsFloat32x4() &&
5357 !value->IsInt32x4() && !value->IsUndefined()) {
5359 Handle<Object> number =
5360 Execution::ToNumber(isolate, value, &has_exception);
5361 if (has_exception) return Handle<Object>(); // exception
5365 return JSObject::SetElement(js_object, index, value, attr, strict_mode,
5369 if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
5370 return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
5374 // Call-back into JavaScript to convert the key to a string.
5375 bool has_pending_exception = false;
5376 Handle<Object> converted =
5377 Execution::ToString(isolate, key, &has_pending_exception);
5378 if (has_pending_exception) return Handle<Object>(); // exception
5379 Handle<String> name = Handle<String>::cast(converted);
5381 if (name->AsArrayIndex(&index)) {
5382 return JSObject::SetElement(js_object, index, value, attr, strict_mode,
5386 return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
5391 Handle<Object> Runtime::ForceSetObjectProperty(Isolate* isolate,
5392 Handle<JSObject> js_object,
5394 Handle<Object> value,
5395 PropertyAttributes attr) {
5396 // Check if the given key is an array index.
5398 if (key->ToArrayIndex(&index)) {
5399 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
5400 // of a string using [] notation. We need to support this too in
5402 // In the case of a String object we just need to redirect the assignment to
5403 // the underlying string if the index is in range. Since the underlying
5404 // string does nothing with the assignment then we can ignore such
5406 if (js_object->IsStringObjectWithCharacterAt(index)) {
5410 return JSObject::SetElement(js_object, index, value, attr, SLOPPY,
5415 if (key->IsName()) {
5416 Handle<Name> name = Handle<Name>::cast(key);
5417 if (name->AsArrayIndex(&index)) {
5418 return JSObject::SetElement(js_object, index, value, attr, SLOPPY,
5422 if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
5423 return JSObject::SetLocalPropertyIgnoreAttributes(js_object, name,
5428 // Call-back into JavaScript to convert the key to a string.
5429 bool has_pending_exception = false;
5430 Handle<Object> converted =
5431 Execution::ToString(isolate, key, &has_pending_exception);
5432 if (has_pending_exception) return Handle<Object>(); // exception
5433 Handle<String> name = Handle<String>::cast(converted);
5435 if (name->AsArrayIndex(&index)) {
5436 return JSObject::SetElement(js_object, index, value, attr, SLOPPY,
5440 return JSObject::SetLocalPropertyIgnoreAttributes(js_object, name, value,
5446 MaybeObject* Runtime::DeleteObjectProperty(Isolate* isolate,
5447 Handle<JSReceiver> receiver,
5449 JSReceiver::DeleteMode mode) {
5450 HandleScope scope(isolate);
5452 // Check if the given key is an array index.
5454 if (key->ToArrayIndex(&index)) {
5455 // In Firefox/SpiderMonkey, Safari and Opera you can access the
5456 // characters of a string using [] notation. In the case of a
5457 // String object we just need to redirect the deletion to the
5458 // underlying string if the index is in range. Since the
5459 // underlying string does nothing with the deletion, we can ignore
5461 if (receiver->IsStringObjectWithCharacterAt(index)) {
5462 return isolate->heap()->true_value();
5465 Handle<Object> result = JSReceiver::DeleteElement(receiver, index, mode);
5466 RETURN_IF_EMPTY_HANDLE(isolate, result);
5471 if (key->IsName()) {
5472 name = Handle<Name>::cast(key);
5474 // Call-back into JavaScript to convert the key to a string.
5475 bool has_pending_exception = false;
5476 Handle<Object> converted = Execution::ToString(
5477 isolate, key, &has_pending_exception);
5478 if (has_pending_exception) return Failure::Exception();
5479 name = Handle<String>::cast(converted);
5482 if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
5483 Handle<Object> result = JSReceiver::DeleteProperty(receiver, name, mode);
5484 RETURN_IF_EMPTY_HANDLE(isolate, result);
5489 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenProperty) {
5490 HandleScope scope(isolate);
5491 RUNTIME_ASSERT(args.length() == 3);
5493 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5494 CONVERT_ARG_HANDLE_CHECKED(String, key, 1);
5495 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
5496 return *JSObject::SetHiddenProperty(object, key, value);
5500 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
5501 HandleScope scope(isolate);
5502 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
5504 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
5505 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
5506 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
5507 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
5509 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5510 // Compute attributes.
5511 PropertyAttributes attributes =
5512 static_cast<PropertyAttributes>(unchecked_attributes);
5514 StrictMode strict_mode = SLOPPY;
5515 if (args.length() == 5) {
5516 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_arg, 4);
5517 strict_mode = strict_mode_arg;
5520 Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key,
5524 RETURN_IF_EMPTY_HANDLE(isolate, result);
5529 RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsKind) {
5530 HandleScope scope(isolate);
5531 RUNTIME_ASSERT(args.length() == 2);
5532 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
5533 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
5534 JSObject::TransitionElementsKind(array, map->elements_kind());
5539 // Set the native flag on the function.
5540 // This is used to decide if we should transform null and undefined
5541 // into the global object when doing call and apply.
5542 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
5543 SealHandleScope shs(isolate);
5544 RUNTIME_ASSERT(args.length() == 1);
5546 CONVERT_ARG_CHECKED(Object, object, 0);
5548 if (object->IsJSFunction()) {
5549 JSFunction* func = JSFunction::cast(object);
5550 func->shared()->set_native(true);
5552 return isolate->heap()->undefined_value();
5556 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInlineBuiltinFlag) {
5557 SealHandleScope shs(isolate);
5558 RUNTIME_ASSERT(args.length() == 1);
5560 Handle<Object> object = args.at<Object>(0);
5562 if (object->IsJSFunction()) {
5563 JSFunction* func = JSFunction::cast(*object);
5564 func->shared()->set_inline_builtin(true);
5566 return isolate->heap()->undefined_value();
5570 RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
5571 HandleScope scope(isolate);
5572 RUNTIME_ASSERT(args.length() == 5);
5573 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5574 CONVERT_SMI_ARG_CHECKED(store_index, 1);
5575 Handle<Object> value = args.at<Object>(2);
5576 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
5577 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
5579 Object* raw_literal_cell = literals->get(literal_index);
5580 JSArray* boilerplate = NULL;
5581 if (raw_literal_cell->IsAllocationSite()) {
5582 AllocationSite* site = AllocationSite::cast(raw_literal_cell);
5583 boilerplate = JSArray::cast(site->transition_info());
5585 boilerplate = JSArray::cast(raw_literal_cell);
5587 Handle<JSArray> boilerplate_object(boilerplate);
5588 ElementsKind elements_kind = object->GetElementsKind();
5589 ASSERT(IsFastElementsKind(elements_kind));
5590 // Smis should never trigger transitions.
5591 ASSERT(!value->IsSmi());
5593 if (value->IsNumber()) {
5594 ASSERT(IsFastSmiElementsKind(elements_kind));
5595 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
5596 ? FAST_HOLEY_DOUBLE_ELEMENTS
5597 : FAST_DOUBLE_ELEMENTS;
5598 if (IsMoreGeneralElementsKindTransition(
5599 boilerplate_object->GetElementsKind(),
5600 transitioned_kind)) {
5601 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
5603 JSObject::TransitionElementsKind(object, transitioned_kind);
5604 ASSERT(IsFastDoubleElementsKind(object->GetElementsKind()));
5605 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
5606 HeapNumber* number = HeapNumber::cast(*value);
5607 double_array->set(store_index, number->Number());
5609 ASSERT(IsFastSmiElementsKind(elements_kind) ||
5610 IsFastDoubleElementsKind(elements_kind));
5611 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
5612 ? FAST_HOLEY_ELEMENTS
5614 JSObject::TransitionElementsKind(object, transitioned_kind);
5615 if (IsMoreGeneralElementsKindTransition(
5616 boilerplate_object->GetElementsKind(),
5617 transitioned_kind)) {
5618 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
5620 FixedArray* object_array = FixedArray::cast(object->elements());
5621 object_array->set(store_index, *value);
5627 // Check whether debugger and is about to step into the callback that is passed
5628 // to a built-in function such as Array.forEach.
5629 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) {
5630 SealHandleScope shs(isolate);
5631 #ifdef ENABLE_DEBUGGER_SUPPORT
5632 if (!isolate->IsDebuggerActive() || !isolate->debug()->StepInActive()) {
5633 return isolate->heap()->false_value();
5635 CONVERT_ARG_CHECKED(Object, callback, 0);
5636 // We do not step into the callback if it's a builtin or not even a function.
5637 if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) {
5638 return isolate->heap()->false_value();
5640 return isolate->heap()->true_value();
5642 return isolate->heap()->false_value();
5643 #endif // ENABLE_DEBUGGER_SUPPORT
5647 // Set one shot breakpoints for the callback function that is passed to a
5648 // built-in function such as Array.forEach to enable stepping into the callback.
5649 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) {
5650 SealHandleScope shs(isolate);
5651 #ifdef ENABLE_DEBUGGER_SUPPORT
5652 Debug* debug = isolate->debug();
5653 if (!debug->IsStepping()) return isolate->heap()->undefined_value();
5654 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 0);
5655 HandleScope scope(isolate);
5656 // When leaving the callback, step out has been activated, but not performed
5657 // if we do not leave the builtin. To be able to step into the callback
5658 // again, we need to clear the step out at this point.
5659 debug->ClearStepOut();
5660 debug->FloodWithOneShot(callback);
5661 #endif // ENABLE_DEBUGGER_SUPPORT
5662 return isolate->heap()->undefined_value();
5666 // Set a local property, even if it is READ_ONLY. If the property does not
5667 // exist, it will be added with attributes NONE.
5668 RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
5669 HandleScope scope(isolate);
5670 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
5671 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5672 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
5673 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
5674 // Compute attributes.
5675 PropertyAttributes attributes = NONE;
5676 if (args.length() == 4) {
5677 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
5678 // Only attribute bits should be set.
5680 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5681 attributes = static_cast<PropertyAttributes>(unchecked_value);
5683 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
5684 object, name, value, attributes);
5685 RETURN_IF_EMPTY_HANDLE(isolate, result);
5690 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
5691 HandleScope scope(isolate);
5692 ASSERT(args.length() == 3);
5693 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
5694 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5695 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
5696 JSReceiver::DeleteMode delete_mode = strict_mode == STRICT
5697 ? JSReceiver::STRICT_DELETION : JSReceiver::NORMAL_DELETION;
5698 Handle<Object> result = JSReceiver::DeleteProperty(object, key, delete_mode);
5699 RETURN_IF_EMPTY_HANDLE(isolate, result);
5704 static MaybeObject* HasLocalPropertyImplementation(Isolate* isolate,
5705 Handle<JSObject> object,
5707 if (JSReceiver::HasLocalProperty(object, key)) {
5708 return isolate->heap()->true_value();
5710 // Handle hidden prototypes. If there's a hidden prototype above this thing
5711 // then we have to check it for properties, because they are supposed to
5712 // look like they are on this object.
5713 Handle<Object> proto(object->GetPrototype(), isolate);
5714 if (proto->IsJSObject() &&
5715 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
5716 return HasLocalPropertyImplementation(isolate,
5717 Handle<JSObject>::cast(proto),
5720 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5721 return isolate->heap()->false_value();
5725 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
5726 HandleScope scope(isolate);
5727 ASSERT(args.length() == 2);
5728 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5729 Handle<Object> object = args.at<Object>(0);
5732 const bool key_is_array_index = key->AsArrayIndex(&index);
5734 // Only JS objects can have properties.
5735 if (object->IsJSObject()) {
5736 Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
5737 // Fast case: either the key is a real named property or it is not
5738 // an array index and there are no interceptors or hidden
5740 if (JSObject::HasRealNamedProperty(js_obj, key)) {
5741 ASSERT(!isolate->has_scheduled_exception());
5742 return isolate->heap()->true_value();
5744 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5746 Map* map = js_obj->map();
5747 if (!key_is_array_index &&
5748 !map->has_named_interceptor() &&
5749 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
5750 return isolate->heap()->false_value();
5753 return HasLocalPropertyImplementation(isolate,
5754 Handle<JSObject>(js_obj),
5756 } else if (object->IsString() && key_is_array_index) {
5757 // Well, there is one exception: Handle [] on strings.
5758 Handle<String> string = Handle<String>::cast(object);
5759 if (index < static_cast<uint32_t>(string->length())) {
5760 return isolate->heap()->true_value();
5763 return isolate->heap()->false_value();
5767 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
5768 HandleScope scope(isolate);
5769 ASSERT(args.length() == 2);
5770 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
5771 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5773 bool result = JSReceiver::HasProperty(receiver, key);
5774 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5775 if (isolate->has_pending_exception()) return Failure::Exception();
5776 return isolate->heap()->ToBoolean(result);
5780 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
5781 HandleScope scope(isolate);
5782 ASSERT(args.length() == 2);
5783 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
5784 CONVERT_SMI_ARG_CHECKED(index, 1);
5786 bool result = JSReceiver::HasElement(receiver, index);
5787 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5788 if (isolate->has_pending_exception()) return Failure::Exception();
5789 return isolate->heap()->ToBoolean(result);
5793 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
5794 HandleScope scope(isolate);
5795 ASSERT(args.length() == 2);
5797 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5798 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5800 PropertyAttributes att = JSReceiver::GetLocalPropertyAttribute(object, key);
5801 if (att == ABSENT || (att & DONT_ENUM) != 0) {
5802 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5803 return isolate->heap()->false_value();
5805 ASSERT(!isolate->has_scheduled_exception());
5806 return isolate->heap()->true_value();
5810 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
5811 HandleScope scope(isolate);
5812 ASSERT(args.length() == 1);
5813 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
5815 Handle<JSArray> result = GetKeysFor(object, &threw);
5816 if (threw) return Failure::Exception();
5821 // Returns either a FixedArray as Runtime_GetPropertyNames,
5822 // or, if the given object has an enum cache that contains
5823 // all enumerable properties of the object and its prototypes
5824 // have none, the map of the object. This is used to speed up
5825 // the check for deletions during a for-in.
5826 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
5827 SealHandleScope shs(isolate);
5828 ASSERT(args.length() == 1);
5830 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
5832 if (raw_object->IsSimpleEnum()) return raw_object->map();
5834 HandleScope scope(isolate);
5835 Handle<JSReceiver> object(raw_object);
5837 Handle<FixedArray> content =
5838 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
5839 if (threw) return Failure::Exception();
5841 // Test again, since cache may have been built by preceding call.
5842 if (object->IsSimpleEnum()) return object->map();
5848 // Find the length of the prototype chain that is to to handled as one. If a
5849 // prototype object is hidden it is to be viewed as part of the the object it
5850 // is prototype for.
5851 static int LocalPrototypeChainLength(JSObject* obj) {
5853 Object* proto = obj->GetPrototype();
5854 while (proto->IsJSObject() &&
5855 JSObject::cast(proto)->map()->is_hidden_prototype()) {
5857 proto = JSObject::cast(proto)->GetPrototype();
5863 // Return the names of the local named properties.
5865 // args[1]: PropertyAttributes as int
5866 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
5867 HandleScope scope(isolate);
5868 ASSERT(args.length() == 2);
5869 if (!args[0]->IsJSObject()) {
5870 return isolate->heap()->undefined_value();
5872 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5873 CONVERT_SMI_ARG_CHECKED(filter_value, 1);
5874 PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value);
5876 // Skip the global proxy as it has no properties and always delegates to the
5877 // real global object.
5878 if (obj->IsJSGlobalProxy()) {
5879 // Only collect names if access is permitted.
5880 if (obj->IsAccessCheckNeeded() &&
5881 !isolate->MayNamedAccessWrapper(obj,
5882 isolate->factory()->undefined_value(),
5884 isolate->ReportFailedAccessCheckWrapper(obj, v8::ACCESS_KEYS);
5885 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5886 return *isolate->factory()->NewJSArray(0);
5888 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
5891 // Find the number of objects making up this.
5892 int length = LocalPrototypeChainLength(*obj);
5894 // Find the number of local properties for each of the objects.
5895 ScopedVector<int> local_property_count(length);
5896 int total_property_count = 0;
5897 Handle<JSObject> jsproto = obj;
5898 for (int i = 0; i < length; i++) {
5899 // Only collect names if access is permitted.
5900 if (jsproto->IsAccessCheckNeeded() &&
5901 !isolate->MayNamedAccessWrapper(jsproto,
5902 isolate->factory()->undefined_value(),
5904 isolate->ReportFailedAccessCheckWrapper(jsproto, v8::ACCESS_KEYS);
5905 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5906 return *isolate->factory()->NewJSArray(0);
5909 n = jsproto->NumberOfLocalProperties(filter);
5910 local_property_count[i] = n;
5911 total_property_count += n;
5912 if (i < length - 1) {
5913 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5917 // Allocate an array with storage for all the property names.
5918 Handle<FixedArray> names =
5919 isolate->factory()->NewFixedArray(total_property_count);
5921 // Get the property names.
5923 int next_copy_index = 0;
5924 int hidden_strings = 0;
5925 for (int i = 0; i < length; i++) {
5926 jsproto->GetLocalPropertyNames(*names, next_copy_index, filter);
5928 // Names from hidden prototypes may already have been added
5929 // for inherited function template instances. Count the duplicates
5930 // and stub them out; the final copy pass at the end ignores holes.
5931 for (int j = next_copy_index;
5932 j < next_copy_index + local_property_count[i];
5934 Object* name_from_hidden_proto = names->get(j);
5935 for (int k = 0; k < next_copy_index; k++) {
5936 if (names->get(k) != isolate->heap()->hidden_string()) {
5937 Object* name = names->get(k);
5938 if (name_from_hidden_proto == name) {
5939 names->set(j, isolate->heap()->hidden_string());
5947 next_copy_index += local_property_count[i];
5949 // Hidden properties only show up if the filter does not skip strings.
5950 if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) {
5953 if (i < length - 1) {
5954 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5958 // Filter out name of hidden properties object and
5959 // hidden prototype duplicates.
5960 if (hidden_strings > 0) {
5961 Handle<FixedArray> old_names = names;
5962 names = isolate->factory()->NewFixedArray(
5963 names->length() - hidden_strings);
5965 for (int i = 0; i < total_property_count; i++) {
5966 Object* name = old_names->get(i);
5967 if (name == isolate->heap()->hidden_string()) {
5971 names->set(dest_pos++, name);
5973 ASSERT_EQ(0, hidden_strings);
5976 return *isolate->factory()->NewJSArrayWithElements(names);
5980 // Return the names of the local indexed properties.
5982 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
5983 HandleScope scope(isolate);
5984 ASSERT(args.length() == 1);
5985 if (!args[0]->IsJSObject()) {
5986 return isolate->heap()->undefined_value();
5988 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5990 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
5991 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
5992 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
5993 return *isolate->factory()->NewJSArrayWithElements(names);
5997 // Return information on whether an object has a named or indexed interceptor.
5999 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
6000 HandleScope scope(isolate);
6001 ASSERT(args.length() == 1);
6002 if (!args[0]->IsJSObject()) {
6003 return Smi::FromInt(0);
6005 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
6008 if (obj->HasNamedInterceptor()) result |= 2;
6009 if (obj->HasIndexedInterceptor()) result |= 1;
6011 return Smi::FromInt(result);
6015 // Return property names from named interceptor.
6017 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
6018 HandleScope scope(isolate);
6019 ASSERT(args.length() == 1);
6020 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
6022 if (obj->HasNamedInterceptor()) {
6023 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
6024 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
6026 return isolate->heap()->undefined_value();
6030 // Return element names from indexed interceptor.
6032 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
6033 HandleScope scope(isolate);
6034 ASSERT(args.length() == 1);
6035 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
6037 if (obj->HasIndexedInterceptor()) {
6038 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
6039 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
6041 return isolate->heap()->undefined_value();
6045 RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
6046 HandleScope scope(isolate);
6047 ASSERT_EQ(args.length(), 1);
6048 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
6049 Handle<JSObject> object(raw_object);
6051 if (object->IsJSGlobalProxy()) {
6052 // Do access checks before going to the global object.
6053 if (object->IsAccessCheckNeeded() &&
6054 !isolate->MayNamedAccessWrapper(object,
6055 isolate->factory()->undefined_value(),
6057 isolate->ReportFailedAccessCheckWrapper(object, v8::ACCESS_KEYS);
6058 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
6059 return *isolate->factory()->NewJSArray(0);
6062 Handle<Object> proto(object->GetPrototype(), isolate);
6063 // If proxy is detached we simply return an empty array.
6064 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
6065 object = Handle<JSObject>::cast(proto);
6069 Handle<FixedArray> contents =
6070 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
6071 if (threw) return Failure::Exception();
6073 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
6074 // property array and since the result is mutable we have to create
6075 // a fresh clone on each invocation.
6076 int length = contents->length();
6077 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
6078 for (int i = 0; i < length; i++) {
6079 Object* entry = contents->get(i);
6080 if (entry->IsString()) {
6081 copy->set(i, entry);
6083 ASSERT(entry->IsNumber());
6084 HandleScope scope(isolate);
6085 Handle<Object> entry_handle(entry, isolate);
6086 Handle<Object> entry_str =
6087 isolate->factory()->NumberToString(entry_handle);
6088 copy->set(i, *entry_str);
6091 return *isolate->factory()->NewJSArrayWithElements(copy);
6095 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
6096 SealHandleScope shs(isolate);
6097 ASSERT(args.length() == 1);
6099 // Compute the frame holding the arguments.
6100 JavaScriptFrameIterator it(isolate);
6101 it.AdvanceToArgumentsFrame();
6102 JavaScriptFrame* frame = it.frame();
6104 // Get the actual number of provided arguments.
6105 const uint32_t n = frame->ComputeParametersCount();
6107 // Try to convert the key to an index. If successful and within
6108 // index return the the argument from the frame.
6110 if (args[0]->ToArrayIndex(&index) && index < n) {
6111 return frame->GetParameter(index);
6114 if (args[0]->IsSymbol()) {
6115 // Lookup in the initial Object.prototype object.
6116 return isolate->initial_object_prototype()->GetProperty(
6117 Symbol::cast(args[0]));
6120 // Convert the key to a string.
6121 HandleScope scope(isolate);
6122 bool exception = false;
6123 Handle<Object> converted =
6124 Execution::ToString(isolate, args.at<Object>(0), &exception);
6125 if (exception) return Failure::Exception();
6126 Handle<String> key = Handle<String>::cast(converted);
6128 // Try to convert the string key into an array index.
6129 if (key->AsArrayIndex(&index)) {
6131 return frame->GetParameter(index);
6133 Handle<Object> initial_prototype(isolate->initial_object_prototype());
6134 Handle<Object> result =
6135 Object::GetElement(isolate, initial_prototype, index);
6136 RETURN_IF_EMPTY_HANDLE(isolate, result);
6141 // Handle special arguments properties.
6142 if (key->Equals(isolate->heap()->length_string())) return Smi::FromInt(n);
6143 if (key->Equals(isolate->heap()->callee_string())) {
6144 JSFunction* function = frame->function();
6145 if (function->shared()->strict_mode() == STRICT) {
6146 return isolate->Throw(*isolate->factory()->NewTypeError(
6147 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
6152 // Lookup in the initial Object.prototype object.
6153 return isolate->initial_object_prototype()->GetProperty(*key);
6157 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
6158 HandleScope scope(isolate);
6159 ASSERT(args.length() == 1);
6160 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
6161 if (object->IsJSObject() && !object->IsGlobalObject()) {
6162 JSObject::TransformToFastProperties(Handle<JSObject>::cast(object), 0);
6168 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
6169 SealHandleScope shs(isolate);
6170 ASSERT(args.length() == 1);
6172 return isolate->heap()->ToBoolean(args[0]->BooleanValue());
6176 // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
6177 // Possible optimizations: put the type string into the oddballs.
6178 RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
6179 SealHandleScope shs(isolate);
6181 Object* obj = args[0];
6182 if (obj->IsNumber()) return isolate->heap()->number_string();
6183 if (obj->IsFloat32x4()) return isolate->heap()->float32x4_string();
6184 if (obj->IsInt32x4()) return isolate->heap()->int32x4_string();
6185 HeapObject* heap_obj = HeapObject::cast(obj);
6187 // typeof an undetectable object is 'undefined'
6188 if (heap_obj->map()->is_undetectable()) {
6189 return isolate->heap()->undefined_string();
6192 InstanceType instance_type = heap_obj->map()->instance_type();
6193 if (instance_type < FIRST_NONSTRING_TYPE) {
6194 return isolate->heap()->string_string();
6197 switch (instance_type) {
6199 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
6200 return isolate->heap()->boolean_string();
6202 if (heap_obj->IsNull()) {
6203 return FLAG_harmony_typeof
6204 ? isolate->heap()->null_string()
6205 : isolate->heap()->object_string();
6207 ASSERT(heap_obj->IsUndefined());
6208 return isolate->heap()->undefined_string();
6210 return isolate->heap()->symbol_string();
6211 case JS_FUNCTION_TYPE:
6212 case JS_FUNCTION_PROXY_TYPE:
6213 return isolate->heap()->function_string();
6215 // For any kind of object not handled above, the spec rule for
6216 // host objects gives that it is okay to return "object"
6217 return isolate->heap()->object_string();
6222 static bool AreDigits(const uint8_t*s, int from, int to) {
6223 for (int i = from; i < to; i++) {
6224 if (s[i] < '0' || s[i] > '9') return false;
6231 static int ParseDecimalInteger(const uint8_t*s, int from, int to) {
6232 ASSERT(to - from < 10); // Overflow is not possible.
6234 int d = s[from] - '0';
6236 for (int i = from + 1; i < to; i++) {
6237 d = 10 * d + (s[i] - '0');
6244 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
6245 SealHandleScope shs(isolate);
6246 ASSERT(args.length() == 1);
6247 CONVERT_ARG_CHECKED(String, subject, 0);
6248 subject->TryFlatten();
6250 // Fast case: short integer or some sorts of junk values.
6251 int len = subject->length();
6252 if (subject->IsSeqOneByteString()) {
6253 if (len == 0) return Smi::FromInt(0);
6255 uint8_t const* data = SeqOneByteString::cast(subject)->GetChars();
6256 bool minus = (data[0] == '-');
6257 int start_pos = (minus ? 1 : 0);
6259 if (start_pos == len) {
6260 return isolate->heap()->nan_value();
6261 } else if (data[start_pos] > '9') {
6262 // Fast check for a junk value. A valid string may start from a
6263 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
6264 // the 'I' character ('Infinity'). All of that have codes not greater than
6265 // '9' except 'I' and .
6266 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
6267 return isolate->heap()->nan_value();
6269 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
6270 // The maximal/minimal smi has 10 digits. If the string has less digits we
6271 // know it will fit into the smi-data type.
6272 int d = ParseDecimalInteger(data, start_pos, len);
6274 if (d == 0) return isolate->heap()->minus_zero_value();
6276 } else if (!subject->HasHashCode() &&
6277 len <= String::kMaxArrayIndexSize &&
6278 (len == 1 || data[0] != '0')) {
6279 // String hash is not calculated yet but all the data are present.
6280 // Update the hash field to speed up sequential convertions.
6281 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
6283 subject->Hash(); // Force hash calculation.
6284 ASSERT_EQ(static_cast<int>(subject->hash_field()),
6285 static_cast<int>(hash));
6287 subject->set_hash_field(hash);
6289 return Smi::FromInt(d);
6294 int flags = ALLOW_HEX;
6295 if (FLAG_harmony_numeric_literals) {
6296 // The current spec draft has not updated "ToNumber Applied to the String
6297 // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584
6298 flags |= ALLOW_OCTAL | ALLOW_BINARY;
6300 return isolate->heap()->NumberFromDouble(
6301 StringToDouble(isolate->unicode_cache(), subject, flags));
6305 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewString) {
6306 SealHandleScope shs(isolate);
6307 CONVERT_SMI_ARG_CHECKED(length, 0);
6308 CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1);
6309 if (length == 0) return isolate->heap()->empty_string();
6311 return isolate->heap()->AllocateRawOneByteString(length);
6313 return isolate->heap()->AllocateRawTwoByteString(length);
6318 RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) {
6319 HandleScope scope(isolate);
6320 CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0);
6321 CONVERT_SMI_ARG_CHECKED(new_length, 1);
6322 return *SeqString::Truncate(string, new_length);
6326 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
6327 HandleScope scope(isolate);
6328 ASSERT(args.length() == 1);
6329 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
6330 Handle<String> string = FlattenGetString(source);
6331 ASSERT(string->IsFlat());
6332 Handle<String> result = string->IsOneByteRepresentationUnderneath()
6333 ? URIEscape::Escape<uint8_t>(isolate, source)
6334 : URIEscape::Escape<uc16>(isolate, source);
6335 RETURN_IF_EMPTY_HANDLE(isolate, result);
6340 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
6341 HandleScope scope(isolate);
6342 ASSERT(args.length() == 1);
6343 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
6344 Handle<String> string = FlattenGetString(source);
6345 ASSERT(string->IsFlat());
6346 return string->IsOneByteRepresentationUnderneath()
6347 ? *URIUnescape::Unescape<uint8_t>(isolate, source)
6348 : *URIUnescape::Unescape<uc16>(isolate, source);
6352 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
6353 HandleScope scope(isolate);
6354 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
6355 ASSERT(args.length() == 1);
6356 return BasicJsonStringifier::StringifyString(isolate, string);
6360 RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) {
6361 HandleScope scope(isolate);
6362 ASSERT(args.length() == 1);
6363 BasicJsonStringifier stringifier(isolate);
6364 return stringifier.Stringify(Handle<Object>(args[0], isolate));
6368 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
6369 SealHandleScope shs(isolate);
6371 CONVERT_ARG_CHECKED(String, s, 0);
6372 CONVERT_SMI_ARG_CHECKED(radix, 1);
6376 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
6377 double value = StringToInt(isolate->unicode_cache(), s, radix);
6378 return isolate->heap()->NumberFromDouble(value);
6382 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
6383 SealHandleScope shs(isolate);
6384 CONVERT_ARG_CHECKED(String, str, 0);
6386 // ECMA-262 section 15.1.2.3, empty string is NaN
6387 double value = StringToDouble(isolate->unicode_cache(),
6388 str, ALLOW_TRAILING_JUNK, OS::nan_value());
6390 // Create a number object from the value.
6391 return isolate->heap()->NumberFromDouble(value);
6395 static inline bool ToUpperOverflows(uc32 character) {
6396 // y with umlauts and the micro sign are the only characters that stop
6397 // fitting into one-byte when converting to uppercase.
6398 static const uc32 yuml_code = 0xff;
6399 static const uc32 micro_code = 0xb5;
6400 return (character == yuml_code || character == micro_code);
6404 template <class Converter>
6405 MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
6410 unibrow::Mapping<Converter, 128>* mapping) {
6411 DisallowHeapAllocation no_gc;
6412 // We try this twice, once with the assumption that the result is no longer
6413 // than the input and, if that assumption breaks, again with the exact
6414 // length. This may not be pretty, but it is nicer than what was here before
6415 // and I hereby claim my vaffel-is.
6417 // NOTE: This assumes that the upper/lower case of an ASCII
6418 // character is also ASCII. This is currently the case, but it
6419 // might break in the future if we implement more context and locale
6420 // dependent upper/lower conversions.
6421 bool has_changed_character = false;
6423 // Convert all characters to upper case, assuming that they will fit
6425 Access<ConsStringIteratorOp> op(
6426 isolate->runtime_state()->string_iterator());
6427 StringCharacterStream stream(string, op.value());
6428 unibrow::uchar chars[Converter::kMaxWidth];
6429 // We can assume that the string is not empty
6430 uc32 current = stream.GetNext();
6431 bool ignore_overflow = Converter::kIsToLower || result->IsSeqTwoByteString();
6432 for (int i = 0; i < result_length;) {
6433 bool has_next = stream.HasMore();
6434 uc32 next = has_next ? stream.GetNext() : 0;
6435 int char_length = mapping->get(current, next, chars);
6436 if (char_length == 0) {
6437 // The case conversion of this character is the character itself.
6438 result->Set(i, current);
6440 } else if (char_length == 1 &&
6441 (ignore_overflow || !ToUpperOverflows(current))) {
6442 // Common case: converting the letter resulted in one character.
6443 ASSERT(static_cast<uc32>(chars[0]) != current);
6444 result->Set(i, chars[0]);
6445 has_changed_character = true;
6447 } else if (result_length == string->length()) {
6448 bool overflows = ToUpperOverflows(current);
6449 // We've assumed that the result would be as long as the
6450 // input but here is a character that converts to several
6451 // characters. No matter, we calculate the exact length
6452 // of the result and try the whole thing again.
6454 // Note that this leaves room for optimization. We could just
6455 // memcpy what we already have to the result string. Also,
6456 // the result string is the last object allocated we could
6457 // "realloc" it and probably, in the vast majority of cases,
6458 // extend the existing string to be able to hold the full
6460 int next_length = 0;
6462 next_length = mapping->get(next, 0, chars);
6463 if (next_length == 0) next_length = 1;
6465 int current_length = i + char_length + next_length;
6466 while (stream.HasMore()) {
6467 current = stream.GetNext();
6468 overflows |= ToUpperOverflows(current);
6469 // NOTE: we use 0 as the next character here because, while
6470 // the next character may affect what a character converts to,
6471 // it does not in any case affect the length of what it convert
6473 int char_length = mapping->get(current, 0, chars);
6474 if (char_length == 0) char_length = 1;
6475 current_length += char_length;
6476 if (current_length > String::kMaxLength) {
6477 AllowHeapAllocation allocate_error_and_return;
6478 return isolate->ThrowInvalidStringLength();
6481 // Try again with the real length. Return signed if we need
6482 // to allocate a two-byte string for to uppercase.
6483 return (overflows && !ignore_overflow) ? Smi::FromInt(-current_length)
6484 : Smi::FromInt(current_length);
6486 for (int j = 0; j < char_length; j++) {
6487 result->Set(i, chars[j]);
6490 has_changed_character = true;
6494 if (has_changed_character) {
6497 // If we didn't actually change anything in doing the conversion
6498 // we simple return the result and let the converted string
6499 // become garbage; there is no reason to keep two identical strings
6508 static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6509 static const uintptr_t kAsciiMask = kOneInEveryByte << 7;
6511 // Given a word and two range boundaries returns a word with high bit
6512 // set in every byte iff the corresponding input byte was strictly in
6513 // the range (m, n). All the other bits in the result are cleared.
6514 // This function is only useful when it can be inlined and the
6515 // boundaries are statically known.
6516 // Requires: all bytes in the input word and the boundaries must be
6517 // ASCII (less than 0x7F).
6518 static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6519 // Use strict inequalities since in edge cases the function could be
6520 // further simplified.
6521 ASSERT(0 < m && m < n);
6522 // Has high bit set in every w byte less than n.
6523 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6524 // Has high bit set in every w byte greater than m.
6525 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6526 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6531 static bool CheckFastAsciiConvert(char* dst,
6536 bool expected_changed = false;
6537 for (int i = 0; i < length; i++) {
6538 if (dst[i] == src[i]) continue;
6539 expected_changed = true;
6541 ASSERT('A' <= src[i] && src[i] <= 'Z');
6542 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6544 ASSERT('a' <= src[i] && src[i] <= 'z');
6545 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6548 return (expected_changed == changed);
6553 template<class Converter>
6554 static bool FastAsciiConvert(char* dst,
6557 bool* changed_out) {
6559 char* saved_dst = dst;
6560 const char* saved_src = src;
6562 DisallowHeapAllocation no_gc;
6563 // We rely on the distance between upper and lower case letters
6564 // being a known power of 2.
6565 ASSERT('a' - 'A' == (1 << 5));
6566 // Boundaries for the range of input characters than require conversion.
6567 static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1;
6568 static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1;
6569 bool changed = false;
6570 uintptr_t or_acc = 0;
6571 const char* const limit = src + length;
6572 #ifdef V8_HOST_CAN_READ_UNALIGNED
6573 // Process the prefix of the input that requires no conversion one
6574 // (machine) word at a time.
6575 while (src <= limit - sizeof(uintptr_t)) {
6576 const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src);
6578 if (AsciiRangeMask(w, lo, hi) != 0) {
6582 *reinterpret_cast<uintptr_t*>(dst) = w;
6583 src += sizeof(uintptr_t);
6584 dst += sizeof(uintptr_t);
6586 // Process the remainder of the input performing conversion when
6587 // required one word at a time.
6588 while (src <= limit - sizeof(uintptr_t)) {
6589 const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src);
6591 uintptr_t m = AsciiRangeMask(w, lo, hi);
6592 // The mask has high (7th) bit set in every byte that needs
6593 // conversion and we know that the distance between cases is
6595 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6596 src += sizeof(uintptr_t);
6597 dst += sizeof(uintptr_t);
6600 // Process the last few bytes of the input (or the whole input if
6601 // unaligned access is not supported).
6602 while (src < limit) {
6605 if (lo < c && c < hi) {
6613 if ((or_acc & kAsciiMask) != 0) {
6617 ASSERT(CheckFastAsciiConvert(
6618 saved_dst, saved_src, length, changed, Converter::kIsToLower));
6620 *changed_out = changed;
6627 template <class Converter>
6628 MUST_USE_RESULT static MaybeObject* ConvertCase(
6631 unibrow::Mapping<Converter, 128>* mapping) {
6632 HandleScope handle_scope(isolate);
6633 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
6634 s = FlattenGetString(s);
6635 int length = s->length();
6636 // Assume that the string is not empty; we need this assumption later
6637 if (length == 0) return *s;
6639 // Simpler handling of ASCII strings.
6641 // NOTE: This assumes that the upper/lower case of an ASCII
6642 // character is also ASCII. This is currently the case, but it
6643 // might break in the future if we implement more context and locale
6644 // dependent upper/lower conversions.
6645 if (s->IsOneByteRepresentationUnderneath()) {
6646 Handle<SeqOneByteString> result =
6647 isolate->factory()->NewRawOneByteString(length);
6648 ASSERT(!result.is_null()); // Same length as input.
6649 DisallowHeapAllocation no_gc;
6650 String::FlatContent flat_content = s->GetFlatContent();
6651 ASSERT(flat_content.IsFlat());
6652 bool has_changed_character = false;
6653 bool is_ascii = FastAsciiConvert<Converter>(
6654 reinterpret_cast<char*>(result->GetChars()),
6655 reinterpret_cast<const char*>(flat_content.ToOneByteVector().start()),
6657 &has_changed_character);
6658 // If not ASCII, we discard the result and take the 2 byte path.
6659 if (is_ascii) return has_changed_character ? *result : *s;
6662 Handle<SeqString> result;
6663 if (s->IsOneByteRepresentation()) {
6664 result = isolate->factory()->NewRawOneByteString(length);
6666 result = isolate->factory()->NewRawTwoByteString(length);
6668 ASSERT(!result.is_null()); // Same length as input.
6670 MaybeObject* maybe = ConvertCaseHelper(isolate, *s, *result, length, mapping);
6672 if (!maybe->ToObject(&answer)) return maybe;
6673 if (answer->IsString()) return answer;
6675 ASSERT(answer->IsSmi());
6676 length = Smi::cast(answer)->value();
6677 if (s->IsOneByteRepresentation() && length > 0) {
6678 result = isolate->factory()->NewRawOneByteString(length);
6680 if (length < 0) length = -length;
6681 result = isolate->factory()->NewRawTwoByteString(length);
6683 RETURN_IF_EMPTY_HANDLE(isolate, result);
6684 return ConvertCaseHelper(isolate, *s, *result, length, mapping);
6688 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
6690 args, isolate, isolate->runtime_state()->to_lower_mapping());
6694 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
6696 args, isolate, isolate->runtime_state()->to_upper_mapping());
6700 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
6701 HandleScope scope(isolate);
6702 ASSERT(args.length() == 3);
6704 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
6705 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6706 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
6708 string = FlattenGetString(string);
6709 int length = string->length();
6712 UnicodeCache* unicode_cache = isolate->unicode_cache();
6714 while (left < length &&
6715 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
6722 while (right > left &&
6723 unicode_cache->IsWhiteSpaceOrLineTerminator(
6724 string->Get(right - 1))) {
6729 return *isolate->factory()->NewSubString(string, left, right);
6733 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
6734 HandleScope handle_scope(isolate);
6735 ASSERT(args.length() == 3);
6736 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6737 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
6738 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6740 int subject_length = subject->length();
6741 int pattern_length = pattern->length();
6742 RUNTIME_ASSERT(pattern_length > 0);
6744 if (limit == 0xffffffffu) {
6745 Handle<Object> cached_answer(
6746 RegExpResultsCache::Lookup(isolate->heap(),
6749 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS),
6751 if (*cached_answer != Smi::FromInt(0)) {
6752 // The cache FixedArray is a COW-array and can therefore be reused.
6753 Handle<JSArray> result =
6754 isolate->factory()->NewJSArrayWithElements(
6755 Handle<FixedArray>::cast(cached_answer));
6760 // The limit can be very large (0xffffffffu), but since the pattern
6761 // isn't empty, we can never create more parts than ~half the length
6764 if (!subject->IsFlat()) FlattenString(subject);
6766 static const int kMaxInitialListCapacity = 16;
6768 ZoneScope zone_scope(isolate->runtime_zone());
6770 // Find (up to limit) indices of separator and end-of-string in subject
6771 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6772 ZoneList<int> indices(initial_capacity, zone_scope.zone());
6773 if (!pattern->IsFlat()) FlattenString(pattern);
6775 FindStringIndicesDispatch(isolate, *subject, *pattern,
6776 &indices, limit, zone_scope.zone());
6778 if (static_cast<uint32_t>(indices.length()) < limit) {
6779 indices.Add(subject_length, zone_scope.zone());
6782 // The list indices now contains the end of each part to create.
6784 // Create JSArray of substrings separated by separator.
6785 int part_count = indices.length();
6787 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
6788 JSObject::EnsureCanContainHeapObjectElements(result);
6789 result->set_length(Smi::FromInt(part_count));
6791 ASSERT(result->HasFastObjectElements());
6793 if (part_count == 1 && indices.at(0) == subject_length) {
6794 FixedArray::cast(result->elements())->set(0, *subject);
6798 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6800 for (int i = 0; i < part_count; i++) {
6801 HandleScope local_loop_handle(isolate);
6802 int part_end = indices.at(i);
6803 Handle<String> substring =
6804 isolate->factory()->NewProperSubString(subject, part_start, part_end);
6805 elements->set(i, *substring);
6806 part_start = part_end + pattern_length;
6809 if (limit == 0xffffffffu) {
6810 if (result->HasFastObjectElements()) {
6811 RegExpResultsCache::Enter(isolate->heap(),
6815 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS);
6823 // Copies ASCII characters to the given fixed array looking up
6824 // one-char strings in the cache. Gives up on the first char that is
6825 // not in the cache and fills the remainder with smi zeros. Returns
6826 // the length of the successfully copied prefix.
6827 static int CopyCachedAsciiCharsToArray(Heap* heap,
6828 const uint8_t* chars,
6829 FixedArray* elements,
6831 DisallowHeapAllocation no_gc;
6832 FixedArray* ascii_cache = heap->single_character_string_cache();
6833 Object* undefined = heap->undefined_value();
6835 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
6836 for (i = 0; i < length; ++i) {
6837 Object* value = ascii_cache->get(chars[i]);
6838 if (value == undefined) break;
6839 elements->set(i, value, mode);
6842 ASSERT(Smi::FromInt(0) == 0);
6843 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6846 for (int j = 0; j < length; ++j) {
6847 Object* element = elements->get(j);
6848 ASSERT(element == Smi::FromInt(0) ||
6849 (element->IsString() && String::cast(element)->LooksValid()));
6856 // Converts a String to JSArray.
6857 // For example, "foo" => ["f", "o", "o"].
6858 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
6859 HandleScope scope(isolate);
6860 ASSERT(args.length() == 2);
6861 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
6862 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
6864 s = FlattenGetString(s);
6865 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
6867 Handle<FixedArray> elements;
6869 if (s->IsFlat() && s->IsOneByteRepresentation()) {
6870 // Try using cached chars where possible.
6872 { MaybeObject* maybe_obj =
6873 isolate->heap()->AllocateUninitializedFixedArray(length);
6874 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6876 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
6877 DisallowHeapAllocation no_gc;
6878 String::FlatContent content = s->GetFlatContent();
6879 if (content.IsAscii()) {
6880 Vector<const uint8_t> chars = content.ToOneByteVector();
6881 // Note, this will initialize all elements (not only the prefix)
6882 // to prevent GC from seeing partially initialized array.
6883 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6888 MemsetPointer(elements->data_start(),
6889 isolate->heap()->undefined_value(),
6893 elements = isolate->factory()->NewFixedArray(length);
6895 for (int i = position; i < length; ++i) {
6896 Handle<Object> str =
6897 LookupSingleCharacterStringFromCode(isolate, s->Get(i));
6898 elements->set(i, *str);
6902 for (int i = 0; i < length; ++i) {
6903 ASSERT(String::cast(elements->get(i))->length() == 1);
6907 return *isolate->factory()->NewJSArrayWithElements(elements);
6911 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
6912 SealHandleScope shs(isolate);
6913 ASSERT(args.length() == 1);
6914 CONVERT_ARG_CHECKED(String, value, 0);
6915 return value->ToObject(isolate);
6919 bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
6920 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
6921 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
6922 return char_length == 0;
6926 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NumberToString) {
6927 SealHandleScope shs(isolate);
6928 ASSERT(args.length() == 1);
6930 Object* number = args[0];
6931 RUNTIME_ASSERT(number->IsNumber());
6933 return isolate->heap()->NumberToString(number);
6937 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NumberToStringSkipCache) {
6938 SealHandleScope shs(isolate);
6939 ASSERT(args.length() == 1);
6941 Object* number = args[0];
6942 RUNTIME_ASSERT(number->IsNumber());
6944 return isolate->heap()->NumberToString(number, false);
6948 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
6949 SealHandleScope shs(isolate);
6950 ASSERT(args.length() == 1);
6952 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6954 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6955 if (number > 0 && number <= Smi::kMaxValue) {
6956 return Smi::FromInt(static_cast<int>(number));
6958 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
6962 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
6963 SealHandleScope shs(isolate);
6964 ASSERT(args.length() == 1);
6966 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6968 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6969 if (number > 0 && number <= Smi::kMaxValue) {
6970 return Smi::FromInt(static_cast<int>(number));
6973 double double_value = DoubleToInteger(number);
6974 // Map both -0 and +0 to +0.
6975 if (double_value == 0) double_value = 0;
6977 return isolate->heap()->NumberFromDouble(double_value);
6981 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
6982 SealHandleScope shs(isolate);
6983 ASSERT(args.length() == 1);
6985 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
6986 return isolate->heap()->NumberFromUint32(number);
6990 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
6991 SealHandleScope shs(isolate);
6992 ASSERT(args.length() == 1);
6994 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6996 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6997 if (number > 0 && number <= Smi::kMaxValue) {
6998 return Smi::FromInt(static_cast<int>(number));
7000 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
7004 // Converts a Number to a Smi, if possible. Returns NaN if the number is not
7006 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NumberToSmi) {
7007 SealHandleScope shs(isolate);
7008 ASSERT(args.length() == 1);
7010 Object* obj = args[0];
7014 if (obj->IsHeapNumber()) {
7015 double value = HeapNumber::cast(obj)->value();
7016 int int_value = FastD2I(value);
7017 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
7018 return Smi::FromInt(int_value);
7021 return isolate->heap()->nan_value();
7025 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_AllocateHeapNumber) {
7026 SealHandleScope shs(isolate);
7027 ASSERT(args.length() == 0);
7028 return isolate->heap()->AllocateHeapNumber(0);
7032 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateFloat32x4) {
7033 SealHandleScope shs(isolate);
7034 ASSERT(args.length() == 0);
7036 float32x4_value_t zero = {{0, 0, 0, 0}};
7037 return isolate->heap()->AllocateFloat32x4(zero);
7041 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInt32x4) {
7042 SealHandleScope shs(isolate);
7043 ASSERT(args.length() == 0);
7045 int32x4_value_t zero = {{0, 0, 0, 0}};
7046 return isolate->heap()->AllocateInt32x4(zero);
7050 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
7051 SealHandleScope shs(isolate);
7052 ASSERT(args.length() == 2);
7054 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7055 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7056 return isolate->heap()->NumberFromDouble(x + y);
7060 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
7061 SealHandleScope shs(isolate);
7062 ASSERT(args.length() == 2);
7064 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7065 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7066 return isolate->heap()->NumberFromDouble(x - y);
7070 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
7071 SealHandleScope shs(isolate);
7072 ASSERT(args.length() == 2);
7074 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7075 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7076 return isolate->heap()->NumberFromDouble(x * y);
7080 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
7081 SealHandleScope shs(isolate);
7082 ASSERT(args.length() == 1);
7084 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7085 return isolate->heap()->NumberFromDouble(-x);
7089 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
7090 SealHandleScope shs(isolate);
7091 ASSERT(args.length() == 0);
7093 return isolate->heap()->NumberFromDouble(9876543210.0);
7097 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
7098 SealHandleScope shs(isolate);
7099 ASSERT(args.length() == 2);
7101 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7102 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7103 return isolate->heap()->NumberFromDouble(x / y);
7107 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
7108 SealHandleScope shs(isolate);
7109 ASSERT(args.length() == 2);
7111 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7112 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7115 // NumberFromDouble may return a Smi instead of a Number object
7116 return isolate->heap()->NumberFromDouble(x);
7120 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberImul) {
7121 SealHandleScope shs(isolate);
7122 ASSERT(args.length() == 2);
7124 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7125 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7126 return isolate->heap()->NumberFromInt32(x * y);
7130 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_StringAdd) {
7131 HandleScope scope(isolate);
7132 ASSERT(args.length() == 2);
7133 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
7134 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
7135 isolate->counters()->string_add_runtime()->Increment();
7136 Handle<String> result = isolate->factory()->NewConsString(str1, str2);
7137 RETURN_IF_EMPTY_HANDLE(isolate, result);
7142 template <typename sinkchar>
7143 static inline void StringBuilderConcatHelper(String* special,
7145 FixedArray* fixed_array,
7148 for (int i = 0; i < array_length; i++) {
7149 Object* element = fixed_array->get(i);
7150 if (element->IsSmi()) {
7151 // Smi encoding of position and length.
7152 int encoded_slice = Smi::cast(element)->value();
7155 if (encoded_slice > 0) {
7156 // Position and length encoded in one smi.
7157 pos = StringBuilderSubstringPosition::decode(encoded_slice);
7158 len = StringBuilderSubstringLength::decode(encoded_slice);
7160 // Position and length encoded in two smis.
7161 Object* obj = fixed_array->get(++i);
7162 ASSERT(obj->IsSmi());
7163 pos = Smi::cast(obj)->value();
7164 len = -encoded_slice;
7166 String::WriteToFlat(special,
7172 String* string = String::cast(element);
7173 int element_length = string->length();
7174 String::WriteToFlat(string, sink + position, 0, element_length);
7175 position += element_length;
7181 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
7182 HandleScope scope(isolate);
7183 ASSERT(args.length() == 3);
7184 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
7185 if (!args[1]->IsSmi()) return isolate->ThrowInvalidStringLength();
7186 int array_length = args.smi_at(1);
7187 CONVERT_ARG_HANDLE_CHECKED(String, special, 2);
7189 // This assumption is used by the slice encoding in one or two smis.
7190 ASSERT(Smi::kMaxValue >= String::kMaxLength);
7192 JSObject::EnsureCanContainHeapObjectElements(array);
7194 int special_length = special->length();
7195 if (!array->HasFastObjectElements()) {
7196 return isolate->Throw(isolate->heap()->illegal_argument_string());
7198 FixedArray* fixed_array = FixedArray::cast(array->elements());
7199 if (fixed_array->length() < array_length) {
7200 array_length = fixed_array->length();
7203 if (array_length == 0) {
7204 return isolate->heap()->empty_string();
7205 } else if (array_length == 1) {
7206 Object* first = fixed_array->get(0);
7207 if (first->IsString()) return first;
7210 bool one_byte = special->HasOnlyOneByteChars();
7212 for (int i = 0; i < array_length; i++) {
7214 Object* elt = fixed_array->get(i);
7216 // Smi encoding of position and length.
7217 int smi_value = Smi::cast(elt)->value();
7220 if (smi_value > 0) {
7221 // Position and length encoded in one smi.
7222 pos = StringBuilderSubstringPosition::decode(smi_value);
7223 len = StringBuilderSubstringLength::decode(smi_value);
7225 // Position and length encoded in two smis.
7227 // Get the position and check that it is a positive smi.
7229 if (i >= array_length) {
7230 return isolate->Throw(isolate->heap()->illegal_argument_string());
7232 Object* next_smi = fixed_array->get(i);
7233 if (!next_smi->IsSmi()) {
7234 return isolate->Throw(isolate->heap()->illegal_argument_string());
7236 pos = Smi::cast(next_smi)->value();
7238 return isolate->Throw(isolate->heap()->illegal_argument_string());
7243 if (pos > special_length || len > special_length - pos) {
7244 return isolate->Throw(isolate->heap()->illegal_argument_string());
7247 } else if (elt->IsString()) {
7248 String* element = String::cast(elt);
7249 int element_length = element->length();
7250 increment = element_length;
7251 if (one_byte && !element->HasOnlyOneByteChars()) {
7255 ASSERT(!elt->IsTheHole());
7256 return isolate->Throw(isolate->heap()->illegal_argument_string());
7258 if (increment > String::kMaxLength - position) {
7259 return isolate->ThrowInvalidStringLength();
7261 position += increment;
7264 int length = position;
7268 { MaybeObject* maybe_object =
7269 isolate->heap()->AllocateRawOneByteString(length);
7270 if (!maybe_object->ToObject(&object)) return maybe_object;
7272 SeqOneByteString* answer = SeqOneByteString::cast(object);
7273 StringBuilderConcatHelper(*special,
7279 { MaybeObject* maybe_object =
7280 isolate->heap()->AllocateRawTwoByteString(length);
7281 if (!maybe_object->ToObject(&object)) return maybe_object;
7283 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
7284 StringBuilderConcatHelper(*special,
7293 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
7294 HandleScope scope(isolate);
7295 ASSERT(args.length() == 3);
7296 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
7297 if (!args[1]->IsSmi()) return isolate->ThrowInvalidStringLength();
7298 int array_length = args.smi_at(1);
7299 CONVERT_ARG_HANDLE_CHECKED(String, separator, 2);
7300 RUNTIME_ASSERT(array->HasFastObjectElements());
7302 Handle<FixedArray> fixed_array(FixedArray::cast(array->elements()));
7303 if (fixed_array->length() < array_length) {
7304 array_length = fixed_array->length();
7307 if (array_length == 0) {
7308 return isolate->heap()->empty_string();
7309 } else if (array_length == 1) {
7310 Object* first = fixed_array->get(0);
7311 RUNTIME_ASSERT(first->IsString());
7315 int separator_length = separator->length();
7316 int max_nof_separators =
7317 (String::kMaxLength + separator_length - 1) / separator_length;
7318 if (max_nof_separators < (array_length - 1)) {
7319 return isolate->ThrowInvalidStringLength();
7321 int length = (array_length - 1) * separator_length;
7322 for (int i = 0; i < array_length; i++) {
7323 Object* element_obj = fixed_array->get(i);
7324 RUNTIME_ASSERT(element_obj->IsString());
7325 String* element = String::cast(element_obj);
7326 int increment = element->length();
7327 if (increment > String::kMaxLength - length) {
7328 STATIC_ASSERT(String::kMaxLength < kMaxInt);
7329 length = kMaxInt; // Provoke exception;
7332 length += increment;
7335 Handle<SeqTwoByteString> answer =
7336 isolate->factory()->NewRawTwoByteString(length);
7337 RETURN_IF_EMPTY_HANDLE(isolate, answer);
7339 DisallowHeapAllocation no_gc;
7341 uc16* sink = answer->GetChars();
7343 uc16* end = sink + length;
7346 String* first = String::cast(fixed_array->get(0));
7347 String* seperator_raw = *separator;
7348 int first_length = first->length();
7349 String::WriteToFlat(first, sink, 0, first_length);
7350 sink += first_length;
7352 for (int i = 1; i < array_length; i++) {
7353 ASSERT(sink + separator_length <= end);
7354 String::WriteToFlat(seperator_raw, sink, 0, separator_length);
7355 sink += separator_length;
7357 String* element = String::cast(fixed_array->get(i));
7358 int element_length = element->length();
7359 ASSERT(sink + element_length <= end);
7360 String::WriteToFlat(element, sink, 0, element_length);
7361 sink += element_length;
7363 ASSERT(sink == end);
7365 // Use %_FastAsciiArrayJoin instead.
7366 ASSERT(!answer->IsOneByteRepresentation());
7370 template <typename Char>
7371 static void JoinSparseArrayWithSeparator(FixedArray* elements,
7372 int elements_length,
7373 uint32_t array_length,
7375 Vector<Char> buffer) {
7376 int previous_separator_position = 0;
7377 int separator_length = separator->length();
7379 for (int i = 0; i < elements_length; i += 2) {
7380 int position = NumberToInt32(elements->get(i));
7381 String* string = String::cast(elements->get(i + 1));
7382 int string_length = string->length();
7383 if (string->length() > 0) {
7384 while (previous_separator_position < position) {
7385 String::WriteToFlat<Char>(separator, &buffer[cursor],
7386 0, separator_length);
7387 cursor += separator_length;
7388 previous_separator_position++;
7390 String::WriteToFlat<Char>(string, &buffer[cursor],
7392 cursor += string->length();
7395 if (separator_length > 0) {
7396 // Array length must be representable as a signed 32-bit number,
7397 // otherwise the total string length would have been too large.
7398 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
7399 int last_array_index = static_cast<int>(array_length - 1);
7400 while (previous_separator_position < last_array_index) {
7401 String::WriteToFlat<Char>(separator, &buffer[cursor],
7402 0, separator_length);
7403 cursor += separator_length;
7404 previous_separator_position++;
7407 ASSERT(cursor <= buffer.length());
7411 RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
7412 HandleScope scope(isolate);
7413 ASSERT(args.length() == 3);
7414 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
7415 RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements());
7416 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
7417 CONVERT_ARG_CHECKED(String, separator, 2);
7418 // elements_array is fast-mode JSarray of alternating positions
7419 // (increasing order) and strings.
7420 // array_length is length of original array (used to add separators);
7421 // separator is string to put between elements. Assumed to be non-empty.
7423 // Find total length of join result.
7424 int string_length = 0;
7425 bool is_ascii = separator->IsOneByteRepresentation();
7426 bool overflow = false;
7427 CONVERT_NUMBER_CHECKED(int, elements_length,
7428 Int32, elements_array->length());
7429 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
7430 FixedArray* elements = FixedArray::cast(elements_array->elements());
7431 for (int i = 0; i < elements_length; i += 2) {
7432 RUNTIME_ASSERT(elements->get(i)->IsNumber());
7433 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
7434 String* string = String::cast(elements->get(i + 1));
7435 int length = string->length();
7436 if (is_ascii && !string->IsOneByteRepresentation()) {
7439 if (length > String::kMaxLength ||
7440 String::kMaxLength - length < string_length) {
7444 string_length += length;
7446 int separator_length = separator->length();
7447 if (!overflow && separator_length > 0) {
7448 if (array_length <= 0x7fffffffu) {
7449 int separator_count = static_cast<int>(array_length) - 1;
7450 int remaining_length = String::kMaxLength - string_length;
7451 if ((remaining_length / separator_length) >= separator_count) {
7452 string_length += separator_length * (array_length - 1);
7454 // Not room for the separators within the maximal string length.
7458 // Nonempty separator and at least 2^31-1 separators necessary
7459 // means that the string is too large to create.
7460 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7465 // Throw an exception if the resulting string is too large. See
7466 // https://code.google.com/p/chromium/issues/detail?id=336820
7468 return isolate->ThrowInvalidStringLength();
7472 MaybeObject* result_allocation =
7473 isolate->heap()->AllocateRawOneByteString(string_length);
7474 if (result_allocation->IsFailure()) return result_allocation;
7475 SeqOneByteString* result_string =
7476 SeqOneByteString::cast(result_allocation->ToObjectUnchecked());
7477 JoinSparseArrayWithSeparator<uint8_t>(elements,
7482 result_string->GetChars(),
7484 return result_string;
7486 MaybeObject* result_allocation =
7487 isolate->heap()->AllocateRawTwoByteString(string_length);
7488 if (result_allocation->IsFailure()) return result_allocation;
7489 SeqTwoByteString* result_string =
7490 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7491 JoinSparseArrayWithSeparator<uc16>(elements,
7495 Vector<uc16>(result_string->GetChars(),
7497 return result_string;
7502 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
7503 SealHandleScope shs(isolate);
7504 ASSERT(args.length() == 2);
7506 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7507 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7508 return isolate->heap()->NumberFromInt32(x | y);
7512 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
7513 SealHandleScope shs(isolate);
7514 ASSERT(args.length() == 2);
7516 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7517 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7518 return isolate->heap()->NumberFromInt32(x & y);
7522 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
7523 SealHandleScope shs(isolate);
7524 ASSERT(args.length() == 2);
7526 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7527 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7528 return isolate->heap()->NumberFromInt32(x ^ y);
7532 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
7533 SealHandleScope shs(isolate);
7534 ASSERT(args.length() == 2);
7536 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7537 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7538 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
7542 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
7543 SealHandleScope shs(isolate);
7544 ASSERT(args.length() == 2);
7546 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7547 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7548 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
7552 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
7553 SealHandleScope shs(isolate);
7554 ASSERT(args.length() == 2);
7556 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7557 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7558 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
7562 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
7563 SealHandleScope shs(isolate);
7564 ASSERT(args.length() == 2);
7566 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7567 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7568 if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL);
7569 if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL);
7570 if (x == y) return Smi::FromInt(EQUAL);
7572 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7573 result = Smi::FromInt(EQUAL);
7575 result = Smi::FromInt(NOT_EQUAL);
7581 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
7582 SealHandleScope shs(isolate);
7583 ASSERT(args.length() == 2);
7585 CONVERT_ARG_CHECKED(String, x, 0);
7586 CONVERT_ARG_CHECKED(String, y, 1);
7588 bool not_equal = !x->Equals(y);
7589 // This is slightly convoluted because the value that signifies
7590 // equality is 0 and inequality is 1 so we have to negate the result
7591 // from String::Equals.
7592 ASSERT(not_equal == 0 || not_equal == 1);
7593 STATIC_CHECK(EQUAL == 0);
7594 STATIC_CHECK(NOT_EQUAL == 1);
7595 return Smi::FromInt(not_equal);
7599 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
7600 SealHandleScope shs(isolate);
7601 ASSERT(args.length() == 3);
7603 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7604 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7605 if (std::isnan(x) || std::isnan(y)) return args[2];
7606 if (x == y) return Smi::FromInt(EQUAL);
7607 if (isless(x, y)) return Smi::FromInt(LESS);
7608 return Smi::FromInt(GREATER);
7612 // Compare two Smis as if they were converted to strings and then
7613 // compared lexicographically.
7614 RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
7615 SealHandleScope shs(isolate);
7616 ASSERT(args.length() == 2);
7617 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7618 CONVERT_SMI_ARG_CHECKED(y_value, 1);
7620 // If the integers are equal so are the string representations.
7621 if (x_value == y_value) return Smi::FromInt(EQUAL);
7623 // If one of the integers is zero the normal integer order is the
7624 // same as the lexicographic order of the string representations.
7625 if (x_value == 0 || y_value == 0)
7626 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
7628 // If only one of the integers is negative the negative number is
7629 // smallest because the char code of '-' is less than the char code
7630 // of any digit. Otherwise, we make both values positive.
7632 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7633 // architectures using 32-bit Smis.
7634 uint32_t x_scaled = x_value;
7635 uint32_t y_scaled = y_value;
7636 if (x_value < 0 || y_value < 0) {
7637 if (y_value >= 0) return Smi::FromInt(LESS);
7638 if (x_value >= 0) return Smi::FromInt(GREATER);
7639 x_scaled = -x_value;
7640 y_scaled = -y_value;
7643 static const uint32_t kPowersOf10[] = {
7644 1, 10, 100, 1000, 10*1000, 100*1000,
7645 1000*1000, 10*1000*1000, 100*1000*1000,
7649 // If the integers have the same number of decimal digits they can be
7650 // compared directly as the numeric order is the same as the
7651 // lexicographic order. If one integer has fewer digits, it is scaled
7652 // by some power of 10 to have the same number of digits as the longer
7653 // integer. If the scaled integers are equal it means the shorter
7654 // integer comes first in the lexicographic order.
7656 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7657 int x_log2 = IntegerLog2(x_scaled);
7658 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7659 x_log10 -= x_scaled < kPowersOf10[x_log10];
7661 int y_log2 = IntegerLog2(y_scaled);
7662 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7663 y_log10 -= y_scaled < kPowersOf10[y_log10];
7667 if (x_log10 < y_log10) {
7668 // X has fewer digits. We would like to simply scale up X but that
7669 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7670 // be scaled up to 9_000_000_000. So we scale up by the next
7671 // smallest power and scale down Y to drop one digit. It is OK to
7672 // drop one digit from the longer integer since the final digit is
7673 // past the length of the shorter integer.
7674 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7677 } else if (y_log10 < x_log10) {
7678 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7683 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7684 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7685 return Smi::FromInt(tie);
7689 static Object* StringCharacterStreamCompare(RuntimeState* state,
7692 StringCharacterStream stream_x(x, state->string_iterator_compare_x());
7693 StringCharacterStream stream_y(y, state->string_iterator_compare_y());
7694 while (stream_x.HasMore() && stream_y.HasMore()) {
7695 int d = stream_x.GetNext() - stream_y.GetNext();
7696 if (d < 0) return Smi::FromInt(LESS);
7697 else if (d > 0) return Smi::FromInt(GREATER);
7700 // x is (non-trivial) prefix of y:
7701 if (stream_y.HasMore()) return Smi::FromInt(LESS);
7702 // y is prefix of x:
7703 return Smi::FromInt(stream_x.HasMore() ? GREATER : EQUAL);
7707 static Object* FlatStringCompare(String* x, String* y) {
7708 ASSERT(x->IsFlat());
7709 ASSERT(y->IsFlat());
7710 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7711 int prefix_length = x->length();
7712 if (y->length() < prefix_length) {
7713 prefix_length = y->length();
7714 equal_prefix_result = Smi::FromInt(GREATER);
7715 } else if (y->length() > prefix_length) {
7716 equal_prefix_result = Smi::FromInt(LESS);
7719 DisallowHeapAllocation no_gc;
7720 String::FlatContent x_content = x->GetFlatContent();
7721 String::FlatContent y_content = y->GetFlatContent();
7722 if (x_content.IsAscii()) {
7723 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
7724 if (y_content.IsAscii()) {
7725 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
7726 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7728 Vector<const uc16> y_chars = y_content.ToUC16Vector();
7729 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7732 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7733 if (y_content.IsAscii()) {
7734 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
7735 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7737 Vector<const uc16> y_chars = y_content.ToUC16Vector();
7738 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7743 result = equal_prefix_result;
7745 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7748 StringCharacterStreamCompare(x->GetIsolate()->runtime_state(), x, y));
7753 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_StringCompare) {
7754 SealHandleScope shs(isolate);
7755 ASSERT(args.length() == 2);
7757 CONVERT_ARG_CHECKED(String, x, 0);
7758 CONVERT_ARG_CHECKED(String, y, 1);
7760 isolate->counters()->string_compare_runtime()->Increment();
7762 // A few fast case tests before we flatten.
7763 if (x == y) return Smi::FromInt(EQUAL);
7764 if (y->length() == 0) {
7765 if (x->length() == 0) return Smi::FromInt(EQUAL);
7766 return Smi::FromInt(GREATER);
7767 } else if (x->length() == 0) {
7768 return Smi::FromInt(LESS);
7771 int d = x->Get(0) - y->Get(0);
7772 if (d < 0) return Smi::FromInt(LESS);
7773 else if (d > 0) return Smi::FromInt(GREATER);
7776 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
7777 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7779 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
7780 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7783 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
7784 : StringCharacterStreamCompare(isolate->runtime_state(), x, y);
7788 #define RUNTIME_UNARY_MATH(NAME) \
7789 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_##NAME) { \
7790 SealHandleScope shs(isolate); \
7791 ASSERT(args.length() == 1); \
7792 isolate->counters()->math_##NAME()->Increment(); \
7793 CONVERT_DOUBLE_ARG_CHECKED(x, 0); \
7794 return isolate->heap()->AllocateHeapNumber(std::NAME(x)); \
7797 RUNTIME_UNARY_MATH(acos)
7798 RUNTIME_UNARY_MATH(asin)
7799 RUNTIME_UNARY_MATH(atan)
7800 RUNTIME_UNARY_MATH(log)
7801 #undef RUNTIME_UNARY_MATH
7804 RUNTIME_FUNCTION(MaybeObject*, Runtime_DoubleHi) {
7805 SealHandleScope shs(isolate);
7806 ASSERT(args.length() == 1);
7807 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7808 uint64_t integer = double_to_uint64(x);
7809 integer = (integer >> 32) & 0xFFFFFFFFu;
7810 return isolate->heap()->NumberFromDouble(static_cast<int32_t>(integer));
7814 RUNTIME_FUNCTION(MaybeObject*, Runtime_DoubleLo) {
7815 SealHandleScope shs(isolate);
7816 ASSERT(args.length() == 1);
7817 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7818 return isolate->heap()->NumberFromDouble(
7819 static_cast<int32_t>(double_to_uint64(x) & 0xFFFFFFFFu));
7823 RUNTIME_FUNCTION(MaybeObject*, Runtime_ConstructDouble) {
7824 SealHandleScope shs(isolate);
7825 ASSERT(args.length() == 2);
7826 CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]);
7827 CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]);
7828 uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo;
7829 return isolate->heap()->AllocateHeapNumber(uint64_to_double(result));
7833 static const double kPiDividedBy4 = 0.78539816339744830962;
7836 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
7837 SealHandleScope shs(isolate);
7838 ASSERT(args.length() == 2);
7839 isolate->counters()->math_atan2()->Increment();
7841 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7842 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7844 if (std::isinf(x) && std::isinf(y)) {
7845 // Make sure that the result in case of two infinite arguments
7846 // is a multiple of Pi / 4. The sign of the result is determined
7847 // by the first argument (x) and the sign of the second argument
7848 // determines the multiplier: one or three.
7849 int multiplier = (x < 0) ? -1 : 1;
7850 if (y < 0) multiplier *= 3;
7851 result = multiplier * kPiDividedBy4;
7853 result = std::atan2(x, y);
7855 return isolate->heap()->AllocateHeapNumber(result);
7859 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
7860 SealHandleScope shs(isolate);
7861 ASSERT(args.length() == 1);
7862 isolate->counters()->math_exp()->Increment();
7864 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7865 lazily_initialize_fast_exp();
7866 return isolate->heap()->NumberFromDouble(fast_exp(x));
7870 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
7871 SealHandleScope shs(isolate);
7872 ASSERT(args.length() == 1);
7873 isolate->counters()->math_floor()->Increment();
7875 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7876 return isolate->heap()->NumberFromDouble(std::floor(x));
7880 // Slow version of Math.pow. We check for fast paths for special cases.
7881 // Used if SSE2/VFP3 is not available.
7882 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
7883 SealHandleScope shs(isolate);
7884 ASSERT(args.length() == 2);
7885 isolate->counters()->math_pow()->Increment();
7887 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7889 // If the second argument is a smi, it is much faster to call the
7890 // custom powi() function than the generic pow().
7891 if (args[1]->IsSmi()) {
7892 int y = args.smi_at(1);
7893 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
7896 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7897 double result = power_helper(x, y);
7898 if (std::isnan(result)) return isolate->heap()->nan_value();
7899 return isolate->heap()->AllocateHeapNumber(result);
7903 // Fast version of Math.pow if we know that y is not an integer and y is not
7904 // -0.5 or 0.5. Used as slow case from full codegen.
7905 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
7906 SealHandleScope shs(isolate);
7907 ASSERT(args.length() == 2);
7908 isolate->counters()->math_pow()->Increment();
7910 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7911 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7913 return Smi::FromInt(1);
7915 double result = power_double_double(x, y);
7916 if (std::isnan(result)) return isolate->heap()->nan_value();
7917 return isolate->heap()->AllocateHeapNumber(result);
7922 RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
7923 SealHandleScope shs(isolate);
7924 ASSERT(args.length() == 1);
7925 isolate->counters()->math_round()->Increment();
7927 if (!args[0]->IsHeapNumber()) {
7928 // Must be smi. Return the argument unchanged for all the other types
7929 // to make fuzz-natives test happy.
7933 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7935 double value = number->value();
7936 int exponent = number->get_exponent();
7937 int sign = number->get_sign();
7939 if (exponent < -1) {
7940 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7941 if (sign) return isolate->heap()->minus_zero_value();
7942 return Smi::FromInt(0);
7945 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7946 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7947 // argument holds for 32-bit smis).
7948 if (!sign && exponent < kSmiValueSize - 2) {
7949 return Smi::FromInt(static_cast<int>(value + 0.5));
7952 // If the magnitude is big enough, there's no place for fraction part. If we
7953 // try to add 0.5 to this number, 1.0 will be added instead.
7954 if (exponent >= 52) {
7958 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
7960 // Do not call NumberFromDouble() to avoid extra checks.
7961 return isolate->heap()->AllocateHeapNumber(std::floor(value + 0.5));
7965 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
7966 SealHandleScope shs(isolate);
7967 ASSERT(args.length() == 1);
7968 isolate->counters()->math_sqrt()->Increment();
7970 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7971 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
7975 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_fround) {
7976 SealHandleScope shs(isolate);
7977 ASSERT(args.length() == 1);
7979 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7980 float xf = static_cast<float>(x);
7981 return isolate->heap()->AllocateHeapNumber(xf);
7985 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
7986 SealHandleScope shs(isolate);
7987 ASSERT(args.length() == 2);
7989 CONVERT_SMI_ARG_CHECKED(year, 0);
7990 CONVERT_SMI_ARG_CHECKED(month, 1);
7992 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
7996 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7997 HandleScope scope(isolate);
7998 ASSERT(args.length() == 3);
8000 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
8001 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
8002 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
8004 DateCache* date_cache = isolate->date_cache();
8006 Object* value = NULL;
8007 bool is_value_nan = false;
8008 if (std::isnan(time)) {
8009 value = isolate->heap()->nan_value();
8010 is_value_nan = true;
8011 } else if (!is_utc &&
8012 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
8013 time > DateCache::kMaxTimeBeforeUTCInMs)) {
8014 value = isolate->heap()->nan_value();
8015 is_value_nan = true;
8017 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
8018 if (time < -DateCache::kMaxTimeInMs ||
8019 time > DateCache::kMaxTimeInMs) {
8020 value = isolate->heap()->nan_value();
8021 is_value_nan = true;
8023 MaybeObject* maybe_result =
8024 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
8025 if (!maybe_result->ToObject(&value)) return maybe_result;
8028 date->SetValue(value, is_value_nan);
8033 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NewArgumentsFast) {
8034 HandleScope scope(isolate);
8035 ASSERT(args.length() == 3);
8037 Handle<JSFunction> callee = args.at<JSFunction>(0);
8038 Object** parameters = reinterpret_cast<Object**>(args[1]);
8039 const int argument_count = Smi::cast(args[2])->value();
8041 Handle<JSObject> result =
8042 isolate->factory()->NewArgumentsObject(callee, argument_count);
8043 // Allocate the elements if needed.
8044 int parameter_count = callee->shared()->formal_parameter_count();
8045 if (argument_count > 0) {
8046 if (parameter_count > 0) {
8047 int mapped_count = Min(argument_count, parameter_count);
8048 Handle<FixedArray> parameter_map =
8049 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
8050 parameter_map->set_map(
8051 isolate->heap()->sloppy_arguments_elements_map());
8053 Handle<Map> old_map(result->map());
8054 Handle<Map> new_map = isolate->factory()->CopyMap(old_map);
8055 new_map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
8057 result->set_map(*new_map);
8058 result->set_elements(*parameter_map);
8060 // Store the context and the arguments array at the beginning of the
8062 Handle<Context> context(isolate->context());
8063 Handle<FixedArray> arguments =
8064 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8065 parameter_map->set(0, *context);
8066 parameter_map->set(1, *arguments);
8068 // Loop over the actual parameters backwards.
8069 int index = argument_count - 1;
8070 while (index >= mapped_count) {
8071 // These go directly in the arguments array and have no
8072 // corresponding slot in the parameter map.
8073 arguments->set(index, *(parameters - index - 1));
8077 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
8078 while (index >= 0) {
8079 // Detect duplicate names to the right in the parameter list.
8080 Handle<String> name(scope_info->ParameterName(index));
8081 int context_local_count = scope_info->ContextLocalCount();
8082 bool duplicate = false;
8083 for (int j = index + 1; j < parameter_count; ++j) {
8084 if (scope_info->ParameterName(j) == *name) {
8091 // This goes directly in the arguments array with a hole in the
8093 arguments->set(index, *(parameters - index - 1));
8094 parameter_map->set_the_hole(index + 2);
8096 // The context index goes in the parameter map with a hole in the
8098 int context_index = -1;
8099 for (int j = 0; j < context_local_count; ++j) {
8100 if (scope_info->ContextLocalName(j) == *name) {
8105 ASSERT(context_index >= 0);
8106 arguments->set_the_hole(index);
8107 parameter_map->set(index + 2, Smi::FromInt(
8108 Context::MIN_CONTEXT_SLOTS + context_index));
8114 // If there is no aliasing, the arguments object elements are not
8115 // special in any way.
8116 Handle<FixedArray> elements =
8117 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8118 result->set_elements(*elements);
8119 for (int i = 0; i < argument_count; ++i) {
8120 elements->set(i, *(parameters - i - 1));
8128 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NewStrictArgumentsFast) {
8129 SealHandleScope shs(isolate);
8130 ASSERT(args.length() == 3);
8132 JSFunction* callee = JSFunction::cast(args[0]);
8133 Object** parameters = reinterpret_cast<Object**>(args[1]);
8134 const int length = args.smi_at(2);
8137 { MaybeObject* maybe_result =
8138 isolate->heap()->AllocateArgumentsObject(callee, length);
8139 if (!maybe_result->ToObject(&result)) return maybe_result;
8141 // Allocate the elements if needed.
8143 // Allocate the fixed array.
8145 { MaybeObject* maybe_obj =
8146 isolate->heap()->AllocateUninitializedFixedArray(length);
8147 if (!maybe_obj->To(&array)) return maybe_obj;
8150 DisallowHeapAllocation no_gc;
8151 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
8152 for (int i = 0; i < length; i++) {
8153 array->set(i, *--parameters, mode);
8155 JSObject::cast(result)->set_elements(array);
8161 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NewClosureFromStubFailure) {
8162 HandleScope scope(isolate);
8163 ASSERT(args.length() == 1);
8164 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
8165 Handle<Context> context(isolate->context());
8166 PretenureFlag pretenure_flag = NOT_TENURED;
8167 Handle<JSFunction> result =
8168 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8175 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NewClosure) {
8176 HandleScope scope(isolate);
8177 ASSERT(args.length() == 3);
8178 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8179 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
8180 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
8182 // The caller ensures that we pretenure closures that are assigned
8183 // directly to properties.
8184 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
8185 Handle<JSFunction> result =
8186 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8193 // Find the arguments of the JavaScript function invocation that called
8194 // into C++ code. Collect these in a newly allocated array of handles (possibly
8195 // prefixed by a number of empty handles).
8196 static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8200 // Find frame containing arguments passed to the caller.
8201 JavaScriptFrameIterator it(isolate);
8202 JavaScriptFrame* frame = it.frame();
8203 List<JSFunction*> functions(2);
8204 frame->GetFunctions(&functions);
8205 if (functions.length() > 1) {
8206 int inlined_jsframe_index = functions.length() - 1;
8207 JSFunction* inlined_function = functions[inlined_jsframe_index];
8208 SlotRefValueBuilder slot_refs(
8210 inlined_jsframe_index,
8211 inlined_function->shared()->formal_parameter_count());
8213 int args_count = slot_refs.args_length();
8215 *total_argc = prefix_argc + args_count;
8216 SmartArrayPointer<Handle<Object> > param_data(
8217 NewArray<Handle<Object> >(*total_argc));
8218 slot_refs.Prepare(isolate);
8219 for (int i = 0; i < args_count; i++) {
8220 Handle<Object> val = slot_refs.GetNext(isolate, 0);
8221 param_data[prefix_argc + i] = val;
8223 slot_refs.Finish(isolate);
8227 it.AdvanceToArgumentsFrame();
8229 int args_count = frame->ComputeParametersCount();
8231 *total_argc = prefix_argc + args_count;
8232 SmartArrayPointer<Handle<Object> > param_data(
8233 NewArray<Handle<Object> >(*total_argc));
8234 for (int i = 0; i < args_count; i++) {
8235 Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
8236 param_data[prefix_argc + i] = val;
8243 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8244 HandleScope scope(isolate);
8245 ASSERT(args.length() == 4);
8246 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
8247 RUNTIME_ASSERT(args[3]->IsNumber());
8248 Handle<Object> bindee = args.at<Object>(1);
8250 // TODO(lrn): Create bound function in C++ code from premade shared info.
8251 bound_function->shared()->set_bound(true);
8252 // Get all arguments of calling function (Function.prototype.bind).
8254 SmartArrayPointer<Handle<Object> > arguments =
8255 GetCallerArguments(isolate, 0, &argc);
8256 // Don't count the this-arg.
8258 ASSERT(*arguments[0] == args[2]);
8261 ASSERT(args[2]->IsUndefined());
8263 // Initialize array of bindings (function, this, and any existing arguments
8264 // if the function was already bound).
8265 Handle<FixedArray> new_bindings;
8267 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8268 Handle<FixedArray> old_bindings(
8269 JSFunction::cast(*bindee)->function_bindings());
8271 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8272 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex),
8275 for (int n = old_bindings->length(); i < n; i++) {
8276 new_bindings->set(i, old_bindings->get(i));
8279 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8280 new_bindings = isolate->factory()->NewFixedArray(array_size);
8281 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8282 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8285 // Copy arguments, skipping the first which is "this_arg".
8286 for (int j = 0; j < argc; j++, i++) {
8287 new_bindings->set(i, *arguments[j + 1]);
8289 new_bindings->set_map_no_write_barrier(
8290 isolate->heap()->fixed_cow_array_map());
8291 bound_function->set_function_bindings(*new_bindings);
8294 Handle<String> length_string = isolate->factory()->length_string();
8295 Handle<Object> new_length(args.at<Object>(3));
8296 PropertyAttributes attr =
8297 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8298 ForceSetProperty(bound_function, length_string, new_length, attr);
8299 return *bound_function;
8303 RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8304 HandleScope handles(isolate);
8305 ASSERT(args.length() == 1);
8306 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
8307 if (callable->IsJSFunction()) {
8308 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8309 if (function->shared()->bound()) {
8310 Handle<FixedArray> bindings(function->function_bindings());
8311 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8312 return *isolate->factory()->NewJSArrayWithElements(bindings);
8315 return isolate->heap()->undefined_value();
8319 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
8320 HandleScope scope(isolate);
8321 ASSERT(args.length() == 1);
8322 // First argument is a function to use as a constructor.
8323 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8324 RUNTIME_ASSERT(function->shared()->bound());
8326 // The argument is a bound function. Extract its bound arguments
8328 Handle<FixedArray> bound_args =
8329 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8330 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8331 Handle<Object> bound_function(
8332 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
8334 ASSERT(!bound_function->IsJSFunction() ||
8335 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
8338 SmartArrayPointer<Handle<Object> > param_data =
8339 GetCallerArguments(isolate, bound_argc, &total_argc);
8340 for (int i = 0; i < bound_argc; i++) {
8341 param_data[i] = Handle<Object>(bound_args->get(
8342 JSFunction::kBoundArgumentsStartIndex + i), isolate);
8345 if (!bound_function->IsJSFunction()) {
8346 bool exception_thrown;
8347 bound_function = Execution::TryGetConstructorDelegate(isolate,
8350 if (exception_thrown) return Failure::Exception();
8352 ASSERT(bound_function->IsJSFunction());
8354 bool exception = false;
8355 Handle<Object> result =
8356 Execution::New(Handle<JSFunction>::cast(bound_function),
8357 total_argc, param_data.get(), &exception);
8359 return Failure::Exception();
8361 ASSERT(!result.is_null());
8366 static MaybeObject* Runtime_NewObjectHelper(Isolate* isolate,
8367 Handle<Object> constructor,
8368 Handle<AllocationSite> site) {
8369 // If the constructor isn't a proper function we throw a type error.
8370 if (!constructor->IsJSFunction()) {
8371 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8372 Handle<Object> type_error =
8373 isolate->factory()->NewTypeError("not_constructor", arguments);
8374 return isolate->Throw(*type_error);
8377 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
8379 // If function should not have prototype, construction is not allowed. In this
8380 // case generated code bailouts here, since function has no initial_map.
8381 if (!function->should_have_prototype() && !function->shared()->bound()) {
8382 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8383 Handle<Object> type_error =
8384 isolate->factory()->NewTypeError("not_constructor", arguments);
8385 return isolate->Throw(*type_error);
8388 #ifdef ENABLE_DEBUGGER_SUPPORT
8389 Debug* debug = isolate->debug();
8390 // Handle stepping into constructors if step into is active.
8391 if (debug->StepInActive()) {
8392 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
8396 if (function->has_initial_map()) {
8397 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
8398 // The 'Function' function ignores the receiver object when
8399 // called using 'new' and creates a new JSFunction object that
8400 // is returned. The receiver object is only used for error
8401 // reporting if an error occurs when constructing the new
8402 // JSFunction. Factory::NewJSObject() should not be used to
8403 // allocate JSFunctions since it does not properly initialize
8404 // the shared part of the function. Since the receiver is
8405 // ignored anyway, we use the global object as the receiver
8406 // instead of a new JSFunction object. This way, errors are
8407 // reported the same way whether or not 'Function' is called
8409 return isolate->context()->global_object();
8413 // The function should be compiled for the optimization hints to be
8415 Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
8417 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
8418 if (!function->has_initial_map() &&
8419 shared->IsInobjectSlackTrackingInProgress()) {
8420 // The tracking is already in progress for another function. We can only
8421 // track one initial_map at a time, so we force the completion before the
8422 // function is called as a constructor for the first time.
8423 shared->CompleteInobjectSlackTracking();
8426 Handle<JSObject> result;
8427 if (site.is_null()) {
8428 result = isolate->factory()->NewJSObject(function);
8430 result = isolate->factory()->NewJSObjectWithMemento(function, site);
8432 RETURN_IF_EMPTY_HANDLE(isolate, result);
8434 isolate->counters()->constructed_objects()->Increment();
8435 isolate->counters()->constructed_objects_runtime()->Increment();
8441 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NewObject) {
8442 HandleScope scope(isolate);
8443 ASSERT(args.length() == 1);
8445 Handle<Object> constructor = args.at<Object>(0);
8446 return Runtime_NewObjectHelper(isolate,
8448 Handle<AllocationSite>::null());
8452 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NewObjectWithAllocationSite) {
8453 HandleScope scope(isolate);
8454 ASSERT(args.length() == 2);
8456 Handle<Object> constructor = args.at<Object>(1);
8457 Handle<Object> feedback = args.at<Object>(0);
8458 Handle<AllocationSite> site;
8459 if (feedback->IsAllocationSite()) {
8460 // The feedback can be an AllocationSite or undefined.
8461 site = Handle<AllocationSite>::cast(feedback);
8463 return Runtime_NewObjectHelper(isolate,
8469 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_FinalizeInstanceSize) {
8470 HandleScope scope(isolate);
8471 ASSERT(args.length() == 1);
8473 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8474 function->shared()->CompleteInobjectSlackTracking();
8476 return isolate->heap()->undefined_value();
8480 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_CompileUnoptimized) {
8481 HandleScope scope(isolate);
8482 ASSERT(args.length() == 1);
8484 Handle<JSFunction> function = args.at<JSFunction>(0);
8486 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
8487 PrintF("[unoptimized: ");
8488 function->PrintName();
8493 // Compile the target function.
8494 ASSERT(function->shared()->allows_lazy_compilation());
8496 Handle<Code> code = Compiler::GetUnoptimizedCode(function);
8497 RETURN_IF_EMPTY_HANDLE(isolate, code);
8498 function->ReplaceCode(*code);
8500 // All done. Return the compiled code.
8501 ASSERT(function->is_compiled());
8502 ASSERT(function->code()->kind() == Code::FUNCTION ||
8504 function->code()->kind() == Code::OPTIMIZED_FUNCTION));
8509 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_CompileOptimized) {
8510 HandleScope scope(isolate);
8511 ASSERT(args.length() == 2);
8512 Handle<JSFunction> function = args.at<JSFunction>(0);
8513 CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1);
8515 Handle<Code> unoptimized(function->shared()->code());
8516 if (!function->shared()->is_compiled()) {
8517 // If the function is not compiled, do not optimize.
8518 // This can happen if the debugger is activated and
8519 // the function is returned to the not compiled state.
8520 // TODO(yangguo): reconsider this.
8521 function->ReplaceCode(function->shared()->code());
8522 } else if (!isolate->use_crankshaft() ||
8523 function->shared()->optimization_disabled() ||
8524 isolate->DebuggerHasBreakPoints()) {
8525 // If the function is not optimizable or debugger is active continue
8526 // using the code from the full compiler.
8527 if (FLAG_trace_opt) {
8528 PrintF("[failed to optimize ");
8529 function->PrintName();
8530 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8531 function->shared()->optimization_disabled() ? "F" : "T",
8532 isolate->DebuggerHasBreakPoints() ? "T" : "F");
8534 function->ReplaceCode(*unoptimized);
8536 Compiler::ConcurrencyMode mode = concurrent ? Compiler::CONCURRENT
8537 : Compiler::NOT_CONCURRENT;
8538 Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized, mode);
8539 function->ReplaceCode(code.is_null() ? *unoptimized : *code);
8542 ASSERT(function->code()->kind() == Code::FUNCTION ||
8543 function->code()->kind() == Code::OPTIMIZED_FUNCTION ||
8544 function->IsInOptimizationQueue());
8545 return function->code();
8549 class ActivationsFinder : public ThreadVisitor {
8552 bool has_code_activations_;
8554 explicit ActivationsFinder(Code* code)
8556 has_code_activations_(false) { }
8558 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8559 JavaScriptFrameIterator it(isolate, top);
8563 void VisitFrames(JavaScriptFrameIterator* it) {
8564 for (; !it->done(); it->Advance()) {
8565 JavaScriptFrame* frame = it->frame();
8566 if (code_->contains(frame->pc())) has_code_activations_ = true;
8572 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NotifyStubFailure) {
8573 HandleScope scope(isolate);
8574 ASSERT(args.length() == 0);
8575 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8576 ASSERT(AllowHeapAllocation::IsAllowed());
8578 return isolate->heap()->undefined_value();
8582 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NotifyDeoptimized) {
8583 HandleScope scope(isolate);
8584 ASSERT(args.length() == 1);
8585 RUNTIME_ASSERT(args[0]->IsSmi());
8586 Deoptimizer::BailoutType type =
8587 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8588 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8589 ASSERT(AllowHeapAllocation::IsAllowed());
8591 Handle<JSFunction> function = deoptimizer->function();
8592 Handle<Code> optimized_code = deoptimizer->compiled_code();
8594 ASSERT(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
8595 ASSERT(type == deoptimizer->bailout_type());
8597 // Make sure to materialize objects before causing any allocation.
8598 JavaScriptFrameIterator it(isolate);
8599 deoptimizer->MaterializeHeapObjects(&it);
8602 JavaScriptFrame* frame = it.frame();
8603 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8604 ASSERT(frame->function() == *function);
8606 // Avoid doing too much work when running with --always-opt and keep
8607 // the optimized code around.
8608 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
8609 return isolate->heap()->undefined_value();
8612 // Search for other activations of the same function and code.
8613 ActivationsFinder activations_finder(*optimized_code);
8614 activations_finder.VisitFrames(&it);
8615 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8617 if (!activations_finder.has_code_activations_) {
8618 if (function->code() == *optimized_code) {
8619 if (FLAG_trace_deopt) {
8620 PrintF("[removing optimized code for: ");
8621 function->PrintName();
8624 function->ReplaceCode(function->shared()->code());
8625 // Evict optimized code for this function from the cache so that it
8626 // doesn't get used for new closures.
8627 function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
8628 "notify deoptimized");
8631 // TODO(titzer): we should probably do DeoptimizeCodeList(code)
8632 // unconditionally if the code is not already marked for deoptimization.
8633 // If there is an index by shared function info, all the better.
8634 Deoptimizer::DeoptimizeFunction(*function);
8637 return isolate->heap()->undefined_value();
8641 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
8642 HandleScope scope(isolate);
8643 ASSERT(args.length() == 1);
8644 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8645 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
8647 Deoptimizer::DeoptimizeFunction(*function);
8649 return isolate->heap()->undefined_value();
8653 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) {
8654 HandleScope scope(isolate);
8655 ASSERT(args.length() == 1);
8656 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8657 Code* unoptimized = function->shared()->code();
8658 if (unoptimized->kind() == Code::FUNCTION) {
8659 unoptimized->ClearInlineCaches();
8660 unoptimized->ClearTypeFeedbackInfo(isolate->heap());
8662 return isolate->heap()->undefined_value();
8666 RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8667 SealHandleScope shs(isolate);
8668 #if defined(USE_SIMULATOR)
8669 return isolate->heap()->true_value();
8671 return isolate->heap()->false_value();
8676 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConcurrentRecompilationSupported) {
8677 HandleScope scope(isolate);
8678 return isolate->concurrent_recompilation_enabled()
8679 ? isolate->heap()->true_value() : isolate->heap()->false_value();
8683 RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8684 HandleScope scope(isolate);
8685 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
8686 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8688 if (!function->IsOptimizable() &&
8689 !function->IsMarkedForConcurrentOptimization() &&
8690 !function->IsInOptimizationQueue()) {
8691 return isolate->heap()->undefined_value();
8694 function->MarkForOptimization();
8696 Code* unoptimized = function->shared()->code();
8697 if (args.length() == 2 &&
8698 unoptimized->kind() == Code::FUNCTION) {
8699 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8700 if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr"))) {
8701 // Start patching from the currently patched loop nesting level.
8702 int current_level = unoptimized->allow_osr_at_loop_nesting_level();
8703 ASSERT(BackEdgeTable::Verify(isolate, unoptimized, current_level));
8704 for (int i = current_level + 1; i <= Code::kMaxLoopNestingMarker; i++) {
8705 unoptimized->set_allow_osr_at_loop_nesting_level(i);
8706 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8708 } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("concurrent")) &&
8709 isolate->concurrent_recompilation_enabled()) {
8710 function->MarkForConcurrentOptimization();
8714 return isolate->heap()->undefined_value();
8718 RUNTIME_FUNCTION(MaybeObject*, Runtime_NeverOptimizeFunction) {
8719 HandleScope scope(isolate);
8720 ASSERT(args.length() == 1);
8721 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8722 function->shared()->set_optimization_disabled(true);
8723 return isolate->heap()->undefined_value();
8727 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8728 HandleScope scope(isolate);
8729 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
8730 if (!isolate->use_crankshaft()) {
8731 return Smi::FromInt(4); // 4 == "never".
8733 bool sync_with_compiler_thread = true;
8734 if (args.length() == 2) {
8735 CONVERT_ARG_HANDLE_CHECKED(String, sync, 1);
8736 if (sync->IsOneByteEqualTo(STATIC_ASCII_VECTOR("no sync"))) {
8737 sync_with_compiler_thread = false;
8740 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8741 if (isolate->concurrent_recompilation_enabled() &&
8742 sync_with_compiler_thread) {
8743 while (function->IsInOptimizationQueue()) {
8744 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
8748 if (FLAG_always_opt) {
8749 // We may have always opt, but that is more best-effort than a real
8750 // promise, so we still say "no" if it is not optimized.
8751 return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always".
8752 : Smi::FromInt(2); // 2 == "no".
8754 if (FLAG_deopt_every_n_times) {
8755 return Smi::FromInt(6); // 6 == "maybe deopted".
8757 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8758 : Smi::FromInt(2); // 2 == "no".
8762 RUNTIME_FUNCTION(MaybeObject*, Runtime_UnblockConcurrentRecompilation) {
8763 RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
8764 RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled());
8765 isolate->optimizing_compiler_thread()->Unblock();
8766 return isolate->heap()->undefined_value();
8770 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8771 HandleScope scope(isolate);
8772 ASSERT(args.length() == 1);
8773 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8774 return Smi::FromInt(function->shared()->opt_count());
8778 static bool IsSuitableForOnStackReplacement(Isolate* isolate,
8779 Handle<JSFunction> function,
8780 Handle<Code> current_code) {
8781 // Keep track of whether we've succeeded in optimizing.
8782 if (!isolate->use_crankshaft() || !current_code->optimizable()) return false;
8783 // If we are trying to do OSR when there are already optimized
8784 // activations of the function, it means (a) the function is directly or
8785 // indirectly recursive and (b) an optimized invocation has been
8786 // deoptimized so that we are currently in an unoptimized activation.
8787 // Check for optimized activations of this function.
8788 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
8789 JavaScriptFrame* frame = it.frame();
8790 if (frame->is_optimized() && frame->function() == *function) return false;
8797 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
8798 HandleScope scope(isolate);
8799 ASSERT(args.length() == 1);
8800 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8801 Handle<Code> caller_code(function->shared()->code());
8803 // We're not prepared to handle a function with arguments object.
8804 ASSERT(!function->shared()->uses_arguments());
8806 // Passing the PC in the javascript frame from the caller directly is
8807 // not GC safe, so we walk the stack to get it.
8808 JavaScriptFrameIterator it(isolate);
8809 JavaScriptFrame* frame = it.frame();
8810 if (!caller_code->contains(frame->pc())) {
8811 // Code on the stack may not be the code object referenced by the shared
8812 // function info. It may have been replaced to include deoptimization data.
8813 caller_code = Handle<Code>(frame->LookupCode());
8816 uint32_t pc_offset = static_cast<uint32_t>(
8817 frame->pc() - caller_code->instruction_start());
8820 ASSERT_EQ(frame->function(), *function);
8821 ASSERT_EQ(frame->LookupCode(), *caller_code);
8822 ASSERT(caller_code->contains(frame->pc()));
8826 BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset);
8827 ASSERT(!ast_id.IsNone());
8829 Compiler::ConcurrencyMode mode = isolate->concurrent_osr_enabled()
8830 ? Compiler::CONCURRENT : Compiler::NOT_CONCURRENT;
8831 Handle<Code> result = Handle<Code>::null();
8833 OptimizedCompileJob* job = NULL;
8834 if (mode == Compiler::CONCURRENT) {
8835 // Gate the OSR entry with a stack check.
8836 BackEdgeTable::AddStackCheck(caller_code, pc_offset);
8837 // Poll already queued compilation jobs.
8838 OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread();
8839 if (thread->IsQueuedForOSR(function, ast_id)) {
8840 if (FLAG_trace_osr) {
8841 PrintF("[OSR - Still waiting for queued: ");
8842 function->PrintName();
8843 PrintF(" at AST id %d]\n", ast_id.ToInt());
8848 job = thread->FindReadyOSRCandidate(function, ast_id);
8852 if (FLAG_trace_osr) {
8853 PrintF("[OSR - Found ready: ");
8854 function->PrintName();
8855 PrintF(" at AST id %d]\n", ast_id.ToInt());
8857 result = Compiler::GetConcurrentlyOptimizedCode(job);
8858 } else if (result.is_null() &&
8859 IsSuitableForOnStackReplacement(isolate, function, caller_code)) {
8860 if (FLAG_trace_osr) {
8861 PrintF("[OSR - Compiling: ");
8862 function->PrintName();
8863 PrintF(" at AST id %d]\n", ast_id.ToInt());
8865 result = Compiler::GetOptimizedCode(function, caller_code, mode, ast_id);
8866 if (result.is_identical_to(isolate->builtins()->InOptimizationQueue())) {
8867 // Optimization is queued. Return to check later.
8872 // Revert the patched back edge table, regardless of whether OSR succeeds.
8873 BackEdgeTable::Revert(isolate, *caller_code);
8875 // Check whether we ended up with usable optimized code.
8876 if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) {
8877 DeoptimizationInputData* data =
8878 DeoptimizationInputData::cast(result->deoptimization_data());
8880 if (data->OsrPcOffset()->value() >= 0) {
8881 ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
8882 if (FLAG_trace_osr) {
8883 PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
8884 ast_id.ToInt(), data->OsrPcOffset()->value());
8886 // TODO(titzer): this is a massive hack to make the deopt counts
8887 // match. Fix heuristics for reenabling optimizations!
8888 function->shared()->increment_deopt_count();
8890 // TODO(titzer): Do not install code into the function.
8891 function->ReplaceCode(*result);
8897 if (FLAG_trace_osr) {
8898 PrintF("[OSR - Failed: ");
8899 function->PrintName();
8900 PrintF(" at AST id %d]\n", ast_id.ToInt());
8903 if (!function->IsOptimized()) {
8904 function->ReplaceCode(function->shared()->code());
8910 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAllocationTimeout) {
8911 SealHandleScope shs(isolate);
8912 ASSERT(args.length() == 2 || args.length() == 3);
8914 CONVERT_SMI_ARG_CHECKED(interval, 0);
8915 CONVERT_SMI_ARG_CHECKED(timeout, 1);
8916 isolate->heap()->set_allocation_timeout(timeout);
8917 FLAG_gc_interval = interval;
8918 if (args.length() == 3) {
8919 // Enable/disable inline allocation if requested.
8920 CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2);
8921 if (inline_allocation) {
8922 isolate->heap()->EnableInlineAllocation();
8924 isolate->heap()->DisableInlineAllocation();
8928 return isolate->heap()->undefined_value();
8932 RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8933 SealHandleScope shs(isolate);
8934 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8935 return isolate->heap()->undefined_value();
8939 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) {
8940 SealHandleScope shs(isolate);
8941 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8942 return isolate->heap()->nan_value();
8946 RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8947 HandleScope scope(isolate);
8948 ASSERT(args.length() >= 2);
8949 int argc = args.length() - 2;
8950 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8951 Object* receiver = args[0];
8953 // If there are too many arguments, allocate argv via malloc.
8954 const int argv_small_size = 10;
8955 Handle<Object> argv_small_buffer[argv_small_size];
8956 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8957 Handle<Object>* argv = argv_small_buffer;
8958 if (argc > argv_small_size) {
8959 argv = new Handle<Object>[argc];
8960 if (argv == NULL) return isolate->StackOverflow();
8961 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8964 for (int i = 0; i < argc; ++i) {
8965 MaybeObject* maybe = args[1 + i];
8967 if (!maybe->To<Object>(&object)) return maybe;
8968 argv[i] = Handle<Object>(object, isolate);
8972 Handle<JSReceiver> hfun(fun);
8973 Handle<Object> hreceiver(receiver, isolate);
8974 Handle<Object> result = Execution::Call(
8975 isolate, hfun, hreceiver, argc, argv, &threw, true);
8977 if (threw) return Failure::Exception();
8982 RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8983 HandleScope scope(isolate);
8984 ASSERT(args.length() == 5);
8985 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
8986 Handle<Object> receiver = args.at<Object>(1);
8987 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
8988 CONVERT_SMI_ARG_CHECKED(offset, 3);
8989 CONVERT_SMI_ARG_CHECKED(argc, 4);
8990 RUNTIME_ASSERT(offset >= 0);
8991 RUNTIME_ASSERT(argc >= 0);
8993 // If there are too many arguments, allocate argv via malloc.
8994 const int argv_small_size = 10;
8995 Handle<Object> argv_small_buffer[argv_small_size];
8996 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8997 Handle<Object>* argv = argv_small_buffer;
8998 if (argc > argv_small_size) {
8999 argv = new Handle<Object>[argc];
9000 if (argv == NULL) return isolate->StackOverflow();
9001 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
9004 for (int i = 0; i < argc; ++i) {
9005 argv[i] = Object::GetElement(isolate, arguments, offset + i);
9006 RETURN_IF_EMPTY_HANDLE(isolate, argv[i]);
9010 Handle<Object> result = Execution::Call(
9011 isolate, fun, receiver, argc, argv, &threw, true);
9013 if (threw) return Failure::Exception();
9018 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
9019 HandleScope scope(isolate);
9020 ASSERT(args.length() == 1);
9021 RUNTIME_ASSERT(!args[0]->IsJSFunction());
9022 return *Execution::GetFunctionDelegate(isolate, args.at<Object>(0));
9026 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
9027 HandleScope scope(isolate);
9028 ASSERT(args.length() == 1);
9029 RUNTIME_ASSERT(!args[0]->IsJSFunction());
9030 return *Execution::GetConstructorDelegate(isolate, args.at<Object>(0));
9034 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NewGlobalContext) {
9035 SealHandleScope shs(isolate);
9036 ASSERT(args.length() == 2);
9038 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9039 CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 1);
9041 MaybeObject* maybe_result =
9042 isolate->heap()->AllocateGlobalContext(function, scope_info);
9043 if (!maybe_result->To(&result)) return maybe_result;
9045 ASSERT(function->context() == isolate->context());
9046 ASSERT(function->context()->global_object() == result->global_object());
9047 result->global_object()->set_global_context(result);
9049 return result; // non-failure
9053 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_NewFunctionContext) {
9054 SealHandleScope shs(isolate);
9055 ASSERT(args.length() == 1);
9057 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9058 int length = function->shared()->scope_info()->ContextLength();
9059 return isolate->heap()->AllocateFunctionContext(length, function);
9063 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_PushWithContext) {
9064 SealHandleScope shs(isolate);
9065 ASSERT(args.length() == 2);
9066 JSReceiver* extension_object;
9067 if (args[0]->IsJSReceiver()) {
9068 extension_object = JSReceiver::cast(args[0]);
9070 // Convert the object to a proper JavaScript object.
9071 MaybeObject* maybe_js_object = args[0]->ToObject(isolate);
9072 if (!maybe_js_object->To(&extension_object)) {
9073 if (Failure::cast(maybe_js_object)->IsInternalError()) {
9074 HandleScope scope(isolate);
9075 Handle<Object> handle = args.at<Object>(0);
9076 Handle<Object> result =
9077 isolate->factory()->NewTypeError("with_expression",
9078 HandleVector(&handle, 1));
9079 return isolate->Throw(*result);
9081 return maybe_js_object;
9086 JSFunction* function;
9087 if (args[1]->IsSmi()) {
9088 // A smi sentinel indicates a context nested inside global code rather
9089 // than some function. There is a canonical empty function that can be
9090 // gotten from the native context.
9091 function = isolate->context()->native_context()->closure();
9093 function = JSFunction::cast(args[1]);
9097 MaybeObject* maybe_context =
9098 isolate->heap()->AllocateWithContext(function,
9101 if (!maybe_context->To(&context)) return maybe_context;
9102 isolate->set_context(context);
9107 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_PushCatchContext) {
9108 SealHandleScope shs(isolate);
9109 ASSERT(args.length() == 3);
9110 String* name = String::cast(args[0]);
9111 Object* thrown_object = args[1];
9112 JSFunction* function;
9113 if (args[2]->IsSmi()) {
9114 // A smi sentinel indicates a context nested inside global code rather
9115 // than some function. There is a canonical empty function that can be
9116 // gotten from the native context.
9117 function = isolate->context()->native_context()->closure();
9119 function = JSFunction::cast(args[2]);
9122 MaybeObject* maybe_context =
9123 isolate->heap()->AllocateCatchContext(function,
9127 if (!maybe_context->To(&context)) return maybe_context;
9128 isolate->set_context(context);
9133 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_PushBlockContext) {
9134 SealHandleScope shs(isolate);
9135 ASSERT(args.length() == 2);
9136 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
9137 JSFunction* function;
9138 if (args[1]->IsSmi()) {
9139 // A smi sentinel indicates a context nested inside global code rather
9140 // than some function. There is a canonical empty function that can be
9141 // gotten from the native context.
9142 function = isolate->context()->native_context()->closure();
9144 function = JSFunction::cast(args[1]);
9147 MaybeObject* maybe_context =
9148 isolate->heap()->AllocateBlockContext(function,
9151 if (!maybe_context->To(&context)) return maybe_context;
9152 isolate->set_context(context);
9157 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSModule) {
9158 SealHandleScope shs(isolate);
9159 ASSERT(args.length() == 1);
9160 Object* obj = args[0];
9161 return isolate->heap()->ToBoolean(obj->IsJSModule());
9165 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_PushModuleContext) {
9166 SealHandleScope shs(isolate);
9167 ASSERT(args.length() == 2);
9168 CONVERT_SMI_ARG_CHECKED(index, 0);
9170 if (!args[1]->IsScopeInfo()) {
9171 // Module already initialized. Find hosting context and retrieve context.
9172 Context* host = Context::cast(isolate->context())->global_context();
9173 Context* context = Context::cast(host->get(index));
9174 ASSERT(context->previous() == isolate->context());
9175 isolate->set_context(context);
9179 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
9181 // Allocate module context.
9182 HandleScope scope(isolate);
9183 Factory* factory = isolate->factory();
9184 Handle<Context> context = factory->NewModuleContext(scope_info);
9185 Handle<JSModule> module = factory->NewJSModule(context, scope_info);
9186 context->set_module(*module);
9187 Context* previous = isolate->context();
9188 context->set_previous(previous);
9189 context->set_closure(previous->closure());
9190 context->set_global_object(previous->global_object());
9191 isolate->set_context(*context);
9193 // Find hosting scope and initialize internal variable holding module there.
9194 previous->global_context()->set(index, *context);
9200 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_DeclareModules) {
9201 HandleScope scope(isolate);
9202 ASSERT(args.length() == 1);
9203 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
9204 Context* host_context = isolate->context();
9206 for (int i = 0; i < descriptions->length(); ++i) {
9207 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
9208 int host_index = description->host_index();
9209 Handle<Context> context(Context::cast(host_context->get(host_index)));
9210 Handle<JSModule> module(context->module());
9212 for (int j = 0; j < description->length(); ++j) {
9213 Handle<String> name(description->name(j));
9214 VariableMode mode = description->mode(j);
9215 int index = description->index(j);
9220 case CONST_LEGACY: {
9221 PropertyAttributes attr =
9222 IsImmutableVariableMode(mode) ? FROZEN : SEALED;
9223 Handle<AccessorInfo> info =
9224 Accessors::MakeModuleExport(name, index, attr);
9225 Handle<Object> result = JSObject::SetAccessor(module, info);
9226 ASSERT(!(result.is_null() || result->IsUndefined()));
9231 Object* referenced_context = Context::cast(host_context)->get(index);
9232 Handle<JSModule> value(Context::cast(referenced_context)->module());
9233 JSReceiver::SetProperty(module, name, value, FROZEN, STRICT);
9239 case DYNAMIC_GLOBAL:
9245 JSObject::PreventExtensions(module);
9248 ASSERT(!isolate->has_pending_exception());
9249 return isolate->heap()->undefined_value();
9253 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_DeleteContextSlot) {
9254 HandleScope scope(isolate);
9255 ASSERT(args.length() == 2);
9257 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
9258 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
9261 PropertyAttributes attributes;
9262 ContextLookupFlags flags = FOLLOW_CHAINS;
9263 BindingFlags binding_flags;
9264 Handle<Object> holder = context->Lookup(name,
9270 // If the slot was not found the result is true.
9271 if (holder.is_null()) {
9272 return isolate->heap()->true_value();
9275 // If the slot was found in a context, it should be DONT_DELETE.
9276 if (holder->IsContext()) {
9277 return isolate->heap()->false_value();
9280 // The slot was found in a JSObject, either a context extension object,
9281 // the global object, or the subject of a with. Try to delete it
9282 // (respecting DONT_DELETE).
9283 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9284 Handle<Object> result = JSReceiver::DeleteProperty(object, name);
9285 RETURN_IF_EMPTY_HANDLE(isolate, result);
9290 // A mechanism to return a pair of Object pointers in registers (if possible).
9291 // How this is achieved is calling convention-dependent.
9292 // All currently supported x86 compiles uses calling conventions that are cdecl
9293 // variants where a 64-bit value is returned in two 32-bit registers
9294 // (edx:eax on ia32, r1:r0 on ARM).
9295 // In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
9296 // In Win64 calling convention, a struct of two pointers is returned in memory,
9297 // allocated by the caller, and passed as a pointer in a hidden first parameter.
9298 #ifdef V8_HOST_ARCH_64_BIT
9305 static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
9306 ObjectPair result = {x, y};
9307 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
9308 // In Win64 they are assigned to a hidden first argument.
9312 typedef uint64_t ObjectPair;
9313 static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
9314 return reinterpret_cast<uint32_t>(x) |
9315 (reinterpret_cast<ObjectPair>(y) << 32);
9320 static inline MaybeObject* Unhole(Heap* heap,
9322 PropertyAttributes attributes) {
9323 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
9325 return x->IsTheHole() ? heap->undefined_value() : x;
9329 static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9331 ASSERT(!holder->IsGlobalObject());
9332 Context* top = isolate->context();
9333 // Get the context extension function.
9334 JSFunction* context_extension_function =
9335 top->native_context()->context_extension_function();
9336 // If the holder isn't a context extension object, we just return it
9337 // as the receiver. This allows arguments objects to be used as
9338 // receivers, but only if they are put in the context scope chain
9339 // explicitly via a with-statement.
9340 Object* constructor = holder->map()->constructor();
9341 if (constructor != context_extension_function) return holder;
9342 // Fall back to using the global object as the implicit receiver if
9343 // the property turns out to be a local variable allocated in a
9344 // context extension object - introduced via eval.
9345 return isolate->heap()->undefined_value();
9349 static ObjectPair LoadContextSlotHelper(Arguments args,
9352 HandleScope scope(isolate);
9353 ASSERT_EQ(2, args.length());
9355 if (!args[0]->IsContext() || !args[1]->IsString()) {
9356 return MakePair(isolate->ThrowIllegalOperation(), NULL);
9358 Handle<Context> context = args.at<Context>(0);
9359 Handle<String> name = args.at<String>(1);
9362 PropertyAttributes attributes;
9363 ContextLookupFlags flags = FOLLOW_CHAINS;
9364 BindingFlags binding_flags;
9365 Handle<Object> holder = context->Lookup(name,
9370 if (isolate->has_pending_exception()) {
9371 return MakePair(Failure::Exception(), NULL);
9374 // If the index is non-negative, the slot has been found in a context.
9376 ASSERT(holder->IsContext());
9377 // If the "property" we were looking for is a local variable, the
9378 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
9379 Handle<Object> receiver = isolate->factory()->undefined_value();
9380 Object* value = Context::cast(*holder)->get(index);
9381 // Check for uninitialized bindings.
9382 switch (binding_flags) {
9383 case MUTABLE_CHECK_INITIALIZED:
9384 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9385 if (value->IsTheHole()) {
9386 Handle<Object> reference_error =
9387 isolate->factory()->NewReferenceError("not_defined",
9388 HandleVector(&name, 1));
9389 return MakePair(isolate->Throw(*reference_error), NULL);
9392 case MUTABLE_IS_INITIALIZED:
9393 case IMMUTABLE_IS_INITIALIZED:
9394 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9395 ASSERT(!value->IsTheHole());
9396 return MakePair(value, *receiver);
9397 case IMMUTABLE_CHECK_INITIALIZED:
9398 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9399 case MISSING_BINDING:
9401 return MakePair(NULL, NULL);
9405 // Otherwise, if the slot was found the holder is a context extension
9406 // object, subject of a with, or a global object. We read the named
9407 // property from it.
9408 if (!holder.is_null()) {
9409 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
9410 ASSERT(object->IsJSProxy() || JSReceiver::HasProperty(object, name));
9411 // GetProperty below can cause GC.
9412 Handle<Object> receiver_handle(
9413 object->IsGlobalObject()
9414 ? Object::cast(isolate->heap()->undefined_value())
9415 : object->IsJSProxy() ? static_cast<Object*>(*object)
9416 : ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)),
9419 // No need to unhole the value here. This is taken care of by the
9420 // GetProperty function.
9421 MaybeObject* value = object->GetProperty(*name);
9422 return MakePair(value, *receiver_handle);
9426 // The property doesn't exist - throw exception.
9427 Handle<Object> reference_error =
9428 isolate->factory()->NewReferenceError("not_defined",
9429 HandleVector(&name, 1));
9430 return MakePair(isolate->Throw(*reference_error), NULL);
9432 // The property doesn't exist - return undefined.
9433 return MakePair(isolate->heap()->undefined_value(),
9434 isolate->heap()->undefined_value());
9439 RUNTIME_FUNCTION(ObjectPair, RuntimeHidden_LoadContextSlot) {
9440 return LoadContextSlotHelper(args, isolate, true);
9444 RUNTIME_FUNCTION(ObjectPair, RuntimeHidden_LoadContextSlotNoReferenceError) {
9445 return LoadContextSlotHelper(args, isolate, false);
9449 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_StoreContextSlot) {
9450 HandleScope scope(isolate);
9451 ASSERT(args.length() == 4);
9453 Handle<Object> value(args[0], isolate);
9454 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
9455 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
9456 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 3);
9459 PropertyAttributes attributes;
9460 ContextLookupFlags flags = FOLLOW_CHAINS;
9461 BindingFlags binding_flags;
9462 Handle<Object> holder = context->Lookup(name,
9467 if (isolate->has_pending_exception()) return Failure::Exception();
9470 // The property was found in a context slot.
9471 Handle<Context> context = Handle<Context>::cast(holder);
9472 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9473 context->get(index)->IsTheHole()) {
9474 Handle<Object> error =
9475 isolate->factory()->NewReferenceError("not_defined",
9476 HandleVector(&name, 1));
9477 return isolate->Throw(*error);
9479 // Ignore if read_only variable.
9480 if ((attributes & READ_ONLY) == 0) {
9481 // Context is a fixed array and set cannot fail.
9482 context->set(index, *value);
9483 } else if (strict_mode == STRICT) {
9484 // Setting read only property in strict mode.
9485 Handle<Object> error =
9486 isolate->factory()->NewTypeError("strict_cannot_assign",
9487 HandleVector(&name, 1));
9488 return isolate->Throw(*error);
9493 // Slow case: The property is not in a context slot. It is either in a
9494 // context extension object, a property of the subject of a with, or a
9495 // property of the global object.
9496 Handle<JSReceiver> object;
9498 if (!holder.is_null()) {
9499 // The property exists on the holder.
9500 object = Handle<JSReceiver>::cast(holder);
9502 // The property was not found.
9503 ASSERT(attributes == ABSENT);
9505 if (strict_mode == STRICT) {
9506 // Throw in strict mode (assignment to undefined variable).
9507 Handle<Object> error =
9508 isolate->factory()->NewReferenceError(
9509 "not_defined", HandleVector(&name, 1));
9510 return isolate->Throw(*error);
9512 // In sloppy mode, the property is added to the global object.
9514 object = Handle<JSReceiver>(isolate->context()->global_object());
9517 // Set the property if it's not read only or doesn't yet exist.
9518 if ((attributes & READ_ONLY) == 0 ||
9519 (JSReceiver::GetLocalPropertyAttribute(object, name) == ABSENT)) {
9520 RETURN_IF_EMPTY_HANDLE(
9522 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
9523 } else if (strict_mode == STRICT && (attributes & READ_ONLY) != 0) {
9524 // Setting read only property in strict mode.
9525 Handle<Object> error =
9526 isolate->factory()->NewTypeError(
9527 "strict_cannot_assign", HandleVector(&name, 1));
9528 return isolate->Throw(*error);
9534 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_Throw) {
9535 HandleScope scope(isolate);
9536 ASSERT(args.length() == 1);
9538 return isolate->Throw(args[0]);
9542 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_ReThrow) {
9543 HandleScope scope(isolate);
9544 ASSERT(args.length() == 1);
9546 return isolate->ReThrow(args[0]);
9550 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_PromoteScheduledException) {
9551 SealHandleScope shs(isolate);
9552 ASSERT_EQ(0, args.length());
9553 return isolate->PromoteScheduledException();
9557 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_ThrowReferenceError) {
9558 HandleScope scope(isolate);
9559 ASSERT(args.length() == 1);
9561 Handle<Object> name(args[0], isolate);
9562 Handle<Object> reference_error =
9563 isolate->factory()->NewReferenceError("not_defined",
9564 HandleVector(&name, 1));
9565 return isolate->Throw(*reference_error);
9569 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_ThrowNotDateError) {
9570 HandleScope scope(isolate);
9571 ASSERT(args.length() == 0);
9572 return isolate->Throw(*isolate->factory()->NewTypeError(
9573 "not_date_object", HandleVector<Object>(NULL, 0)));
9577 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_ThrowMessage) {
9578 HandleScope scope(isolate);
9579 ASSERT(args.length() == 1);
9580 CONVERT_SMI_ARG_CHECKED(message_id, 0);
9581 const char* message = GetBailoutReason(
9582 static_cast<BailoutReason>(message_id));
9583 Handle<String> message_handle =
9584 isolate->factory()->NewStringFromAscii(CStrVector(message));
9585 RETURN_IF_EMPTY_HANDLE(isolate, message_handle);
9586 return isolate->Throw(*message_handle);
9590 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_StackGuard) {
9591 SealHandleScope shs(isolate);
9592 ASSERT(args.length() == 0);
9594 // First check if this is a real stack overflow.
9595 if (isolate->stack_guard()->IsStackOverflow()) {
9596 return isolate->StackOverflow();
9599 return Execution::HandleStackGuardInterrupt(isolate);
9603 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_TryInstallOptimizedCode) {
9604 HandleScope scope(isolate);
9605 ASSERT(args.length() == 1);
9606 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
9608 // First check if this is a real stack overflow.
9609 if (isolate->stack_guard()->IsStackOverflow()) {
9610 SealHandleScope shs(isolate);
9611 return isolate->StackOverflow();
9614 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
9615 return (function->IsOptimized()) ? function->code()
9616 : function->shared()->code();
9620 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_Interrupt) {
9621 SealHandleScope shs(isolate);
9622 ASSERT(args.length() == 0);
9623 return Execution::HandleStackGuardInterrupt(isolate);
9627 static int StackSize(Isolate* isolate) {
9629 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
9634 static void PrintTransition(Isolate* isolate, Object* result) {
9636 { const int nmax = 80;
9637 int n = StackSize(isolate);
9639 PrintF("%4d:%*s", n, n, "");
9641 PrintF("%4d:%*s", n, nmax, "...");
9644 if (result == NULL) {
9645 JavaScriptFrame::PrintTop(isolate, stdout, true, false);
9650 result->ShortPrint();
9656 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
9657 SealHandleScope shs(isolate);
9658 ASSERT(args.length() == 0);
9659 PrintTransition(isolate, NULL);
9660 return isolate->heap()->undefined_value();
9664 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
9665 SealHandleScope shs(isolate);
9666 PrintTransition(isolate, args[0]);
9667 return args[0]; // return TOS
9671 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
9672 SealHandleScope shs(isolate);
9673 ASSERT(args.length() == 1);
9676 if (args[0]->IsString()) {
9677 // If we have a string, assume it's a code "marker"
9678 // and print some interesting cpu debugging info.
9679 JavaScriptFrameIterator it(isolate);
9680 JavaScriptFrame* frame = it.frame();
9681 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9682 frame->fp(), frame->sp(), frame->caller_sp());
9684 PrintF("DebugPrint: ");
9687 if (args[0]->IsHeapObject()) {
9689 HeapObject::cast(args[0])->map()->Print();
9692 // ShortPrint is available in release mode. Print is not.
9693 args[0]->ShortPrint();
9698 return args[0]; // return TOS
9702 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
9703 SealHandleScope shs(isolate);
9704 ASSERT(args.length() == 0);
9705 isolate->PrintStack(stdout);
9706 return isolate->heap()->undefined_value();
9710 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
9711 SealHandleScope shs(isolate);
9712 ASSERT(args.length() == 0);
9714 // According to ECMA-262, section 15.9.1, page 117, the precision of
9715 // the number in a Date object representing a particular instant in
9716 // time is milliseconds. Therefore, we floor the result of getting
9718 double millis = std::floor(OS::TimeCurrentMillis());
9719 return isolate->heap()->NumberFromDouble(millis);
9723 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
9724 HandleScope scope(isolate);
9725 ASSERT(args.length() == 2);
9727 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
9730 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
9732 JSObject::EnsureCanContainHeapObjectElements(output);
9733 RUNTIME_ASSERT(output->HasFastObjectElements());
9735 DisallowHeapAllocation no_gc;
9737 FixedArray* output_array = FixedArray::cast(output->elements());
9738 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9740 String::FlatContent str_content = str->GetFlatContent();
9741 if (str_content.IsAscii()) {
9742 result = DateParser::Parse(str_content.ToOneByteVector(),
9744 isolate->unicode_cache());
9746 ASSERT(str_content.IsTwoByte());
9747 result = DateParser::Parse(str_content.ToUC16Vector(),
9749 isolate->unicode_cache());
9755 return isolate->heap()->null_value();
9760 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
9761 SealHandleScope shs(isolate);
9762 ASSERT(args.length() == 1);
9764 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
9766 isolate->date_cache()->LocalTimezone(static_cast<int64_t>(x));
9767 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
9771 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
9772 SealHandleScope shs(isolate);
9773 ASSERT(args.length() == 1);
9775 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
9776 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9778 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
9782 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCacheVersion) {
9783 HandleScope hs(isolate);
9784 ASSERT(args.length() == 0);
9785 if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) {
9786 Handle<FixedArray> date_cache_version =
9787 isolate->factory()->NewFixedArray(1, TENURED);
9788 date_cache_version->set(0, Smi::FromInt(0));
9789 isolate->eternal_handles()->CreateSingleton(
9790 isolate, *date_cache_version, EternalHandles::DATE_CACHE_VERSION);
9792 Handle<FixedArray> date_cache_version =
9793 Handle<FixedArray>::cast(isolate->eternal_handles()->GetSingleton(
9794 EternalHandles::DATE_CACHE_VERSION));
9795 // Return result as a JS array.
9796 Handle<JSObject> result =
9797 isolate->factory()->NewJSObject(isolate->array_function());
9798 JSArray::SetContent(Handle<JSArray>::cast(result), date_cache_version);
9803 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
9804 SealHandleScope shs(isolate);
9805 ASSERT(args.length() == 1);
9806 Object* global = args[0];
9807 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
9808 return JSGlobalObject::cast(global)->global_receiver();
9812 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAttachedGlobal) {
9813 SealHandleScope shs(isolate);
9814 ASSERT(args.length() == 1);
9815 Object* global = args[0];
9816 if (!global->IsJSGlobalObject()) return isolate->heap()->false_value();
9817 return isolate->heap()->ToBoolean(
9818 !JSGlobalObject::cast(global)->IsDetached());
9822 RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
9823 HandleScope scope(isolate);
9824 ASSERT_EQ(1, args.length());
9825 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
9827 source = Handle<String>(FlattenGetString(source));
9828 // Optimized fast case where we only have ASCII characters.
9829 Handle<Object> result;
9830 if (source->IsSeqOneByteString()) {
9831 result = JsonParser<true>::Parse(source);
9833 result = JsonParser<false>::Parse(source);
9835 if (result.is_null()) {
9836 // Syntax error or stack overflow in scanner.
9837 ASSERT(isolate->has_pending_exception());
9838 return Failure::Exception();
9844 bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9845 Handle<Context> context) {
9846 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9847 // Check with callback if set.
9848 AllowCodeGenerationFromStringsCallback callback =
9849 isolate->allow_code_gen_callback();
9850 if (callback == NULL) {
9851 // No callback set and code generation disallowed.
9854 // Callback set. Let it decide if code generation is allowed.
9855 VMState<EXTERNAL> state(isolate);
9856 return callback(v8::Utils::ToLocal(context));
9861 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
9862 HandleScope scope(isolate);
9863 ASSERT_EQ(2, args.length());
9864 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
9865 CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1);
9867 // Extract native context.
9868 Handle<Context> context(isolate->context()->native_context());
9870 // Check if native context allows code generation from
9871 // strings. Throw an exception if it doesn't.
9872 if (context->allow_code_gen_from_strings()->IsFalse() &&
9873 !CodeGenerationFromStringsAllowed(isolate, context)) {
9874 Handle<Object> error_message =
9875 context->ErrorMessageForCodeGenerationFromStrings();
9876 return isolate->Throw(*isolate->factory()->NewEvalError(
9877 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
9880 // Compile source string in the native context.
9881 ParseRestriction restriction = function_literal_only
9882 ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION;
9883 Handle<JSFunction> fun = Compiler::GetFunctionFromEval(
9884 source, context, SLOPPY, restriction, RelocInfo::kNoPosition);
9885 RETURN_IF_EMPTY_HANDLE(isolate, fun);
9890 static ObjectPair CompileGlobalEval(Isolate* isolate,
9891 Handle<String> source,
9892 Handle<Object> receiver,
9893 StrictMode strict_mode,
9894 int scope_position) {
9895 Handle<Context> context = Handle<Context>(isolate->context());
9896 Handle<Context> native_context = Handle<Context>(context->native_context());
9898 // Check if native context allows code generation from
9899 // strings. Throw an exception if it doesn't.
9900 if (native_context->allow_code_gen_from_strings()->IsFalse() &&
9901 !CodeGenerationFromStringsAllowed(isolate, native_context)) {
9902 Handle<Object> error_message =
9903 native_context->ErrorMessageForCodeGenerationFromStrings();
9904 isolate->Throw(*isolate->factory()->NewEvalError(
9905 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
9906 return MakePair(Failure::Exception(), NULL);
9909 // Deal with a normal eval call with a string argument. Compile it
9910 // and return the compiled function bound in the local context.
9911 static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
9912 Handle<JSFunction> compiled = Compiler::GetFunctionFromEval(
9913 source, context, strict_mode, restriction, scope_position);
9914 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, compiled,
9915 MakePair(Failure::Exception(), NULL));
9916 return MakePair(*compiled, *receiver);
9920 RUNTIME_FUNCTION(ObjectPair, RuntimeHidden_ResolvePossiblyDirectEval) {
9921 HandleScope scope(isolate);
9922 ASSERT(args.length() == 5);
9924 Handle<Object> callee = args.at<Object>(0);
9926 // If "eval" didn't refer to the original GlobalEval, it's not a
9927 // direct call to eval.
9928 // (And even if it is, but the first argument isn't a string, just let
9929 // execution default to an indirect call to eval, which will also return
9930 // the first argument without doing anything).
9931 if (*callee != isolate->native_context()->global_eval_fun() ||
9932 !args[1]->IsString()) {
9933 return MakePair(*callee, isolate->heap()->undefined_value());
9936 ASSERT(args[3]->IsSmi());
9937 ASSERT(args.smi_at(3) == SLOPPY || args.smi_at(3) == STRICT);
9938 StrictMode strict_mode = static_cast<StrictMode>(args.smi_at(3));
9939 ASSERT(args[4]->IsSmi());
9940 return CompileGlobalEval(isolate,
9948 // Allocate a block of memory in the given space (filled with a filler).
9949 // Used as a fall-back for generated code when the space is full.
9950 static MaybeObject* Allocate(Isolate* isolate,
9953 AllocationSpace space) {
9954 Heap* heap = isolate->heap();
9955 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9956 RUNTIME_ASSERT(size > 0);
9957 RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize);
9958 HeapObject* allocation;
9959 { MaybeObject* maybe_allocation = heap->AllocateRaw(size, space, space);
9960 if (!maybe_allocation->To(&allocation)) return maybe_allocation;
9963 MemoryChunk* chunk = MemoryChunk::FromAddress(allocation->address());
9964 ASSERT(chunk->owner()->identity() == space);
9966 heap->CreateFillerObjectAt(allocation->address(), size);
9971 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_AllocateInNewSpace) {
9972 SealHandleScope shs(isolate);
9973 ASSERT(args.length() == 1);
9974 CONVERT_SMI_ARG_CHECKED(size, 0);
9975 return Allocate(isolate, size, false, NEW_SPACE);
9979 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_AllocateInTargetSpace) {
9980 SealHandleScope shs(isolate);
9981 ASSERT(args.length() == 2);
9982 CONVERT_SMI_ARG_CHECKED(size, 0);
9983 CONVERT_SMI_ARG_CHECKED(flags, 1);
9984 bool double_align = AllocateDoubleAlignFlag::decode(flags);
9985 AllocationSpace space = AllocateTargetSpace::decode(flags);
9986 return Allocate(isolate, size, double_align, space);
9990 // Push an object unto an array of objects if it is not already in the
9991 // array. Returns true if the element was pushed on the stack and
9993 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
9994 HandleScope scope(isolate);
9995 ASSERT(args.length() == 2);
9996 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
9997 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, element, 1);
9998 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements());
9999 int length = Smi::cast(array->length())->value();
10000 FixedArray* elements = FixedArray::cast(array->elements());
10001 for (int i = 0; i < length; i++) {
10002 if (elements->get(i) == *element) return isolate->heap()->false_value();
10005 // Strict not needed. Used for cycle detection in Array join implementation.
10006 RETURN_IF_EMPTY_HANDLE(isolate, JSObject::SetFastElement(array, length,
10010 return isolate->heap()->true_value();
10015 * A simple visitor visits every element of Array's.
10016 * The backend storage can be a fixed array for fast elements case,
10017 * or a dictionary for sparse array. Since Dictionary is a subtype
10018 * of FixedArray, the class can be used by both fast and slow cases.
10019 * The second parameter of the constructor, fast_elements, specifies
10020 * whether the storage is a FixedArray or Dictionary.
10022 * An index limit is used to deal with the situation that a result array
10023 * length overflows 32-bit non-negative integer.
10025 class ArrayConcatVisitor {
10027 ArrayConcatVisitor(Isolate* isolate,
10028 Handle<FixedArray> storage,
10029 bool fast_elements) :
10031 storage_(Handle<FixedArray>::cast(
10032 isolate->global_handles()->Create(*storage))),
10034 fast_elements_(fast_elements),
10035 exceeds_array_limit_(false) { }
10037 ~ArrayConcatVisitor() {
10041 void visit(uint32_t i, Handle<Object> elm) {
10042 if (i > JSObject::kMaxElementCount - index_offset_) {
10043 exceeds_array_limit_ = true;
10046 uint32_t index = index_offset_ + i;
10048 if (fast_elements_) {
10049 if (index < static_cast<uint32_t>(storage_->length())) {
10050 storage_->set(index, *elm);
10053 // Our initial estimate of length was foiled, possibly by
10054 // getters on the arrays increasing the length of later arrays
10055 // during iteration.
10056 // This shouldn't happen in anything but pathological cases.
10057 SetDictionaryMode(index);
10058 // Fall-through to dictionary mode.
10060 ASSERT(!fast_elements_);
10061 Handle<SeededNumberDictionary> dict(
10062 SeededNumberDictionary::cast(*storage_));
10063 Handle<SeededNumberDictionary> result =
10064 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
10065 if (!result.is_identical_to(dict)) {
10066 // Dictionary needed to grow.
10068 set_storage(*result);
10072 void increase_index_offset(uint32_t delta) {
10073 if (JSObject::kMaxElementCount - index_offset_ < delta) {
10074 index_offset_ = JSObject::kMaxElementCount;
10076 index_offset_ += delta;
10080 bool exceeds_array_limit() {
10081 return exceeds_array_limit_;
10084 Handle<JSArray> ToArray() {
10085 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
10086 Handle<Object> length =
10087 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
10089 if (fast_elements_) {
10090 map = JSObject::GetElementsTransitionMap(array, FAST_HOLEY_ELEMENTS);
10092 map = JSObject::GetElementsTransitionMap(array, DICTIONARY_ELEMENTS);
10094 array->set_map(*map);
10095 array->set_length(*length);
10096 array->set_elements(*storage_);
10101 // Convert storage to dictionary mode.
10102 void SetDictionaryMode(uint32_t index) {
10103 ASSERT(fast_elements_);
10104 Handle<FixedArray> current_storage(*storage_);
10105 Handle<SeededNumberDictionary> slow_storage(
10106 isolate_->factory()->NewSeededNumberDictionary(
10107 current_storage->length()));
10108 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
10109 for (uint32_t i = 0; i < current_length; i++) {
10110 HandleScope loop_scope(isolate_);
10111 Handle<Object> element(current_storage->get(i), isolate_);
10112 if (!element->IsTheHole()) {
10113 Handle<SeededNumberDictionary> new_storage =
10114 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
10115 if (!new_storage.is_identical_to(slow_storage)) {
10116 slow_storage = loop_scope.CloseAndEscape(new_storage);
10121 set_storage(*slow_storage);
10122 fast_elements_ = false;
10125 inline void clear_storage() {
10126 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
10129 inline void set_storage(FixedArray* storage) {
10130 storage_ = Handle<FixedArray>::cast(
10131 isolate_->global_handles()->Create(storage));
10135 Handle<FixedArray> storage_; // Always a global handle.
10136 // Index after last seen index. Always less than or equal to
10137 // JSObject::kMaxElementCount.
10138 uint32_t index_offset_;
10139 bool fast_elements_ : 1;
10140 bool exceeds_array_limit_ : 1;
10144 static uint32_t EstimateElementCount(Handle<JSArray> array) {
10145 uint32_t length = static_cast<uint32_t>(array->length()->Number());
10146 int element_count = 0;
10147 switch (array->GetElementsKind()) {
10148 case FAST_SMI_ELEMENTS:
10149 case FAST_HOLEY_SMI_ELEMENTS:
10150 case FAST_ELEMENTS:
10151 case FAST_HOLEY_ELEMENTS: {
10152 // Fast elements can't have lengths that are not representable by
10153 // a 32-bit signed integer.
10154 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
10155 int fast_length = static_cast<int>(length);
10156 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
10157 for (int i = 0; i < fast_length; i++) {
10158 if (!elements->get(i)->IsTheHole()) element_count++;
10162 case FAST_DOUBLE_ELEMENTS:
10163 case FAST_HOLEY_DOUBLE_ELEMENTS: {
10164 // Fast elements can't have lengths that are not representable by
10165 // a 32-bit signed integer.
10166 ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
10167 int fast_length = static_cast<int>(length);
10168 if (array->elements()->IsFixedArray()) {
10169 ASSERT(FixedArray::cast(array->elements())->length() == 0);
10172 Handle<FixedDoubleArray> elements(
10173 FixedDoubleArray::cast(array->elements()));
10174 for (int i = 0; i < fast_length; i++) {
10175 if (!elements->is_the_hole(i)) element_count++;
10179 case DICTIONARY_ELEMENTS: {
10180 Handle<SeededNumberDictionary> dictionary(
10181 SeededNumberDictionary::cast(array->elements()));
10182 int capacity = dictionary->Capacity();
10183 for (int i = 0; i < capacity; i++) {
10184 Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate());
10185 if (dictionary->IsKey(*key)) {
10191 case SLOPPY_ARGUMENTS_ELEMENTS:
10192 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
10193 case EXTERNAL_##TYPE##_ELEMENTS: \
10194 case TYPE##_ELEMENTS: \
10196 TYPED_ARRAYS(TYPED_ARRAY_CASE)
10197 #undef TYPED_ARRAY_CASE
10198 // External arrays are always dense.
10201 // As an estimate, we assume that the prototype doesn't contain any
10202 // inherited elements.
10203 return element_count;
10208 template<class ExternalArrayClass, class ElementType>
10209 static void IterateExternalArrayElements(Isolate* isolate,
10210 Handle<JSObject> receiver,
10211 bool elements_are_ints,
10212 bool elements_are_guaranteed_smis,
10213 ArrayConcatVisitor* visitor) {
10214 Handle<ExternalArrayClass> array(
10215 ExternalArrayClass::cast(receiver->elements()));
10216 uint32_t len = static_cast<uint32_t>(array->length());
10218 ASSERT(visitor != NULL);
10219 if (elements_are_ints) {
10220 if (elements_are_guaranteed_smis) {
10221 for (uint32_t j = 0; j < len; j++) {
10222 HandleScope loop_scope(isolate);
10223 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
10225 visitor->visit(j, e);
10228 for (uint32_t j = 0; j < len; j++) {
10229 HandleScope loop_scope(isolate);
10230 int64_t val = static_cast<int64_t>(array->get_scalar(j));
10231 if (Smi::IsValid(static_cast<intptr_t>(val))) {
10232 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
10233 visitor->visit(j, e);
10236 isolate->factory()->NewNumber(static_cast<ElementType>(val));
10237 visitor->visit(j, e);
10242 for (uint32_t j = 0; j < len; j++) {
10243 HandleScope loop_scope(isolate);
10244 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
10245 visitor->visit(j, e);
10251 static void IterateExternalFloat32x4ArrayElements(Isolate* isolate,
10252 Handle<JSObject> receiver,
10253 ArrayConcatVisitor* visitor) {
10254 Handle<ExternalFloat32x4Array> array(
10255 ExternalFloat32x4Array::cast(receiver->elements()));
10256 uint32_t len = static_cast<uint32_t>(array->length());
10258 ASSERT(visitor != NULL);
10259 for (uint32_t j = 0; j < len; j++) {
10260 HandleScope loop_scope(isolate);
10261 Handle<Object> e = isolate->factory()->NewFloat32x4(array->get_scalar(j));
10262 visitor->visit(j, e);
10267 static void IterateExternalInt32x4ArrayElements(Isolate* isolate,
10268 Handle<JSObject> receiver,
10269 ArrayConcatVisitor* visitor) {
10270 Handle<ExternalInt32x4Array> array(
10271 ExternalInt32x4Array::cast(receiver->elements()));
10272 uint32_t len = static_cast<uint32_t>(array->length());
10274 ASSERT(visitor != NULL);
10275 for (uint32_t j = 0; j < len; j++) {
10276 HandleScope loop_scope(isolate);
10277 Handle<Object> e = isolate->factory()->NewInt32x4(array->get_scalar(j));
10278 visitor->visit(j, e);
10283 // Used for sorting indices in a List<uint32_t>.
10284 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
10287 return (a == b) ? 0 : (a < b) ? -1 : 1;
10291 static void CollectElementIndices(Handle<JSObject> object,
10293 List<uint32_t>* indices) {
10294 Isolate* isolate = object->GetIsolate();
10295 ElementsKind kind = object->GetElementsKind();
10297 case FAST_SMI_ELEMENTS:
10298 case FAST_ELEMENTS:
10299 case FAST_HOLEY_SMI_ELEMENTS:
10300 case FAST_HOLEY_ELEMENTS: {
10301 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
10302 uint32_t length = static_cast<uint32_t>(elements->length());
10303 if (range < length) length = range;
10304 for (uint32_t i = 0; i < length; i++) {
10305 if (!elements->get(i)->IsTheHole()) {
10311 case FAST_HOLEY_DOUBLE_ELEMENTS:
10312 case FAST_DOUBLE_ELEMENTS: {
10313 // TODO(1810): Decide if it's worthwhile to implement this.
10317 case DICTIONARY_ELEMENTS: {
10318 Handle<SeededNumberDictionary> dict(
10319 SeededNumberDictionary::cast(object->elements()));
10320 uint32_t capacity = dict->Capacity();
10321 for (uint32_t j = 0; j < capacity; j++) {
10322 HandleScope loop_scope(isolate);
10323 Handle<Object> k(dict->KeyAt(j), isolate);
10324 if (dict->IsKey(*k)) {
10325 ASSERT(k->IsNumber());
10326 uint32_t index = static_cast<uint32_t>(k->Number());
10327 if (index < range) {
10328 indices->Add(index);
10335 int dense_elements_length;
10337 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
10338 case EXTERNAL_##TYPE##_ELEMENTS: { \
10339 dense_elements_length = \
10340 External##Type##Array::cast(object->elements())->length(); \
10344 TYPED_ARRAYS(TYPED_ARRAY_CASE)
10345 #undef TYPED_ARRAY_CASE
10349 dense_elements_length = 0;
10352 uint32_t length = static_cast<uint32_t>(dense_elements_length);
10353 if (range <= length) {
10355 // We will add all indices, so we might as well clear it first
10356 // and avoid duplicates.
10359 for (uint32_t i = 0; i < length; i++) {
10362 if (length == range) return; // All indices accounted for already.
10367 Handle<Object> prototype(object->GetPrototype(), isolate);
10368 if (prototype->IsJSObject()) {
10369 // The prototype will usually have no inherited element indices,
10370 // but we have to check.
10371 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
10377 * A helper function that visits elements of a JSArray in numerical
10380 * The visitor argument called for each existing element in the array
10381 * with the element index and the element's value.
10382 * Afterwards it increments the base-index of the visitor by the array
10384 * Returns false if any access threw an exception, otherwise true.
10386 static bool IterateElements(Isolate* isolate,
10387 Handle<JSArray> receiver,
10388 ArrayConcatVisitor* visitor) {
10389 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
10390 switch (receiver->GetElementsKind()) {
10391 case FAST_SMI_ELEMENTS:
10392 case FAST_ELEMENTS:
10393 case FAST_HOLEY_SMI_ELEMENTS:
10394 case FAST_HOLEY_ELEMENTS: {
10395 // Run through the elements FixedArray and use HasElement and GetElement
10396 // to check the prototype for missing elements.
10397 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
10398 int fast_length = static_cast<int>(length);
10399 ASSERT(fast_length <= elements->length());
10400 for (int j = 0; j < fast_length; j++) {
10401 HandleScope loop_scope(isolate);
10402 Handle<Object> element_value(elements->get(j), isolate);
10403 if (!element_value->IsTheHole()) {
10404 visitor->visit(j, element_value);
10405 } else if (JSReceiver::HasElement(receiver, j)) {
10406 // Call GetElement on receiver, not its prototype, or getters won't
10407 // have the correct receiver.
10408 element_value = Object::GetElement(isolate, receiver, j);
10409 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
10410 visitor->visit(j, element_value);
10415 case FAST_HOLEY_DOUBLE_ELEMENTS:
10416 case FAST_DOUBLE_ELEMENTS: {
10417 // Run through the elements FixedArray and use HasElement and GetElement
10418 // to check the prototype for missing elements.
10419 Handle<FixedDoubleArray> elements(
10420 FixedDoubleArray::cast(receiver->elements()));
10421 int fast_length = static_cast<int>(length);
10422 ASSERT(fast_length <= elements->length());
10423 for (int j = 0; j < fast_length; j++) {
10424 HandleScope loop_scope(isolate);
10425 if (!elements->is_the_hole(j)) {
10426 double double_value = elements->get_scalar(j);
10427 Handle<Object> element_value =
10428 isolate->factory()->NewNumber(double_value);
10429 visitor->visit(j, element_value);
10430 } else if (JSReceiver::HasElement(receiver, j)) {
10431 // Call GetElement on receiver, not its prototype, or getters won't
10432 // have the correct receiver.
10433 Handle<Object> element_value =
10434 Object::GetElement(isolate, receiver, j);
10435 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
10436 visitor->visit(j, element_value);
10441 case DICTIONARY_ELEMENTS: {
10442 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
10443 List<uint32_t> indices(dict->Capacity() / 2);
10444 // Collect all indices in the object and the prototypes less
10445 // than length. This might introduce duplicates in the indices list.
10446 CollectElementIndices(receiver, length, &indices);
10447 indices.Sort(&compareUInt32);
10449 int n = indices.length();
10451 HandleScope loop_scope(isolate);
10452 uint32_t index = indices[j];
10453 Handle<Object> element = Object::GetElement(isolate, receiver, index);
10454 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
10455 visitor->visit(index, element);
10456 // Skip to next different index (i.e., omit duplicates).
10459 } while (j < n && indices[j] == index);
10463 case EXTERNAL_UINT8_CLAMPED_ELEMENTS: {
10464 Handle<ExternalUint8ClampedArray> pixels(ExternalUint8ClampedArray::cast(
10465 receiver->elements()));
10466 for (uint32_t j = 0; j < length; j++) {
10467 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
10468 visitor->visit(j, e);
10472 case EXTERNAL_INT8_ELEMENTS: {
10473 IterateExternalArrayElements<ExternalInt8Array, int8_t>(
10474 isolate, receiver, true, true, visitor);
10477 case EXTERNAL_UINT8_ELEMENTS: {
10478 IterateExternalArrayElements<ExternalUint8Array, uint8_t>(
10479 isolate, receiver, true, true, visitor);
10482 case EXTERNAL_INT16_ELEMENTS: {
10483 IterateExternalArrayElements<ExternalInt16Array, int16_t>(
10484 isolate, receiver, true, true, visitor);
10487 case EXTERNAL_UINT16_ELEMENTS: {
10488 IterateExternalArrayElements<ExternalUint16Array, uint16_t>(
10489 isolate, receiver, true, true, visitor);
10492 case EXTERNAL_INT32_ELEMENTS: {
10493 IterateExternalArrayElements<ExternalInt32Array, int32_t>(
10494 isolate, receiver, true, false, visitor);
10497 case EXTERNAL_UINT32_ELEMENTS: {
10498 IterateExternalArrayElements<ExternalUint32Array, uint32_t>(
10499 isolate, receiver, true, false, visitor);
10502 case EXTERNAL_FLOAT32_ELEMENTS: {
10503 IterateExternalArrayElements<ExternalFloat32Array, float>(
10504 isolate, receiver, false, false, visitor);
10507 case EXTERNAL_FLOAT32x4_ELEMENTS: {
10508 IterateExternalFloat32x4ArrayElements(isolate, receiver, visitor);
10511 case EXTERNAL_INT32x4_ELEMENTS: {
10512 IterateExternalInt32x4ArrayElements(isolate, receiver, visitor);
10515 case EXTERNAL_FLOAT64_ELEMENTS: {
10516 IterateExternalArrayElements<ExternalFloat64Array, double>(
10517 isolate, receiver, false, false, visitor);
10524 visitor->increase_index_offset(length);
10530 * Array::concat implementation.
10531 * See ECMAScript 262, 15.4.4.4.
10532 * TODO(581): Fix non-compliance for very large concatenations and update to
10533 * following the ECMAScript 5 specification.
10535 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
10536 HandleScope handle_scope(isolate);
10537 ASSERT(args.length() == 1);
10539 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
10540 int argument_count = static_cast<int>(arguments->length()->Number());
10541 RUNTIME_ASSERT(arguments->HasFastObjectElements());
10542 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
10544 // Pass 1: estimate the length and number of elements of the result.
10545 // The actual length can be larger if any of the arguments have getters
10546 // that mutate other arguments (but will otherwise be precise).
10547 // The number of elements is precise if there are no inherited elements.
10549 ElementsKind kind = FAST_SMI_ELEMENTS;
10551 uint32_t estimate_result_length = 0;
10552 uint32_t estimate_nof_elements = 0;
10553 for (int i = 0; i < argument_count; i++) {
10554 HandleScope loop_scope(isolate);
10555 Handle<Object> obj(elements->get(i), isolate);
10556 uint32_t length_estimate;
10557 uint32_t element_estimate;
10558 if (obj->IsJSArray()) {
10559 Handle<JSArray> array(Handle<JSArray>::cast(obj));
10560 length_estimate = static_cast<uint32_t>(array->length()->Number());
10561 if (length_estimate != 0) {
10562 ElementsKind array_kind =
10563 GetPackedElementsKind(array->map()->elements_kind());
10564 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) {
10568 element_estimate = EstimateElementCount(array);
10570 if (obj->IsHeapObject()) {
10571 if (obj->IsNumber()) {
10572 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) {
10573 kind = FAST_DOUBLE_ELEMENTS;
10575 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) {
10576 kind = FAST_ELEMENTS;
10579 length_estimate = 1;
10580 element_estimate = 1;
10582 // Avoid overflows by capping at kMaxElementCount.
10583 if (JSObject::kMaxElementCount - estimate_result_length <
10585 estimate_result_length = JSObject::kMaxElementCount;
10587 estimate_result_length += length_estimate;
10589 if (JSObject::kMaxElementCount - estimate_nof_elements <
10590 element_estimate) {
10591 estimate_nof_elements = JSObject::kMaxElementCount;
10593 estimate_nof_elements += element_estimate;
10597 // If estimated number of elements is more than half of length, a
10598 // fixed array (fast case) is more time and space-efficient than a
10600 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
10602 Handle<FixedArray> storage;
10604 if (kind == FAST_DOUBLE_ELEMENTS) {
10605 Handle<FixedDoubleArray> double_storage =
10606 isolate->factory()->NewFixedDoubleArray(estimate_result_length);
10608 bool failure = false;
10609 for (int i = 0; i < argument_count; i++) {
10610 Handle<Object> obj(elements->get(i), isolate);
10611 if (obj->IsSmi()) {
10612 double_storage->set(j, Smi::cast(*obj)->value());
10614 } else if (obj->IsNumber()) {
10615 double_storage->set(j, obj->Number());
10618 JSArray* array = JSArray::cast(*obj);
10619 uint32_t length = static_cast<uint32_t>(array->length()->Number());
10620 switch (array->map()->elements_kind()) {
10621 case FAST_HOLEY_DOUBLE_ELEMENTS:
10622 case FAST_DOUBLE_ELEMENTS: {
10623 // Empty fixed array indicates that there are no elements.
10624 if (array->elements()->IsFixedArray()) break;
10625 FixedDoubleArray* elements =
10626 FixedDoubleArray::cast(array->elements());
10627 for (uint32_t i = 0; i < length; i++) {
10628 if (elements->is_the_hole(i)) {
10632 double double_value = elements->get_scalar(i);
10633 double_storage->set(j, double_value);
10638 case FAST_HOLEY_SMI_ELEMENTS:
10639 case FAST_SMI_ELEMENTS: {
10640 FixedArray* elements(
10641 FixedArray::cast(array->elements()));
10642 for (uint32_t i = 0; i < length; i++) {
10643 Object* element = elements->get(i);
10644 if (element->IsTheHole()) {
10648 int32_t int_value = Smi::cast(element)->value();
10649 double_storage->set(j, int_value);
10654 case FAST_HOLEY_ELEMENTS:
10655 ASSERT_EQ(0, length);
10661 if (failure) break;
10663 Handle<JSArray> array = isolate->factory()->NewJSArray(0);
10664 Smi* length = Smi::FromInt(j);
10666 map = JSObject::GetElementsTransitionMap(array, kind);
10667 array->set_map(*map);
10668 array->set_length(length);
10669 array->set_elements(*double_storage);
10672 // The backing storage array must have non-existing elements to preserve
10673 // holes across concat operations.
10674 storage = isolate->factory()->NewFixedArrayWithHoles(
10675 estimate_result_length);
10677 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10678 uint32_t at_least_space_for = estimate_nof_elements +
10679 (estimate_nof_elements >> 2);
10680 storage = Handle<FixedArray>::cast(
10681 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
10684 ArrayConcatVisitor visitor(isolate, storage, fast_case);
10686 for (int i = 0; i < argument_count; i++) {
10687 Handle<Object> obj(elements->get(i), isolate);
10688 if (obj->IsJSArray()) {
10689 Handle<JSArray> array = Handle<JSArray>::cast(obj);
10690 if (!IterateElements(isolate, array, &visitor)) {
10691 return Failure::Exception();
10694 visitor.visit(0, obj);
10695 visitor.increase_index_offset(1);
10699 if (visitor.exceeds_array_limit()) {
10700 return isolate->Throw(
10701 *isolate->factory()->NewRangeError("invalid_array_length",
10702 HandleVector<Object>(NULL, 0)));
10704 return *visitor.ToArray();
10708 // This will not allocate (flatten the string), but it may run
10709 // very slowly for very deeply nested ConsStrings. For debugging use only.
10710 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
10711 SealHandleScope shs(isolate);
10712 ASSERT(args.length() == 1);
10714 CONVERT_ARG_CHECKED(String, string, 0);
10715 ConsStringIteratorOp op;
10716 StringCharacterStream stream(string, &op);
10717 while (stream.HasMore()) {
10718 uint16_t character = stream.GetNext();
10719 PrintF("%c", character);
10725 // Moves all own elements of an object, that are below a limit, to positions
10726 // starting at zero. All undefined values are placed after non-undefined values,
10727 // and are followed by non-existing element. Does not change the length
10729 // Returns the number of non-undefined elements collected.
10730 // Returns -1 if hole removal is not supported by this method.
10731 RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
10732 HandleScope scope(isolate);
10733 ASSERT(args.length() == 2);
10734 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
10735 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10736 return *JSObject::PrepareElementsForSort(object, limit);
10740 // Move contents of argument 0 (an array) to argument 1 (an array)
10741 RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
10742 SealHandleScope shs(isolate);
10743 ASSERT(args.length() == 2);
10744 CONVERT_ARG_CHECKED(JSArray, from, 0);
10745 CONVERT_ARG_CHECKED(JSArray, to, 1);
10746 from->ValidateElements();
10747 to->ValidateElements();
10748 FixedArrayBase* new_elements = from->elements();
10749 ElementsKind from_kind = from->GetElementsKind();
10750 MaybeObject* maybe_new_map;
10751 maybe_new_map = to->GetElementsTransitionMap(isolate, from_kind);
10753 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
10754 to->set_map_and_elements(Map::cast(new_map), new_elements);
10755 to->set_length(from->length());
10757 { MaybeObject* maybe_obj = from->ResetElements();
10758 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10760 from->set_length(Smi::FromInt(0));
10761 to->ValidateElements();
10766 // How many elements does this object/array have?
10767 RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
10768 SealHandleScope shs(isolate);
10769 ASSERT(args.length() == 1);
10770 CONVERT_ARG_CHECKED(JSObject, object, 0);
10771 HeapObject* elements = object->elements();
10772 if (elements->IsDictionary()) {
10773 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10774 return Smi::FromInt(result);
10775 } else if (object->IsJSArray()) {
10776 return JSArray::cast(object)->length();
10778 return Smi::FromInt(FixedArray::cast(elements)->length());
10783 // Returns an array that tells you where in the [0, length) interval an array
10784 // might have elements. Can either return an array of keys (positive integers
10785 // or undefined) or a number representing the positive length of an interval
10786 // starting at index 0.
10787 // Intervals can span over some keys that are not in the object.
10788 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
10789 HandleScope scope(isolate);
10790 ASSERT(args.length() == 2);
10791 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
10792 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
10793 if (array->elements()->IsDictionary()) {
10794 Handle<FixedArray> keys = isolate->factory()->empty_fixed_array();
10795 for (Handle<Object> p = array;
10797 p = Handle<Object>(p->GetPrototype(isolate), isolate)) {
10798 if (p->IsJSProxy() || JSObject::cast(*p)->HasIndexedInterceptor()) {
10799 // Bail out if we find a proxy or interceptor, likely not worth
10800 // collecting keys in that case.
10801 return *isolate->factory()->NewNumberFromUint(length);
10803 Handle<JSObject> current = Handle<JSObject>::cast(p);
10804 Handle<FixedArray> current_keys =
10805 isolate->factory()->NewFixedArray(
10806 current->NumberOfLocalElements(NONE));
10807 current->GetLocalElementKeys(*current_keys, NONE);
10808 keys = UnionOfKeys(keys, current_keys);
10810 // Erase any keys >= length.
10811 // TODO(adamk): Remove this step when the contract of %GetArrayKeys
10812 // is changed to let this happen on the JS side.
10813 for (int i = 0; i < keys->length(); i++) {
10814 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i);
10816 return *isolate->factory()->NewJSArrayWithElements(keys);
10818 ASSERT(array->HasFastSmiOrObjectElements() ||
10819 array->HasFastDoubleElements());
10820 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
10821 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
10826 RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
10827 HandleScope scope(isolate);
10828 ASSERT(args.length() == 3);
10829 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
10830 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
10831 CONVERT_SMI_ARG_CHECKED(flag, 2);
10832 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10833 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value();
10834 Handle<Object> result =
10835 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component);
10836 RETURN_IF_EMPTY_HANDLE(isolate, result);
10841 #ifdef ENABLE_DEBUGGER_SUPPORT
10842 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
10843 SealHandleScope shs(isolate);
10844 ASSERT(args.length() == 0);
10845 return Execution::DebugBreakHelper(isolate);
10849 // Helper functions for wrapping and unwrapping stack frame ids.
10850 static Smi* WrapFrameId(StackFrame::Id id) {
10851 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
10852 return Smi::FromInt(id >> 2);
10856 static StackFrame::Id UnwrapFrameId(int wrapped) {
10857 return static_cast<StackFrame::Id>(wrapped << 2);
10861 // Adds a JavaScript function as a debug event listener.
10862 // args[0]: debug event listener function to set or null or undefined for
10863 // clearing the event listener function
10864 // args[1]: object supplied during callback
10865 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
10866 SealHandleScope shs(isolate);
10867 ASSERT(args.length() == 2);
10868 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10869 args[0]->IsUndefined() ||
10870 args[0]->IsNull());
10871 Handle<Object> callback = args.at<Object>(0);
10872 Handle<Object> data = args.at<Object>(1);
10873 isolate->debugger()->SetEventListener(callback, data);
10875 return isolate->heap()->undefined_value();
10879 RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
10880 SealHandleScope shs(isolate);
10881 ASSERT(args.length() == 0);
10882 isolate->stack_guard()->DebugBreak();
10883 return isolate->heap()->undefined_value();
10887 static MaybeObject* DebugLookupResultValue(Heap* heap,
10890 LookupResult* result,
10891 bool* caught_exception) {
10893 switch (result->type()) {
10895 value = result->holder()->GetNormalizedProperty(result);
10896 if (value->IsTheHole()) {
10897 return heap->undefined_value();
10902 MaybeObject* maybe_value =
10903 JSObject::cast(result->holder())->FastPropertyAt(
10904 result->representation(),
10905 result->GetFieldIndex().field_index());
10906 if (!maybe_value->To(&value)) return maybe_value;
10907 if (value->IsTheHole()) {
10908 return heap->undefined_value();
10913 return result->GetConstant();
10915 Object* structure = result->GetCallbackObject();
10916 if (structure->IsForeign() || structure->IsAccessorInfo()) {
10917 Isolate* isolate = heap->isolate();
10918 HandleScope scope(isolate);
10919 Handle<Object> value = JSObject::GetPropertyWithCallback(
10920 handle(result->holder(), isolate),
10921 handle(receiver, isolate),
10922 handle(structure, isolate),
10923 handle(name, isolate));
10924 if (value.is_null()) {
10925 MaybeObject* exception = heap->isolate()->pending_exception();
10926 heap->isolate()->clear_pending_exception();
10927 if (caught_exception != NULL) *caught_exception = true;
10932 return heap->undefined_value();
10937 return heap->undefined_value();
10941 return heap->undefined_value();
10943 UNREACHABLE(); // keep the compiler happy
10944 return heap->undefined_value();
10948 // Get debugger related details for an object property.
10949 // args[0]: object holding property
10950 // args[1]: name of the property
10952 // The array returned contains the following information:
10953 // 0: Property value
10954 // 1: Property details
10955 // 2: Property value is exception
10956 // 3: Getter function if defined
10957 // 4: Setter function if defined
10958 // Items 2-4 are only filled if the property has either a getter or a setter
10959 // defined through __defineGetter__ and/or __defineSetter__.
10960 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
10961 HandleScope scope(isolate);
10963 ASSERT(args.length() == 2);
10965 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10966 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
10968 // Make sure to set the current context to the context before the debugger was
10969 // entered (if the debugger is entered). The reason for switching context here
10970 // is that for some property lookups (accessors and interceptors) callbacks
10971 // into the embedding application can occour, and the embedding application
10972 // could have the assumption that its own native context is the current
10973 // context and not some internal debugger context.
10974 SaveContext save(isolate);
10975 if (isolate->debug()->InDebugger()) {
10976 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
10979 // Skip the global proxy as it has no properties and always delegates to the
10980 // real global object.
10981 if (obj->IsJSGlobalProxy()) {
10982 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10986 // Check if the name is trivially convertible to an index and get the element
10989 if (name->AsArrayIndex(&index)) {
10990 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
10991 Handle<Object> element_or_char =
10992 Runtime::GetElementOrCharAt(isolate, obj, index);
10993 RETURN_IF_EMPTY_HANDLE(isolate, element_or_char);
10994 details->set(0, *element_or_char);
10996 1, PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi());
10997 return *isolate->factory()->NewJSArrayWithElements(details);
11000 // Find the number of objects making up this.
11001 int length = LocalPrototypeChainLength(*obj);
11003 // Try local lookup on each of the objects.
11004 Handle<JSObject> jsproto = obj;
11005 for (int i = 0; i < length; i++) {
11006 LookupResult result(isolate);
11007 jsproto->LocalLookup(*name, &result);
11008 if (result.IsFound()) {
11009 // LookupResult is not GC safe as it holds raw object pointers.
11010 // GC can happen later in this code so put the required fields into
11011 // local variables using handles when required for later use.
11012 Handle<Object> result_callback_obj;
11013 if (result.IsPropertyCallbacks()) {
11014 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
11017 Smi* property_details = result.GetPropertyDetails().AsSmi();
11018 // DebugLookupResultValue can cause GC so details from LookupResult needs
11019 // to be copied to handles before this.
11020 bool caught_exception = false;
11022 { MaybeObject* maybe_raw_value =
11023 DebugLookupResultValue(isolate->heap(), *obj, *name,
11024 &result, &caught_exception);
11025 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
11027 Handle<Object> value(raw_value, isolate);
11029 // If the callback object is a fixed array then it contains JavaScript
11030 // getter and/or setter.
11031 bool hasJavaScriptAccessors = result.IsPropertyCallbacks() &&
11032 result_callback_obj->IsAccessorPair();
11033 Handle<FixedArray> details =
11034 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
11035 details->set(0, *value);
11036 details->set(1, property_details);
11037 if (hasJavaScriptAccessors) {
11038 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
11039 details->set(2, isolate->heap()->ToBoolean(caught_exception));
11040 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
11041 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
11044 return *isolate->factory()->NewJSArrayWithElements(details);
11046 if (i < length - 1) {
11047 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
11051 return isolate->heap()->undefined_value();
11055 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
11056 HandleScope scope(isolate);
11058 ASSERT(args.length() == 2);
11060 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
11061 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
11063 LookupResult result(isolate);
11064 obj->Lookup(*name, &result);
11065 if (result.IsFound()) {
11066 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
11068 return isolate->heap()->undefined_value();
11072 // Return the property type calculated from the property details.
11073 // args[0]: smi with property details.
11074 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
11075 SealHandleScope shs(isolate);
11076 ASSERT(args.length() == 1);
11077 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
11078 return Smi::FromInt(static_cast<int>(details.type()));
11082 // Return the property attribute calculated from the property details.
11083 // args[0]: smi with property details.
11084 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
11085 SealHandleScope shs(isolate);
11086 ASSERT(args.length() == 1);
11087 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
11088 return Smi::FromInt(static_cast<int>(details.attributes()));
11092 // Return the property insertion index calculated from the property details.
11093 // args[0]: smi with property details.
11094 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
11095 SealHandleScope shs(isolate);
11096 ASSERT(args.length() == 1);
11097 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
11098 // TODO(verwaest): Depends on the type of details.
11099 return Smi::FromInt(details.dictionary_index());
11103 // Return property value from named interceptor.
11105 // args[1]: property name
11106 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
11107 HandleScope scope(isolate);
11108 ASSERT(args.length() == 2);
11109 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
11110 RUNTIME_ASSERT(obj->HasNamedInterceptor());
11111 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
11113 PropertyAttributes attributes;
11114 Handle<Object> result =
11115 JSObject::GetPropertyWithInterceptor(obj, obj, name, &attributes);
11116 RETURN_IF_EMPTY_HANDLE(isolate, result);
11121 // Return element value from indexed interceptor.
11124 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
11125 HandleScope scope(isolate);
11126 ASSERT(args.length() == 2);
11127 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
11128 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
11129 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
11130 Handle<Object> result = JSObject::GetElementWithInterceptor(obj, obj, index);
11131 RETURN_IF_EMPTY_HANDLE(isolate, result);
11136 RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
11137 SealHandleScope shs(isolate);
11138 ASSERT(args.length() >= 1);
11139 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
11140 // Check that the break id is valid.
11141 if (isolate->debug()->break_id() == 0 ||
11142 break_id != isolate->debug()->break_id()) {
11143 return isolate->Throw(
11144 isolate->heap()->illegal_execution_state_string());
11147 return isolate->heap()->true_value();
11151 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
11152 HandleScope scope(isolate);
11153 ASSERT(args.length() == 1);
11155 // Check arguments.
11157 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11158 RUNTIME_ARGUMENTS(isolate, args));
11159 if (!maybe_result->ToObject(&result)) return maybe_result;
11162 // Count all frames which are relevant to debugging stack trace.
11164 StackFrame::Id id = isolate->debug()->break_frame_id();
11165 if (id == StackFrame::NO_ID) {
11166 // If there is no JavaScript stack frame count is 0.
11167 return Smi::FromInt(0);
11170 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
11171 n += it.frame()->GetInlineCount();
11173 return Smi::FromInt(n);
11177 class FrameInspector {
11179 FrameInspector(JavaScriptFrame* frame,
11180 int inlined_jsframe_index,
11182 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
11183 // Calculate the deoptimized frame.
11184 if (frame->is_optimized()) {
11185 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
11186 frame, inlined_jsframe_index, isolate);
11188 has_adapted_arguments_ = frame_->has_adapted_arguments();
11189 is_bottommost_ = inlined_jsframe_index == 0;
11190 is_optimized_ = frame_->is_optimized();
11193 ~FrameInspector() {
11194 // Get rid of the calculated deoptimized frame if any.
11195 if (deoptimized_frame_ != NULL) {
11196 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
11201 int GetParametersCount() {
11202 return is_optimized_
11203 ? deoptimized_frame_->parameters_count()
11204 : frame_->ComputeParametersCount();
11206 int expression_count() { return deoptimized_frame_->expression_count(); }
11207 Object* GetFunction() {
11208 return is_optimized_
11209 ? deoptimized_frame_->GetFunction()
11210 : frame_->function();
11212 Object* GetParameter(int index) {
11213 return is_optimized_
11214 ? deoptimized_frame_->GetParameter(index)
11215 : frame_->GetParameter(index);
11217 Object* GetExpression(int index) {
11218 return is_optimized_
11219 ? deoptimized_frame_->GetExpression(index)
11220 : frame_->GetExpression(index);
11222 int GetSourcePosition() {
11223 return is_optimized_
11224 ? deoptimized_frame_->GetSourcePosition()
11225 : frame_->LookupCode()->SourcePosition(frame_->pc());
11227 bool IsConstructor() {
11228 return is_optimized_ && !is_bottommost_
11229 ? deoptimized_frame_->HasConstructStub()
11230 : frame_->IsConstructor();
11233 // To inspect all the provided arguments the frame might need to be
11234 // replaced with the arguments frame.
11235 void SetArgumentsFrame(JavaScriptFrame* frame) {
11236 ASSERT(has_adapted_arguments_);
11238 is_optimized_ = frame_->is_optimized();
11239 ASSERT(!is_optimized_);
11243 JavaScriptFrame* frame_;
11244 DeoptimizedFrameInfo* deoptimized_frame_;
11246 bool is_optimized_;
11247 bool is_bottommost_;
11248 bool has_adapted_arguments_;
11250 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
11254 static const int kFrameDetailsFrameIdIndex = 0;
11255 static const int kFrameDetailsReceiverIndex = 1;
11256 static const int kFrameDetailsFunctionIndex = 2;
11257 static const int kFrameDetailsArgumentCountIndex = 3;
11258 static const int kFrameDetailsLocalCountIndex = 4;
11259 static const int kFrameDetailsSourcePositionIndex = 5;
11260 static const int kFrameDetailsConstructCallIndex = 6;
11261 static const int kFrameDetailsAtReturnIndex = 7;
11262 static const int kFrameDetailsFlagsIndex = 8;
11263 static const int kFrameDetailsFirstDynamicIndex = 9;
11266 static SaveContext* FindSavedContextForFrame(Isolate* isolate,
11267 JavaScriptFrame* frame) {
11268 SaveContext* save = isolate->save_context();
11269 while (save != NULL && !save->IsBelowFrame(frame)) {
11270 save = save->prev();
11272 ASSERT(save != NULL);
11277 // Return an array with frame details
11278 // args[0]: number: break id
11279 // args[1]: number: frame index
11281 // The array returned contains the following information:
11285 // 3: Argument count
11287 // 5: Source position
11288 // 6: Constructor call
11291 // Arguments name, value
11292 // Locals name, value
11293 // Return value if any
11294 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
11295 HandleScope scope(isolate);
11296 ASSERT(args.length() == 2);
11298 // Check arguments.
11300 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11301 RUNTIME_ARGUMENTS(isolate, args));
11302 if (!maybe_check->ToObject(&check)) return maybe_check;
11304 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11305 Heap* heap = isolate->heap();
11307 // Find the relevant frame with the requested index.
11308 StackFrame::Id id = isolate->debug()->break_frame_id();
11309 if (id == StackFrame::NO_ID) {
11310 // If there are no JavaScript stack frames return undefined.
11311 return heap->undefined_value();
11315 JavaScriptFrameIterator it(isolate, id);
11316 for (; !it.done(); it.Advance()) {
11317 if (index < count + it.frame()->GetInlineCount()) break;
11318 count += it.frame()->GetInlineCount();
11320 if (it.done()) return heap->undefined_value();
11322 bool is_optimized = it.frame()->is_optimized();
11324 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
11325 if (is_optimized) {
11326 inlined_jsframe_index =
11327 it.frame()->GetInlineCount() - (index - count) - 1;
11329 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
11331 // Traverse the saved contexts chain to find the active context for the
11333 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
11335 // Get the frame id.
11336 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
11338 // Find source position in unoptimized code.
11339 int position = frame_inspector.GetSourcePosition();
11341 // Check for constructor frame.
11342 bool constructor = frame_inspector.IsConstructor();
11344 // Get scope info and read from it for local variable information.
11345 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
11346 Handle<SharedFunctionInfo> shared(function->shared());
11347 Handle<ScopeInfo> scope_info(shared->scope_info());
11348 ASSERT(*scope_info != ScopeInfo::Empty(isolate));
11350 // Get the locals names and values into a temporary array.
11352 // TODO(1240907): Hide compiler-introduced stack variables
11353 // (e.g. .result)? For users of the debugger, they will probably be
11355 Handle<FixedArray> locals =
11356 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
11358 // Fill in the values of the locals.
11360 for (; i < scope_info->StackLocalCount(); ++i) {
11361 // Use the value from the stack.
11362 locals->set(i * 2, scope_info->LocalName(i));
11363 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
11365 if (i < scope_info->LocalCount()) {
11366 // Get the context containing declarations.
11367 Handle<Context> context(
11368 Context::cast(it.frame()->context())->declaration_context());
11369 for (; i < scope_info->LocalCount(); ++i) {
11370 Handle<String> name(scope_info->LocalName(i));
11372 InitializationFlag init_flag;
11373 locals->set(i * 2, *name);
11374 int context_slot_index =
11375 scope_info->ContextSlotIndex(*name, &mode, &init_flag);
11376 Object* value = context->get(context_slot_index);
11377 locals->set(i * 2 + 1, value);
11381 // Check whether this frame is positioned at return. If not top
11382 // frame or if the frame is optimized it cannot be at a return.
11383 bool at_return = false;
11384 if (!is_optimized && index == 0) {
11385 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
11388 // If positioned just before return find the value to be returned and add it
11389 // to the frame information.
11390 Handle<Object> return_value = isolate->factory()->undefined_value();
11392 StackFrameIterator it2(isolate);
11393 Address internal_frame_sp = NULL;
11394 while (!it2.done()) {
11395 if (it2.frame()->is_internal()) {
11396 internal_frame_sp = it2.frame()->sp();
11398 if (it2.frame()->is_java_script()) {
11399 if (it2.frame()->id() == it.frame()->id()) {
11400 // The internal frame just before the JavaScript frame contains the
11401 // value to return on top. A debug break at return will create an
11402 // internal frame to store the return value (eax/rax/r0) before
11403 // entering the debug break exit frame.
11404 if (internal_frame_sp != NULL) {
11406 Handle<Object>(Memory::Object_at(internal_frame_sp),
11413 // Indicate that the previous frame was not an internal frame.
11414 internal_frame_sp = NULL;
11420 // Now advance to the arguments adapter frame (if any). It contains all
11421 // the provided parameters whereas the function frame always have the number
11422 // of arguments matching the functions parameters. The rest of the
11423 // information (except for what is collected above) is the same.
11424 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
11425 it.AdvanceToArgumentsFrame();
11426 frame_inspector.SetArgumentsFrame(it.frame());
11429 // Find the number of arguments to fill. At least fill the number of
11430 // parameters for the function and fill more if more parameters are provided.
11431 int argument_count = scope_info->ParameterCount();
11432 if (argument_count < frame_inspector.GetParametersCount()) {
11433 argument_count = frame_inspector.GetParametersCount();
11436 // Calculate the size of the result.
11437 int details_size = kFrameDetailsFirstDynamicIndex +
11438 2 * (argument_count + scope_info->LocalCount()) +
11439 (at_return ? 1 : 0);
11440 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
11442 // Add the frame id.
11443 details->set(kFrameDetailsFrameIdIndex, *frame_id);
11445 // Add the function (same as in function frame).
11446 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
11448 // Add the arguments count.
11449 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
11451 // Add the locals count
11452 details->set(kFrameDetailsLocalCountIndex,
11453 Smi::FromInt(scope_info->LocalCount()));
11455 // Add the source position.
11456 if (position != RelocInfo::kNoPosition) {
11457 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
11459 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
11462 // Add the constructor information.
11463 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
11465 // Add the at return information.
11466 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
11468 // Add flags to indicate information on whether this frame is
11469 // bit 0: invoked in the debugger context.
11470 // bit 1: optimized frame.
11471 // bit 2: inlined in optimized frame
11473 if (*save->context() == *isolate->debug()->debug_context()) {
11476 if (is_optimized) {
11478 flags |= inlined_jsframe_index << 2;
11480 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
11482 // Fill the dynamic part.
11483 int details_index = kFrameDetailsFirstDynamicIndex;
11485 // Add arguments name and value.
11486 for (int i = 0; i < argument_count; i++) {
11487 // Name of the argument.
11488 if (i < scope_info->ParameterCount()) {
11489 details->set(details_index++, scope_info->ParameterName(i));
11491 details->set(details_index++, heap->undefined_value());
11494 // Parameter value.
11495 if (i < frame_inspector.GetParametersCount()) {
11496 // Get the value from the stack.
11497 details->set(details_index++, frame_inspector.GetParameter(i));
11499 details->set(details_index++, heap->undefined_value());
11503 // Add locals name and value from the temporary copy from the function frame.
11504 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
11505 details->set(details_index++, locals->get(i));
11508 // Add the value being returned.
11510 details->set(details_index++, *return_value);
11513 // Add the receiver (same as in function frame).
11514 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11515 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
11516 Handle<Object> receiver(it.frame()->receiver(), isolate);
11517 if (!receiver->IsJSObject() &&
11518 shared->strict_mode() == SLOPPY &&
11519 !function->IsBuiltin()) {
11520 // If the receiver is not a JSObject and the function is not a
11521 // builtin or strict-mode we have hit an optimization where a
11522 // value object is not converted into a wrapped JS objects. To
11523 // hide this optimization from the debugger, we wrap the receiver
11524 // by creating correct wrapper object based on the calling frame's
11527 if (receiver->IsUndefined()) {
11528 Context* context = function->context();
11529 receiver = handle(context->global_object()->global_receiver());
11531 ASSERT(!receiver->IsNull());
11532 Context* context = Context::cast(it.frame()->context());
11533 Handle<Context> native_context(Context::cast(context->native_context()));
11534 receiver = isolate->factory()->ToObject(receiver, native_context);
11537 details->set(kFrameDetailsReceiverIndex, *receiver);
11539 ASSERT_EQ(details_size, details_index);
11540 return *isolate->factory()->NewJSArrayWithElements(details);
11544 static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info,
11547 InitializationFlag flag;
11548 return info->ContextSlotIndex(info->ParameterName(index), &mode, &flag) != -1;
11552 // Create a plain JSObject which materializes the local scope for the specified
11554 static Handle<JSObject> MaterializeStackLocalsWithFrameInspector(
11556 Handle<JSObject> target,
11557 Handle<JSFunction> function,
11558 FrameInspector* frame_inspector) {
11559 Handle<SharedFunctionInfo> shared(function->shared());
11560 Handle<ScopeInfo> scope_info(shared->scope_info());
11562 // First fill all parameters.
11563 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
11564 // Do not materialize the parameter if it is shadowed by a context local.
11565 if (ParameterIsShadowedByContextLocal(scope_info, i)) continue;
11567 HandleScope scope(isolate);
11568 Handle<Object> value(i < frame_inspector->GetParametersCount()
11569 ? frame_inspector->GetParameter(i)
11570 : isolate->heap()->undefined_value(),
11572 ASSERT(!value->IsTheHole());
11573 Handle<String> name(scope_info->ParameterName(i));
11575 RETURN_IF_EMPTY_HANDLE_VALUE(
11577 Runtime::SetObjectProperty(isolate, target, name, value, NONE, SLOPPY),
11578 Handle<JSObject>());
11581 // Second fill all stack locals.
11582 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
11583 Handle<String> name(scope_info->StackLocalName(i));
11584 Handle<Object> value(frame_inspector->GetExpression(i), isolate);
11585 if (value->IsTheHole()) continue;
11587 RETURN_IF_EMPTY_HANDLE_VALUE(
11589 Runtime::SetObjectProperty(isolate, target, name, value, NONE, SLOPPY),
11590 Handle<JSObject>());
11597 static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate,
11598 Handle<JSObject> target,
11599 Handle<JSFunction> function,
11600 JavaScriptFrame* frame,
11601 int inlined_jsframe_index) {
11602 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
11603 // Optimized frames are not supported.
11604 // TODO(yangguo): make sure all code deoptimized when debugger is active
11605 // and assert that this cannot happen.
11609 Handle<SharedFunctionInfo> shared(function->shared());
11610 Handle<ScopeInfo> scope_info(shared->scope_info());
11613 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
11614 // Shadowed parameters were not materialized.
11615 if (ParameterIsShadowedByContextLocal(scope_info, i)) continue;
11617 ASSERT(!frame->GetParameter(i)->IsTheHole());
11618 HandleScope scope(isolate);
11619 Handle<String> name(scope_info->ParameterName(i));
11620 Handle<Object> value = GetProperty(isolate, target, name);
11621 frame->SetParameterValue(i, *value);
11625 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
11626 if (frame->GetExpression(i)->IsTheHole()) continue;
11627 HandleScope scope(isolate);
11628 Handle<Object> value = GetProperty(
11629 isolate, target, Handle<String>(scope_info->StackLocalName(i)));
11630 frame->SetExpression(i, *value);
11635 static Handle<JSObject> MaterializeLocalContext(Isolate* isolate,
11636 Handle<JSObject> target,
11637 Handle<JSFunction> function,
11638 JavaScriptFrame* frame) {
11639 HandleScope scope(isolate);
11640 Handle<SharedFunctionInfo> shared(function->shared());
11641 Handle<ScopeInfo> scope_info(shared->scope_info());
11643 if (!scope_info->HasContext()) return target;
11645 // Third fill all context locals.
11646 Handle<Context> frame_context(Context::cast(frame->context()));
11647 Handle<Context> function_context(frame_context->declaration_context());
11648 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11649 scope_info, function_context, target)) {
11650 return Handle<JSObject>();
11653 // Finally copy any properties from the function context extension.
11654 // These will be variables introduced by eval.
11655 if (function_context->closure() == *function) {
11656 if (function_context->has_extension() &&
11657 !function_context->IsNativeContext()) {
11658 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
11659 bool threw = false;
11660 Handle<FixedArray> keys =
11661 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11662 if (threw) return Handle<JSObject>();
11664 for (int i = 0; i < keys->length(); i++) {
11665 // Names of variables introduced by eval are strings.
11666 ASSERT(keys->get(i)->IsString());
11667 Handle<String> key(String::cast(keys->get(i)));
11668 RETURN_IF_EMPTY_HANDLE_VALUE(
11670 Runtime::SetObjectProperty(isolate,
11673 GetProperty(isolate, ext, key),
11676 Handle<JSObject>());
11685 static Handle<JSObject> MaterializeLocalScope(
11687 JavaScriptFrame* frame,
11688 int inlined_jsframe_index) {
11689 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11690 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
11692 Handle<JSObject> local_scope =
11693 isolate->factory()->NewJSObject(isolate->object_function());
11694 local_scope = MaterializeStackLocalsWithFrameInspector(
11695 isolate, local_scope, function, &frame_inspector);
11696 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, local_scope, Handle<JSObject>());
11698 return MaterializeLocalContext(isolate, local_scope, function, frame);
11702 // Set the context local variable value.
11703 static bool SetContextLocalValue(Isolate* isolate,
11704 Handle<ScopeInfo> scope_info,
11705 Handle<Context> context,
11706 Handle<String> variable_name,
11707 Handle<Object> new_value) {
11708 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11709 Handle<String> next_name(scope_info->ContextLocalName(i));
11710 if (variable_name->Equals(*next_name)) {
11712 InitializationFlag init_flag;
11713 int context_index =
11714 scope_info->ContextSlotIndex(*next_name, &mode, &init_flag);
11715 context->set(context_index, *new_value);
11724 static bool SetLocalVariableValue(Isolate* isolate,
11725 JavaScriptFrame* frame,
11726 int inlined_jsframe_index,
11727 Handle<String> variable_name,
11728 Handle<Object> new_value) {
11729 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
11730 // Optimized frames are not supported.
11734 Handle<JSFunction> function(frame->function());
11735 Handle<SharedFunctionInfo> shared(function->shared());
11736 Handle<ScopeInfo> scope_info(shared->scope_info());
11738 bool default_result = false;
11741 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
11742 if (scope_info->ParameterName(i)->Equals(*variable_name)) {
11743 frame->SetParameterValue(i, *new_value);
11744 // Argument might be shadowed in heap context, don't stop here.
11745 default_result = true;
11750 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
11751 if (scope_info->StackLocalName(i)->Equals(*variable_name)) {
11752 frame->SetExpression(i, *new_value);
11757 if (scope_info->HasContext()) {
11759 Handle<Context> frame_context(Context::cast(frame->context()));
11760 Handle<Context> function_context(frame_context->declaration_context());
11761 if (SetContextLocalValue(
11762 isolate, scope_info, function_context, variable_name, new_value)) {
11766 // Function context extension. These are variables introduced by eval.
11767 if (function_context->closure() == *function) {
11768 if (function_context->has_extension() &&
11769 !function_context->IsNativeContext()) {
11770 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
11772 if (JSReceiver::HasProperty(ext, variable_name)) {
11773 // We don't expect this to do anything except replacing
11775 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
11783 return default_result;
11787 // Create a plain JSObject which materializes the closure content for the
11789 static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11790 Handle<Context> context) {
11791 ASSERT(context->IsFunctionContext());
11793 Handle<SharedFunctionInfo> shared(context->closure()->shared());
11794 Handle<ScopeInfo> scope_info(shared->scope_info());
11796 // Allocate and initialize a JSObject with all the content of this function
11798 Handle<JSObject> closure_scope =
11799 isolate->factory()->NewJSObject(isolate->object_function());
11801 // Fill all context locals to the context extension.
11802 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11803 scope_info, context, closure_scope)) {
11804 return Handle<JSObject>();
11807 // Finally copy any properties from the function context extension. This will
11808 // be variables introduced by eval.
11809 if (context->has_extension()) {
11810 Handle<JSObject> ext(JSObject::cast(context->extension()));
11811 bool threw = false;
11812 Handle<FixedArray> keys =
11813 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11814 if (threw) return Handle<JSObject>();
11816 for (int i = 0; i < keys->length(); i++) {
11817 // Names of variables introduced by eval are strings.
11818 ASSERT(keys->get(i)->IsString());
11819 Handle<String> key(String::cast(keys->get(i)));
11820 RETURN_IF_EMPTY_HANDLE_VALUE(
11822 Runtime::SetObjectProperty(isolate, closure_scope, key,
11823 GetProperty(isolate, ext, key),
11825 Handle<JSObject>());
11829 return closure_scope;
11833 // This method copies structure of MaterializeClosure method above.
11834 static bool SetClosureVariableValue(Isolate* isolate,
11835 Handle<Context> context,
11836 Handle<String> variable_name,
11837 Handle<Object> new_value) {
11838 ASSERT(context->IsFunctionContext());
11840 Handle<SharedFunctionInfo> shared(context->closure()->shared());
11841 Handle<ScopeInfo> scope_info(shared->scope_info());
11843 // Context locals to the context extension.
11844 if (SetContextLocalValue(
11845 isolate, scope_info, context, variable_name, new_value)) {
11849 // Properties from the function context extension. This will
11850 // be variables introduced by eval.
11851 if (context->has_extension()) {
11852 Handle<JSObject> ext(JSObject::cast(context->extension()));
11853 if (JSReceiver::HasProperty(ext, variable_name)) {
11854 // We don't expect this to do anything except replacing property value.
11855 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
11865 // Create a plain JSObject which materializes the scope for the specified
11867 static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11868 Handle<Context> context) {
11869 ASSERT(context->IsCatchContext());
11870 Handle<String> name(String::cast(context->extension()));
11871 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
11873 Handle<JSObject> catch_scope =
11874 isolate->factory()->NewJSObject(isolate->object_function());
11875 RETURN_IF_EMPTY_HANDLE_VALUE(
11877 Runtime::SetObjectProperty(isolate, catch_scope, name, thrown_object,
11879 Handle<JSObject>());
11880 return catch_scope;
11884 static bool SetCatchVariableValue(Isolate* isolate,
11885 Handle<Context> context,
11886 Handle<String> variable_name,
11887 Handle<Object> new_value) {
11888 ASSERT(context->IsCatchContext());
11889 Handle<String> name(String::cast(context->extension()));
11890 if (!name->Equals(*variable_name)) {
11893 context->set(Context::THROWN_OBJECT_INDEX, *new_value);
11898 // Create a plain JSObject which materializes the block scope for the specified
11900 static Handle<JSObject> MaterializeBlockScope(
11902 Handle<Context> context) {
11903 ASSERT(context->IsBlockContext());
11904 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11906 // Allocate and initialize a JSObject with all the arguments, stack locals
11907 // heap locals and extension properties of the debugged function.
11908 Handle<JSObject> block_scope =
11909 isolate->factory()->NewJSObject(isolate->object_function());
11911 // Fill all context locals.
11912 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11913 scope_info, context, block_scope)) {
11914 return Handle<JSObject>();
11917 return block_scope;
11921 // Create a plain JSObject which materializes the module scope for the specified
11923 static Handle<JSObject> MaterializeModuleScope(
11925 Handle<Context> context) {
11926 ASSERT(context->IsModuleContext());
11927 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11929 // Allocate and initialize a JSObject with all the members of the debugged
11931 Handle<JSObject> module_scope =
11932 isolate->factory()->NewJSObject(isolate->object_function());
11934 // Fill all context locals.
11935 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11936 scope_info, context, module_scope)) {
11937 return Handle<JSObject>();
11940 return module_scope;
11944 // Iterate over the actual scopes visible from a stack frame or from a closure.
11945 // The iteration proceeds from the innermost visible nested scope outwards.
11946 // All scopes are backed by an actual context except the local scope,
11947 // which is inserted "artificially" in the context chain.
11948 class ScopeIterator {
11951 ScopeTypeGlobal = 0,
11960 ScopeIterator(Isolate* isolate,
11961 JavaScriptFrame* frame,
11962 int inlined_jsframe_index,
11963 bool ignore_nested_scopes = false)
11964 : isolate_(isolate),
11966 inlined_jsframe_index_(inlined_jsframe_index),
11967 function_(frame->function()),
11968 context_(Context::cast(frame->context())),
11969 nested_scope_chain_(4),
11972 // Catch the case when the debugger stops in an internal function.
11973 Handle<SharedFunctionInfo> shared_info(function_->shared());
11974 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11975 if (shared_info->script() == isolate->heap()->undefined_value()) {
11976 while (context_->closure() == *function_) {
11977 context_ = Handle<Context>(context_->previous(), isolate_);
11982 // Get the debug info (create it if it does not exist).
11983 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
11984 // Return if ensuring debug info failed.
11988 // Currently it takes too much time to find nested scopes due to script
11989 // parsing. Sometimes we want to run the ScopeIterator as fast as possible
11990 // (for example, while collecting async call stacks on every
11991 // addEventListener call), even if we drop some nested scopes.
11992 // Later we may optimize getting the nested scopes (cache the result?)
11993 // and include nested scopes into the "fast" iteration case as well.
11994 if (!ignore_nested_scopes) {
11995 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11997 // Find the break point where execution has stopped.
11998 BreakLocationIterator break_location_iterator(debug_info,
11999 ALL_BREAK_LOCATIONS);
12000 // pc points to the instruction after the current one, possibly a break
12001 // location as well. So the "- 1" to exclude it from the search.
12002 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
12004 // Within the return sequence at the moment it is not possible to
12005 // get a source position which is consistent with the current scope chain.
12006 // Thus all nested with, catch and block contexts are skipped and we only
12007 // provide the function scope.
12008 ignore_nested_scopes = break_location_iterator.IsExit();
12011 if (ignore_nested_scopes) {
12012 if (scope_info->HasContext()) {
12013 context_ = Handle<Context>(context_->declaration_context(), isolate_);
12015 while (context_->closure() == *function_) {
12016 context_ = Handle<Context>(context_->previous(), isolate_);
12019 if (scope_info->scope_type() == FUNCTION_SCOPE) {
12020 nested_scope_chain_.Add(scope_info);
12023 // Reparse the code and analyze the scopes.
12024 Handle<Script> script(Script::cast(shared_info->script()));
12025 Scope* scope = NULL;
12027 // Check whether we are in global, eval or function code.
12028 Handle<ScopeInfo> scope_info(shared_info->scope_info());
12029 if (scope_info->scope_type() != FUNCTION_SCOPE) {
12030 // Global or eval code.
12031 CompilationInfoWithZone info(script);
12032 if (scope_info->scope_type() == GLOBAL_SCOPE) {
12033 info.MarkAsGlobal();
12035 ASSERT(scope_info->scope_type() == EVAL_SCOPE);
12037 info.SetContext(Handle<Context>(function_->context()));
12039 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
12040 scope = info.function()->scope();
12042 RetrieveScopeChain(scope, shared_info);
12045 CompilationInfoWithZone info(shared_info);
12046 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
12047 scope = info.function()->scope();
12049 RetrieveScopeChain(scope, shared_info);
12054 ScopeIterator(Isolate* isolate,
12055 Handle<JSFunction> function)
12056 : isolate_(isolate),
12058 inlined_jsframe_index_(0),
12059 function_(function),
12060 context_(function->context()),
12062 if (function->IsBuiltin()) {
12063 context_ = Handle<Context>();
12070 return context_.is_null();
12073 bool Failed() { return failed_; }
12075 // Move to the next scope.
12078 ScopeType scope_type = Type();
12079 if (scope_type == ScopeTypeGlobal) {
12080 // The global scope is always the last in the chain.
12081 ASSERT(context_->IsNativeContext());
12082 context_ = Handle<Context>();
12085 if (nested_scope_chain_.is_empty()) {
12086 context_ = Handle<Context>(context_->previous(), isolate_);
12088 if (nested_scope_chain_.last()->HasContext()) {
12089 ASSERT(context_->previous() != NULL);
12090 context_ = Handle<Context>(context_->previous(), isolate_);
12092 nested_scope_chain_.RemoveLast();
12096 // Return the type of the current scope.
12099 if (!nested_scope_chain_.is_empty()) {
12100 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
12101 switch (scope_info->scope_type()) {
12102 case FUNCTION_SCOPE:
12103 ASSERT(context_->IsFunctionContext() ||
12104 !scope_info->HasContext());
12105 return ScopeTypeLocal;
12107 ASSERT(context_->IsModuleContext());
12108 return ScopeTypeModule;
12110 ASSERT(context_->IsNativeContext());
12111 return ScopeTypeGlobal;
12113 ASSERT(context_->IsWithContext());
12114 return ScopeTypeWith;
12116 ASSERT(context_->IsCatchContext());
12117 return ScopeTypeCatch;
12119 ASSERT(!scope_info->HasContext() ||
12120 context_->IsBlockContext());
12121 return ScopeTypeBlock;
12126 if (context_->IsNativeContext()) {
12127 ASSERT(context_->global_object()->IsGlobalObject());
12128 return ScopeTypeGlobal;
12130 if (context_->IsFunctionContext()) {
12131 return ScopeTypeClosure;
12133 if (context_->IsCatchContext()) {
12134 return ScopeTypeCatch;
12136 if (context_->IsBlockContext()) {
12137 return ScopeTypeBlock;
12139 if (context_->IsModuleContext()) {
12140 return ScopeTypeModule;
12142 ASSERT(context_->IsWithContext());
12143 return ScopeTypeWith;
12146 // Return the JavaScript object with the content of the current scope.
12147 Handle<JSObject> ScopeObject() {
12150 case ScopeIterator::ScopeTypeGlobal:
12151 return Handle<JSObject>(CurrentContext()->global_object());
12152 case ScopeIterator::ScopeTypeLocal:
12153 // Materialize the content of the local scope into a JSObject.
12154 ASSERT(nested_scope_chain_.length() == 1);
12155 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
12156 case ScopeIterator::ScopeTypeWith:
12157 // Return the with object.
12158 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
12159 case ScopeIterator::ScopeTypeCatch:
12160 return MaterializeCatchScope(isolate_, CurrentContext());
12161 case ScopeIterator::ScopeTypeClosure:
12162 // Materialize the content of the closure scope into a JSObject.
12163 return MaterializeClosure(isolate_, CurrentContext());
12164 case ScopeIterator::ScopeTypeBlock:
12165 return MaterializeBlockScope(isolate_, CurrentContext());
12166 case ScopeIterator::ScopeTypeModule:
12167 return MaterializeModuleScope(isolate_, CurrentContext());
12170 return Handle<JSObject>();
12173 bool SetVariableValue(Handle<String> variable_name,
12174 Handle<Object> new_value) {
12177 case ScopeIterator::ScopeTypeGlobal:
12179 case ScopeIterator::ScopeTypeLocal:
12180 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
12181 variable_name, new_value);
12182 case ScopeIterator::ScopeTypeWith:
12184 case ScopeIterator::ScopeTypeCatch:
12185 return SetCatchVariableValue(isolate_, CurrentContext(),
12186 variable_name, new_value);
12187 case ScopeIterator::ScopeTypeClosure:
12188 return SetClosureVariableValue(isolate_, CurrentContext(),
12189 variable_name, new_value);
12190 case ScopeIterator::ScopeTypeBlock:
12191 // TODO(2399): should we implement it?
12193 case ScopeIterator::ScopeTypeModule:
12194 // TODO(2399): should we implement it?
12200 Handle<ScopeInfo> CurrentScopeInfo() {
12202 if (!nested_scope_chain_.is_empty()) {
12203 return nested_scope_chain_.last();
12204 } else if (context_->IsBlockContext()) {
12205 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
12206 } else if (context_->IsFunctionContext()) {
12207 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
12209 return Handle<ScopeInfo>::null();
12212 // Return the context for this scope. For the local context there might not
12213 // be an actual context.
12214 Handle<Context> CurrentContext() {
12216 if (Type() == ScopeTypeGlobal ||
12217 nested_scope_chain_.is_empty()) {
12219 } else if (nested_scope_chain_.last()->HasContext()) {
12222 return Handle<Context>();
12227 // Debug print of the content of the current scope.
12228 void DebugPrint() {
12231 case ScopeIterator::ScopeTypeGlobal:
12232 PrintF("Global:\n");
12233 CurrentContext()->Print();
12236 case ScopeIterator::ScopeTypeLocal: {
12237 PrintF("Local:\n");
12238 function_->shared()->scope_info()->Print();
12239 if (!CurrentContext().is_null()) {
12240 CurrentContext()->Print();
12241 if (CurrentContext()->has_extension()) {
12242 Handle<Object> extension(CurrentContext()->extension(), isolate_);
12243 if (extension->IsJSContextExtensionObject()) {
12244 extension->Print();
12251 case ScopeIterator::ScopeTypeWith:
12253 CurrentContext()->extension()->Print();
12256 case ScopeIterator::ScopeTypeCatch:
12257 PrintF("Catch:\n");
12258 CurrentContext()->extension()->Print();
12259 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
12262 case ScopeIterator::ScopeTypeClosure:
12263 PrintF("Closure:\n");
12264 CurrentContext()->Print();
12265 if (CurrentContext()->has_extension()) {
12266 Handle<Object> extension(CurrentContext()->extension(), isolate_);
12267 if (extension->IsJSContextExtensionObject()) {
12268 extension->Print();
12282 JavaScriptFrame* frame_;
12283 int inlined_jsframe_index_;
12284 Handle<JSFunction> function_;
12285 Handle<Context> context_;
12286 List<Handle<ScopeInfo> > nested_scope_chain_;
12289 void RetrieveScopeChain(Scope* scope,
12290 Handle<SharedFunctionInfo> shared_info) {
12291 if (scope != NULL) {
12292 int source_position = shared_info->code()->SourcePosition(frame_->pc());
12293 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
12295 // A failed reparse indicates that the preparser has diverged from the
12296 // parser or that the preparse data given to the initial parse has been
12297 // faulty. We fail in debug mode but in release mode we only provide the
12298 // information we get from the context chain but nothing about
12299 // completely stack allocated scopes or stack allocated locals.
12300 // Or it could be due to stack overflow.
12301 ASSERT(isolate_->has_pending_exception());
12306 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
12310 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
12311 HandleScope scope(isolate);
12312 ASSERT(args.length() == 2);
12314 // Check arguments.
12316 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12317 RUNTIME_ARGUMENTS(isolate, args));
12318 if (!maybe_check->ToObject(&check)) return maybe_check;
12320 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12322 // Get the frame where the debugging is performed.
12323 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12324 JavaScriptFrameIterator it(isolate, id);
12325 JavaScriptFrame* frame = it.frame();
12327 // Count the visible scopes.
12329 for (ScopeIterator it(isolate, frame, 0);
12335 return Smi::FromInt(n);
12339 // Returns the list of step-in positions (text offset) in a function of the
12340 // stack frame in a range from the current debug break position to the end
12341 // of the corresponding statement.
12342 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) {
12343 HandleScope scope(isolate);
12344 ASSERT(args.length() == 2);
12346 // Check arguments.
12348 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12349 RUNTIME_ARGUMENTS(isolate, args));
12350 if (!maybe_check->ToObject(&check)) return maybe_check;
12352 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12354 // Get the frame where the debugging is performed.
12355 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12356 JavaScriptFrameIterator frame_it(isolate, id);
12357 RUNTIME_ASSERT(!frame_it.done());
12359 JavaScriptFrame* frame = frame_it.frame();
12361 Handle<JSFunction> fun =
12362 Handle<JSFunction>(frame->function());
12363 Handle<SharedFunctionInfo> shared =
12364 Handle<SharedFunctionInfo>(fun->shared());
12366 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
12367 return isolate->heap()->undefined_value();
12370 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
12373 Handle<JSArray> array(isolate->factory()->NewJSArray(10));
12374 // Find the break point where execution has stopped.
12375 BreakLocationIterator break_location_iterator(debug_info,
12376 ALL_BREAK_LOCATIONS);
12378 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
12379 int current_statement_pos = break_location_iterator.statement_position();
12381 while (!break_location_iterator.Done()) {
12383 if (break_location_iterator.pc() > frame->pc()) {
12386 StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
12387 // The break point is near our pc. Could be a step-in possibility,
12388 // that is currently taken by active debugger call.
12389 if (break_frame_id == StackFrame::NO_ID) {
12390 // We are not stepping.
12393 JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
12394 // If our frame is a top frame and we are stepping, we can do step-in
12396 accept = additional_frame_it.frame()->id() == id;
12400 if (break_location_iterator.IsStepInLocation(isolate)) {
12401 Smi* position_value = Smi::FromInt(break_location_iterator.position());
12402 JSObject::SetElement(array, len,
12403 Handle<Object>(position_value, isolate),
12408 // Advance iterator.
12409 break_location_iterator.Next();
12410 if (current_statement_pos !=
12411 break_location_iterator.statement_position()) {
12419 static const int kScopeDetailsTypeIndex = 0;
12420 static const int kScopeDetailsObjectIndex = 1;
12421 static const int kScopeDetailsSize = 2;
12424 static Handle<JSObject> MaterializeScopeDetails(Isolate* isolate,
12425 ScopeIterator* it) {
12426 // Calculate the size of the result.
12427 int details_size = kScopeDetailsSize;
12428 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
12430 // Fill in scope details.
12431 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
12432 Handle<JSObject> scope_object = it->ScopeObject();
12433 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, scope_object, Handle<JSObject>());
12434 details->set(kScopeDetailsObjectIndex, *scope_object);
12436 return isolate->factory()->NewJSArrayWithElements(details);
12440 // Return an array with scope details
12441 // args[0]: number: break id
12442 // args[1]: number: frame index
12443 // args[2]: number: inlined frame index
12444 // args[3]: number: scope index
12446 // The array returned contains the following information:
12449 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
12450 HandleScope scope(isolate);
12451 ASSERT(args.length() == 4);
12453 // Check arguments.
12455 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12456 RUNTIME_ARGUMENTS(isolate, args));
12457 if (!maybe_check->ToObject(&check)) return maybe_check;
12459 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12460 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
12461 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
12463 // Get the frame where the debugging is performed.
12464 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12465 JavaScriptFrameIterator frame_it(isolate, id);
12466 JavaScriptFrame* frame = frame_it.frame();
12468 // Find the requested scope.
12470 ScopeIterator it(isolate, frame, inlined_jsframe_index);
12471 for (; !it.Done() && n < index; it.Next()) {
12475 return isolate->heap()->undefined_value();
12477 Handle<JSObject> details = MaterializeScopeDetails(isolate, &it);
12478 RETURN_IF_EMPTY_HANDLE(isolate, details);
12483 // Return an array of scope details
12484 // args[0]: number: break id
12485 // args[1]: number: frame index
12486 // args[2]: number: inlined frame index
12487 // args[3]: boolean: ignore nested scopes
12489 // The array returned contains arrays with the following information:
12492 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAllScopesDetails) {
12493 HandleScope scope(isolate);
12494 ASSERT(args.length() == 3 || args.length() == 4);
12496 // Check arguments.
12498 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12499 RUNTIME_ARGUMENTS(isolate, args));
12500 if (!maybe_check->ToObject(&check)) return maybe_check;
12502 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12503 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
12505 bool ignore_nested_scopes = false;
12506 if (args.length() == 4) {
12507 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3);
12508 ignore_nested_scopes = flag;
12511 // Get the frame where the debugging is performed.
12512 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12513 JavaScriptFrameIterator frame_it(isolate, id);
12514 JavaScriptFrame* frame = frame_it.frame();
12516 List<Handle<JSObject> > result(4);
12517 ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes);
12518 for (; !it.Done(); it.Next()) {
12519 Handle<JSObject> details = MaterializeScopeDetails(isolate, &it);
12520 RETURN_IF_EMPTY_HANDLE(isolate, details);
12521 result.Add(details);
12524 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length());
12525 for (int i = 0; i < result.length(); ++i) {
12526 array->set(i, *result[i]);
12528 return *isolate->factory()->NewJSArrayWithElements(array);
12532 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) {
12533 HandleScope scope(isolate);
12534 ASSERT(args.length() == 1);
12536 // Check arguments.
12537 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12539 // Count the visible scopes.
12541 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
12545 return Smi::FromInt(n);
12549 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) {
12550 HandleScope scope(isolate);
12551 ASSERT(args.length() == 2);
12553 // Check arguments.
12554 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12555 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12557 // Find the requested scope.
12559 ScopeIterator it(isolate, fun);
12560 for (; !it.Done() && n < index; it.Next()) {
12564 return isolate->heap()->undefined_value();
12567 Handle<JSObject> details = MaterializeScopeDetails(isolate, &it);
12568 RETURN_IF_EMPTY_HANDLE(isolate, details);
12573 static bool SetScopeVariableValue(ScopeIterator* it, int index,
12574 Handle<String> variable_name,
12575 Handle<Object> new_value) {
12576 for (int n = 0; !it->Done() && n < index; it->Next()) {
12582 return it->SetVariableValue(variable_name, new_value);
12586 // Change variable value in closure or local scope
12587 // args[0]: number or JsFunction: break id or function
12588 // args[1]: number: frame index (when arg[0] is break id)
12589 // args[2]: number: inlined frame index (when arg[0] is break id)
12590 // args[3]: number: scope index
12591 // args[4]: string: variable name
12592 // args[5]: object: new value
12594 // Return true if success and false otherwise
12595 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScopeVariableValue) {
12596 HandleScope scope(isolate);
12597 ASSERT(args.length() == 6);
12599 // Check arguments.
12600 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
12601 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
12602 Handle<Object> new_value = args.at<Object>(5);
12605 if (args[0]->IsNumber()) {
12607 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12608 RUNTIME_ARGUMENTS(isolate, args));
12609 if (!maybe_check->ToObject(&check)) return maybe_check;
12611 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12612 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
12614 // Get the frame where the debugging is performed.
12615 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12616 JavaScriptFrameIterator frame_it(isolate, id);
12617 JavaScriptFrame* frame = frame_it.frame();
12619 ScopeIterator it(isolate, frame, inlined_jsframe_index);
12620 res = SetScopeVariableValue(&it, index, variable_name, new_value);
12622 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12623 ScopeIterator it(isolate, fun);
12624 res = SetScopeVariableValue(&it, index, variable_name, new_value);
12627 return isolate->heap()->ToBoolean(res);
12631 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
12632 HandleScope scope(isolate);
12633 ASSERT(args.length() == 0);
12636 // Print the scopes for the top frame.
12637 StackFrameLocator locator(isolate);
12638 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
12639 for (ScopeIterator it(isolate, frame, 0);
12645 return isolate->heap()->undefined_value();
12649 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
12650 HandleScope scope(isolate);
12651 ASSERT(args.length() == 1);
12653 // Check arguments.
12655 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
12656 RUNTIME_ARGUMENTS(isolate, args));
12657 if (!maybe_result->ToObject(&result)) return maybe_result;
12660 // Count all archived V8 threads.
12662 for (ThreadState* thread =
12663 isolate->thread_manager()->FirstThreadStateInUse();
12665 thread = thread->Next()) {
12669 // Total number of threads is current thread and archived threads.
12670 return Smi::FromInt(n + 1);
12674 static const int kThreadDetailsCurrentThreadIndex = 0;
12675 static const int kThreadDetailsThreadIdIndex = 1;
12676 static const int kThreadDetailsSize = 2;
12678 // Return an array with thread details
12679 // args[0]: number: break id
12680 // args[1]: number: thread index
12682 // The array returned contains the following information:
12683 // 0: Is current thread?
12685 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
12686 HandleScope scope(isolate);
12687 ASSERT(args.length() == 2);
12689 // Check arguments.
12691 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12692 RUNTIME_ARGUMENTS(isolate, args));
12693 if (!maybe_check->ToObject(&check)) return maybe_check;
12695 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12697 // Allocate array for result.
12698 Handle<FixedArray> details =
12699 isolate->factory()->NewFixedArray(kThreadDetailsSize);
12701 // Thread index 0 is current thread.
12703 // Fill the details.
12704 details->set(kThreadDetailsCurrentThreadIndex,
12705 isolate->heap()->true_value());
12706 details->set(kThreadDetailsThreadIdIndex,
12707 Smi::FromInt(ThreadId::Current().ToInteger()));
12709 // Find the thread with the requested index.
12711 ThreadState* thread =
12712 isolate->thread_manager()->FirstThreadStateInUse();
12713 while (index != n && thread != NULL) {
12714 thread = thread->Next();
12717 if (thread == NULL) {
12718 return isolate->heap()->undefined_value();
12721 // Fill the details.
12722 details->set(kThreadDetailsCurrentThreadIndex,
12723 isolate->heap()->false_value());
12724 details->set(kThreadDetailsThreadIdIndex,
12725 Smi::FromInt(thread->id().ToInteger()));
12728 // Convert to JS array and return.
12729 return *isolate->factory()->NewJSArrayWithElements(details);
12733 // Sets the disable break state
12734 // args[0]: disable break state
12735 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
12736 HandleScope scope(isolate);
12737 ASSERT(args.length() == 1);
12738 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
12739 isolate->debug()->set_disable_break(disable_break);
12740 return isolate->heap()->undefined_value();
12744 static bool IsPositionAlignmentCodeCorrect(int alignment) {
12745 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
12749 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
12750 HandleScope scope(isolate);
12751 ASSERT(args.length() == 2);
12753 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12754 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
12756 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
12757 return isolate->ThrowIllegalOperation();
12759 BreakPositionAlignment alignment =
12760 static_cast<BreakPositionAlignment>(statement_aligned_code);
12762 Handle<SharedFunctionInfo> shared(fun->shared());
12763 // Find the number of break points
12764 Handle<Object> break_locations =
12765 Debug::GetSourceBreakLocations(shared, alignment);
12766 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
12767 // Return array as JS array
12768 return *isolate->factory()->NewJSArrayWithElements(
12769 Handle<FixedArray>::cast(break_locations));
12773 // Set a break point in a function.
12774 // args[0]: function
12775 // args[1]: number: break source position (within the function source)
12776 // args[2]: number: break point object
12777 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
12778 HandleScope scope(isolate);
12779 ASSERT(args.length() == 3);
12780 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12781 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12782 RUNTIME_ASSERT(source_position >= 0);
12783 Handle<Object> break_point_object_arg = args.at<Object>(2);
12785 // Set break point.
12786 isolate->debug()->SetBreakPoint(function, break_point_object_arg,
12789 return Smi::FromInt(source_position);
12793 // Changes the state of a break point in a script and returns source position
12794 // where break point was set. NOTE: Regarding performance see the NOTE for
12795 // GetScriptFromScriptData.
12796 // args[0]: script to set break point in
12797 // args[1]: number: break source position (within the script source)
12798 // args[2]: number, breakpoint position alignment
12799 // args[3]: number: break point object
12800 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
12801 HandleScope scope(isolate);
12802 ASSERT(args.length() == 4);
12803 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
12804 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12805 RUNTIME_ASSERT(source_position >= 0);
12806 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
12807 Handle<Object> break_point_object_arg = args.at<Object>(3);
12809 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
12810 return isolate->ThrowIllegalOperation();
12812 BreakPositionAlignment alignment =
12813 static_cast<BreakPositionAlignment>(statement_aligned_code);
12815 // Get the script from the script wrapper.
12816 RUNTIME_ASSERT(wrapper->value()->IsScript());
12817 Handle<Script> script(Script::cast(wrapper->value()));
12819 // Set break point.
12820 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
12823 return isolate->heap()->undefined_value();
12826 return Smi::FromInt(source_position);
12830 // Clear a break point
12831 // args[0]: number: break point object
12832 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
12833 HandleScope scope(isolate);
12834 ASSERT(args.length() == 1);
12835 Handle<Object> break_point_object_arg = args.at<Object>(0);
12837 // Clear break point.
12838 isolate->debug()->ClearBreakPoint(break_point_object_arg);
12840 return isolate->heap()->undefined_value();
12844 // Change the state of break on exceptions.
12845 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
12846 // args[1]: Boolean indicating on/off.
12847 RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
12848 HandleScope scope(isolate);
12849 ASSERT(args.length() == 2);
12850 RUNTIME_ASSERT(args[0]->IsNumber());
12851 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
12853 // If the number doesn't match an enum value, the ChangeBreakOnException
12854 // function will default to affecting caught exceptions.
12855 ExceptionBreakType type =
12856 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
12857 // Update break point state.
12858 isolate->debug()->ChangeBreakOnException(type, enable);
12859 return isolate->heap()->undefined_value();
12863 // Returns the state of break on exceptions
12864 // args[0]: boolean indicating uncaught exceptions
12865 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
12866 HandleScope scope(isolate);
12867 ASSERT(args.length() == 1);
12868 RUNTIME_ASSERT(args[0]->IsNumber());
12870 ExceptionBreakType type =
12871 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
12872 bool result = isolate->debug()->IsBreakOnException(type);
12873 return Smi::FromInt(result);
12877 // Prepare for stepping
12878 // args[0]: break id for checking execution state
12879 // args[1]: step action from the enumeration StepAction
12880 // args[2]: number of times to perform the step, for step out it is the number
12881 // of frames to step down.
12882 RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
12883 HandleScope scope(isolate);
12884 ASSERT(args.length() == 4);
12885 // Check arguments.
12887 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12888 RUNTIME_ARGUMENTS(isolate, args));
12889 if (!maybe_check->ToObject(&check)) return maybe_check;
12891 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
12892 return isolate->Throw(isolate->heap()->illegal_argument_string());
12895 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
12897 StackFrame::Id frame_id;
12898 if (wrapped_frame_id == 0) {
12899 frame_id = StackFrame::NO_ID;
12901 frame_id = UnwrapFrameId(wrapped_frame_id);
12904 // Get the step action and check validity.
12905 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
12906 if (step_action != StepIn &&
12907 step_action != StepNext &&
12908 step_action != StepOut &&
12909 step_action != StepInMin &&
12910 step_action != StepMin) {
12911 return isolate->Throw(isolate->heap()->illegal_argument_string());
12914 if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
12915 step_action != StepMin && step_action != StepOut) {
12916 return isolate->ThrowIllegalOperation();
12919 // Get the number of steps.
12920 int step_count = NumberToInt32(args[2]);
12921 if (step_count < 1) {
12922 return isolate->Throw(isolate->heap()->illegal_argument_string());
12925 // Clear all current stepping setup.
12926 isolate->debug()->ClearStepping();
12929 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
12932 return isolate->heap()->undefined_value();
12936 // Clear all stepping set by PrepareStep.
12937 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
12938 HandleScope scope(isolate);
12939 ASSERT(args.length() == 0);
12940 isolate->debug()->ClearStepping();
12941 return isolate->heap()->undefined_value();
12945 // Helper function to find or create the arguments object for
12946 // Runtime_DebugEvaluate.
12947 static Handle<JSObject> MaterializeArgumentsObject(
12949 Handle<JSObject> target,
12950 Handle<JSFunction> function) {
12951 // Do not materialize the arguments object for eval or top-level code.
12952 // Skip if "arguments" is already taken.
12953 if (!function->shared()->is_function() ||
12954 JSReceiver::HasLocalProperty(target,
12955 isolate->factory()->arguments_string())) {
12959 // FunctionGetArguments can't throw an exception.
12960 Handle<JSObject> arguments = Handle<JSObject>::cast(
12961 Accessors::FunctionGetArguments(function));
12962 Runtime::SetObjectProperty(isolate, target,
12963 isolate->factory()->arguments_string(),
12971 // Compile and evaluate source for the given context.
12972 static MaybeObject* DebugEvaluate(Isolate* isolate,
12973 Handle<Context> context,
12974 Handle<Object> context_extension,
12975 Handle<Object> receiver,
12976 Handle<String> source) {
12977 if (context_extension->IsJSObject()) {
12978 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
12979 Handle<JSFunction> closure(context->closure(), isolate);
12980 context = isolate->factory()->NewWithContext(closure, context, extension);
12983 Handle<JSFunction> eval_fun =
12984 Compiler::GetFunctionFromEval(source,
12987 NO_PARSE_RESTRICTION,
12988 RelocInfo::kNoPosition);
12989 RETURN_IF_EMPTY_HANDLE(isolate, eval_fun);
12991 bool pending_exception;
12992 Handle<Object> result = Execution::Call(
12993 isolate, eval_fun, receiver, 0, NULL, &pending_exception);
12995 if (pending_exception) return Failure::Exception();
12997 // Skip the global proxy as it has no properties and always delegates to the
12998 // real global object.
12999 if (result->IsJSGlobalProxy()) {
13000 result = Handle<JSObject>(JSObject::cast(result->GetPrototype(isolate)));
13003 // Clear the oneshot breakpoints so that the debugger does not step further.
13004 isolate->debug()->ClearStepping();
13009 // Evaluate a piece of JavaScript in the context of a stack frame for
13010 // debugging. Things that need special attention are:
13011 // - Parameters and stack-allocated locals need to be materialized. Altered
13012 // values need to be written back to the stack afterwards.
13013 // - The arguments object needs to materialized.
13014 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
13015 HandleScope scope(isolate);
13017 // Check the execution state and decode arguments frame and source to be
13019 ASSERT(args.length() == 6);
13020 Object* check_result;
13021 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
13022 RUNTIME_ARGUMENTS(isolate, args));
13023 if (!maybe_result->ToObject(&check_result)) return maybe_result;
13025 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
13026 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
13027 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
13028 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
13029 Handle<Object> context_extension(args[5], isolate);
13031 // Handle the processing of break.
13032 DisableBreak disable_break_save(isolate, disable_break);
13034 // Get the frame where the debugging is performed.
13035 StackFrame::Id id = UnwrapFrameId(wrapped_id);
13036 JavaScriptFrameIterator it(isolate, id);
13037 JavaScriptFrame* frame = it.frame();
13038 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
13039 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
13041 // Traverse the saved contexts chain to find the active context for the
13043 SaveContext* save = FindSavedContextForFrame(isolate, frame);
13045 SaveContext savex(isolate);
13046 isolate->set_context(*(save->context()));
13048 // Evaluate on the context of the frame.
13049 Handle<Context> context(Context::cast(frame->context()));
13050 ASSERT(!context.is_null());
13052 // Materialize stack locals and the arguments object.
13053 Handle<JSObject> materialized =
13054 isolate->factory()->NewJSObject(isolate->object_function());
13056 materialized = MaterializeStackLocalsWithFrameInspector(
13057 isolate, materialized, function, &frame_inspector);
13058 RETURN_IF_EMPTY_HANDLE(isolate, materialized);
13060 materialized = MaterializeArgumentsObject(isolate, materialized, function);
13061 RETURN_IF_EMPTY_HANDLE(isolate, materialized);
13063 // Add the materialized object in a with-scope to shadow the stack locals.
13064 context = isolate->factory()->NewWithContext(function, context, materialized);
13066 Handle<Object> receiver(frame->receiver(), isolate);
13067 Object* evaluate_result_object;
13068 { MaybeObject* maybe_result =
13069 DebugEvaluate(isolate, context, context_extension, receiver, source);
13070 if (!maybe_result->ToObject(&evaluate_result_object)) return maybe_result;
13073 Handle<Object> result(evaluate_result_object, isolate);
13075 // Write back potential changes to materialized stack locals to the stack.
13076 UpdateStackLocalsFromMaterializedObject(
13077 isolate, materialized, function, frame, inlined_jsframe_index);
13083 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
13084 HandleScope scope(isolate);
13086 // Check the execution state and decode arguments frame and source to be
13088 ASSERT(args.length() == 4);
13089 Object* check_result;
13090 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
13091 RUNTIME_ARGUMENTS(isolate, args));
13092 if (!maybe_result->ToObject(&check_result)) return maybe_result;
13094 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
13095 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
13096 Handle<Object> context_extension(args[3], isolate);
13098 // Handle the processing of break.
13099 DisableBreak disable_break_save(isolate, disable_break);
13101 // Enter the top context from before the debugger was invoked.
13102 SaveContext save(isolate);
13103 SaveContext* top = &save;
13104 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
13108 isolate->set_context(*top->context());
13111 // Get the native context now set to the top context from before the
13112 // debugger was invoked.
13113 Handle<Context> context = isolate->native_context();
13114 Handle<Object> receiver = isolate->global_object();
13115 return DebugEvaluate(isolate, context, context_extension, receiver, source);
13119 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
13120 HandleScope scope(isolate);
13121 ASSERT(args.length() == 0);
13123 // Fill the script objects.
13124 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
13126 // Convert the script objects to proper JS objects.
13127 for (int i = 0; i < instances->length(); i++) {
13128 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
13129 // Get the script wrapper in a local handle before calling GetScriptWrapper,
13131 // instances->set(i, *GetScriptWrapper(script))
13132 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
13133 // already have dereferenced the instances handle.
13134 Handle<JSValue> wrapper = GetScriptWrapper(script);
13135 instances->set(i, *wrapper);
13138 // Return result as a JS array.
13139 Handle<JSObject> result =
13140 isolate->factory()->NewJSObject(isolate->array_function());
13141 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
13146 // Helper function used by Runtime_DebugReferencedBy below.
13147 static int DebugReferencedBy(HeapIterator* iterator,
13149 Object* instance_filter, int max_references,
13150 FixedArray* instances, int instances_size,
13151 JSFunction* arguments_function) {
13152 Isolate* isolate = target->GetIsolate();
13153 SealHandleScope shs(isolate);
13154 DisallowHeapAllocation no_allocation;
13156 // Iterate the heap.
13158 JSObject* last = NULL;
13159 HeapObject* heap_obj = NULL;
13160 while (((heap_obj = iterator->next()) != NULL) &&
13161 (max_references == 0 || count < max_references)) {
13162 // Only look at all JSObjects.
13163 if (heap_obj->IsJSObject()) {
13164 // Skip context extension objects and argument arrays as these are
13165 // checked in the context of functions using them.
13166 JSObject* obj = JSObject::cast(heap_obj);
13167 if (obj->IsJSContextExtensionObject() ||
13168 obj->map()->constructor() == arguments_function) {
13172 // Check if the JS object has a reference to the object looked for.
13173 if (obj->ReferencesObject(target)) {
13174 // Check instance filter if supplied. This is normally used to avoid
13175 // references from mirror objects (see Runtime_IsInPrototypeChain).
13176 if (!instance_filter->IsUndefined()) {
13179 Object* prototype = V->GetPrototype(isolate);
13180 if (prototype->IsNull()) {
13183 if (instance_filter == prototype) {
13184 obj = NULL; // Don't add this object.
13192 // Valid reference found add to instance array if supplied an update
13194 if (instances != NULL && count < instances_size) {
13195 instances->set(count, obj);
13204 // Check for circular reference only. This can happen when the object is only
13205 // referenced from mirrors and has a circular reference in which case the
13206 // object is not really alive and would have been garbage collected if not
13207 // referenced from the mirror.
13208 if (count == 1 && last == target) {
13212 // Return the number of referencing objects found.
13217 // Scan the heap for objects with direct references to an object
13218 // args[0]: the object to find references to
13219 // args[1]: constructor function for instances to exclude (Mirror)
13220 // args[2]: the the maximum number of objects to return
13221 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
13222 HandleScope scope(isolate);
13223 ASSERT(args.length() == 3);
13225 // First perform a full GC in order to avoid references from dead objects.
13226 Heap* heap = isolate->heap();
13227 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugReferencedBy");
13228 // The heap iterator reserves the right to do a GC to make the heap iterable.
13229 // Due to the GC above we know it won't need to do that, but it seems cleaner
13230 // to get the heap iterator constructed before we start having unprotected
13231 // Object* locals that are not protected by handles.
13233 // Check parameters.
13234 CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
13235 Handle<Object> instance_filter = args.at<Object>(1);
13236 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
13237 instance_filter->IsJSObject());
13238 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
13239 RUNTIME_ASSERT(max_references >= 0);
13242 // Get the constructor function for context extension and arguments array.
13243 Handle<JSObject> arguments_boilerplate(
13244 isolate->context()->native_context()->sloppy_arguments_boilerplate());
13245 Handle<JSFunction> arguments_function(
13246 JSFunction::cast(arguments_boilerplate->map()->constructor()));
13248 // Get the number of referencing objects.
13250 HeapIterator heap_iterator(heap);
13251 count = DebugReferencedBy(&heap_iterator,
13252 *target, *instance_filter, max_references,
13253 NULL, 0, *arguments_function);
13255 // Allocate an array to hold the result.
13256 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
13258 // Fill the referencing objects.
13259 // AllocateFixedArray above does not make the heap non-iterable.
13260 ASSERT(heap->IsHeapIterable());
13261 HeapIterator heap_iterator2(heap);
13262 count = DebugReferencedBy(&heap_iterator2,
13263 *target, *instance_filter, max_references,
13264 *instances, count, *arguments_function);
13266 // Return result as JS array.
13267 Handle<JSFunction> constructor(
13268 isolate->context()->native_context()->array_function());
13270 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
13271 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
13276 // Helper function used by Runtime_DebugConstructedBy below.
13277 static int DebugConstructedBy(HeapIterator* iterator,
13278 JSFunction* constructor,
13279 int max_references,
13280 FixedArray* instances,
13281 int instances_size) {
13282 DisallowHeapAllocation no_allocation;
13284 // Iterate the heap.
13286 HeapObject* heap_obj = NULL;
13287 while (((heap_obj = iterator->next()) != NULL) &&
13288 (max_references == 0 || count < max_references)) {
13289 // Only look at all JSObjects.
13290 if (heap_obj->IsJSObject()) {
13291 JSObject* obj = JSObject::cast(heap_obj);
13292 if (obj->map()->constructor() == constructor) {
13293 // Valid reference found add to instance array if supplied an update
13295 if (instances != NULL && count < instances_size) {
13296 instances->set(count, obj);
13303 // Return the number of referencing objects found.
13308 // Scan the heap for objects constructed by a specific function.
13309 // args[0]: the constructor to find instances of
13310 // args[1]: the the maximum number of objects to return
13311 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
13312 HandleScope scope(isolate);
13313 ASSERT(args.length() == 2);
13315 // First perform a full GC in order to avoid dead objects.
13316 Heap* heap = isolate->heap();
13317 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
13319 // Check parameters.
13320 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
13321 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
13322 RUNTIME_ASSERT(max_references >= 0);
13324 // Get the number of referencing objects.
13326 HeapIterator heap_iterator(heap);
13327 count = DebugConstructedBy(&heap_iterator,
13333 // Allocate an array to hold the result.
13334 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
13336 ASSERT(heap->IsHeapIterable());
13337 // Fill the referencing objects.
13338 HeapIterator heap_iterator2(heap);
13339 count = DebugConstructedBy(&heap_iterator2,
13345 // Return result as JS array.
13346 Handle<JSFunction> array_function(
13347 isolate->context()->native_context()->array_function());
13348 Handle<JSObject> result = isolate->factory()->NewJSObject(array_function);
13349 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
13354 // Find the effective prototype object as returned by __proto__.
13355 // args[0]: the object to find the prototype for.
13356 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
13357 SealHandleScope shs(isolate);
13358 ASSERT(args.length() == 1);
13359 CONVERT_ARG_CHECKED(JSObject, obj, 0);
13360 return GetPrototypeSkipHiddenPrototypes(isolate, obj);
13364 // Patches script source (should be called upon BeforeCompile event).
13365 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
13366 HandleScope scope(isolate);
13367 ASSERT(args.length() == 2);
13369 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
13370 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
13372 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
13373 Handle<Script> script(Script::cast(script_wrapper->value()));
13375 int compilation_state = script->compilation_state();
13376 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
13377 script->set_source(*source);
13379 return isolate->heap()->undefined_value();
13383 RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
13384 SealHandleScope shs(isolate);
13385 ASSERT(args.length() == 0);
13387 return isolate->heap()->undefined_value();
13391 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
13392 HandleScope scope(isolate);
13394 ASSERT(args.length() == 1);
13395 // Get the function and make sure it is compiled.
13396 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
13397 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
13398 return Failure::Exception();
13400 func->code()->PrintLn();
13402 return isolate->heap()->undefined_value();
13406 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
13407 HandleScope scope(isolate);
13409 ASSERT(args.length() == 1);
13410 // Get the function and make sure it is compiled.
13411 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
13412 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
13413 return Failure::Exception();
13415 func->shared()->construct_stub()->PrintLn();
13417 return isolate->heap()->undefined_value();
13421 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
13422 SealHandleScope shs(isolate);
13423 ASSERT(args.length() == 1);
13425 CONVERT_ARG_CHECKED(JSFunction, f, 0);
13426 return f->shared()->inferred_name();
13430 static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
13432 FixedArray* buffer) {
13433 DisallowHeapAllocation no_allocation;
13435 int buffer_size = buffer->length();
13436 for (HeapObject* obj = iterator->next();
13438 obj = iterator->next()) {
13439 ASSERT(obj != NULL);
13440 if (!obj->IsSharedFunctionInfo()) {
13443 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
13444 if (shared->script() != script) {
13447 if (counter < buffer_size) {
13448 buffer->set(counter, shared);
13456 // For a script finds all SharedFunctionInfo's in the heap that points
13457 // to this script. Returns JSArray of SharedFunctionInfo wrapped
13458 // in OpaqueReferences.
13459 RUNTIME_FUNCTION(MaybeObject*,
13460 Runtime_LiveEditFindSharedFunctionInfosForScript) {
13461 HandleScope scope(isolate);
13462 CHECK(isolate->debugger()->live_edit_enabled());
13463 ASSERT(args.length() == 1);
13464 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
13466 RUNTIME_ASSERT(script_value->value()->IsScript());
13467 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
13469 const int kBufferSize = 32;
13471 Handle<FixedArray> array;
13472 array = isolate->factory()->NewFixedArray(kBufferSize);
13474 Heap* heap = isolate->heap();
13476 heap->EnsureHeapIsIterable();
13477 DisallowHeapAllocation no_allocation;
13478 HeapIterator heap_iterator(heap);
13479 Script* scr = *script;
13480 FixedArray* arr = *array;
13481 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
13483 if (number > kBufferSize) {
13484 array = isolate->factory()->NewFixedArray(number);
13485 heap->EnsureHeapIsIterable();
13486 DisallowHeapAllocation no_allocation;
13487 HeapIterator heap_iterator(heap);
13488 Script* scr = *script;
13489 FixedArray* arr = *array;
13490 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
13493 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
13494 result->set_length(Smi::FromInt(number));
13496 LiveEdit::WrapSharedFunctionInfos(result);
13502 // For a script calculates compilation information about all its functions.
13503 // The script source is explicitly specified by the second argument.
13504 // The source of the actual script is not used, however it is important that
13505 // all generated code keeps references to this particular instance of script.
13506 // Returns a JSArray of compilation infos. The array is ordered so that
13507 // each function with all its descendant is always stored in a continues range
13508 // with the function itself going first. The root function is a script function.
13509 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
13510 HandleScope scope(isolate);
13511 CHECK(isolate->debugger()->live_edit_enabled());
13512 ASSERT(args.length() == 2);
13513 CONVERT_ARG_CHECKED(JSValue, script, 0);
13514 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
13516 RUNTIME_ASSERT(script->value()->IsScript());
13517 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
13519 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
13521 if (isolate->has_pending_exception()) {
13522 return Failure::Exception();
13529 // Changes the source of the script to a new_source.
13530 // If old_script_name is provided (i.e. is a String), also creates a copy of
13531 // the script with its original source and sends notification to debugger.
13532 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
13533 HandleScope scope(isolate);
13534 CHECK(isolate->debugger()->live_edit_enabled());
13535 ASSERT(args.length() == 3);
13536 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
13537 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
13538 Handle<Object> old_script_name(args[2], isolate);
13540 RUNTIME_ASSERT(original_script_value->value()->IsScript());
13541 Handle<Script> original_script(Script::cast(original_script_value->value()));
13543 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
13547 if (old_script->IsScript()) {
13548 Handle<Script> script_handle(Script::cast(old_script));
13549 return *(GetScriptWrapper(script_handle));
13551 return isolate->heap()->null_value();
13556 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
13557 HandleScope scope(isolate);
13558 CHECK(isolate->debugger()->live_edit_enabled());
13559 ASSERT(args.length() == 1);
13560 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
13561 return LiveEdit::FunctionSourceUpdated(shared_info);
13565 // Replaces code of SharedFunctionInfo with a new one.
13566 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
13567 HandleScope scope(isolate);
13568 CHECK(isolate->debugger()->live_edit_enabled());
13569 ASSERT(args.length() == 2);
13570 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
13571 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
13573 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
13577 // Connects SharedFunctionInfo to another script.
13578 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
13579 HandleScope scope(isolate);
13580 CHECK(isolate->debugger()->live_edit_enabled());
13581 ASSERT(args.length() == 2);
13582 Handle<Object> function_object(args[0], isolate);
13583 Handle<Object> script_object(args[1], isolate);
13585 if (function_object->IsJSValue()) {
13586 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
13587 if (script_object->IsJSValue()) {
13588 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
13589 Script* script = Script::cast(JSValue::cast(*script_object)->value());
13590 script_object = Handle<Object>(script, isolate);
13593 LiveEdit::SetFunctionScript(function_wrapper, script_object);
13595 // Just ignore this. We may not have a SharedFunctionInfo for some functions
13596 // and we check it in this function.
13599 return isolate->heap()->undefined_value();
13603 // In a code of a parent function replaces original function as embedded object
13604 // with a substitution one.
13605 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
13606 HandleScope scope(isolate);
13607 CHECK(isolate->debugger()->live_edit_enabled());
13608 ASSERT(args.length() == 3);
13610 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
13611 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
13612 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
13614 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
13617 return isolate->heap()->undefined_value();
13621 // Updates positions of a shared function info (first parameter) according
13622 // to script source change. Text change is described in second parameter as
13623 // array of groups of 3 numbers:
13624 // (change_begin, change_end, change_end_new_position).
13625 // Each group describes a change in text; groups are sorted by change_begin.
13626 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
13627 HandleScope scope(isolate);
13628 CHECK(isolate->debugger()->live_edit_enabled());
13629 ASSERT(args.length() == 2);
13630 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
13631 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
13633 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
13637 // For array of SharedFunctionInfo's (each wrapped in JSValue)
13638 // checks that none of them have activations on stacks (of any thread).
13639 // Returns array of the same length with corresponding results of
13640 // LiveEdit::FunctionPatchabilityStatus type.
13641 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
13642 HandleScope scope(isolate);
13643 CHECK(isolate->debugger()->live_edit_enabled());
13644 ASSERT(args.length() == 2);
13645 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
13646 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
13648 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
13652 // Compares 2 strings line-by-line, then token-wise and returns diff in form
13653 // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
13655 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
13656 HandleScope scope(isolate);
13657 CHECK(isolate->debugger()->live_edit_enabled());
13658 ASSERT(args.length() == 2);
13659 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
13660 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
13662 return *LiveEdit::CompareStrings(s1, s2);
13666 // Restarts a call frame and completely drops all frames above.
13667 // Returns true if successful. Otherwise returns undefined or an error message.
13668 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditRestartFrame) {
13669 HandleScope scope(isolate);
13670 CHECK(isolate->debugger()->live_edit_enabled());
13671 ASSERT(args.length() == 2);
13673 // Check arguments.
13675 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
13676 RUNTIME_ARGUMENTS(isolate, args));
13677 if (!maybe_check->ToObject(&check)) return maybe_check;
13679 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
13680 Heap* heap = isolate->heap();
13682 // Find the relevant frame with the requested index.
13683 StackFrame::Id id = isolate->debug()->break_frame_id();
13684 if (id == StackFrame::NO_ID) {
13685 // If there are no JavaScript stack frames return undefined.
13686 return heap->undefined_value();
13690 JavaScriptFrameIterator it(isolate, id);
13691 for (; !it.done(); it.Advance()) {
13692 if (index < count + it.frame()->GetInlineCount()) break;
13693 count += it.frame()->GetInlineCount();
13695 if (it.done()) return heap->undefined_value();
13697 const char* error_message = LiveEdit::RestartFrame(it.frame());
13698 if (error_message) {
13699 return *(isolate->factory()->InternalizeUtf8String(error_message));
13701 return heap->true_value();
13705 // A testing entry. Returns statement position which is the closest to
13706 // source_position.
13707 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
13708 HandleScope scope(isolate);
13709 CHECK(isolate->debugger()->live_edit_enabled());
13710 ASSERT(args.length() == 2);
13711 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
13712 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
13714 Handle<Code> code(function->code(), isolate);
13716 if (code->kind() != Code::FUNCTION &&
13717 code->kind() != Code::OPTIMIZED_FUNCTION) {
13718 return isolate->heap()->undefined_value();
13721 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
13722 int closest_pc = 0;
13723 int distance = kMaxInt;
13724 while (!it.done()) {
13725 int statement_position = static_cast<int>(it.rinfo()->data());
13726 // Check if this break point is closer that what was previously found.
13727 if (source_position <= statement_position &&
13728 statement_position - source_position < distance) {
13730 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
13731 distance = statement_position - source_position;
13732 // Check whether we can't get any closer.
13733 if (distance == 0) break;
13738 return Smi::FromInt(closest_pc);
13742 // Calls specified function with or without entering the debugger.
13743 // This is used in unit tests to run code as if debugger is entered or simply
13744 // to have a stack with C++ frame in the middle.
13745 RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
13746 HandleScope scope(isolate);
13747 ASSERT(args.length() == 2);
13748 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
13749 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
13751 Handle<Object> result;
13752 bool pending_exception;
13754 if (without_debugger) {
13755 result = Execution::Call(isolate,
13757 isolate->global_object(),
13760 &pending_exception);
13762 EnterDebugger enter_debugger(isolate);
13763 result = Execution::Call(isolate,
13765 isolate->global_object(),
13768 &pending_exception);
13771 if (!pending_exception) {
13774 return Failure::Exception();
13780 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
13781 SealHandleScope shs(isolate);
13782 CONVERT_ARG_CHECKED(String, arg, 0);
13783 SmartArrayPointer<char> flags =
13784 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
13785 FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get()));
13786 return isolate->heap()->undefined_value();
13791 // Presently, it only does a full GC.
13792 RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
13793 SealHandleScope shs(isolate);
13794 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
13795 return isolate->heap()->undefined_value();
13799 // Gets the current heap usage.
13800 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
13801 SealHandleScope shs(isolate);
13802 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
13803 if (!Smi::IsValid(usage)) {
13804 return *isolate->factory()->NewNumberFromInt(usage);
13806 return Smi::FromInt(usage);
13809 #endif // ENABLE_DEBUGGER_SUPPORT
13812 #ifdef V8_I18N_SUPPORT
13813 RUNTIME_FUNCTION(MaybeObject*, Runtime_CanonicalizeLanguageTag) {
13814 HandleScope scope(isolate);
13816 ASSERT(args.length() == 1);
13817 CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0);
13819 v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str));
13821 // Return value which denotes invalid language tag.
13822 const char* const kInvalidTag = "invalid-tag";
13824 UErrorCode error = U_ZERO_ERROR;
13825 char icu_result[ULOC_FULLNAME_CAPACITY];
13826 int icu_length = 0;
13828 uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY,
13829 &icu_length, &error);
13830 if (U_FAILURE(error) || icu_length == 0) {
13831 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag));
13834 char result[ULOC_FULLNAME_CAPACITY];
13836 // Force strict BCP47 rules.
13837 uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
13839 if (U_FAILURE(error)) {
13840 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag));
13843 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result));
13847 RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) {
13848 HandleScope scope(isolate);
13850 ASSERT(args.length() == 1);
13851 CONVERT_ARG_HANDLE_CHECKED(String, service, 0);
13853 const icu::Locale* available_locales = NULL;
13856 if (service->IsUtf8EqualTo(CStrVector("collator"))) {
13857 available_locales = icu::Collator::getAvailableLocales(count);
13858 } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) {
13859 available_locales = icu::NumberFormat::getAvailableLocales(count);
13860 } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) {
13861 available_locales = icu::DateFormat::getAvailableLocales(count);
13862 } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) {
13863 available_locales = icu::BreakIterator::getAvailableLocales(count);
13866 UErrorCode error = U_ZERO_ERROR;
13867 char result[ULOC_FULLNAME_CAPACITY];
13868 Handle<JSObject> locales =
13869 isolate->factory()->NewJSObject(isolate->object_function());
13871 for (int32_t i = 0; i < count; ++i) {
13872 const char* icu_name = available_locales[i].getName();
13874 error = U_ZERO_ERROR;
13875 // No need to force strict BCP47 rules.
13876 uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
13877 if (U_FAILURE(error)) {
13878 // This shouldn't happen, but lets not break the user.
13882 RETURN_IF_EMPTY_HANDLE(isolate,
13883 JSObject::SetLocalPropertyIgnoreAttributes(
13885 isolate->factory()->NewStringFromAscii(CStrVector(result)),
13886 isolate->factory()->NewNumber(i),
13894 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultICULocale) {
13895 SealHandleScope shs(isolate);
13897 ASSERT(args.length() == 0);
13899 icu::Locale default_locale;
13902 char result[ULOC_FULLNAME_CAPACITY];
13903 UErrorCode status = U_ZERO_ERROR;
13904 uloc_toLanguageTag(
13905 default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
13906 if (U_SUCCESS(status)) {
13907 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result));
13910 return isolate->heap()->AllocateStringFromOneByte(CStrVector("und"));
13914 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) {
13915 HandleScope scope(isolate);
13917 ASSERT(args.length() == 1);
13919 CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0);
13921 uint32_t length = static_cast<uint32_t>(input->length()->Number());
13922 Handle<FixedArray> output = isolate->factory()->NewFixedArray(length);
13923 Handle<Name> maximized =
13924 isolate->factory()->NewStringFromAscii(CStrVector("maximized"));
13925 Handle<Name> base =
13926 isolate->factory()->NewStringFromAscii(CStrVector("base"));
13927 for (unsigned int i = 0; i < length; ++i) {
13928 Handle<Object> locale_id = Object::GetElement(isolate, input, i);
13929 RETURN_IF_EMPTY_HANDLE(isolate, locale_id);
13930 if (!locale_id->IsString()) {
13931 return isolate->Throw(isolate->heap()->illegal_argument_string());
13934 v8::String::Utf8Value utf8_locale_id(
13935 v8::Utils::ToLocal(Handle<String>::cast(locale_id)));
13937 UErrorCode error = U_ZERO_ERROR;
13939 // Convert from BCP47 to ICU format.
13940 // de-DE-u-co-phonebk -> de_DE@collation=phonebook
13941 char icu_locale[ULOC_FULLNAME_CAPACITY];
13942 int icu_locale_length = 0;
13943 uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY,
13944 &icu_locale_length, &error);
13945 if (U_FAILURE(error) || icu_locale_length == 0) {
13946 return isolate->Throw(isolate->heap()->illegal_argument_string());
13949 // Maximize the locale.
13950 // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook
13951 char icu_max_locale[ULOC_FULLNAME_CAPACITY];
13952 uloc_addLikelySubtags(
13953 icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error);
13955 // Remove extensions from maximized locale.
13956 // de_Latn_DE@collation=phonebook -> de_Latn_DE
13957 char icu_base_max_locale[ULOC_FULLNAME_CAPACITY];
13959 icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error);
13961 // Get original name without extensions.
13962 // de_DE@collation=phonebook -> de_DE
13963 char icu_base_locale[ULOC_FULLNAME_CAPACITY];
13965 icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error);
13967 // Convert from ICU locale format to BCP47 format.
13968 // de_Latn_DE -> de-Latn-DE
13969 char base_max_locale[ULOC_FULLNAME_CAPACITY];
13970 uloc_toLanguageTag(icu_base_max_locale, base_max_locale,
13971 ULOC_FULLNAME_CAPACITY, FALSE, &error);
13974 char base_locale[ULOC_FULLNAME_CAPACITY];
13975 uloc_toLanguageTag(
13976 icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error);
13978 if (U_FAILURE(error)) {
13979 return isolate->Throw(isolate->heap()->illegal_argument_string());
13982 Handle<JSObject> result =
13983 isolate->factory()->NewJSObject(isolate->object_function());
13984 RETURN_IF_EMPTY_HANDLE(isolate,
13985 JSObject::SetLocalPropertyIgnoreAttributes(
13988 isolate->factory()->NewStringFromAscii(CStrVector(base_max_locale)),
13990 RETURN_IF_EMPTY_HANDLE(isolate,
13991 JSObject::SetLocalPropertyIgnoreAttributes(
13994 isolate->factory()->NewStringFromAscii(CStrVector(base_locale)),
13996 output->set(i, *result);
13999 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(output);
14000 result->set_length(Smi::FromInt(length));
14005 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) {
14006 HandleScope scope(isolate);
14008 ASSERT(args.length() == 3);
14010 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14011 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14012 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14014 Handle<ObjectTemplateInfo> date_format_template =
14015 I18N::GetTemplate(isolate);
14017 // Create an empty object wrapper.
14018 bool has_pending_exception = false;
14019 Handle<JSObject> local_object = Execution::InstantiateObject(
14020 date_format_template, &has_pending_exception);
14021 if (has_pending_exception) {
14022 ASSERT(isolate->has_pending_exception());
14023 return Failure::Exception();
14026 // Set date time formatter as internal field of the resulting JS object.
14027 icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat(
14028 isolate, locale, options, resolved);
14030 if (!date_format) return isolate->ThrowIllegalOperation();
14032 local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format));
14034 RETURN_IF_EMPTY_HANDLE(isolate,
14035 JSObject::SetLocalPropertyIgnoreAttributes(
14037 isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")),
14038 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
14041 // Make object handle weak so we can delete the data format once GC kicks in.
14042 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
14043 GlobalHandles::MakeWeak(wrapper.location(),
14044 reinterpret_cast<void*>(wrapper.location()),
14045 DateFormat::DeleteDateFormat);
14046 return *local_object;
14050 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateFormat) {
14051 HandleScope scope(isolate);
14053 ASSERT(args.length() == 2);
14055 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
14056 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1);
14058 bool has_pending_exception = false;
14059 Handle<Object> value =
14060 Execution::ToNumber(isolate, date, &has_pending_exception);
14061 if (has_pending_exception) {
14062 ASSERT(isolate->has_pending_exception());
14063 return Failure::Exception();
14066 icu::SimpleDateFormat* date_format =
14067 DateFormat::UnpackDateFormat(isolate, date_format_holder);
14068 if (!date_format) return isolate->ThrowIllegalOperation();
14070 icu::UnicodeString result;
14071 date_format->format(value->Number(), result);
14073 return *isolate->factory()->NewStringFromTwoByte(
14074 Vector<const uint16_t>(
14075 reinterpret_cast<const uint16_t*>(result.getBuffer()),
14080 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateParse) {
14081 HandleScope scope(isolate);
14083 ASSERT(args.length() == 2);
14085 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
14086 CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1);
14088 v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string));
14089 icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date));
14090 icu::SimpleDateFormat* date_format =
14091 DateFormat::UnpackDateFormat(isolate, date_format_holder);
14092 if (!date_format) return isolate->ThrowIllegalOperation();
14094 UErrorCode status = U_ZERO_ERROR;
14095 UDate date = date_format->parse(u_date, status);
14096 if (U_FAILURE(status)) return isolate->heap()->undefined_value();
14098 bool has_pending_exception = false;
14099 Handle<JSDate> result = Handle<JSDate>::cast(
14100 Execution::NewDate(
14101 isolate, static_cast<double>(date), &has_pending_exception));
14102 if (has_pending_exception) {
14103 ASSERT(isolate->has_pending_exception());
14104 return Failure::Exception();
14110 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateNumberFormat) {
14111 HandleScope scope(isolate);
14113 ASSERT(args.length() == 3);
14115 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14116 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14117 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14119 Handle<ObjectTemplateInfo> number_format_template =
14120 I18N::GetTemplate(isolate);
14122 // Create an empty object wrapper.
14123 bool has_pending_exception = false;
14124 Handle<JSObject> local_object = Execution::InstantiateObject(
14125 number_format_template, &has_pending_exception);
14126 if (has_pending_exception) {
14127 ASSERT(isolate->has_pending_exception());
14128 return Failure::Exception();
14131 // Set number formatter as internal field of the resulting JS object.
14132 icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat(
14133 isolate, locale, options, resolved);
14135 if (!number_format) return isolate->ThrowIllegalOperation();
14137 local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format));
14139 RETURN_IF_EMPTY_HANDLE(isolate,
14140 JSObject::SetLocalPropertyIgnoreAttributes(
14142 isolate->factory()->NewStringFromAscii(CStrVector("numberFormat")),
14143 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
14146 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
14147 GlobalHandles::MakeWeak(wrapper.location(),
14148 reinterpret_cast<void*>(wrapper.location()),
14149 NumberFormat::DeleteNumberFormat);
14150 return *local_object;
14154 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberFormat) {
14155 HandleScope scope(isolate);
14157 ASSERT(args.length() == 2);
14159 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
14160 CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
14162 bool has_pending_exception = false;
14163 Handle<Object> value = Execution::ToNumber(
14164 isolate, number, &has_pending_exception);
14165 if (has_pending_exception) {
14166 ASSERT(isolate->has_pending_exception());
14167 return Failure::Exception();
14170 icu::DecimalFormat* number_format =
14171 NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
14172 if (!number_format) return isolate->ThrowIllegalOperation();
14174 icu::UnicodeString result;
14175 number_format->format(value->Number(), result);
14177 return *isolate->factory()->NewStringFromTwoByte(
14178 Vector<const uint16_t>(
14179 reinterpret_cast<const uint16_t*>(result.getBuffer()),
14184 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberParse) {
14185 HandleScope scope(isolate);
14187 ASSERT(args.length() == 2);
14189 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
14190 CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1);
14192 v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string));
14193 icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number));
14194 icu::DecimalFormat* number_format =
14195 NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
14196 if (!number_format) return isolate->ThrowIllegalOperation();
14198 UErrorCode status = U_ZERO_ERROR;
14199 icu::Formattable result;
14200 // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
14201 // to be part of Chrome.
14202 // TODO(cira): Include currency parsing code using parseCurrency call.
14203 // We need to check if the formatter parses all currencies or only the
14204 // one it was constructed with (it will impact the API - how to return ISO
14205 // code and the value).
14206 number_format->parse(u_number, result, status);
14207 if (U_FAILURE(status)) return isolate->heap()->undefined_value();
14209 switch (result.getType()) {
14210 case icu::Formattable::kDouble:
14211 return *isolate->factory()->NewNumber(result.getDouble());
14212 case icu::Formattable::kLong:
14213 return *isolate->factory()->NewNumberFromInt(result.getLong());
14214 case icu::Formattable::kInt64:
14215 return *isolate->factory()->NewNumber(
14216 static_cast<double>(result.getInt64()));
14218 return isolate->heap()->undefined_value();
14223 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCollator) {
14224 HandleScope scope(isolate);
14226 ASSERT(args.length() == 3);
14228 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14229 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14230 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14232 Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate);
14234 // Create an empty object wrapper.
14235 bool has_pending_exception = false;
14236 Handle<JSObject> local_object = Execution::InstantiateObject(
14237 collator_template, &has_pending_exception);
14238 if (has_pending_exception) {
14239 ASSERT(isolate->has_pending_exception());
14240 return Failure::Exception();
14243 // Set collator as internal field of the resulting JS object.
14244 icu::Collator* collator = Collator::InitializeCollator(
14245 isolate, locale, options, resolved);
14247 if (!collator) return isolate->ThrowIllegalOperation();
14249 local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator));
14251 RETURN_IF_EMPTY_HANDLE(isolate,
14252 JSObject::SetLocalPropertyIgnoreAttributes(
14254 isolate->factory()->NewStringFromAscii(CStrVector("collator")),
14255 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
14258 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
14259 GlobalHandles::MakeWeak(wrapper.location(),
14260 reinterpret_cast<void*>(wrapper.location()),
14261 Collator::DeleteCollator);
14262 return *local_object;
14266 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalCompare) {
14267 HandleScope scope(isolate);
14269 ASSERT(args.length() == 3);
14271 CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0);
14272 CONVERT_ARG_HANDLE_CHECKED(String, string1, 1);
14273 CONVERT_ARG_HANDLE_CHECKED(String, string2, 2);
14275 icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder);
14276 if (!collator) return isolate->ThrowIllegalOperation();
14278 v8::String::Value string_value1(v8::Utils::ToLocal(string1));
14279 v8::String::Value string_value2(v8::Utils::ToLocal(string2));
14280 const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1);
14281 const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2);
14282 UErrorCode status = U_ZERO_ERROR;
14283 UCollationResult result = collator->compare(u_string1,
14284 string_value1.length(),
14286 string_value2.length(),
14288 if (U_FAILURE(status)) return isolate->ThrowIllegalOperation();
14290 return *isolate->factory()->NewNumberFromInt(result);
14294 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringNormalize) {
14295 HandleScope scope(isolate);
14296 static const UNormalizationMode normalizationForms[] =
14297 { UNORM_NFC, UNORM_NFD, UNORM_NFKC, UNORM_NFKD };
14299 ASSERT(args.length() == 2);
14301 CONVERT_ARG_HANDLE_CHECKED(String, stringValue, 0);
14302 CONVERT_NUMBER_CHECKED(int, form_id, Int32, args[1]);
14304 v8::String::Value string_value(v8::Utils::ToLocal(stringValue));
14305 const UChar* u_value = reinterpret_cast<const UChar*>(*string_value);
14307 // TODO(mnita): check Normalizer2 (not available in ICU 46)
14308 UErrorCode status = U_ZERO_ERROR;
14309 icu::UnicodeString result;
14310 icu::Normalizer::normalize(u_value, normalizationForms[form_id], 0,
14312 if (U_FAILURE(status)) {
14313 return isolate->heap()->undefined_value();
14316 return *isolate->factory()->NewStringFromTwoByte(
14317 Vector<const uint16_t>(
14318 reinterpret_cast<const uint16_t*>(result.getBuffer()),
14323 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateBreakIterator) {
14324 HandleScope scope(isolate);
14326 ASSERT(args.length() == 3);
14328 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14329 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14330 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14332 Handle<ObjectTemplateInfo> break_iterator_template =
14333 I18N::GetTemplate2(isolate);
14335 // Create an empty object wrapper.
14336 bool has_pending_exception = false;
14337 Handle<JSObject> local_object = Execution::InstantiateObject(
14338 break_iterator_template, &has_pending_exception);
14339 if (has_pending_exception) {
14340 ASSERT(isolate->has_pending_exception());
14341 return Failure::Exception();
14344 // Set break iterator as internal field of the resulting JS object.
14345 icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator(
14346 isolate, locale, options, resolved);
14348 if (!break_iterator) return isolate->ThrowIllegalOperation();
14350 local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator));
14351 // Make sure that the pointer to adopted text is NULL.
14352 local_object->SetInternalField(1, reinterpret_cast<Smi*>(NULL));
14354 RETURN_IF_EMPTY_HANDLE(isolate,
14355 JSObject::SetLocalPropertyIgnoreAttributes(
14357 isolate->factory()->NewStringFromAscii(CStrVector("breakIterator")),
14358 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
14361 // Make object handle weak so we can delete the break iterator once GC kicks
14363 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
14364 GlobalHandles::MakeWeak(wrapper.location(),
14365 reinterpret_cast<void*>(wrapper.location()),
14366 BreakIterator::DeleteBreakIterator);
14367 return *local_object;
14371 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorAdoptText) {
14372 HandleScope scope(isolate);
14374 ASSERT(args.length() == 2);
14376 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14377 CONVERT_ARG_HANDLE_CHECKED(String, text, 1);
14379 icu::BreakIterator* break_iterator =
14380 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14381 if (!break_iterator) return isolate->ThrowIllegalOperation();
14383 icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>(
14384 break_iterator_holder->GetInternalField(1));
14387 v8::String::Value text_value(v8::Utils::ToLocal(text));
14388 u_text = new icu::UnicodeString(
14389 reinterpret_cast<const UChar*>(*text_value), text_value.length());
14390 break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text));
14392 break_iterator->setText(*u_text);
14394 return isolate->heap()->undefined_value();
14398 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorFirst) {
14399 HandleScope scope(isolate);
14401 ASSERT(args.length() == 1);
14403 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14405 icu::BreakIterator* break_iterator =
14406 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14407 if (!break_iterator) return isolate->ThrowIllegalOperation();
14409 return *isolate->factory()->NewNumberFromInt(break_iterator->first());
14413 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorNext) {
14414 HandleScope scope(isolate);
14416 ASSERT(args.length() == 1);
14418 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14420 icu::BreakIterator* break_iterator =
14421 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14422 if (!break_iterator) return isolate->ThrowIllegalOperation();
14424 return *isolate->factory()->NewNumberFromInt(break_iterator->next());
14428 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorCurrent) {
14429 HandleScope scope(isolate);
14431 ASSERT(args.length() == 1);
14433 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14435 icu::BreakIterator* break_iterator =
14436 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14437 if (!break_iterator) return isolate->ThrowIllegalOperation();
14439 return *isolate->factory()->NewNumberFromInt(break_iterator->current());
14443 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorBreakType) {
14444 HandleScope scope(isolate);
14446 ASSERT(args.length() == 1);
14448 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14450 icu::BreakIterator* break_iterator =
14451 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14452 if (!break_iterator) return isolate->ThrowIllegalOperation();
14454 // TODO(cira): Remove cast once ICU fixes base BreakIterator class.
14455 icu::RuleBasedBreakIterator* rule_based_iterator =
14456 static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
14457 int32_t status = rule_based_iterator->getRuleStatus();
14458 // Keep return values in sync with JavaScript BreakType enum.
14459 if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
14460 return *isolate->factory()->NewStringFromAscii(CStrVector("none"));
14461 } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
14462 return *isolate->factory()->NewStringFromAscii(CStrVector("number"));
14463 } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
14464 return *isolate->factory()->NewStringFromAscii(CStrVector("letter"));
14465 } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
14466 return *isolate->factory()->NewStringFromAscii(CStrVector("kana"));
14467 } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
14468 return *isolate->factory()->NewStringFromAscii(CStrVector("ideo"));
14470 return *isolate->factory()->NewStringFromAscii(CStrVector("unknown"));
14473 #endif // V8_I18N_SUPPORT
14476 // Finds the script object from the script data. NOTE: This operation uses
14477 // heap traversal to find the function generated for the source position
14478 // for the requested break point. For lazily compiled functions several heap
14479 // traversals might be required rendering this operation as a rather slow
14480 // operation. However for setting break points which is normally done through
14481 // some kind of user interaction the performance is not crucial.
14482 static Handle<Object> Runtime_GetScriptFromScriptName(
14483 Handle<String> script_name) {
14484 // Scan the heap for Script objects to find the script with the requested
14486 Handle<Script> script;
14487 Factory* factory = script_name->GetIsolate()->factory();
14488 Heap* heap = script_name->GetHeap();
14489 heap->EnsureHeapIsIterable();
14490 DisallowHeapAllocation no_allocation_during_heap_iteration;
14491 HeapIterator iterator(heap);
14492 HeapObject* obj = NULL;
14493 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
14494 // If a script is found check if it has the script data requested.
14495 if (obj->IsScript()) {
14496 if (Script::cast(obj)->name()->IsString()) {
14497 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
14498 script = Handle<Script>(Script::cast(obj));
14504 // If no script with the requested script data is found return undefined.
14505 if (script.is_null()) return factory->undefined_value();
14507 // Return the script found.
14508 return GetScriptWrapper(script);
14512 // Get the script object from script data. NOTE: Regarding performance
14513 // see the NOTE for GetScriptFromScriptData.
14514 // args[0]: script data for the script to find the source for
14515 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
14516 HandleScope scope(isolate);
14518 ASSERT(args.length() == 1);
14520 CONVERT_ARG_CHECKED(String, script_name, 0);
14522 // Find the requested script.
14523 Handle<Object> result =
14524 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
14529 // Collect the raw data for a stack trace. Returns an array of 4
14530 // element segments each containing a receiver, function, code and
14531 // native code offset.
14532 RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
14533 HandleScope scope(isolate);
14534 ASSERT_EQ(args.length(), 3);
14535 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
14536 Handle<Object> caller = args.at<Object>(1);
14537 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
14539 // Optionally capture a more detailed stack trace for the message.
14540 isolate->CaptureAndSetDetailedStackTrace(error_object);
14541 // Capture a simple stack trace for the stack property.
14542 return *isolate->CaptureSimpleStackTrace(error_object, caller, limit);
14546 // Retrieve the stack trace. This is the raw stack trace that yet has to
14547 // be formatted. Since we only need this once, clear it afterwards.
14548 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAndClearOverflowedStackTrace) {
14549 HandleScope scope(isolate);
14550 ASSERT_EQ(args.length(), 1);
14551 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
14552 Handle<String> key = isolate->factory()->hidden_stack_trace_string();
14553 Handle<Object> result(error_object->GetHiddenProperty(*key), isolate);
14554 if (result->IsTheHole()) return isolate->heap()->undefined_value();
14555 RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined());
14556 JSObject::DeleteHiddenProperty(error_object, key);
14561 // Returns V8 version as a string.
14562 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
14563 SealHandleScope shs(isolate);
14564 ASSERT_EQ(args.length(), 0);
14566 const char* version_string = v8::V8::GetVersion();
14568 return isolate->heap()->AllocateStringFromOneByte(CStrVector(version_string),
14573 RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
14574 SealHandleScope shs(isolate);
14575 ASSERT(args.length() == 1);
14576 CONVERT_SMI_ARG_CHECKED(message_id, 0);
14577 const char* message = GetBailoutReason(
14578 static_cast<BailoutReason>(message_id));
14579 OS::PrintError("abort: %s\n", message);
14580 isolate->PrintStack(stderr);
14587 RUNTIME_FUNCTION(MaybeObject*, Runtime_AbortJS) {
14588 HandleScope scope(isolate);
14589 ASSERT(args.length() == 1);
14590 CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
14591 OS::PrintError("abort: %s\n", message->ToCString().get());
14592 isolate->PrintStack(stderr);
14599 RUNTIME_FUNCTION(MaybeObject*, Runtime_FlattenString) {
14600 HandleScope scope(isolate);
14601 ASSERT(args.length() == 1);
14602 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
14603 FlattenString(str);
14604 return isolate->heap()->undefined_value();
14608 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyContextDisposed) {
14609 HandleScope scope(isolate);
14610 ASSERT(args.length() == 0);
14611 isolate->heap()->NotifyContextDisposed();
14612 return isolate->heap()->undefined_value();
14616 RUNTIME_FUNCTION(MaybeObject*, Runtime_TryMigrateInstance) {
14617 HandleScope scope(isolate);
14618 ASSERT(args.length() == 1);
14619 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
14620 if (!object->IsJSObject()) return Smi::FromInt(0);
14621 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
14622 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
14623 // This call must not cause lazy deopts, because it's called from deferred
14624 // code where we can't handle lazy deopts for lack of a suitable bailout
14625 // ID. So we just try migration and signal failure if necessary,
14626 // which will also trigger a deopt.
14627 Handle<Object> result = JSObject::TryMigrateInstance(js_object);
14628 if (result.is_null()) return Smi::FromInt(0);
14633 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_GetFromCache) {
14634 SealHandleScope shs(isolate);
14635 // This is only called from codegen, so checks might be more lax.
14636 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
14637 Object* key = args[1];
14639 int finger_index = cache->finger_index();
14640 Object* o = cache->get(finger_index);
14642 // The fastest case: hit the same place again.
14643 return cache->get(finger_index + 1);
14646 for (int i = finger_index - 2;
14647 i >= JSFunctionResultCache::kEntriesIndex;
14651 cache->set_finger_index(i);
14652 return cache->get(i + 1);
14656 int size = cache->size();
14657 ASSERT(size <= cache->length());
14659 for (int i = size - 2; i > finger_index; i -= 2) {
14662 cache->set_finger_index(i);
14663 return cache->get(i + 1);
14667 // There is no value in the cache. Invoke the function and cache result.
14668 HandleScope scope(isolate);
14670 Handle<JSFunctionResultCache> cache_handle(cache);
14671 Handle<Object> key_handle(key, isolate);
14672 Handle<Object> value;
14674 Handle<JSFunction> factory(JSFunction::cast(
14675 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
14676 // TODO(antonm): consider passing a receiver when constructing a cache.
14677 Handle<Object> receiver(isolate->native_context()->global_object(),
14679 // This handle is nor shared, nor used later, so it's safe.
14680 Handle<Object> argv[] = { key_handle };
14681 bool pending_exception;
14682 value = Execution::Call(isolate,
14687 &pending_exception);
14688 if (pending_exception) return Failure::Exception();
14692 if (FLAG_verify_heap) {
14693 cache_handle->JSFunctionResultCacheVerify();
14697 // Function invocation may have cleared the cache. Reread all the data.
14698 finger_index = cache_handle->finger_index();
14699 size = cache_handle->size();
14701 // If we have spare room, put new data into it, otherwise evict post finger
14702 // entry which is likely to be the least recently used.
14704 if (size < cache_handle->length()) {
14705 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
14708 index = finger_index + JSFunctionResultCache::kEntrySize;
14709 if (index == cache_handle->length()) {
14710 index = JSFunctionResultCache::kEntriesIndex;
14714 ASSERT(index % 2 == 0);
14715 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
14716 ASSERT(index < cache_handle->length());
14718 cache_handle->set(index, *key_handle);
14719 cache_handle->set(index + 1, *value);
14720 cache_handle->set_finger_index(index);
14723 if (FLAG_verify_heap) {
14724 cache_handle->JSFunctionResultCacheVerify();
14732 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
14733 SealHandleScope shs(isolate);
14734 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
14735 return Smi::FromInt(message->start_position());
14739 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
14740 SealHandleScope shs(isolate);
14741 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
14742 return message->script();
14747 // ListNatives is ONLY used by the fuzz-natives.js in debug mode
14748 // Exclude the code in release mode.
14749 RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
14750 HandleScope scope(isolate);
14751 ASSERT(args.length() == 0);
14752 #define COUNT_ENTRY(Name, argc, ressize) + 1
14753 int entry_count = 0
14754 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
14755 RUNTIME_HIDDEN_FUNCTION_LIST(COUNT_ENTRY)
14756 INLINE_FUNCTION_LIST(COUNT_ENTRY);
14758 Factory* factory = isolate->factory();
14759 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
14761 bool inline_runtime_functions = false;
14762 #define ADD_ENTRY(Name, argc, ressize) \
14764 HandleScope inner(isolate); \
14765 Handle<String> name; \
14766 /* Inline runtime functions have an underscore in front of the name. */ \
14767 if (inline_runtime_functions) { \
14768 name = factory->NewStringFromAscii( \
14769 Vector<const char>("_" #Name, StrLength("_" #Name))); \
14771 name = factory->NewStringFromAscii( \
14772 Vector<const char>(#Name, StrLength(#Name))); \
14774 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
14775 pair_elements->set(0, *name); \
14776 pair_elements->set(1, Smi::FromInt(argc)); \
14777 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
14778 elements->set(index++, *pair); \
14780 inline_runtime_functions = false;
14781 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
14782 // Calling hidden runtime functions should just throw.
14783 RUNTIME_HIDDEN_FUNCTION_LIST(ADD_ENTRY)
14784 inline_runtime_functions = true;
14785 INLINE_FUNCTION_LIST(ADD_ENTRY)
14787 ASSERT_EQ(index, entry_count);
14788 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
14794 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_Log) {
14795 HandleScope handle_scope(isolate);
14796 ASSERT(args.length() == 2);
14797 CONVERT_ARG_HANDLE_CHECKED(String, format, 0);
14798 CONVERT_ARG_HANDLE_CHECKED(JSArray, elms, 1);
14800 SmartArrayPointer<char> format_chars = format->ToCString();
14801 isolate->logger()->LogRuntime(
14802 Vector<const char>(format_chars.get(), format->length()), elms);
14803 return isolate->heap()->undefined_value();
14807 RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
14808 UNREACHABLE(); // implemented as macro in the parser
14813 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
14814 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
14815 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
14816 return isolate->heap()->ToBoolean(obj->Has##Name()); \
14819 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
14820 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
14821 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
14822 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
14823 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
14824 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
14825 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements)
14826 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
14827 // Properties test sitting with elements tests - not fooling anyone.
14828 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
14830 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
14833 #define TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, size) \
14834 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasExternal##Type##Elements) { \
14835 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
14836 return isolate->heap()->ToBoolean(obj->HasExternal##Type##Elements()); \
14839 TYPED_ARRAYS(TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
14841 #undef TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
14844 #define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \
14845 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasFixed##Type##Elements) { \
14846 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
14847 return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \
14850 TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
14852 #undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
14855 RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
14856 SealHandleScope shs(isolate);
14857 ASSERT(args.length() == 2);
14858 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
14859 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
14860 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
14864 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessCheckNeeded) {
14865 SealHandleScope shs(isolate);
14866 ASSERT(args.length() == 1);
14867 CONVERT_ARG_CHECKED(HeapObject, obj, 0);
14868 return isolate->heap()->ToBoolean(obj->IsAccessCheckNeeded());
14872 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) {
14873 SealHandleScope shs(isolate);
14874 ASSERT(args.length() == 1);
14876 if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value();
14877 JSReceiver* obj = JSReceiver::cast(args[0]);
14878 if (obj->IsJSGlobalProxy()) {
14879 Object* proto = obj->GetPrototype();
14880 if (proto->IsNull()) return isolate->heap()->false_value();
14881 ASSERT(proto->IsJSGlobalObject());
14882 obj = JSReceiver::cast(proto);
14884 return isolate->heap()->ToBoolean(obj->map()->is_observed());
14888 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) {
14889 HandleScope scope(isolate);
14890 ASSERT(args.length() == 1);
14891 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
14892 if (obj->IsJSGlobalProxy()) {
14893 Object* proto = obj->GetPrototype();
14894 if (proto->IsNull()) return isolate->heap()->undefined_value();
14895 ASSERT(proto->IsJSGlobalObject());
14896 obj = handle(JSReceiver::cast(proto));
14898 if (obj->IsJSProxy())
14899 return isolate->heap()->undefined_value();
14901 ASSERT(!(obj->map()->is_observed() && obj->IsJSObject() &&
14902 Handle<JSObject>::cast(obj)->HasFastElements()));
14903 ASSERT(obj->IsJSObject());
14904 JSObject::SetObserved(Handle<JSObject>::cast(obj));
14905 return isolate->heap()->undefined_value();
14909 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetMicrotaskPending) {
14910 SealHandleScope shs(isolate);
14911 ASSERT(args.length() == 1);
14912 CONVERT_BOOLEAN_ARG_CHECKED(new_state, 0);
14913 bool old_state = isolate->microtask_pending();
14914 isolate->set_microtask_pending(new_state);
14915 return isolate->heap()->ToBoolean(old_state);
14919 RUNTIME_FUNCTION(MaybeObject*, Runtime_RunMicrotasks) {
14920 HandleScope scope(isolate);
14921 ASSERT(args.length() == 0);
14922 if (isolate->microtask_pending())
14923 Execution::RunMicrotasks(isolate);
14924 return isolate->heap()->undefined_value();
14928 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetMicrotaskState) {
14929 SealHandleScope shs(isolate);
14930 ASSERT(args.length() == 0);
14931 return isolate->heap()->microtask_state();
14935 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetObservationState) {
14936 SealHandleScope shs(isolate);
14937 ASSERT(args.length() == 0);
14938 return isolate->heap()->observation_state();
14942 RUNTIME_FUNCTION(MaybeObject*, Runtime_ObservationWeakMapCreate) {
14943 HandleScope scope(isolate);
14944 ASSERT(args.length() == 0);
14945 // TODO(adamk): Currently this runtime function is only called three times per
14946 // isolate. If it's called more often, the map should be moved into the
14947 // strong root list.
14949 isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize);
14950 Handle<JSWeakMap> weakmap =
14951 Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map));
14952 return WeakCollectionInitialize(isolate, weakmap);
14956 RUNTIME_FUNCTION(MaybeObject*, Runtime_UnwrapGlobalProxy) {
14957 SealHandleScope shs(isolate);
14958 ASSERT(args.length() == 1);
14959 Object* object = args[0];
14960 if (object->IsJSGlobalProxy()) {
14961 object = object->GetPrototype(isolate);
14962 if (object->IsNull()) return isolate->heap()->undefined_value();
14968 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessAllowedForObserver) {
14969 HandleScope scope(isolate);
14970 ASSERT(args.length() == 3);
14971 CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0);
14972 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1);
14973 ASSERT(object->map()->is_access_check_needed());
14974 Handle<Object> key = args.at<Object>(2);
14975 SaveContext save(isolate);
14976 isolate->set_context(observer->context());
14977 if (!isolate->MayNamedAccessWrapper(object,
14978 isolate->factory()->undefined_value(),
14979 v8::ACCESS_KEYS)) {
14980 return isolate->heap()->false_value();
14982 bool access_allowed = false;
14983 uint32_t index = 0;
14984 if (key->ToArrayIndex(&index) ||
14985 (key->IsString() && String::cast(*key)->AsArrayIndex(&index))) {
14987 isolate->MayIndexedAccessWrapper(object, index, v8::ACCESS_GET) &&
14988 isolate->MayIndexedAccessWrapper(object, index, v8::ACCESS_HAS);
14991 isolate->MayNamedAccessWrapper(object, key, v8::ACCESS_GET) &&
14992 isolate->MayNamedAccessWrapper(object, key, v8::ACCESS_HAS);
14994 return isolate->heap()->ToBoolean(access_allowed);
14998 static MaybeObject* ArrayConstructorCommon(Isolate* isolate,
14999 Handle<JSFunction> constructor,
15000 Handle<AllocationSite> site,
15001 Arguments* caller_args) {
15002 Factory* factory = isolate->factory();
15004 bool holey = false;
15005 bool can_use_type_feedback = true;
15006 if (caller_args->length() == 1) {
15007 Handle<Object> argument_one = caller_args->at<Object>(0);
15008 if (argument_one->IsSmi()) {
15009 int value = Handle<Smi>::cast(argument_one)->value();
15010 if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) {
15011 // the array is a dictionary in this case.
15012 can_use_type_feedback = false;
15013 } else if (value != 0) {
15017 // Non-smi length argument produces a dictionary
15018 can_use_type_feedback = false;
15022 Handle<JSArray> array;
15023 if (!site.is_null() && can_use_type_feedback) {
15024 ElementsKind to_kind = site->GetElementsKind();
15025 if (holey && !IsFastHoleyElementsKind(to_kind)) {
15026 to_kind = GetHoleyElementsKind(to_kind);
15027 // Update the allocation site info to reflect the advice alteration.
15028 site->SetElementsKind(to_kind);
15031 // We should allocate with an initial map that reflects the allocation site
15032 // advice. Therefore we use AllocateJSObjectFromMap instead of passing
15033 // the constructor.
15034 Handle<Map> initial_map(constructor->initial_map(), isolate);
15035 if (to_kind != initial_map->elements_kind()) {
15036 initial_map = Map::AsElementsKind(initial_map, to_kind);
15037 RETURN_IF_EMPTY_HANDLE(isolate, initial_map);
15040 // If we don't care to track arrays of to_kind ElementsKind, then
15041 // don't emit a memento for them.
15042 Handle<AllocationSite> allocation_site;
15043 if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) {
15044 allocation_site = site;
15047 array = Handle<JSArray>::cast(factory->NewJSObjectFromMap(
15048 initial_map, NOT_TENURED, true, allocation_site));
15050 array = Handle<JSArray>::cast(factory->NewJSObject(constructor));
15052 // We might need to transition to holey
15053 ElementsKind kind = constructor->initial_map()->elements_kind();
15054 if (holey && !IsFastHoleyElementsKind(kind)) {
15055 kind = GetHoleyElementsKind(kind);
15056 JSObject::TransitionElementsKind(array, kind);
15060 factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
15062 ElementsKind old_kind = array->GetElementsKind();
15063 RETURN_IF_EMPTY_HANDLE(isolate,
15064 ArrayConstructInitializeElements(array, caller_args));
15065 if (!site.is_null() &&
15066 (old_kind != array->GetElementsKind() ||
15067 !can_use_type_feedback)) {
15068 // The arguments passed in caused a transition. This kind of complexity
15069 // can't be dealt with in the inlined hydrogen array constructor case.
15070 // We must mark the allocationsite as un-inlinable.
15071 site->SetDoNotInlineCall();
15077 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_ArrayConstructor) {
15078 HandleScope scope(isolate);
15079 // If we get 2 arguments then they are the stub parameters (constructor, type
15080 // info). If we get 4, then the first one is a pointer to the arguments
15081 // passed by the caller, and the last one is the length of the arguments
15082 // passed to the caller (redundant, but useful to check on the deoptimizer
15083 // with an assert).
15084 Arguments empty_args(0, NULL);
15085 bool no_caller_args = args.length() == 2;
15086 ASSERT(no_caller_args || args.length() == 4);
15087 int parameters_start = no_caller_args ? 0 : 1;
15088 Arguments* caller_args = no_caller_args
15090 : reinterpret_cast<Arguments*>(args[0]);
15091 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
15092 CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
15094 if (!no_caller_args) {
15095 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2);
15096 ASSERT(arg_count == caller_args->length());
15100 Handle<AllocationSite> site;
15101 if (!type_info.is_null() &&
15102 *type_info != isolate->heap()->undefined_value()) {
15103 site = Handle<AllocationSite>::cast(type_info);
15104 ASSERT(!site->SitePointsToLiteral());
15107 return ArrayConstructorCommon(isolate,
15114 RUNTIME_FUNCTION(MaybeObject*, RuntimeHidden_InternalArrayConstructor) {
15115 HandleScope scope(isolate);
15116 Arguments empty_args(0, NULL);
15117 bool no_caller_args = args.length() == 1;
15118 ASSERT(no_caller_args || args.length() == 3);
15119 int parameters_start = no_caller_args ? 0 : 1;
15120 Arguments* caller_args = no_caller_args
15122 : reinterpret_cast<Arguments*>(args[0]);
15123 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
15125 if (!no_caller_args) {
15126 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1);
15127 ASSERT(arg_count == caller_args->length());
15130 return ArrayConstructorCommon(isolate,
15132 Handle<AllocationSite>::null(),
15137 RUNTIME_FUNCTION(MaybeObject*, Runtime_MaxSmi) {
15138 return Smi::FromInt(Smi::kMaxValue);
15142 #define RETURN_Float32x4_RESULT(value) \
15143 Float32x4* float32x4; \
15144 MaybeObject* maybe = isolate->heap()->AllocateFloat32x4(value); \
15145 if (!maybe->To(&float32x4)) return maybe; \
15149 #define RETURN_Int32x4_RESULT(value) \
15150 Int32x4* int32x4; \
15151 MaybeObject* maybe = isolate->heap()->AllocateInt32x4(value); \
15152 if (!maybe->To(&int32x4)) return maybe; \
15156 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateFloat32x4) {
15157 HandleScope scope(isolate);
15158 ASSERT(args.length() == 4);
15159 RUNTIME_ASSERT(args[0]->IsNumber());
15160 RUNTIME_ASSERT(args[1]->IsNumber());
15161 RUNTIME_ASSERT(args[2]->IsNumber());
15162 RUNTIME_ASSERT(args[3]->IsNumber());
15164 float32x4_value_t value;
15165 value.storage[0] = static_cast<float>(args.number_at(0));
15166 value.storage[1] = static_cast<float>(args.number_at(1));
15167 value.storage[2] = static_cast<float>(args.number_at(2));
15168 value.storage[3] = static_cast<float>(args.number_at(3));
15170 RETURN_Float32x4_RESULT(value);
15174 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateInt32x4) {
15175 HandleScope scope(isolate);
15176 ASSERT(args.length() == 4);
15177 RUNTIME_ASSERT(args[0]->IsNumber());
15178 RUNTIME_ASSERT(args[1]->IsNumber());
15179 RUNTIME_ASSERT(args[2]->IsNumber());
15180 RUNTIME_ASSERT(args[3]->IsNumber());
15182 int32x4_value_t value;
15183 value.storage[0] = NumberToInt32(args[0]);
15184 value.storage[1] = NumberToInt32(args[1]);
15185 value.storage[2] = NumberToInt32(args[2]);
15186 value.storage[3] = NumberToInt32(args[3]);
15188 RETURN_Int32x4_RESULT(value);
15192 // Used to convert between uint32_t and float32 without breaking strict
15194 union float32_uint32 {
15197 float32_uint32(float v) {
15200 float32_uint32(uint32_t v) {
15206 RUNTIME_FUNCTION(MaybeObject*, Runtime_Float32x4GetSignMask) {
15207 HandleScope scope(isolate);
15208 ASSERT(args.length() == 1);
15209 CONVERT_ARG_CHECKED(Float32x4, self, 0);
15210 float32_uint32 x(self->x());
15211 float32_uint32 y(self->y());
15212 float32_uint32 z(self->z());
15213 float32_uint32 w(self->w());
15214 uint32_t mx = (x.u & 0x80000000) >> 31;
15215 uint32_t my = (y.u & 0x80000000) >> 31;
15216 uint32_t mz = (z.u & 0x80000000) >> 31;
15217 uint32_t mw = (w.u & 0x80000000) >> 31;
15218 uint32_t value = mx | (my << 1) | (mz << 2) | (mw << 3);
15219 return isolate->heap()->NumberFromUint32(value);
15224 RUNTIME_FUNCTION(MaybeObject*, Runtime_Int32x4GetSignMask) {
15225 HandleScope scope(isolate);
15226 ASSERT(args.length() == 1);
15227 CONVERT_ARG_CHECKED(Int32x4, self, 0);
15228 uint32_t mx = (self->x() & 0x80000000) >> 31;
15229 uint32_t my = (self->y() & 0x80000000) >> 31;
15230 uint32_t mz = (self->z() & 0x80000000) >> 31;
15231 uint32_t mw = (self->w() & 0x80000000) >> 31;
15232 uint32_t value = mx | (my << 1) | (mz << 2) | (mw << 3);
15233 return isolate->heap()->NumberFromUint32(value);
15237 #define LANE_VALUE(VALUE, LANE) \
15241 #define LANE_FLAG(VALUE, LANE) \
15245 #define SIMD128_LANE_ACCESS_FUNCTIONS(V) \
15246 V(Float32x4, GetX, AllocateHeapNumber, x, LANE_VALUE) \
15247 V(Float32x4, GetY, AllocateHeapNumber, y, LANE_VALUE) \
15248 V(Float32x4, GetZ, AllocateHeapNumber, z, LANE_VALUE) \
15249 V(Float32x4, GetW, AllocateHeapNumber, w, LANE_VALUE) \
15250 V(Int32x4, GetX, NumberFromInt32, x, LANE_VALUE) \
15251 V(Int32x4, GetY, NumberFromInt32, y, LANE_VALUE) \
15252 V(Int32x4, GetZ, NumberFromInt32, z, LANE_VALUE) \
15253 V(Int32x4, GetW, NumberFromInt32, w, LANE_VALUE) \
15254 V(Int32x4, GetFlagX, ToBoolean, x, LANE_FLAG) \
15255 V(Int32x4, GetFlagY, ToBoolean, y, LANE_FLAG) \
15256 V(Int32x4, GetFlagZ, ToBoolean, z, LANE_FLAG) \
15257 V(Int32x4, GetFlagW, ToBoolean, w, LANE_FLAG)
15260 #define DECLARE_SIMD_LANE_ACCESS_FUNCTION( \
15261 TYPE, NAME, HEAP_FUNCTION, LANE, ACCESS_FUNCTION) \
15262 RUNTIME_FUNCTION(MaybeObject*, Runtime_##TYPE##NAME) { \
15263 SealHandleScope shs(isolate); \
15264 ASSERT(args.length() == 1); \
15266 CONVERT_ARG_CHECKED(TYPE, a, 0); \
15268 return isolate->heap()->HEAP_FUNCTION( \
15269 ACCESS_FUNCTION(a, LANE)); \
15273 SIMD128_LANE_ACCESS_FUNCTIONS(DECLARE_SIMD_LANE_ACCESS_FUNCTION)
15276 template<typename T>
15277 static inline T Neg(T a) {
15282 template<typename T>
15283 static inline T Not(T a) {
15288 template<typename T>
15289 static inline T Reciprocal(T a) {
15295 inline float Reciprocal<float>(float a) {
15300 template<typename T>
15301 static inline T ReciprocalSqrt(T a) {
15307 inline float ReciprocalSqrt<float>(float a) {
15308 return sqrtf(1.0f / a);
15312 template<typename T>
15313 static inline T Sqrt(T a) {
15319 inline float Sqrt<float>(float a) {
15324 #define SIMD128_UNARY_FUNCTIONS(V) \
15325 V(Float32x4, Abs) \
15326 V(Float32x4, Neg) \
15327 V(Float32x4, Reciprocal) \
15328 V(Float32x4, ReciprocalSqrt) \
15329 V(Float32x4, Sqrt) \
15334 #define DECLARE_SIMD_UNARY_FUNCTION(TYPE, FUNCTION) \
15335 RUNTIME_FUNCTION(MaybeObject*, Runtime_##TYPE##FUNCTION) { \
15336 SealHandleScope shs(isolate); \
15337 ASSERT(args.length() == 1); \
15339 CONVERT_ARG_CHECKED(TYPE, a, 0); \
15341 TYPE::value_t result; \
15342 for (int i = 0; i < TYPE::kLanes; i++) { \
15343 result.storage[i] = FUNCTION(a->getAt(i)); \
15346 RETURN_##TYPE##_RESULT(result); \
15350 SIMD128_UNARY_FUNCTIONS(DECLARE_SIMD_UNARY_FUNCTION)
15353 template<typename T1, typename T2>
15354 inline void BitsTo(T1 s, T2* t) {
15355 memcpy(t, &s, sizeof(T2));
15359 template<typename T1, typename T2>
15360 inline void To(T1 s, T2* t) {
15365 inline void To<int32_t, float>(int32_t s, float* t) {
15366 *t = static_cast<float>(s);
15371 inline void To<float, int32_t>(float s, int32_t* t) {
15372 *t = DoubleToInt32(static_cast<double>(s));
15376 #define SIMD128_CONVERSION_FUNCTIONS(V) \
15377 V(Float32x4, BitsTo, Int32x4) \
15378 V(Float32x4, To, Int32x4) \
15379 V(Int32x4, BitsTo, Float32x4) \
15380 V(Int32x4, To, Float32x4)
15383 #define DECLARE_SIMD_CONVERSION_FUNCTION( \
15384 SOURCE_TYPE, FUNCTION, TARGET_TYPE) \
15385 RUNTIME_FUNCTION(MaybeObject*, \
15386 Runtime_##SOURCE_TYPE##FUNCTION##TARGET_TYPE) { \
15387 SealHandleScope shs(isolate); \
15388 ASSERT(args.length() == 1); \
15390 CONVERT_ARG_CHECKED(SOURCE_TYPE, a, 0); \
15392 TARGET_TYPE::value_t result; \
15393 for (int i = 0; i < SOURCE_TYPE::kLanes; i++) { \
15394 FUNCTION(a->getAt(i), &result.storage[i]); \
15397 RETURN_##TARGET_TYPE##_RESULT(result); \
15401 SIMD128_CONVERSION_FUNCTIONS(DECLARE_SIMD_CONVERSION_FUNCTION)
15404 template<typename T>
15405 static inline T Add(T a, T b) {
15410 template<typename T>
15411 static inline T Div(T a, T b) {
15416 template<typename T>
15417 static inline T Mul(T a, T b) {
15422 template<typename T>
15423 static inline T Sub(T a, T b) {
15428 template<typename T>
15429 static inline int32_t Equal(T a, T b) {
15430 return a == b ? -1 : 0;
15434 template<typename T>
15435 static inline int32_t NotEqual(T a, T b) {
15436 return a != b ? -1 : 0;
15440 template<typename T>
15441 static inline int32_t GreaterThanOrEqual(T a, T b) {
15442 return a >= b ? -1 : 0;
15446 template<typename T>
15447 static inline int32_t GreaterThan(T a, T b) {
15448 return a > b ? -1 : 0;
15452 template<typename T>
15453 static inline int32_t LessThan(T a, T b) {
15454 return a < b ? -1 : 0;
15458 template<typename T>
15459 static inline int32_t LessThanOrEqual(T a, T b) {
15460 return a <= b ? -1 : 0;
15464 template<typename T>
15465 static inline T And(T a, T b) {
15470 template<typename T>
15471 static inline T Or(T a, T b) {
15476 template<typename T>
15477 static inline T Xor(T a, T b) {
15482 #define SIMD128_BINARY_FUNCTIONS(V) \
15483 V(Float32x4, Add, Float32x4) \
15484 V(Float32x4, Div, Float32x4) \
15485 V(Float32x4, Max, Float32x4) \
15486 V(Float32x4, Min, Float32x4) \
15487 V(Float32x4, Mul, Float32x4) \
15488 V(Float32x4, Sub, Float32x4) \
15489 V(Float32x4, Equal, Int32x4) \
15490 V(Float32x4, NotEqual, Int32x4) \
15491 V(Float32x4, GreaterThanOrEqual, Int32x4) \
15492 V(Float32x4, GreaterThan, Int32x4) \
15493 V(Float32x4, LessThan, Int32x4) \
15494 V(Float32x4, LessThanOrEqual, Int32x4) \
15495 V(Int32x4, Add, Int32x4) \
15496 V(Int32x4, And, Int32x4) \
15497 V(Int32x4, Mul, Int32x4) \
15498 V(Int32x4, Or, Int32x4) \
15499 V(Int32x4, Sub, Int32x4) \
15500 V(Int32x4, Xor, Int32x4) \
15501 V(Int32x4, Equal, Int32x4) \
15502 V(Int32x4, GreaterThan, Int32x4) \
15503 V(Int32x4, LessThan, Int32x4)
15506 #define DECLARE_SIMD_BINARY_FUNCTION( \
15507 TYPE, FUNCTION, RETURN_TYPE) \
15508 RUNTIME_FUNCTION(MaybeObject*, Runtime_##TYPE##FUNCTION) { \
15509 SealHandleScope shs(isolate); \
15510 ASSERT(args.length() == 2); \
15512 CONVERT_ARG_CHECKED(TYPE, a, 0); \
15513 CONVERT_ARG_CHECKED(TYPE, b, 1); \
15515 RETURN_TYPE::value_t result; \
15516 for (int i = 0; i < TYPE::kLanes; i++) { \
15517 result.storage[i] = FUNCTION(a->getAt(i), b->getAt(i)); \
15520 RETURN_##RETURN_TYPE##_RESULT(result); \
15524 SIMD128_BINARY_FUNCTIONS(DECLARE_SIMD_BINARY_FUNCTION)
15527 #define SIMD128_SHUFFLE_FUNCTIONS(V) \
15532 #define DECLARE_SIMD_SHUFFLE_FUNCTION(TYPE) \
15533 RUNTIME_FUNCTION(MaybeObject*, Runtime_##TYPE##Shuffle) { \
15534 SealHandleScope shs(isolate); \
15535 ASSERT(args.length() == 2); \
15537 CONVERT_ARG_CHECKED(TYPE, a, 0); \
15538 RUNTIME_ASSERT(args[1]->IsNumber()); \
15539 uint32_t m = NumberToUint32(args[1]); \
15541 TYPE::value_t result; \
15542 for (int i = 0; i < TYPE::kLanes; i++) { \
15543 result.storage[i] = a->getAt((m >> (i * 2)) & 0x3); \
15546 RETURN_##TYPE##_RESULT(result); \
15550 SIMD128_SHUFFLE_FUNCTIONS(DECLARE_SIMD_SHUFFLE_FUNCTION)
15553 RUNTIME_FUNCTION(MaybeObject*, Runtime_Float32x4Scale) {
15554 SealHandleScope shs(isolate);
15555 ASSERT(args.length() == 2);
15557 CONVERT_ARG_CHECKED(Float32x4, self, 0);
15558 RUNTIME_ASSERT(args[1]->IsNumber());
15560 float _s = static_cast<float>(args.number_at(1));
15561 float32x4_value_t result;
15562 result.storage[0] = self->x() * _s;
15563 result.storage[1] = self->y() * _s;
15564 result.storage[2] = self->z() * _s;
15565 result.storage[3] = self->w() * _s;
15567 RETURN_Float32x4_RESULT(result);
15571 #define ARG_TO_FLOAT32(x) \
15572 CONVERT_DOUBLE_ARG_CHECKED(t, 1); \
15573 float x = static_cast<float>(t);
15576 #define ARG_TO_INT32(x) \
15577 RUNTIME_ASSERT(args[1]->IsNumber()); \
15578 int32_t x = NumberToInt32(args[1]);
15581 #define ARG_TO_BOOLEAN(x) \
15582 CONVERT_BOOLEAN_ARG_CHECKED(flag, 1); \
15583 int32_t x = flag ? -1 : 0;
15585 #define SIMD128_SET_LANE_FUNCTIONS(V) \
15586 V(Float32x4, WithX, ARG_TO_FLOAT32, 0) \
15587 V(Float32x4, WithY, ARG_TO_FLOAT32, 1) \
15588 V(Float32x4, WithZ, ARG_TO_FLOAT32, 2) \
15589 V(Float32x4, WithW, ARG_TO_FLOAT32, 3) \
15590 V(Int32x4, WithX, ARG_TO_INT32, 0) \
15591 V(Int32x4, WithY, ARG_TO_INT32, 1) \
15592 V(Int32x4, WithZ, ARG_TO_INT32, 2) \
15593 V(Int32x4, WithW, ARG_TO_INT32, 3) \
15594 V(Int32x4, WithFlagX, ARG_TO_BOOLEAN, 0) \
15595 V(Int32x4, WithFlagY, ARG_TO_BOOLEAN, 1) \
15596 V(Int32x4, WithFlagZ, ARG_TO_BOOLEAN, 2) \
15597 V(Int32x4, WithFlagW, ARG_TO_BOOLEAN, 3)
15600 #define DECLARE_SIMD_SET_LANE_FUNCTION( \
15601 TYPE, NAME, ARG_FUNCTION, LANE) \
15602 RUNTIME_FUNCTION(MaybeObject*, Runtime_##TYPE##NAME) { \
15603 SealHandleScope shs(isolate); \
15604 ASSERT(args.length() == 2); \
15606 CONVERT_ARG_CHECKED(TYPE, a, 0); \
15607 ARG_FUNCTION(value); \
15609 TYPE::value_t result; \
15610 for (int i = 0; i < TYPE::kLanes; i++) { \
15612 result.storage[i] = a->getAt(i); \
15614 result.storage[i] = value; \
15617 RETURN_##TYPE##_RESULT(result); \
15621 SIMD128_SET_LANE_FUNCTIONS(DECLARE_SIMD_SET_LANE_FUNCTION)
15624 RUNTIME_FUNCTION(MaybeObject*, Runtime_Float32x4Clamp) {
15625 SealHandleScope shs(isolate);
15626 ASSERT(args.length() == 3);
15628 CONVERT_ARG_CHECKED(Float32x4, self, 0);
15629 CONVERT_ARG_CHECKED(Float32x4, lo, 1);
15630 CONVERT_ARG_CHECKED(Float32x4, hi, 2);
15632 float32x4_value_t result;
15633 float _x = self->x() > lo->x() ? self->x() : lo->x();
15634 float _y = self->y() > lo->y() ? self->y() : lo->y();
15635 float _z = self->z() > lo->z() ? self->z() : lo->z();
15636 float _w = self->w() > lo->w() ? self->w() : lo->w();
15637 result.storage[0] = _x > hi->x() ? hi->x() : _x;
15638 result.storage[1] = _y > hi->y() ? hi->y() : _y;
15639 result.storage[2] = _z > hi->z() ? hi->z() : _z;
15640 result.storage[3] = _w > hi->w() ? hi->w() : _w;
15642 RETURN_Float32x4_RESULT(result);
15646 RUNTIME_FUNCTION(MaybeObject*, Runtime_Float32x4ShuffleMix) {
15647 SealHandleScope shs(isolate);
15648 ASSERT(args.length() == 3);
15650 CONVERT_ARG_CHECKED(Float32x4, first, 0);
15651 CONVERT_ARG_CHECKED(Float32x4, second, 1);
15652 RUNTIME_ASSERT(args[2]->IsNumber());
15654 uint32_t m = NumberToUint32(args[2]);
15655 float32x4_value_t result;
15656 float data1[4] = { first->x(), first->y(), first->z(), first->w() };
15657 float data2[4] = { second->x(), second->y(), second->z(), second->w() };
15658 result.storage[0] = data1[m & 0x3];
15659 result.storage[1] = data1[(m >> 2) & 0x3];
15660 result.storage[2] = data2[(m >> 4) & 0x3];
15661 result.storage[3] = data2[(m >> 6) & 0x3];
15663 RETURN_Float32x4_RESULT(result);
15667 RUNTIME_FUNCTION(MaybeObject*, Runtime_Int32x4Select) {
15668 SealHandleScope shs(isolate);
15669 ASSERT(args.length() == 3);
15671 CONVERT_ARG_CHECKED(Int32x4, self, 0);
15672 CONVERT_ARG_CHECKED(Float32x4, tv, 1);
15673 CONVERT_ARG_CHECKED(Float32x4, fv, 2);
15675 uint32_t _maskX = self->x();
15676 uint32_t _maskY = self->y();
15677 uint32_t _maskZ = self->z();
15678 uint32_t _maskW = self->w();
15679 // Extract floats and interpret them as masks.
15680 float32_uint32 tvx(tv->x());
15681 float32_uint32 tvy(tv->y());
15682 float32_uint32 tvz(tv->z());
15683 float32_uint32 tvw(tv->w());
15684 float32_uint32 fvx(fv->x());
15685 float32_uint32 fvy(fv->y());
15686 float32_uint32 fvz(fv->z());
15687 float32_uint32 fvw(fv->w());
15689 float32_uint32 tempX((_maskX & tvx.u) | (~_maskX & fvx.u));
15690 float32_uint32 tempY((_maskY & tvy.u) | (~_maskY & fvy.u));
15691 float32_uint32 tempZ((_maskZ & tvz.u) | (~_maskZ & fvz.u));
15692 float32_uint32 tempW((_maskW & tvw.u) | (~_maskW & fvw.u));
15694 float32x4_value_t result;
15695 result.storage[0] = tempX.f;
15696 result.storage[1] = tempY.f;
15697 result.storage[2] = tempZ.f;
15698 result.storage[3] = tempW.f;
15700 RETURN_Float32x4_RESULT(result);
15704 // ----------------------------------------------------------------------------
15705 // Implementation of Runtime
15707 #define F(name, number_of_args, result_size) \
15708 { Runtime::k##name, Runtime::RUNTIME, #name, \
15709 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
15712 #define FH(name, number_of_args, result_size) \
15713 { Runtime::kHidden##name, Runtime::RUNTIME_HIDDEN, NULL, \
15714 FUNCTION_ADDR(RuntimeHidden_##name), number_of_args, result_size },
15717 #define I(name, number_of_args, result_size) \
15718 { Runtime::kInline##name, Runtime::INLINE, \
15719 "_" #name, NULL, number_of_args, result_size },
15722 #define IO(name, number_of_args, result_size) \
15723 { Runtime::kInlineOptimized##name, Runtime::INLINE_OPTIMIZED, \
15724 "_" #name, FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
15727 static const Runtime::Function kIntrinsicFunctions[] = {
15728 RUNTIME_FUNCTION_LIST(F)
15729 RUNTIME_HIDDEN_FUNCTION_LIST(FH)
15730 INLINE_FUNCTION_LIST(I)
15731 INLINE_OPTIMIZED_FUNCTION_LIST(IO)
15740 MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
15741 Object* dictionary) {
15742 ASSERT(dictionary != NULL);
15743 ASSERT(NameDictionary::cast(dictionary)->NumberOfElements() == 0);
15744 for (int i = 0; i < kNumFunctions; ++i) {
15745 const char* name = kIntrinsicFunctions[i].name;
15746 if (name == NULL) continue;
15747 Object* name_string;
15748 { MaybeObject* maybe_name_string =
15749 heap->InternalizeUtf8String(name);
15750 if (!maybe_name_string->ToObject(&name_string)) return maybe_name_string;
15752 NameDictionary* name_dictionary = NameDictionary::cast(dictionary);
15753 { MaybeObject* maybe_dictionary = name_dictionary->Add(
15754 String::cast(name_string),
15756 PropertyDetails(NONE, NORMAL, Representation::None()));
15757 if (!maybe_dictionary->ToObject(&dictionary)) {
15758 // Non-recoverable failure. Calling code must restart heap
15760 return maybe_dictionary;
15768 const Runtime::Function* Runtime::FunctionForName(Handle<String> name) {
15769 Heap* heap = name->GetHeap();
15770 int entry = heap->intrinsic_function_names()->FindEntry(*name);
15771 if (entry != kNotFound) {
15772 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
15773 int function_index = Smi::cast(smi_index)->value();
15774 return &(kIntrinsicFunctions[function_index]);
15780 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
15781 return &(kIntrinsicFunctions[static_cast<int>(id)]);
15785 void Runtime::PerformGC(Object* result, Isolate* isolate) {
15786 Failure* failure = Failure::cast(result);
15787 if (failure->IsRetryAfterGC()) {
15788 if (isolate->heap()->new_space()->AddFreshPage()) {
15792 // Try to do a garbage collection; ignore it if it fails. The C
15793 // entry stub will throw an out-of-memory exception in that case.
15794 isolate->heap()->CollectGarbage(failure->allocation_space(),
15795 "Runtime::PerformGC");
15797 // Handle last resort GC and make sure to allow future allocations
15798 // to grow the heap without causing GCs (if possible).
15799 isolate->counters()->gc_last_resort_from_js()->Increment();
15800 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
15801 "Runtime::PerformGC");
15806 } } // namespace v8::internal