blob: c80f1fc348e49154d1df7e72230ee873c38f560f [file] [log] [blame]
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
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.
15//
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.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "compiler.h"
37#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000038#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include "debug.h"
40#include "execution.h"
41#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000042#include "liveedit.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000043#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "platform.h"
45#include "runtime.h"
46#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000047#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000048#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000049#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000050#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051
kasperl@chromium.org71affb52009-05-26 05:44:31 +000052namespace v8 {
53namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
55
ager@chromium.org3e875802009-06-29 08:26:34 +000056#define RUNTIME_ASSERT(value) \
57 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
59// Cast the given object to a value of the specified type and store
60// it in a variable with the given name. If the object is not of the
61// expected type call IllegalOperation and return.
62#define CONVERT_CHECKED(Type, name, obj) \
63 RUNTIME_ASSERT(obj->Is##Type()); \
64 Type* name = Type::cast(obj);
65
66#define CONVERT_ARG_CHECKED(Type, name, index) \
67 RUNTIME_ASSERT(args[index]->Is##Type()); \
68 Handle<Type> name = args.at<Type>(index);
69
kasper.lundbd3ec4e2008-07-09 11:06:54 +000070// Cast the given object to a boolean and store it in a variable with
71// the given name. If the object is not a boolean call IllegalOperation
72// and return.
73#define CONVERT_BOOLEAN_CHECKED(name, obj) \
74 RUNTIME_ASSERT(obj->IsBoolean()); \
75 bool name = (obj)->IsTrue();
76
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000077// Cast the given object to a Smi and store its value in an int variable
78// with the given name. If the object is not a Smi call IllegalOperation
79// and return.
80#define CONVERT_SMI_CHECKED(name, obj) \
81 RUNTIME_ASSERT(obj->IsSmi()); \
82 int name = Smi::cast(obj)->value();
83
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000084// Cast the given object to a double and store it in a variable with
85// the given name. If the object is not a number (as opposed to
86// the number not-a-number) call IllegalOperation and return.
87#define CONVERT_DOUBLE_CHECKED(name, obj) \
88 RUNTIME_ASSERT(obj->IsNumber()); \
89 double name = (obj)->Number();
90
91// Call the specified converter on the object *comand store the result in
92// a variable of the specified type with the given name. If the
93// object is not a Number call IllegalOperation and return.
94#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
95 RUNTIME_ASSERT(obj->IsNumber()); \
96 type name = NumberTo##Type(obj);
97
98// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000099static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000102MUST_USE_RESULT static Object* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000103 StackLimitCheck check;
104 if (check.HasOverflowed()) return Top::StackOverflow();
105
106 Object* result = Heap::CopyJSObject(boilerplate);
107 if (result->IsFailure()) return result;
108 JSObject* copy = JSObject::cast(result);
109
110 // Deep copy local properties.
111 if (copy->HasFastProperties()) {
112 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000113 for (int i = 0; i < properties->length(); i++) {
114 Object* value = properties->get(i);
115 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000116 JSObject* js_object = JSObject::cast(value);
117 result = DeepCopyBoilerplate(js_object);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 if (result->IsFailure()) return result;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000119 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000120 }
121 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000122 int nof = copy->map()->inobject_properties();
123 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000124 Object* value = copy->InObjectPropertyAt(i);
125 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 JSObject* js_object = JSObject::cast(value);
127 result = DeepCopyBoilerplate(js_object);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000128 if (result->IsFailure()) return result;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000129 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 }
131 }
132 } else {
133 result = Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
134 if (result->IsFailure()) return result;
135 FixedArray* names = FixedArray::cast(result);
136 copy->GetLocalPropertyNames(names, 0);
137 for (int i = 0; i < names->length(); i++) {
138 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000139 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000142 // Only deep copy fields from the object literal expression.
143 // In particular, don't try to copy the length attribute of
144 // an array.
145 if (attributes != NONE) continue;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000146 Object* value = copy->GetProperty(key_string, &attributes);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000147 ASSERT(!value->IsFailure());
148 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000149 JSObject* js_object = JSObject::cast(value);
150 result = DeepCopyBoilerplate(js_object);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 if (result->IsFailure()) return result;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 result = copy->SetProperty(key_string, result, NONE);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 if (result->IsFailure()) return result;
154 }
155 }
156 }
157
158 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000159 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000160 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000161 switch (copy->GetElementsKind()) {
162 case JSObject::FAST_ELEMENTS: {
163 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000164 if (elements->map() == Heap::fixed_cow_array_map()) {
165 Counters::cow_arrays_created_runtime.Increment();
166#ifdef DEBUG
167 for (int i = 0; i < elements->length(); i++) {
168 ASSERT(!elements->get(i)->IsJSObject());
169 }
170#endif
171 } else {
172 for (int i = 0; i < elements->length(); i++) {
173 Object* value = elements->get(i);
174 if (value->IsJSObject()) {
175 JSObject* js_object = JSObject::cast(value);
176 result = DeepCopyBoilerplate(js_object);
177 if (result->IsFailure()) return result;
178 elements->set(i, result);
179 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000180 }
181 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000182 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000183 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000184 case JSObject::DICTIONARY_ELEMENTS: {
185 NumberDictionary* element_dictionary = copy->element_dictionary();
186 int capacity = element_dictionary->Capacity();
187 for (int i = 0; i < capacity; i++) {
188 Object* k = element_dictionary->KeyAt(i);
189 if (element_dictionary->IsKey(k)) {
190 Object* value = element_dictionary->ValueAt(i);
191 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000192 JSObject* js_object = JSObject::cast(value);
193 result = DeepCopyBoilerplate(js_object);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000194 if (result->IsFailure()) return result;
195 element_dictionary->ValueAtPut(i, result);
196 }
197 }
198 }
199 break;
200 }
201 default:
202 UNREACHABLE();
203 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000204 }
205 return copy;
206}
207
208
209static Object* Runtime_CloneLiteralBoilerplate(Arguments args) {
210 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
211 return DeepCopyBoilerplate(boilerplate);
212}
213
214
215static Object* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000216 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000217 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218}
219
220
ager@chromium.org236ad962008-09-25 09:45:57 +0000221static Handle<Map> ComputeObjectLiteralMap(
222 Handle<Context> context,
223 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000224 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000225 int properties_length = constant_properties->length();
226 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000227 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000228 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000229 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000230 for (int p = 0; p != properties_length; p += 2) {
231 Object* key = constant_properties->get(p);
232 uint32_t element_index = 0;
233 if (key->IsSymbol()) {
234 number_of_symbol_keys++;
235 } else if (key->ToArrayIndex(&element_index)) {
236 // An index key does not require space in the property backing store.
237 number_of_properties--;
238 } else {
239 // Bail out as a non-symbol non-index key makes caching impossible.
240 // ASSERT to make sure that the if condition after the loop is false.
241 ASSERT(number_of_symbol_keys != number_of_properties);
242 break;
243 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000244 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000245 // If we only have symbols and array indices among keys then we can
246 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000247 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000248 if ((number_of_symbol_keys == number_of_properties) &&
249 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000250 // Create the fixed array with the key.
251 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000252 if (number_of_symbol_keys > 0) {
253 int index = 0;
254 for (int p = 0; p < properties_length; p += 2) {
255 Object* key = constant_properties->get(p);
256 if (key->IsSymbol()) {
257 keys->set(index++, key);
258 }
259 }
260 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000262 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 return Factory::ObjectLiteralMapFromCache(context, keys);
264 }
265 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000266 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000267 return Factory::CopyMap(
268 Handle<Map>(context->object_function()->initial_map()),
269 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000270}
271
272
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000273static Handle<Object> CreateLiteralBoilerplate(
274 Handle<FixedArray> literals,
275 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000276
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000277
278static Handle<Object> CreateObjectLiteralBoilerplate(
279 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000280 Handle<FixedArray> constant_properties,
281 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000282 // Get the global context from the literals array. This is the
283 // context in which the function was created and we use the object
284 // function from this context to create the object literal. We do
285 // not use the object function from the current global context
286 // because this might be the object function from another context
287 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000288 Handle<Context> context =
289 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
290
291 bool is_result_from_cache;
292 Handle<Map> map = ComputeObjectLiteralMap(context,
293 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000294 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000295
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000297
298 // Normalize the elements of the boilerplate to save space if needed.
299 if (!should_have_fast_elements) NormalizeElements(boilerplate);
300
ager@chromium.org32912102009-01-16 10:38:43 +0000301 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000302 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000303 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000304 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000305 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000306 for (int index = 0; index < length; index +=2) {
307 Handle<Object> key(constant_properties->get(index+0));
308 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000309 if (value->IsFixedArray()) {
310 // The value contains the constant_properties of a
311 // simple object literal.
312 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
313 value = CreateLiteralBoilerplate(literals, array);
314 if (value.is_null()) return value;
315 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000316 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000318 if (key->IsSymbol()) {
319 // If key is a symbol it is not an array element.
320 Handle<String> name(String::cast(*key));
321 ASSERT(!name->AsArrayIndex(&element_index));
322 result = SetProperty(boilerplate, name, value, NONE);
323 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324 // Array index (uint32).
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000325 result = SetElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326 } else {
327 // Non-uint32 number.
328 ASSERT(key->IsNumber());
329 double num = key->Number();
330 char arr[100];
331 Vector<char> buffer(arr, ARRAY_SIZE(arr));
332 const char* str = DoubleToCString(num, buffer);
333 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000334 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000336 // If setting the property on the boilerplate throws an
337 // exception, the exception is converted to an empty handle in
338 // the handle based operations. In that case, we need to
339 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000340 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000341 }
342 }
343
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000344 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000345}
346
347
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000348static Handle<Object> CreateArrayLiteralBoilerplate(
349 Handle<FixedArray> literals,
350 Handle<FixedArray> elements) {
351 // Create the JSArray.
352 Handle<JSFunction> constructor(
353 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
354 Handle<Object> object = Factory::NewJSObject(constructor);
355
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000356 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
357 Handle<FixedArray> copied_elements =
358 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000359
360 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000361 if (is_cow) {
362#ifdef DEBUG
363 // Copy-on-write arrays must be shallow (and simple).
364 for (int i = 0; i < content->length(); i++) {
365 ASSERT(!content->get(i)->IsFixedArray());
366 }
367#endif
368 } else {
369 for (int i = 0; i < content->length(); i++) {
370 if (content->get(i)->IsFixedArray()) {
371 // The value contains the constant_properties of a
372 // simple object literal.
373 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
374 Handle<Object> result =
375 CreateLiteralBoilerplate(literals, fa);
376 if (result.is_null()) return result;
377 content->set(i, *result);
378 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000379 }
380 }
381
382 // Set the elements.
383 Handle<JSArray>::cast(object)->SetContent(*content);
384 return object;
385}
386
387
388static Handle<Object> CreateLiteralBoilerplate(
389 Handle<FixedArray> literals,
390 Handle<FixedArray> array) {
391 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
392 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000393 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
394 return CreateObjectLiteralBoilerplate(literals, elements, true);
395 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
396 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000397 case CompileTimeValue::ARRAY_LITERAL:
398 return CreateArrayLiteralBoilerplate(literals, elements);
399 default:
400 UNREACHABLE();
401 return Handle<Object>::null();
402 }
403}
404
405
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000407 // Takes a FixedArray of elements containing the literal elements of
408 // the array literal and produces JSArray with those elements.
409 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000410 // which contains the context from which to get the Array function
411 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000412 HandleScope scope;
413 ASSERT(args.length() == 3);
414 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
415 CONVERT_SMI_CHECKED(literals_index, args[1]);
416 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000418 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
419 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421 // Update the functions literal and return the boilerplate.
422 literals->set(literals_index, *object);
423 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000424}
425
426
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000427static Object* Runtime_CreateObjectLiteral(Arguments args) {
428 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000429 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000430 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
431 CONVERT_SMI_CHECKED(literals_index, args[1]);
432 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000433 CONVERT_SMI_CHECKED(fast_elements, args[3]);
434 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000435
436 // Check if boilerplate exists. If not, create it first.
437 Handle<Object> boilerplate(literals->get(literals_index));
438 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000439 boilerplate = CreateObjectLiteralBoilerplate(literals,
440 constant_properties,
441 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000442 if (boilerplate.is_null()) return Failure::Exception();
443 // Update the functions literal and return the boilerplate.
444 literals->set(literals_index, *boilerplate);
445 }
446 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
447}
448
449
450static Object* Runtime_CreateObjectLiteralShallow(Arguments args) {
451 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000452 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000453 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
454 CONVERT_SMI_CHECKED(literals_index, args[1]);
455 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000456 CONVERT_SMI_CHECKED(fast_elements, args[3]);
457 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000458
459 // Check if boilerplate exists. If not, create it first.
460 Handle<Object> boilerplate(literals->get(literals_index));
461 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000462 boilerplate = CreateObjectLiteralBoilerplate(literals,
463 constant_properties,
464 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000465 if (boilerplate.is_null()) return Failure::Exception();
466 // Update the functions literal and return the boilerplate.
467 literals->set(literals_index, *boilerplate);
468 }
469 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
470}
471
472
473static Object* Runtime_CreateArrayLiteral(Arguments args) {
474 HandleScope scope;
475 ASSERT(args.length() == 3);
476 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
477 CONVERT_SMI_CHECKED(literals_index, args[1]);
478 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
479
480 // Check if boilerplate exists. If not, create it first.
481 Handle<Object> boilerplate(literals->get(literals_index));
482 if (*boilerplate == Heap::undefined_value()) {
483 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
484 if (boilerplate.is_null()) return Failure::Exception();
485 // Update the functions literal and return the boilerplate.
486 literals->set(literals_index, *boilerplate);
487 }
488 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
489}
490
491
492static Object* Runtime_CreateArrayLiteralShallow(Arguments args) {
493 HandleScope scope;
494 ASSERT(args.length() == 3);
495 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
496 CONVERT_SMI_CHECKED(literals_index, args[1]);
497 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
498
499 // Check if boilerplate exists. If not, create it first.
500 Handle<Object> boilerplate(literals->get(literals_index));
501 if (*boilerplate == Heap::undefined_value()) {
502 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
503 if (boilerplate.is_null()) return Failure::Exception();
504 // Update the functions literal and return the boilerplate.
505 literals->set(literals_index, *boilerplate);
506 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000507 if (JSObject::cast(*boilerplate)->elements()->map() ==
508 Heap::fixed_cow_array_map()) {
509 Counters::cow_arrays_created_runtime.Increment();
510 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000511 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
512}
513
514
ager@chromium.org32912102009-01-16 10:38:43 +0000515static Object* Runtime_CreateCatchExtensionObject(Arguments args) {
516 ASSERT(args.length() == 2);
517 CONVERT_CHECKED(String, key, args[0]);
518 Object* value = args[1];
519 // Create a catch context extension object.
520 JSFunction* constructor =
521 Top::context()->global_context()->context_extension_function();
522 Object* object = Heap::AllocateJSObject(constructor);
523 if (object->IsFailure()) return object;
524 // Assign the exception value to the catch variable and make sure
525 // that the catch variable is DontDelete.
526 value = JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
527 if (value->IsFailure()) return value;
528 return object;
529}
530
531
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532static Object* Runtime_ClassOf(Arguments args) {
533 NoHandleAllocation ha;
534 ASSERT(args.length() == 1);
535 Object* obj = args[0];
536 if (!obj->IsJSObject()) return Heap::null_value();
537 return JSObject::cast(obj)->class_name();
538}
539
ager@chromium.org7c537e22008-10-16 08:43:32 +0000540
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000541static Object* Runtime_IsInPrototypeChain(Arguments args) {
542 NoHandleAllocation ha;
543 ASSERT(args.length() == 2);
544 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
545 Object* O = args[0];
546 Object* V = args[1];
547 while (true) {
548 Object* prototype = V->GetPrototype();
549 if (prototype->IsNull()) return Heap::false_value();
550 if (O == prototype) return Heap::true_value();
551 V = prototype;
552 }
553}
554
555
ager@chromium.org9085a012009-05-11 19:22:57 +0000556// Inserts an object as the hidden prototype of another object.
557static Object* Runtime_SetHiddenPrototype(Arguments args) {
558 NoHandleAllocation ha;
559 ASSERT(args.length() == 2);
560 CONVERT_CHECKED(JSObject, jsobject, args[0]);
561 CONVERT_CHECKED(JSObject, proto, args[1]);
562
563 // Sanity checks. The old prototype (that we are replacing) could
564 // theoretically be null, but if it is not null then check that we
565 // didn't already install a hidden prototype here.
566 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
567 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
568 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
569
570 // Allocate up front before we start altering state in case we get a GC.
571 Object* map_or_failure = proto->map()->CopyDropTransitions();
572 if (map_or_failure->IsFailure()) return map_or_failure;
573 Map* new_proto_map = Map::cast(map_or_failure);
574
575 map_or_failure = jsobject->map()->CopyDropTransitions();
576 if (map_or_failure->IsFailure()) return map_or_failure;
577 Map* new_map = Map::cast(map_or_failure);
578
579 // Set proto's prototype to be the old prototype of the object.
580 new_proto_map->set_prototype(jsobject->GetPrototype());
581 proto->set_map(new_proto_map);
582 new_proto_map->set_is_hidden_prototype();
583
584 // Set the object's prototype to proto.
585 new_map->set_prototype(proto);
586 jsobject->set_map(new_map);
587
588 return Heap::undefined_value();
589}
590
591
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000592static Object* Runtime_IsConstructCall(Arguments args) {
593 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000594 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000595 JavaScriptFrameIterator it;
596 return Heap::ToBoolean(it.frame()->IsConstructor());
597}
598
599
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000600// Recursively traverses hidden prototypes if property is not found
601static void GetOwnPropertyImplementation(JSObject* obj,
602 String* name,
603 LookupResult* result) {
604 obj->LocalLookupRealNamedProperty(name, result);
605
606 if (!result->IsProperty()) {
607 Object* proto = obj->GetPrototype();
608 if (proto->IsJSObject() &&
609 JSObject::cast(proto)->map()->is_hidden_prototype())
610 GetOwnPropertyImplementation(JSObject::cast(proto),
611 name, result);
612 }
613}
614
615
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000616// Enumerator used as indices into the array returned from GetOwnProperty
617enum PropertyDescriptorIndices {
618 IS_ACCESSOR_INDEX,
619 VALUE_INDEX,
620 GETTER_INDEX,
621 SETTER_INDEX,
622 WRITABLE_INDEX,
623 ENUMERABLE_INDEX,
624 CONFIGURABLE_INDEX,
625 DESCRIPTOR_SIZE
626};
627
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000628// Returns an array with the property description:
629// if args[1] is not a property on args[0]
630// returns undefined
631// if args[1] is a data property on args[0]
632// [false, value, Writeable, Enumerable, Configurable]
633// if args[1] is an accessor on args[0]
634// [true, GetFunction, SetFunction, Enumerable, Configurable]
635static Object* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000636 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000637 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000638 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000639 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
640 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000641 CONVERT_ARG_CHECKED(JSObject, obj, 0);
642 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000643
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000644 // This could be an element.
645 uint32_t index;
646 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000647 switch (obj->HasLocalElement(index)) {
648 case JSObject::UNDEFINED_ELEMENT:
649 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000650
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000651 case JSObject::STRING_CHARACTER_ELEMENT: {
652 // Special handling of string objects according to ECMAScript 5
653 // 15.5.5.2. Note that this might be a string object with elements
654 // other than the actual string value. This is covered by the
655 // subsequent cases.
656 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
657 Handle<String> str(String::cast(js_value->value()));
658 Handle<String> substr = SubString(str, index, index+1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000659
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000660 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
661 elms->set(VALUE_INDEX, *substr);
662 elms->set(WRITABLE_INDEX, Heap::false_value());
663 elms->set(ENUMERABLE_INDEX, Heap::false_value());
664 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
665 return *desc;
666 }
667
668 case JSObject::INTERCEPTED_ELEMENT:
669 case JSObject::FAST_ELEMENT: {
670 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
671 Handle<Object> element = GetElement(Handle<Object>(obj), index);
672 elms->set(VALUE_INDEX, *element);
673 elms->set(WRITABLE_INDEX, Heap::true_value());
674 elms->set(ENUMERABLE_INDEX, Heap::true_value());
675 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
676 return *desc;
677 }
678
679 case JSObject::DICTIONARY_ELEMENT: {
680 NumberDictionary* dictionary = obj->element_dictionary();
681 int entry = dictionary->FindEntry(index);
682 ASSERT(entry != NumberDictionary::kNotFound);
683 PropertyDetails details = dictionary->DetailsAt(entry);
684 switch (details.type()) {
685 case CALLBACKS: {
686 // This is an accessor property with getter and/or setter.
687 FixedArray* callbacks =
688 FixedArray::cast(dictionary->ValueAt(entry));
689 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
690 elms->set(GETTER_INDEX, callbacks->get(0));
691 elms->set(SETTER_INDEX, callbacks->get(1));
692 break;
693 }
694 case NORMAL:
695 // This is a data property.
696 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
697 elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
698 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
699 break;
700 default:
701 UNREACHABLE();
702 break;
703 }
704 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
705 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
706 return *desc;
707 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000708 }
709 }
710
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000711 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000712 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000713
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000714 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000715 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000716 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000717 if (result.type() == CALLBACKS) {
718 Object* structure = result.GetCallbackObject();
ager@chromium.org5c838252010-02-19 08:53:10 +0000719 if (structure->IsProxy() || structure->IsAccessorInfo()) {
720 // Property that is internally implemented as a callback or
721 // an API defined callback.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000722 Object* value = obj->GetPropertyWithCallback(
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000723 *obj, structure, *name, result.holder());
724 if (value->IsFailure()) return value;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000725 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
726 elms->set(VALUE_INDEX, value);
727 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000728 } else if (structure->IsFixedArray()) {
729 // __defineGetter__/__defineSetter__ callback.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000730 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
731 elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
732 elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000733 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000734 return Heap::undefined_value();
735 }
736 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000737 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
738 elms->set(VALUE_INDEX, result.GetLazyValue());
739 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000740 }
741
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000742 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
743 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000744 return *desc;
745}
746
747
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000748static Object* Runtime_PreventExtensions(Arguments args) {
749 ASSERT(args.length() == 1);
750 CONVERT_CHECKED(JSObject, obj, args[0]);
751 return obj->PreventExtensions();
752}
753
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000754static Object* Runtime_IsExtensible(Arguments args) {
755 ASSERT(args.length() == 1);
756 CONVERT_CHECKED(JSObject, obj, args[0]);
757 return obj->map()->is_extensible() ? Heap::true_value()
758 : Heap::false_value();
759}
760
761
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000762static Object* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000763 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000765 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
766 CONVERT_ARG_CHECKED(String, pattern, 1);
767 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000768 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
769 if (result.is_null()) return Failure::Exception();
770 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771}
772
773
774static Object* Runtime_CreateApiFunction(Arguments args) {
775 HandleScope scope;
776 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000777 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778 return *Factory::CreateApiFunction(data);
779}
780
781
782static Object* Runtime_IsTemplate(Arguments args) {
783 ASSERT(args.length() == 1);
784 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000785 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000786 return Heap::ToBoolean(result);
787}
788
789
790static Object* Runtime_GetTemplateField(Arguments args) {
791 ASSERT(args.length() == 2);
792 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000794 int index = field->value();
795 int offset = index * kPointerSize + HeapObject::kHeaderSize;
796 InstanceType type = templ->map()->instance_type();
797 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
798 type == OBJECT_TEMPLATE_INFO_TYPE);
799 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000800 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000801 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
802 } else {
803 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
804 }
805 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806}
807
808
ager@chromium.org870a0b62008-11-04 11:43:05 +0000809static Object* Runtime_DisableAccessChecks(Arguments args) {
810 ASSERT(args.length() == 1);
811 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000812 Map* old_map = object->map();
813 bool needs_access_checks = old_map->is_access_check_needed();
814 if (needs_access_checks) {
815 // Copy map so it won't interfere constructor's initial map.
816 Object* new_map = old_map->CopyDropTransitions();
817 if (new_map->IsFailure()) return new_map;
818
819 Map::cast(new_map)->set_is_access_check_needed(false);
820 object->set_map(Map::cast(new_map));
821 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000822 return needs_access_checks ? Heap::true_value() : Heap::false_value();
823}
824
825
826static Object* Runtime_EnableAccessChecks(Arguments args) {
827 ASSERT(args.length() == 1);
828 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000829 Map* old_map = object->map();
830 if (!old_map->is_access_check_needed()) {
831 // Copy map so it won't interfere constructor's initial map.
832 Object* new_map = old_map->CopyDropTransitions();
833 if (new_map->IsFailure()) return new_map;
834
835 Map::cast(new_map)->set_is_access_check_needed(true);
836 object->set_map(Map::cast(new_map));
837 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000838 return Heap::undefined_value();
839}
840
841
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
843 HandleScope scope;
844 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
845 Handle<Object> args[2] = { type_handle, name };
846 Handle<Object> error =
847 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
848 return Top::Throw(*error);
849}
850
851
852static Object* Runtime_DeclareGlobals(Arguments args) {
853 HandleScope scope;
854 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
855
ager@chromium.org3811b432009-10-28 14:53:37 +0000856 Handle<Context> context = args.at<Context>(0);
857 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000858 bool is_eval = Smi::cast(args[2])->value() == 1;
859
860 // Compute the property attributes. According to ECMA-262, section
861 // 13, page 71, the property must be read-only and
862 // non-deletable. However, neither SpiderMonkey nor KJS creates the
863 // property as read-only, so we don't either.
864 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866 // Traverse the name/value pairs and set the properties.
867 int length = pairs->length();
868 for (int i = 0; i < length; i += 2) {
869 HandleScope scope;
870 Handle<String> name(String::cast(pairs->get(i)));
871 Handle<Object> value(pairs->get(i + 1));
872
873 // We have to declare a global const property. To capture we only
874 // assign to it when evaluating the assignment for "const x =
875 // <expr>" the initial value is the hole.
876 bool is_const_property = value->IsTheHole();
877
878 if (value->IsUndefined() || is_const_property) {
879 // Lookup the property in the global object, and don't set the
880 // value of the variable if the property is already there.
881 LookupResult lookup;
882 global->Lookup(*name, &lookup);
883 if (lookup.IsProperty()) {
884 // Determine if the property is local by comparing the holder
885 // against the global object. The information will be used to
886 // avoid throwing re-declaration errors when declaring
887 // variables or constants that exist in the prototype chain.
888 bool is_local = (*global == lookup.holder());
889 // Get the property attributes and determine if the property is
890 // read-only.
891 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
892 bool is_read_only = (attributes & READ_ONLY) != 0;
893 if (lookup.type() == INTERCEPTOR) {
894 // If the interceptor says the property is there, we
895 // just return undefined without overwriting the property.
896 // Otherwise, we continue to setting the property.
897 if (attributes != ABSENT) {
898 // Check if the existing property conflicts with regards to const.
899 if (is_local && (is_read_only || is_const_property)) {
900 const char* type = (is_read_only) ? "const" : "var";
901 return ThrowRedeclarationError(type, name);
902 };
903 // The property already exists without conflicting: Go to
904 // the next declaration.
905 continue;
906 }
907 // Fall-through and introduce the absent property by using
908 // SetProperty.
909 } else {
910 if (is_local && (is_read_only || is_const_property)) {
911 const char* type = (is_read_only) ? "const" : "var";
912 return ThrowRedeclarationError(type, name);
913 }
914 // The property already exists without conflicting: Go to
915 // the next declaration.
916 continue;
917 }
918 }
919 } else {
920 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000921 Handle<SharedFunctionInfo> shared =
922 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000924 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 value = function;
926 }
927
928 LookupResult lookup;
929 global->LocalLookup(*name, &lookup);
930
931 PropertyAttributes attributes = is_const_property
932 ? static_cast<PropertyAttributes>(base | READ_ONLY)
933 : base;
934
935 if (lookup.IsProperty()) {
936 // There's a local property that we need to overwrite because
937 // we're either declaring a function or there's an interceptor
938 // that claims the property is absent.
939
940 // Check for conflicting re-declarations. We cannot have
941 // conflicting types in case of intercepted properties because
942 // they are absent.
943 if (lookup.type() != INTERCEPTOR &&
944 (lookup.IsReadOnly() || is_const_property)) {
945 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
946 return ThrowRedeclarationError(type, name);
947 }
948 SetProperty(global, name, value, attributes);
949 } else {
950 // If a property with this name does not already exist on the
951 // global object add the property locally. We take special
952 // precautions to always add it as a local property even in case
953 // of callbacks in the prototype chain (this rules out using
954 // SetProperty). Also, we must use the handle-based version to
955 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000956 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000957 }
958 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000959
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960 return Heap::undefined_value();
961}
962
963
964static Object* Runtime_DeclareContextSlot(Arguments args) {
965 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000966 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000967
ager@chromium.org7c537e22008-10-16 08:43:32 +0000968 CONVERT_ARG_CHECKED(Context, context, 0);
969 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000971 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000972 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000973 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000974
975 // Declarations are always done in the function context.
976 context = Handle<Context>(context->fcontext());
977
978 int index;
979 PropertyAttributes attributes;
980 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000981 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982 context->Lookup(name, flags, &index, &attributes);
983
984 if (attributes != ABSENT) {
985 // The name was declared before; check for conflicting
986 // re-declarations: This is similar to the code in parser.cc in
987 // the AstBuildingParser::Declare function.
988 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
989 // Functions are not read-only.
990 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
991 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
992 return ThrowRedeclarationError(type, name);
993 }
994
995 // Initialize it if necessary.
996 if (*initial_value != NULL) {
997 if (index >= 0) {
998 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000999 // the function context or the arguments object.
1000 if (holder->IsContext()) {
1001 ASSERT(holder.is_identical_to(context));
1002 if (((attributes & READ_ONLY) == 0) ||
1003 context->get(index)->IsTheHole()) {
1004 context->set(index, *initial_value);
1005 }
1006 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001007 // The holder is an arguments object.
1008 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1009 SetElement(arguments, index, initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 }
1011 } else {
1012 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001013 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014 SetProperty(context_ext, name, initial_value, mode);
1015 }
1016 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001019 // The property is not in the function context. It needs to be
1020 // "declared" in the function context's extension context, or in the
1021 // global context.
1022 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001023 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001024 // The function context's extension context exists - use it.
1025 context_ext = Handle<JSObject>(context->extension());
1026 } else {
1027 // The function context's extension context does not exists - allocate
1028 // it.
1029 context_ext = Factory::NewJSObject(Top::context_extension_function());
1030 // And store it in the extension slot.
1031 context->set_extension(*context_ext);
1032 }
1033 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034
ager@chromium.org7c537e22008-10-16 08:43:32 +00001035 // Declare the property by setting it to the initial value if provided,
1036 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1037 // constant declarations).
1038 ASSERT(!context_ext->HasLocalProperty(*name));
1039 Handle<Object> value(Heap::undefined_value());
1040 if (*initial_value != NULL) value = initial_value;
1041 SetProperty(context_ext, name, value, mode);
1042 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1043 }
1044
1045 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046}
1047
1048
1049static Object* Runtime_InitializeVarGlobal(Arguments args) {
1050 NoHandleAllocation nha;
1051
1052 // Determine if we need to assign to the variable if it already
1053 // exists (based on the number of arguments).
1054 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1055 bool assign = args.length() == 2;
1056
1057 CONVERT_ARG_CHECKED(String, name, 0);
1058 GlobalObject* global = Top::context()->global();
1059
1060 // According to ECMA-262, section 12.2, page 62, the property must
1061 // not be deletable.
1062 PropertyAttributes attributes = DONT_DELETE;
1063
1064 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001065 // there, there is a property with this name in the prototype chain.
1066 // We follow Safari and Firefox behavior and only set the property
1067 // locally if there is an explicit initialization value that we have
1068 // to assign to the property. When adding the property we take
1069 // special precautions to always add it as a local property even in
1070 // case of callbacks in the prototype chain (this rules out using
1071 // SetProperty). We have IgnoreAttributesAndSetLocalProperty for
1072 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001073 // Note that objects can have hidden prototypes, so we need to traverse
1074 // the whole chain of hidden prototypes to do a 'local' lookup.
1075 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001077 while (true) {
1078 real_holder->LocalLookup(*name, &lookup);
1079 if (lookup.IsProperty()) {
1080 // Determine if this is a redeclaration of something read-only.
1081 if (lookup.IsReadOnly()) {
1082 // If we found readonly property on one of hidden prototypes,
1083 // just shadow it.
1084 if (real_holder != Top::context()->global()) break;
1085 return ThrowRedeclarationError("const", name);
1086 }
1087
1088 // Determine if this is a redeclaration of an intercepted read-only
1089 // property and figure out if the property exists at all.
1090 bool found = true;
1091 PropertyType type = lookup.type();
1092 if (type == INTERCEPTOR) {
1093 HandleScope handle_scope;
1094 Handle<JSObject> holder(real_holder);
1095 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1096 real_holder = *holder;
1097 if (intercepted == ABSENT) {
1098 // The interceptor claims the property isn't there. We need to
1099 // make sure to introduce it.
1100 found = false;
1101 } else if ((intercepted & READ_ONLY) != 0) {
1102 // The property is present, but read-only. Since we're trying to
1103 // overwrite it with a variable declaration we must throw a
1104 // re-declaration error. However if we found readonly property
1105 // on one of hidden prototypes, just shadow it.
1106 if (real_holder != Top::context()->global()) break;
1107 return ThrowRedeclarationError("const", name);
1108 }
1109 }
1110
1111 if (found && !assign) {
1112 // The global property is there and we're not assigning any value
1113 // to it. Just return.
1114 return Heap::undefined_value();
1115 }
1116
1117 // Assign the value (or undefined) to the property.
1118 Object* value = (assign) ? args[1] : Heap::undefined_value();
1119 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001120 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001121
1122 Object* proto = real_holder->GetPrototype();
1123 if (!proto->IsJSObject())
1124 break;
1125
1126 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1127 break;
1128
1129 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130 }
1131
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001132 global = Top::context()->global();
1133 if (assign) {
1134 return global->IgnoreAttributesAndSetLocalProperty(*name,
1135 args[1],
1136 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001138 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001139}
1140
1141
1142static Object* Runtime_InitializeConstGlobal(Arguments args) {
1143 // All constants are declared with an initial value. The name
1144 // of the constant is the first argument and the initial value
1145 // is the second.
1146 RUNTIME_ASSERT(args.length() == 2);
1147 CONVERT_ARG_CHECKED(String, name, 0);
1148 Handle<Object> value = args.at<Object>(1);
1149
1150 // Get the current global object from top.
1151 GlobalObject* global = Top::context()->global();
1152
1153 // According to ECMA-262, section 12.2, page 62, the property must
1154 // not be deletable. Since it's a const, it must be READ_ONLY too.
1155 PropertyAttributes attributes =
1156 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1157
1158 // Lookup the property locally in the global object. If it isn't
1159 // there, we add the property and take special precautions to always
1160 // add it as a local property even in case of callbacks in the
1161 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001162 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 LookupResult lookup;
1164 global->LocalLookup(*name, &lookup);
1165 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001166 return global->IgnoreAttributesAndSetLocalProperty(*name,
1167 *value,
1168 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001169 }
1170
1171 // Determine if this is a redeclaration of something not
1172 // read-only. In case the result is hidden behind an interceptor we
1173 // need to ask it for the property attributes.
1174 if (!lookup.IsReadOnly()) {
1175 if (lookup.type() != INTERCEPTOR) {
1176 return ThrowRedeclarationError("var", name);
1177 }
1178
1179 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1180
1181 // Throw re-declaration error if the intercepted property is present
1182 // but not read-only.
1183 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1184 return ThrowRedeclarationError("var", name);
1185 }
1186
1187 // Restore global object from context (in case of GC) and continue
1188 // with setting the value because the property is either absent or
1189 // read-only. We also have to do redo the lookup.
1190 global = Top::context()->global();
1191
1192 // BUG 1213579: Handle the case where we have to set a read-only
1193 // property through an interceptor and only do it if it's
1194 // uninitialized, e.g. the hole. Nirk...
1195 global->SetProperty(*name, *value, attributes);
1196 return *value;
1197 }
1198
1199 // Set the value, but only we're assigning the initial value to a
1200 // constant. For now, we determine this by checking if the
1201 // current value is the hole.
1202 PropertyType type = lookup.type();
1203 if (type == FIELD) {
1204 FixedArray* properties = global->properties();
1205 int index = lookup.GetFieldIndex();
1206 if (properties->get(index)->IsTheHole()) {
1207 properties->set(index, *value);
1208 }
1209 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001210 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1211 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212 }
1213 } else {
1214 // Ignore re-initialization of constants that have already been
1215 // assigned a function value.
1216 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1217 }
1218
1219 // Use the set value as the result of the operation.
1220 return *value;
1221}
1222
1223
1224static Object* Runtime_InitializeConstContextSlot(Arguments args) {
1225 HandleScope scope;
1226 ASSERT(args.length() == 3);
1227
1228 Handle<Object> value(args[0]);
1229 ASSERT(!value->IsTheHole());
1230 CONVERT_ARG_CHECKED(Context, context, 1);
1231 Handle<String> name(String::cast(args[2]));
1232
1233 // Initializations are always done in the function context.
1234 context = Handle<Context>(context->fcontext());
1235
1236 int index;
1237 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001238 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001239 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240 context->Lookup(name, flags, &index, &attributes);
1241
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001242 // In most situations, the property introduced by the const
1243 // declaration should be present in the context extension object.
1244 // However, because declaration and initialization are separate, the
1245 // property might have been deleted (if it was introduced by eval)
1246 // before we reach the initialization point.
1247 //
1248 // Example:
1249 //
1250 // function f() { eval("delete x; const x;"); }
1251 //
1252 // In that case, the initialization behaves like a normal assignment
1253 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001255 // Property was found in a context.
1256 if (holder->IsContext()) {
1257 // The holder cannot be the function context. If it is, there
1258 // should have been a const redeclaration error when declaring
1259 // the const property.
1260 ASSERT(!holder.is_identical_to(context));
1261 if ((attributes & READ_ONLY) == 0) {
1262 Handle<Context>::cast(holder)->set(index, *value);
1263 }
1264 } else {
1265 // The holder is an arguments object.
1266 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001267 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1268 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269 }
1270 return *value;
1271 }
1272
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001273 // The property could not be found, we introduce it in the global
1274 // context.
1275 if (attributes == ABSENT) {
1276 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1277 SetProperty(global, name, value, NONE);
1278 return *value;
1279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001281 // The property was present in a context extension object.
1282 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001284 if (*context_ext == context->extension()) {
1285 // This is the property that was introduced by the const
1286 // declaration. Set it if it hasn't been set before. NOTE: We
1287 // cannot use GetProperty() to get the current value as it
1288 // 'unholes' the value.
1289 LookupResult lookup;
1290 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1291 ASSERT(lookup.IsProperty()); // the property was declared
1292 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1293
1294 PropertyType type = lookup.type();
1295 if (type == FIELD) {
1296 FixedArray* properties = context_ext->properties();
1297 int index = lookup.GetFieldIndex();
1298 if (properties->get(index)->IsTheHole()) {
1299 properties->set(index, *value);
1300 }
1301 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001302 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1303 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001304 }
1305 } else {
1306 // We should not reach here. Any real, named property should be
1307 // either a field or a dictionary slot.
1308 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309 }
1310 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001311 // The property was found in a different context extension object.
1312 // Set it if it is not a read-only property.
1313 if ((attributes & READ_ONLY) == 0) {
1314 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1315 // Setting a property might throw an exception. Exceptions
1316 // are converted to empty handles in handle operations. We
1317 // need to convert back to exceptions here.
1318 if (set.is_null()) {
1319 ASSERT(Top::has_pending_exception());
1320 return Failure::Exception();
1321 }
1322 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001324
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 return *value;
1326}
1327
1328
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001329static Object* Runtime_OptimizeObjectForAddingMultipleProperties(
1330 Arguments args) {
1331 HandleScope scope;
1332 ASSERT(args.length() == 2);
1333 CONVERT_ARG_CHECKED(JSObject, object, 0);
1334 CONVERT_SMI_CHECKED(properties, args[1]);
1335 if (object->HasFastProperties()) {
1336 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1337 }
1338 return *object;
1339}
1340
1341
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001342static Object* Runtime_RegExpExec(Arguments args) {
1343 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001344 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001345 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1346 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001347 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001348 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001349 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001350 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001351 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001352 RUNTIME_ASSERT(index >= 0);
1353 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001354 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001355 Handle<Object> result = RegExpImpl::Exec(regexp,
1356 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001357 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001358 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001359 if (result.is_null()) return Failure::Exception();
1360 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361}
1362
1363
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001364static Object* Runtime_RegExpConstructResult(Arguments args) {
1365 ASSERT(args.length() == 3);
1366 CONVERT_SMI_CHECKED(elements_count, args[0]);
1367 if (elements_count > JSArray::kMaxFastElementsLength) {
1368 return Top::ThrowIllegalOperation();
1369 }
1370 Object* new_object = Heap::AllocateFixedArrayWithHoles(elements_count);
1371 if (new_object->IsFailure()) return new_object;
1372 FixedArray* elements = FixedArray::cast(new_object);
1373 new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1374 NEW_SPACE,
1375 OLD_POINTER_SPACE);
1376 if (new_object->IsFailure()) return new_object;
1377 {
1378 AssertNoAllocation no_gc;
1379 HandleScope scope;
1380 reinterpret_cast<HeapObject*>(new_object)->
1381 set_map(Top::global_context()->regexp_result_map());
1382 }
1383 JSArray* array = JSArray::cast(new_object);
1384 array->set_properties(Heap::empty_fixed_array());
1385 array->set_elements(elements);
1386 array->set_length(Smi::FromInt(elements_count));
1387 // Write in-object properties after the length of the array.
1388 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1389 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1390 return array;
1391}
1392
1393
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001394static Object* Runtime_RegExpCloneResult(Arguments args) {
1395 ASSERT(args.length() == 1);
1396 Map* regexp_result_map;
1397 {
1398 AssertNoAllocation no_gc;
1399 HandleScope handles;
1400 regexp_result_map = Top::global_context()->regexp_result_map();
1401 }
1402 if (!args[0]->IsJSArray()) return args[0];
1403
1404 JSArray* result = JSArray::cast(args[0]);
1405 // Arguments to RegExpCloneResult should always be fresh RegExp exec call
1406 // results (either a fresh JSRegExpResult or null).
1407 // If the argument is not a JSRegExpResult, or isn't unmodified, just return
1408 // the argument uncloned.
1409 if (result->map() != regexp_result_map) return result;
1410
1411 // Having the original JSRegExpResult map guarantees that we have
1412 // fast elements and no properties except the two in-object properties.
1413 ASSERT(result->HasFastElements());
1414 ASSERT(result->properties() == Heap::empty_fixed_array());
1415 ASSERT_EQ(2, regexp_result_map->inobject_properties());
1416
1417 Object* new_array_alloc = Heap::AllocateRaw(JSRegExpResult::kSize,
1418 NEW_SPACE,
1419 OLD_POINTER_SPACE);
1420 if (new_array_alloc->IsFailure()) return new_array_alloc;
1421
1422 // Set HeapObject map to JSRegExpResult map.
1423 reinterpret_cast<HeapObject*>(new_array_alloc)->set_map(regexp_result_map);
1424
1425 JSArray* new_array = JSArray::cast(new_array_alloc);
1426
1427 // Copy JSObject properties.
1428 new_array->set_properties(result->properties()); // Empty FixedArray.
1429
1430 // Copy JSObject elements as copy-on-write.
1431 FixedArray* elements = FixedArray::cast(result->elements());
1432 if (elements != Heap::empty_fixed_array()) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001433 elements->set_map(Heap::fixed_cow_array_map());
1434 }
1435 new_array->set_elements(elements);
1436
1437 // Copy JSArray length.
1438 new_array->set_length(result->length());
1439
1440 // Copy JSRegExpResult in-object property fields input and index.
1441 new_array->FastPropertyAtPut(JSRegExpResult::kIndexIndex,
1442 result->FastPropertyAt(
1443 JSRegExpResult::kIndexIndex));
1444 new_array->FastPropertyAtPut(JSRegExpResult::kInputIndex,
1445 result->FastPropertyAt(
1446 JSRegExpResult::kInputIndex));
1447 return new_array;
1448}
1449
1450
lrn@chromium.org25156de2010-04-06 13:10:27 +00001451static Object* Runtime_RegExpInitializeObject(Arguments args) {
1452 AssertNoAllocation no_alloc;
1453 ASSERT(args.length() == 5);
1454 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1455 CONVERT_CHECKED(String, source, args[1]);
1456
1457 Object* global = args[2];
1458 if (!global->IsTrue()) global = Heap::false_value();
1459
1460 Object* ignoreCase = args[3];
1461 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1462
1463 Object* multiline = args[4];
1464 if (!multiline->IsTrue()) multiline = Heap::false_value();
1465
1466 Map* map = regexp->map();
1467 Object* constructor = map->constructor();
1468 if (constructor->IsJSFunction() &&
1469 JSFunction::cast(constructor)->initial_map() == map) {
1470 // If we still have the original map, set in-object properties directly.
1471 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1472 // TODO(lrn): Consider skipping write barrier on booleans as well.
1473 // Both true and false should be in oldspace at all times.
1474 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1475 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1476 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1477 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1478 Smi::FromInt(0),
1479 SKIP_WRITE_BARRIER);
1480 return regexp;
1481 }
1482
1483 // Map has changed, so use generic, but slower, method.
1484 PropertyAttributes final =
1485 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1486 PropertyAttributes writable =
1487 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
1488 regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(),
1489 source,
1490 final);
1491 regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(),
1492 global,
1493 final);
1494 regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(),
1495 ignoreCase,
1496 final);
1497 regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(),
1498 multiline,
1499 final);
1500 regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(),
1501 Smi::FromInt(0),
1502 writable);
1503 return regexp;
1504}
1505
1506
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001507static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) {
1508 HandleScope scope;
1509 ASSERT(args.length() == 1);
1510 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1511 // This is necessary to enable fast checks for absence of elements
1512 // on Array.prototype and below.
1513 prototype->set_elements(Heap::empty_fixed_array());
1514 return Smi::FromInt(0);
1515}
1516
1517
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001518static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1519 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001520 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001521 Handle<String> key = Factory::LookupAsciiSymbol(name);
1522 Handle<Code> code(Builtins::builtin(builtin_name));
1523 Handle<JSFunction> optimized = Factory::NewFunction(key,
1524 JS_OBJECT_TYPE,
1525 JSObject::kHeaderSize,
1526 code,
1527 false);
1528 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001529 SetProperty(holder, key, optimized, NONE);
1530 return optimized;
1531}
1532
1533
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001534static Object* Runtime_SpecialArrayFunctions(Arguments args) {
1535 HandleScope scope;
1536 ASSERT(args.length() == 1);
1537 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1538
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001539 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1540 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001541 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1542 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1543 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1544 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001545 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001546
1547 return *holder;
1548}
1549
1550
ager@chromium.org357bf652010-04-12 11:30:10 +00001551static Object* Runtime_GetGlobalReceiver(Arguments args) {
1552 // Returns a real global receiver, not one of builtins object.
1553 Context* global_context = Top::context()->global()->global_context();
1554 return global_context->global()->global_receiver();
1555}
1556
1557
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001558static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
1559 HandleScope scope;
1560 ASSERT(args.length() == 4);
1561 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1562 int index = Smi::cast(args[1])->value();
1563 Handle<String> pattern = args.at<String>(2);
1564 Handle<String> flags = args.at<String>(3);
1565
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001566 // Get the RegExp function from the context in the literals array.
1567 // This is the RegExp function from the context in which the
1568 // function was created. We do not use the RegExp function from the
1569 // current global context because this might be the RegExp function
1570 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001571 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001572 Handle<JSFunction>(
1573 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 // Compute the regular expression literal.
1575 bool has_pending_exception;
1576 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001577 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1578 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001579 if (has_pending_exception) {
1580 ASSERT(Top::has_pending_exception());
1581 return Failure::Exception();
1582 }
1583 literals->set(index, *regexp);
1584 return *regexp;
1585}
1586
1587
1588static Object* Runtime_FunctionGetName(Arguments args) {
1589 NoHandleAllocation ha;
1590 ASSERT(args.length() == 1);
1591
1592 CONVERT_CHECKED(JSFunction, f, args[0]);
1593 return f->shared()->name();
1594}
1595
1596
ager@chromium.org236ad962008-09-25 09:45:57 +00001597static Object* Runtime_FunctionSetName(Arguments args) {
1598 NoHandleAllocation ha;
1599 ASSERT(args.length() == 2);
1600
1601 CONVERT_CHECKED(JSFunction, f, args[0]);
1602 CONVERT_CHECKED(String, name, args[1]);
1603 f->shared()->set_name(name);
1604 return Heap::undefined_value();
1605}
1606
1607
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001608static Object* Runtime_FunctionRemovePrototype(Arguments args) {
1609 NoHandleAllocation ha;
1610 ASSERT(args.length() == 1);
1611
1612 CONVERT_CHECKED(JSFunction, f, args[0]);
1613 Object* obj = f->RemovePrototype();
1614 if (obj->IsFailure()) return obj;
1615
1616 return Heap::undefined_value();
1617}
1618
1619
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620static Object* Runtime_FunctionGetScript(Arguments args) {
1621 HandleScope scope;
1622 ASSERT(args.length() == 1);
1623
1624 CONVERT_CHECKED(JSFunction, fun, args[0]);
1625 Handle<Object> script = Handle<Object>(fun->shared()->script());
1626 if (!script->IsScript()) return Heap::undefined_value();
1627
1628 return *GetScriptWrapper(Handle<Script>::cast(script));
1629}
1630
1631
1632static Object* Runtime_FunctionGetSourceCode(Arguments args) {
1633 NoHandleAllocation ha;
1634 ASSERT(args.length() == 1);
1635
1636 CONVERT_CHECKED(JSFunction, f, args[0]);
1637 return f->shared()->GetSourceCode();
1638}
1639
1640
1641static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
1642 NoHandleAllocation ha;
1643 ASSERT(args.length() == 1);
1644
1645 CONVERT_CHECKED(JSFunction, fun, args[0]);
1646 int pos = fun->shared()->start_position();
1647 return Smi::FromInt(pos);
1648}
1649
1650
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001651static Object* Runtime_FunctionGetPositionForOffset(Arguments args) {
1652 ASSERT(args.length() == 2);
1653
1654 CONVERT_CHECKED(JSFunction, fun, args[0]);
1655 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1656
1657 Code* code = fun->code();
1658 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1659
1660 Address pc = code->address() + offset;
1661 return Smi::FromInt(fun->code()->SourcePosition(pc));
1662}
1663
1664
1665
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001666static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
1667 NoHandleAllocation ha;
1668 ASSERT(args.length() == 2);
1669
1670 CONVERT_CHECKED(JSFunction, fun, args[0]);
1671 CONVERT_CHECKED(String, name, args[1]);
1672 fun->SetInstanceClassName(name);
1673 return Heap::undefined_value();
1674}
1675
1676
1677static Object* Runtime_FunctionSetLength(Arguments args) {
1678 NoHandleAllocation ha;
1679 ASSERT(args.length() == 2);
1680
1681 CONVERT_CHECKED(JSFunction, fun, args[0]);
1682 CONVERT_CHECKED(Smi, length, args[1]);
1683 fun->shared()->set_length(length->value());
1684 return length;
1685}
1686
1687
1688static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001689 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001690 ASSERT(args.length() == 2);
1691
1692 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001693 ASSERT(fun->should_have_prototype());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001694 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
1695 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001696 return args[0]; // return TOS
1697}
1698
1699
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001700static Object* Runtime_FunctionIsAPIFunction(Arguments args) {
1701 NoHandleAllocation ha;
1702 ASSERT(args.length() == 1);
1703
1704 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001705 return f->shared()->IsApiFunction() ? Heap::true_value()
1706 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001707}
1708
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001709static Object* Runtime_FunctionIsBuiltin(Arguments args) {
1710 NoHandleAllocation ha;
1711 ASSERT(args.length() == 1);
1712
1713 CONVERT_CHECKED(JSFunction, f, args[0]);
1714 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1715}
1716
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001717
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001718static Object* Runtime_SetCode(Arguments args) {
1719 HandleScope scope;
1720 ASSERT(args.length() == 2);
1721
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001722 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723 Handle<Object> code = args.at<Object>(1);
1724
1725 Handle<Context> context(target->context());
1726
1727 if (!code->IsNull()) {
1728 RUNTIME_ASSERT(code->IsJSFunction());
1729 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001730 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001731
1732 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 return Failure::Exception();
1734 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001735 // Set the code, scope info, formal parameter count,
1736 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001737 target->shared()->set_code(shared->code());
1738 target->set_code(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001739 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001740 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001741 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001742 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001743 // Set the source code of the target function to undefined.
1744 // SetCode is only used for built-in constructors like String,
1745 // Array, and Object, and some web code
1746 // doesn't like seeing source code for constructors.
1747 target->shared()->set_script(Heap::undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001748 // Clear the optimization hints related to the compiled code as these are no
1749 // longer valid when the code is overwritten.
1750 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001751 context = Handle<Context>(fun->context());
1752
1753 // Make sure we get a fresh copy of the literal vector to avoid
1754 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001755 int number_of_literals = fun->NumberOfLiterals();
1756 Handle<FixedArray> literals =
1757 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001758 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001759 // Insert the object, regexp and array functions in the literals
1760 // array prefix. These are the functions that will be used when
1761 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001762 literals->set(JSFunction::kLiteralGlobalContextIndex,
1763 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001764 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001765 // It's okay to skip the write barrier here because the literals
1766 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001767 target->set_literals(*literals, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768 }
1769
1770 target->set_context(*context);
1771 return *target;
1772}
1773
1774
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001775static Object* Runtime_SetExpectedNumberOfProperties(Arguments args) {
1776 HandleScope scope;
1777 ASSERT(args.length() == 2);
1778 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1779 CONVERT_SMI_CHECKED(num, args[1]);
1780 RUNTIME_ASSERT(num >= 0);
1781 SetExpectedNofProperties(function, num);
1782 return Heap::undefined_value();
1783}
1784
1785
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001786static Object* CharFromCode(Object* char_code) {
1787 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001788 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001789 if (code <= 0xffff) {
1790 return Heap::LookupSingleCharacterStringFromCode(code);
1791 }
1792 }
1793 return Heap::empty_string();
1794}
1795
1796
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797static Object* Runtime_StringCharCodeAt(Arguments args) {
1798 NoHandleAllocation ha;
1799 ASSERT(args.length() == 2);
1800
1801 CONVERT_CHECKED(String, subject, args[0]);
1802 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001803 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001805 uint32_t i = 0;
1806 if (index->IsSmi()) {
1807 int value = Smi::cast(index)->value();
1808 if (value < 0) return Heap::nan_value();
1809 i = value;
1810 } else {
1811 ASSERT(index->IsHeapNumber());
1812 double value = HeapNumber::cast(index)->value();
1813 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001814 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001815
1816 // Flatten the string. If someone wants to get a char at an index
1817 // in a cons string, it is likely that more indices will be
1818 // accessed.
1819 Object* flat = subject->TryFlatten();
1820 if (flat->IsFailure()) return flat;
1821 subject = String::cast(flat);
1822
1823 if (i >= static_cast<uint32_t>(subject->length())) {
1824 return Heap::nan_value();
1825 }
1826
1827 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001828}
1829
1830
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001831static Object* Runtime_CharFromCode(Arguments args) {
1832 NoHandleAllocation ha;
1833 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001834 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001835}
1836
lrn@chromium.org25156de2010-04-06 13:10:27 +00001837
1838class FixedArrayBuilder {
1839 public:
1840 explicit FixedArrayBuilder(int initial_capacity)
1841 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1842 length_(0) {
1843 // Require a non-zero initial size. Ensures that doubling the size to
1844 // extend the array will work.
1845 ASSERT(initial_capacity > 0);
1846 }
1847
1848 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1849 : array_(backing_store),
1850 length_(0) {
1851 // Require a non-zero initial size. Ensures that doubling the size to
1852 // extend the array will work.
1853 ASSERT(backing_store->length() > 0);
1854 }
1855
1856 bool HasCapacity(int elements) {
1857 int length = array_->length();
1858 int required_length = length_ + elements;
1859 return (length >= required_length);
1860 }
1861
1862 void EnsureCapacity(int elements) {
1863 int length = array_->length();
1864 int required_length = length_ + elements;
1865 if (length < required_length) {
1866 int new_length = length;
1867 do {
1868 new_length *= 2;
1869 } while (new_length < required_length);
1870 Handle<FixedArray> extended_array =
1871 Factory::NewFixedArrayWithHoles(new_length);
1872 array_->CopyTo(0, *extended_array, 0, length_);
1873 array_ = extended_array;
1874 }
1875 }
1876
1877 void Add(Object* value) {
1878 ASSERT(length_ < capacity());
1879 array_->set(length_, value);
1880 length_++;
1881 }
1882
1883 void Add(Smi* value) {
1884 ASSERT(length_ < capacity());
1885 array_->set(length_, value);
1886 length_++;
1887 }
1888
1889 Handle<FixedArray> array() {
1890 return array_;
1891 }
1892
1893 int length() {
1894 return length_;
1895 }
1896
1897 int capacity() {
1898 return array_->length();
1899 }
1900
1901 Handle<JSArray> ToJSArray() {
1902 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1903 result_array->set_length(Smi::FromInt(length_));
1904 return result_array;
1905 }
1906
1907 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1908 target_array->set_elements(*array_);
1909 target_array->set_length(Smi::FromInt(length_));
1910 return target_array;
1911 }
1912
1913 private:
1914 Handle<FixedArray> array_;
1915 int length_;
1916};
1917
1918
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001919// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001920const int kStringBuilderConcatHelperLengthBits = 11;
1921const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001922
1923template <typename schar>
1924static inline void StringBuilderConcatHelper(String*,
1925 schar*,
1926 FixedArray*,
1927 int);
1928
lrn@chromium.org25156de2010-04-06 13:10:27 +00001929typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1930 StringBuilderSubstringLength;
1931typedef BitField<int,
1932 kStringBuilderConcatHelperLengthBits,
1933 kStringBuilderConcatHelperPositionBits>
1934 StringBuilderSubstringPosition;
1935
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001936
1937class ReplacementStringBuilder {
1938 public:
1939 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00001940 : array_builder_(estimated_part_count),
1941 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001942 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001943 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001944 // Require a non-zero initial size. Ensures that doubling the size to
1945 // extend the array will work.
1946 ASSERT(estimated_part_count > 0);
1947 }
1948
lrn@chromium.org25156de2010-04-06 13:10:27 +00001949 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
1950 int from,
1951 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001952 ASSERT(from >= 0);
1953 int length = to - from;
1954 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001955 if (StringBuilderSubstringLength::is_valid(length) &&
1956 StringBuilderSubstringPosition::is_valid(from)) {
1957 int encoded_slice = StringBuilderSubstringLength::encode(length) |
1958 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001959 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001960 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001961 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001962 builder->Add(Smi::FromInt(-length));
1963 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001964 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001965 }
1966
1967
1968 void EnsureCapacity(int elements) {
1969 array_builder_.EnsureCapacity(elements);
1970 }
1971
1972
1973 void AddSubjectSlice(int from, int to) {
1974 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001975 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001976 }
1977
1978
1979 void AddString(Handle<String> string) {
1980 int length = string->length();
1981 ASSERT(length > 0);
1982 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00001983 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001984 is_ascii_ = false;
1985 }
1986 IncrementCharacterCount(length);
1987 }
1988
1989
1990 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001991 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001992 return Factory::empty_string();
1993 }
1994
1995 Handle<String> joined_string;
1996 if (is_ascii_) {
1997 joined_string = NewRawAsciiString(character_count_);
1998 AssertNoAllocation no_alloc;
1999 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2000 char* char_buffer = seq->GetChars();
2001 StringBuilderConcatHelper(*subject_,
2002 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002003 *array_builder_.array(),
2004 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002005 } else {
2006 // Non-ASCII.
2007 joined_string = NewRawTwoByteString(character_count_);
2008 AssertNoAllocation no_alloc;
2009 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2010 uc16* char_buffer = seq->GetChars();
2011 StringBuilderConcatHelper(*subject_,
2012 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002013 *array_builder_.array(),
2014 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002015 }
2016 return joined_string;
2017 }
2018
2019
2020 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002021 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002022 V8::FatalProcessOutOfMemory("String.replace result too large.");
2023 }
2024 character_count_ += by;
2025 }
2026
lrn@chromium.org25156de2010-04-06 13:10:27 +00002027 Handle<JSArray> GetParts() {
2028 Handle<JSArray> result =
2029 Factory::NewJSArrayWithElements(array_builder_.array());
2030 result->set_length(Smi::FromInt(array_builder_.length()));
2031 return result;
2032 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002033
lrn@chromium.org25156de2010-04-06 13:10:27 +00002034 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002035 Handle<String> NewRawAsciiString(int size) {
2036 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2037 }
2038
2039
2040 Handle<String> NewRawTwoByteString(int size) {
2041 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2042 }
2043
2044
2045 void AddElement(Object* element) {
2046 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002047 ASSERT(array_builder_.capacity() > array_builder_.length());
2048 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002049 }
2050
lrn@chromium.org25156de2010-04-06 13:10:27 +00002051 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002052 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002053 int character_count_;
2054 bool is_ascii_;
2055};
2056
2057
2058class CompiledReplacement {
2059 public:
2060 CompiledReplacement()
2061 : parts_(1), replacement_substrings_(0) {}
2062
2063 void Compile(Handle<String> replacement,
2064 int capture_count,
2065 int subject_length);
2066
2067 void Apply(ReplacementStringBuilder* builder,
2068 int match_from,
2069 int match_to,
2070 Handle<JSArray> last_match_info);
2071
2072 // Number of distinct parts of the replacement pattern.
2073 int parts() {
2074 return parts_.length();
2075 }
2076 private:
2077 enum PartType {
2078 SUBJECT_PREFIX = 1,
2079 SUBJECT_SUFFIX,
2080 SUBJECT_CAPTURE,
2081 REPLACEMENT_SUBSTRING,
2082 REPLACEMENT_STRING,
2083
2084 NUMBER_OF_PART_TYPES
2085 };
2086
2087 struct ReplacementPart {
2088 static inline ReplacementPart SubjectMatch() {
2089 return ReplacementPart(SUBJECT_CAPTURE, 0);
2090 }
2091 static inline ReplacementPart SubjectCapture(int capture_index) {
2092 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2093 }
2094 static inline ReplacementPart SubjectPrefix() {
2095 return ReplacementPart(SUBJECT_PREFIX, 0);
2096 }
2097 static inline ReplacementPart SubjectSuffix(int subject_length) {
2098 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2099 }
2100 static inline ReplacementPart ReplacementString() {
2101 return ReplacementPart(REPLACEMENT_STRING, 0);
2102 }
2103 static inline ReplacementPart ReplacementSubString(int from, int to) {
2104 ASSERT(from >= 0);
2105 ASSERT(to > from);
2106 return ReplacementPart(-from, to);
2107 }
2108
2109 // If tag <= 0 then it is the negation of a start index of a substring of
2110 // the replacement pattern, otherwise it's a value from PartType.
2111 ReplacementPart(int tag, int data)
2112 : tag(tag), data(data) {
2113 // Must be non-positive or a PartType value.
2114 ASSERT(tag < NUMBER_OF_PART_TYPES);
2115 }
2116 // Either a value of PartType or a non-positive number that is
2117 // the negation of an index into the replacement string.
2118 int tag;
2119 // The data value's interpretation depends on the value of tag:
2120 // tag == SUBJECT_PREFIX ||
2121 // tag == SUBJECT_SUFFIX: data is unused.
2122 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2123 // tag == REPLACEMENT_SUBSTRING ||
2124 // tag == REPLACEMENT_STRING: data is index into array of substrings
2125 // of the replacement string.
2126 // tag <= 0: Temporary representation of the substring of the replacement
2127 // string ranging over -tag .. data.
2128 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2129 // substring objects.
2130 int data;
2131 };
2132
2133 template<typename Char>
2134 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2135 Vector<Char> characters,
2136 int capture_count,
2137 int subject_length) {
2138 int length = characters.length();
2139 int last = 0;
2140 for (int i = 0; i < length; i++) {
2141 Char c = characters[i];
2142 if (c == '$') {
2143 int next_index = i + 1;
2144 if (next_index == length) { // No next character!
2145 break;
2146 }
2147 Char c2 = characters[next_index];
2148 switch (c2) {
2149 case '$':
2150 if (i > last) {
2151 // There is a substring before. Include the first "$".
2152 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2153 last = next_index + 1; // Continue after the second "$".
2154 } else {
2155 // Let the next substring start with the second "$".
2156 last = next_index;
2157 }
2158 i = next_index;
2159 break;
2160 case '`':
2161 if (i > last) {
2162 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2163 }
2164 parts->Add(ReplacementPart::SubjectPrefix());
2165 i = next_index;
2166 last = i + 1;
2167 break;
2168 case '\'':
2169 if (i > last) {
2170 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2171 }
2172 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2173 i = next_index;
2174 last = i + 1;
2175 break;
2176 case '&':
2177 if (i > last) {
2178 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2179 }
2180 parts->Add(ReplacementPart::SubjectMatch());
2181 i = next_index;
2182 last = i + 1;
2183 break;
2184 case '0':
2185 case '1':
2186 case '2':
2187 case '3':
2188 case '4':
2189 case '5':
2190 case '6':
2191 case '7':
2192 case '8':
2193 case '9': {
2194 int capture_ref = c2 - '0';
2195 if (capture_ref > capture_count) {
2196 i = next_index;
2197 continue;
2198 }
2199 int second_digit_index = next_index + 1;
2200 if (second_digit_index < length) {
2201 // Peek ahead to see if we have two digits.
2202 Char c3 = characters[second_digit_index];
2203 if ('0' <= c3 && c3 <= '9') { // Double digits.
2204 int double_digit_ref = capture_ref * 10 + c3 - '0';
2205 if (double_digit_ref <= capture_count) {
2206 next_index = second_digit_index;
2207 capture_ref = double_digit_ref;
2208 }
2209 }
2210 }
2211 if (capture_ref > 0) {
2212 if (i > last) {
2213 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2214 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002215 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002216 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2217 last = next_index + 1;
2218 }
2219 i = next_index;
2220 break;
2221 }
2222 default:
2223 i = next_index;
2224 break;
2225 }
2226 }
2227 }
2228 if (length > last) {
2229 if (last == 0) {
2230 parts->Add(ReplacementPart::ReplacementString());
2231 } else {
2232 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2233 }
2234 }
2235 }
2236
2237 ZoneList<ReplacementPart> parts_;
2238 ZoneList<Handle<String> > replacement_substrings_;
2239};
2240
2241
2242void CompiledReplacement::Compile(Handle<String> replacement,
2243 int capture_count,
2244 int subject_length) {
2245 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002246 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002247 AssertNoAllocation no_alloc;
2248 ParseReplacementPattern(&parts_,
2249 replacement->ToAsciiVector(),
2250 capture_count,
2251 subject_length);
2252 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002253 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002254 AssertNoAllocation no_alloc;
2255
2256 ParseReplacementPattern(&parts_,
2257 replacement->ToUC16Vector(),
2258 capture_count,
2259 subject_length);
2260 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002261 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002262 int substring_index = 0;
2263 for (int i = 0, n = parts_.length(); i < n; i++) {
2264 int tag = parts_[i].tag;
2265 if (tag <= 0) { // A replacement string slice.
2266 int from = -tag;
2267 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002268 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002269 parts_[i].tag = REPLACEMENT_SUBSTRING;
2270 parts_[i].data = substring_index;
2271 substring_index++;
2272 } else if (tag == REPLACEMENT_STRING) {
2273 replacement_substrings_.Add(replacement);
2274 parts_[i].data = substring_index;
2275 substring_index++;
2276 }
2277 }
2278}
2279
2280
2281void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2282 int match_from,
2283 int match_to,
2284 Handle<JSArray> last_match_info) {
2285 for (int i = 0, n = parts_.length(); i < n; i++) {
2286 ReplacementPart part = parts_[i];
2287 switch (part.tag) {
2288 case SUBJECT_PREFIX:
2289 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2290 break;
2291 case SUBJECT_SUFFIX: {
2292 int subject_length = part.data;
2293 if (match_to < subject_length) {
2294 builder->AddSubjectSlice(match_to, subject_length);
2295 }
2296 break;
2297 }
2298 case SUBJECT_CAPTURE: {
2299 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002300 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002301 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2302 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2303 if (from >= 0 && to > from) {
2304 builder->AddSubjectSlice(from, to);
2305 }
2306 break;
2307 }
2308 case REPLACEMENT_SUBSTRING:
2309 case REPLACEMENT_STRING:
2310 builder->AddString(replacement_substrings_[part.data]);
2311 break;
2312 default:
2313 UNREACHABLE();
2314 }
2315 }
2316}
2317
2318
2319
2320static Object* StringReplaceRegExpWithString(String* subject,
2321 JSRegExp* regexp,
2322 String* replacement,
2323 JSArray* last_match_info) {
2324 ASSERT(subject->IsFlat());
2325 ASSERT(replacement->IsFlat());
2326
2327 HandleScope handles;
2328
2329 int length = subject->length();
2330 Handle<String> subject_handle(subject);
2331 Handle<JSRegExp> regexp_handle(regexp);
2332 Handle<String> replacement_handle(replacement);
2333 Handle<JSArray> last_match_info_handle(last_match_info);
2334 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2335 subject_handle,
2336 0,
2337 last_match_info_handle);
2338 if (match.is_null()) {
2339 return Failure::Exception();
2340 }
2341 if (match->IsNull()) {
2342 return *subject_handle;
2343 }
2344
2345 int capture_count = regexp_handle->CaptureCount();
2346
2347 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002348 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002349 CompiledReplacement compiled_replacement;
2350 compiled_replacement.Compile(replacement_handle,
2351 capture_count,
2352 length);
2353
2354 bool is_global = regexp_handle->GetFlags().is_global();
2355
2356 // Guessing the number of parts that the final result string is built
2357 // from. Global regexps can match any number of times, so we guess
2358 // conservatively.
2359 int expected_parts =
2360 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2361 ReplacementStringBuilder builder(subject_handle, expected_parts);
2362
2363 // Index of end of last match.
2364 int prev = 0;
2365
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002366 // Number of parts added by compiled replacement plus preceeding
2367 // string and possibly suffix after last match. It is possible for
2368 // all components to use two elements when encoded as two smis.
2369 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002370 bool matched = true;
2371 do {
2372 ASSERT(last_match_info_handle->HasFastElements());
2373 // Increase the capacity of the builder before entering local handle-scope,
2374 // so its internal buffer can safely allocate a new handle if it grows.
2375 builder.EnsureCapacity(parts_added_per_loop);
2376
2377 HandleScope loop_scope;
2378 int start, end;
2379 {
2380 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002381 FixedArray* match_info_array =
2382 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002383
2384 ASSERT_EQ(capture_count * 2 + 2,
2385 RegExpImpl::GetLastCaptureCount(match_info_array));
2386 start = RegExpImpl::GetCapture(match_info_array, 0);
2387 end = RegExpImpl::GetCapture(match_info_array, 1);
2388 }
2389
2390 if (prev < start) {
2391 builder.AddSubjectSlice(prev, start);
2392 }
2393 compiled_replacement.Apply(&builder,
2394 start,
2395 end,
2396 last_match_info_handle);
2397 prev = end;
2398
2399 // Only continue checking for global regexps.
2400 if (!is_global) break;
2401
2402 // Continue from where the match ended, unless it was an empty match.
2403 int next = end;
2404 if (start == end) {
2405 next = end + 1;
2406 if (next > length) break;
2407 }
2408
2409 match = RegExpImpl::Exec(regexp_handle,
2410 subject_handle,
2411 next,
2412 last_match_info_handle);
2413 if (match.is_null()) {
2414 return Failure::Exception();
2415 }
2416 matched = !match->IsNull();
2417 } while (matched);
2418
2419 if (prev < length) {
2420 builder.AddSubjectSlice(prev, length);
2421 }
2422
2423 return *(builder.ToString());
2424}
2425
2426
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002427template <typename ResultSeqString>
2428static Object* StringReplaceRegExpWithEmptyString(String* subject,
2429 JSRegExp* regexp,
2430 JSArray* last_match_info) {
2431 ASSERT(subject->IsFlat());
2432
2433 HandleScope handles;
2434
2435 Handle<String> subject_handle(subject);
2436 Handle<JSRegExp> regexp_handle(regexp);
2437 Handle<JSArray> last_match_info_handle(last_match_info);
2438 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2439 subject_handle,
2440 0,
2441 last_match_info_handle);
2442 if (match.is_null()) return Failure::Exception();
2443 if (match->IsNull()) return *subject_handle;
2444
2445 ASSERT(last_match_info_handle->HasFastElements());
2446
2447 HandleScope loop_scope;
2448 int start, end;
2449 {
2450 AssertNoAllocation match_info_array_is_not_in_a_handle;
2451 FixedArray* match_info_array =
2452 FixedArray::cast(last_match_info_handle->elements());
2453
2454 start = RegExpImpl::GetCapture(match_info_array, 0);
2455 end = RegExpImpl::GetCapture(match_info_array, 1);
2456 }
2457
2458 int length = subject->length();
2459 int new_length = length - (end - start);
2460 if (new_length == 0) {
2461 return Heap::empty_string();
2462 }
2463 Handle<ResultSeqString> answer;
2464 if (ResultSeqString::kHasAsciiEncoding) {
2465 answer =
2466 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2467 } else {
2468 answer =
2469 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2470 }
2471
2472 // If the regexp isn't global, only match once.
2473 if (!regexp_handle->GetFlags().is_global()) {
2474 if (start > 0) {
2475 String::WriteToFlat(*subject_handle,
2476 answer->GetChars(),
2477 0,
2478 start);
2479 }
2480 if (end < length) {
2481 String::WriteToFlat(*subject_handle,
2482 answer->GetChars() + start,
2483 end,
2484 length);
2485 }
2486 return *answer;
2487 }
2488
2489 int prev = 0; // Index of end of last match.
2490 int next = 0; // Start of next search (prev unless last match was empty).
2491 int position = 0;
2492
2493 do {
2494 if (prev < start) {
2495 // Add substring subject[prev;start] to answer string.
2496 String::WriteToFlat(*subject_handle,
2497 answer->GetChars() + position,
2498 prev,
2499 start);
2500 position += start - prev;
2501 }
2502 prev = end;
2503 next = end;
2504 // Continue from where the match ended, unless it was an empty match.
2505 if (start == end) {
2506 next++;
2507 if (next > length) break;
2508 }
2509 match = RegExpImpl::Exec(regexp_handle,
2510 subject_handle,
2511 next,
2512 last_match_info_handle);
2513 if (match.is_null()) return Failure::Exception();
2514 if (match->IsNull()) break;
2515
2516 ASSERT(last_match_info_handle->HasFastElements());
2517 HandleScope loop_scope;
2518 {
2519 AssertNoAllocation match_info_array_is_not_in_a_handle;
2520 FixedArray* match_info_array =
2521 FixedArray::cast(last_match_info_handle->elements());
2522 start = RegExpImpl::GetCapture(match_info_array, 0);
2523 end = RegExpImpl::GetCapture(match_info_array, 1);
2524 }
2525 } while (true);
2526
2527 if (prev < length) {
2528 // Add substring subject[prev;length] to answer string.
2529 String::WriteToFlat(*subject_handle,
2530 answer->GetChars() + position,
2531 prev,
2532 length);
2533 position += length - prev;
2534 }
2535
2536 if (position == 0) {
2537 return Heap::empty_string();
2538 }
2539
2540 // Shorten string and fill
2541 int string_size = ResultSeqString::SizeFor(position);
2542 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2543 int delta = allocated_string_size - string_size;
2544
2545 answer->set_length(position);
2546 if (delta == 0) return *answer;
2547
2548 Address end_of_string = answer->address() + string_size;
2549 Heap::CreateFillerObjectAt(end_of_string, delta);
2550
2551 return *answer;
2552}
2553
2554
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002555static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
2556 ASSERT(args.length() == 4);
2557
2558 CONVERT_CHECKED(String, subject, args[0]);
2559 if (!subject->IsFlat()) {
2560 Object* flat_subject = subject->TryFlatten();
2561 if (flat_subject->IsFailure()) {
2562 return flat_subject;
2563 }
2564 subject = String::cast(flat_subject);
2565 }
2566
2567 CONVERT_CHECKED(String, replacement, args[2]);
2568 if (!replacement->IsFlat()) {
2569 Object* flat_replacement = replacement->TryFlatten();
2570 if (flat_replacement->IsFailure()) {
2571 return flat_replacement;
2572 }
2573 replacement = String::cast(flat_replacement);
2574 }
2575
2576 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2577 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2578
2579 ASSERT(last_match_info->HasFastElements());
2580
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002581 if (replacement->length() == 0) {
2582 if (subject->HasOnlyAsciiChars()) {
2583 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2584 subject, regexp, last_match_info);
2585 } else {
2586 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2587 subject, regexp, last_match_info);
2588 }
2589 }
2590
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002591 return StringReplaceRegExpWithString(subject,
2592 regexp,
2593 replacement,
2594 last_match_info);
2595}
2596
2597
ager@chromium.org7c537e22008-10-16 08:43:32 +00002598// Perform string match of pattern on subject, starting at start index.
2599// Caller must ensure that 0 <= start_index <= sub->length(),
2600// and should check that pat->length() + start_index <= sub->length()
2601int Runtime::StringMatch(Handle<String> sub,
2602 Handle<String> pat,
2603 int start_index) {
2604 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002605 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002606
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002607 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002608 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002609
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002610 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002611 if (start_index + pattern_length > subject_length) return -1;
2612
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002613 if (!sub->IsFlat()) FlattenString(sub);
2614 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002615
ager@chromium.org7c537e22008-10-16 08:43:32 +00002616 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002617 // Extract flattened substrings of cons strings before determining asciiness.
2618 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002619 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002620 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002621 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002622
ager@chromium.org7c537e22008-10-16 08:43:32 +00002623 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002624 if (seq_pat->IsAsciiRepresentation()) {
2625 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2626 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002627 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002628 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002629 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002630 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002631 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2632 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002633 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002634 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002635 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002636}
2637
2638
2639static Object* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002640 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002641 ASSERT(args.length() == 3);
2642
ager@chromium.org7c537e22008-10-16 08:43:32 +00002643 CONVERT_ARG_CHECKED(String, sub, 0);
2644 CONVERT_ARG_CHECKED(String, pat, 1);
2645
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002646 Object* index = args[2];
2647 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002648 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002649
ager@chromium.org870a0b62008-11-04 11:43:05 +00002650 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002651 int position = Runtime::StringMatch(sub, pat, start_index);
2652 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002653}
2654
2655
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002656template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002657static int StringMatchBackwards(Vector<const schar> subject,
2658 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002659 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002660 int pattern_length = pattern.length();
2661 ASSERT(pattern_length >= 1);
2662 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002663
2664 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002665 for (int i = 0; i < pattern_length; i++) {
2666 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002667 if (c > String::kMaxAsciiCharCode) {
2668 return -1;
2669 }
2670 }
2671 }
2672
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002673 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002674 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002675 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002676 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002677 while (j < pattern_length) {
2678 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002679 break;
2680 }
2681 j++;
2682 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002683 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002684 return i;
2685 }
2686 }
2687 return -1;
2688}
2689
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002690static Object* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002691 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002692 ASSERT(args.length() == 3);
2693
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002694 CONVERT_ARG_CHECKED(String, sub, 0);
2695 CONVERT_ARG_CHECKED(String, pat, 1);
2696
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002697 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002698 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002699 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002700
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002701 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002702 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002704 if (start_index + pat_length > sub_length) {
2705 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002706 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002707
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002708 if (pat_length == 0) {
2709 return Smi::FromInt(start_index);
2710 }
2711
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002712 if (!sub->IsFlat()) FlattenString(sub);
2713 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002714
2715 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2716
2717 int position = -1;
2718
2719 if (pat->IsAsciiRepresentation()) {
2720 Vector<const char> pat_vector = pat->ToAsciiVector();
2721 if (sub->IsAsciiRepresentation()) {
2722 position = StringMatchBackwards(sub->ToAsciiVector(),
2723 pat_vector,
2724 start_index);
2725 } else {
2726 position = StringMatchBackwards(sub->ToUC16Vector(),
2727 pat_vector,
2728 start_index);
2729 }
2730 } else {
2731 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2732 if (sub->IsAsciiRepresentation()) {
2733 position = StringMatchBackwards(sub->ToAsciiVector(),
2734 pat_vector,
2735 start_index);
2736 } else {
2737 position = StringMatchBackwards(sub->ToUC16Vector(),
2738 pat_vector,
2739 start_index);
2740 }
2741 }
2742
2743 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002744}
2745
2746
2747static Object* Runtime_StringLocaleCompare(Arguments args) {
2748 NoHandleAllocation ha;
2749 ASSERT(args.length() == 2);
2750
2751 CONVERT_CHECKED(String, str1, args[0]);
2752 CONVERT_CHECKED(String, str2, args[1]);
2753
2754 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002755 int str1_length = str1->length();
2756 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002757
2758 // Decide trivial cases without flattening.
2759 if (str1_length == 0) {
2760 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2761 return Smi::FromInt(-str2_length);
2762 } else {
2763 if (str2_length == 0) return Smi::FromInt(str1_length);
2764 }
2765
2766 int end = str1_length < str2_length ? str1_length : str2_length;
2767
2768 // No need to flatten if we are going to find the answer on the first
2769 // character. At this point we know there is at least one character
2770 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002771 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002772 if (d != 0) return Smi::FromInt(d);
2773
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002774 str1->TryFlatten();
2775 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002776
2777 static StringInputBuffer buf1;
2778 static StringInputBuffer buf2;
2779
2780 buf1.Reset(str1);
2781 buf2.Reset(str2);
2782
2783 for (int i = 0; i < end; i++) {
2784 uint16_t char1 = buf1.GetNext();
2785 uint16_t char2 = buf2.GetNext();
2786 if (char1 != char2) return Smi::FromInt(char1 - char2);
2787 }
2788
2789 return Smi::FromInt(str1_length - str2_length);
2790}
2791
2792
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002793static Object* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002794 NoHandleAllocation ha;
2795 ASSERT(args.length() == 3);
2796
2797 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002798 Object* from = args[1];
2799 Object* to = args[2];
2800 int start, end;
2801 // We have a fast integer-only case here to avoid a conversion to double in
2802 // the common case where from and to are Smis.
2803 if (from->IsSmi() && to->IsSmi()) {
2804 start = Smi::cast(from)->value();
2805 end = Smi::cast(to)->value();
2806 } else {
2807 CONVERT_DOUBLE_CHECKED(from_number, from);
2808 CONVERT_DOUBLE_CHECKED(to_number, to);
2809 start = FastD2I(from_number);
2810 end = FastD2I(to_number);
2811 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002812 RUNTIME_ASSERT(end >= start);
2813 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002814 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002815 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002816 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002817}
2818
2819
ager@chromium.org41826e72009-03-30 13:30:57 +00002820static Object* Runtime_StringMatch(Arguments args) {
2821 ASSERT_EQ(3, args.length());
2822
2823 CONVERT_ARG_CHECKED(String, subject, 0);
2824 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2825 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2826 HandleScope handles;
2827
2828 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2829
2830 if (match.is_null()) {
2831 return Failure::Exception();
2832 }
2833 if (match->IsNull()) {
2834 return Heap::null_value();
2835 }
2836 int length = subject->length();
2837
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002838 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002839 ZoneList<int> offsets(8);
2840 do {
2841 int start;
2842 int end;
2843 {
2844 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002845 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002846 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2847 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2848 }
2849 offsets.Add(start);
2850 offsets.Add(end);
2851 int index = start < end ? end : end + 1;
2852 if (index > length) break;
2853 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2854 if (match.is_null()) {
2855 return Failure::Exception();
2856 }
2857 } while (!match->IsNull());
2858 int matches = offsets.length() / 2;
2859 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2860 for (int i = 0; i < matches ; i++) {
2861 int from = offsets.at(i * 2);
2862 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002863 Handle<String> match = Factory::NewSubString(subject, from, to);
2864 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002865 }
2866 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2867 result->set_length(Smi::FromInt(matches));
2868 return *result;
2869}
2870
2871
lrn@chromium.org25156de2010-04-06 13:10:27 +00002872// Two smis before and after the match, for very long strings.
2873const int kMaxBuilderEntriesPerRegExpMatch = 5;
2874
2875
2876static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2877 Handle<JSArray> last_match_info,
2878 int match_start,
2879 int match_end) {
2880 // Fill last_match_info with a single capture.
2881 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2882 AssertNoAllocation no_gc;
2883 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2884 RegExpImpl::SetLastCaptureCount(elements, 2);
2885 RegExpImpl::SetLastInput(elements, *subject);
2886 RegExpImpl::SetLastSubject(elements, *subject);
2887 RegExpImpl::SetCapture(elements, 0, match_start);
2888 RegExpImpl::SetCapture(elements, 1, match_end);
2889}
2890
2891
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002892template <typename SubjectChar, typename PatternChar>
2893static bool SearchStringMultiple(Vector<const SubjectChar> subject,
2894 Vector<const PatternChar> pattern,
2895 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002896 FixedArrayBuilder* builder,
2897 int* match_pos) {
2898 int pos = *match_pos;
2899 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002900 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002901 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002902 StringSearch<PatternChar, SubjectChar> search(pattern);
2903 while (pos <= max_search_start) {
2904 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2905 *match_pos = pos;
2906 return false;
2907 }
2908 // Position of end of previous match.
2909 int match_end = pos + pattern_length;
2910 int new_pos = search.Search(subject, match_end);
2911 if (new_pos >= 0) {
2912 // A match.
2913 if (new_pos > match_end) {
2914 ReplacementStringBuilder::AddSubjectSlice(builder,
2915 match_end,
2916 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002917 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002918 pos = new_pos;
2919 builder->Add(pattern_string);
2920 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002921 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002922 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002923 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002924
lrn@chromium.org25156de2010-04-06 13:10:27 +00002925 if (pos < max_search_start) {
2926 ReplacementStringBuilder::AddSubjectSlice(builder,
2927 pos + pattern_length,
2928 subject_length);
2929 }
2930 *match_pos = pos;
2931 return true;
2932}
2933
2934
2935static bool SearchStringMultiple(Handle<String> subject,
2936 Handle<String> pattern,
2937 Handle<JSArray> last_match_info,
2938 FixedArrayBuilder* builder) {
2939 ASSERT(subject->IsFlat());
2940 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002941
2942 // Treating as if a previous match was before first character.
2943 int match_pos = -pattern->length();
2944
2945 for (;;) { // Break when search complete.
2946 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
2947 AssertNoAllocation no_gc;
2948 if (subject->IsAsciiRepresentation()) {
2949 Vector<const char> subject_vector = subject->ToAsciiVector();
2950 if (pattern->IsAsciiRepresentation()) {
2951 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002952 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002953 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002954 builder,
2955 &match_pos)) break;
2956 } else {
2957 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002958 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002959 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002960 builder,
2961 &match_pos)) break;
2962 }
2963 } else {
2964 Vector<const uc16> subject_vector = subject->ToUC16Vector();
2965 if (pattern->IsAsciiRepresentation()) {
2966 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002967 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002968 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002969 builder,
2970 &match_pos)) break;
2971 } else {
2972 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002973 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002974 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002975 builder,
2976 &match_pos)) break;
2977 }
2978 }
2979 }
2980
2981 if (match_pos >= 0) {
2982 SetLastMatchInfoNoCaptures(subject,
2983 last_match_info,
2984 match_pos,
2985 match_pos + pattern->length());
2986 return true;
2987 }
2988 return false; // No matches at all.
2989}
2990
2991
2992static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
2993 Handle<String> subject,
2994 Handle<JSRegExp> regexp,
2995 Handle<JSArray> last_match_array,
2996 FixedArrayBuilder* builder) {
2997 ASSERT(subject->IsFlat());
2998 int match_start = -1;
2999 int match_end = 0;
3000 int pos = 0;
3001 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3002 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3003
3004 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003005 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003006 int subject_length = subject->length();
3007
3008 for (;;) { // Break on failure, return on exception.
3009 RegExpImpl::IrregexpResult result =
3010 RegExpImpl::IrregexpExecOnce(regexp,
3011 subject,
3012 pos,
3013 register_vector);
3014 if (result == RegExpImpl::RE_SUCCESS) {
3015 match_start = register_vector[0];
3016 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3017 if (match_end < match_start) {
3018 ReplacementStringBuilder::AddSubjectSlice(builder,
3019 match_end,
3020 match_start);
3021 }
3022 match_end = register_vector[1];
3023 HandleScope loop_scope;
3024 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3025 if (match_start != match_end) {
3026 pos = match_end;
3027 } else {
3028 pos = match_end + 1;
3029 if (pos > subject_length) break;
3030 }
3031 } else if (result == RegExpImpl::RE_FAILURE) {
3032 break;
3033 } else {
3034 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3035 return result;
3036 }
3037 }
3038
3039 if (match_start >= 0) {
3040 if (match_end < subject_length) {
3041 ReplacementStringBuilder::AddSubjectSlice(builder,
3042 match_end,
3043 subject_length);
3044 }
3045 SetLastMatchInfoNoCaptures(subject,
3046 last_match_array,
3047 match_start,
3048 match_end);
3049 return RegExpImpl::RE_SUCCESS;
3050 } else {
3051 return RegExpImpl::RE_FAILURE; // No matches at all.
3052 }
3053}
3054
3055
3056static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3057 Handle<String> subject,
3058 Handle<JSRegExp> regexp,
3059 Handle<JSArray> last_match_array,
3060 FixedArrayBuilder* builder) {
3061
3062 ASSERT(subject->IsFlat());
3063 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3064 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3065
3066 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003067 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003068
3069 RegExpImpl::IrregexpResult result =
3070 RegExpImpl::IrregexpExecOnce(regexp,
3071 subject,
3072 0,
3073 register_vector);
3074
3075 int capture_count = regexp->CaptureCount();
3076 int subject_length = subject->length();
3077
3078 // Position to search from.
3079 int pos = 0;
3080 // End of previous match. Differs from pos if match was empty.
3081 int match_end = 0;
3082 if (result == RegExpImpl::RE_SUCCESS) {
3083 // Need to keep a copy of the previous match for creating last_match_info
3084 // at the end, so we have two vectors that we swap between.
3085 OffsetsVector registers2(required_registers);
3086 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3087
3088 do {
3089 int match_start = register_vector[0];
3090 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3091 if (match_end < match_start) {
3092 ReplacementStringBuilder::AddSubjectSlice(builder,
3093 match_end,
3094 match_start);
3095 }
3096 match_end = register_vector[1];
3097
3098 {
3099 // Avoid accumulating new handles inside loop.
3100 HandleScope temp_scope;
3101 // Arguments array to replace function is match, captures, index and
3102 // subject, i.e., 3 + capture count in total.
3103 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003104 Handle<String> match = Factory::NewSubString(subject,
3105 match_start,
3106 match_end);
3107 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003108 for (int i = 1; i <= capture_count; i++) {
3109 int start = register_vector[i * 2];
3110 if (start >= 0) {
3111 int end = register_vector[i * 2 + 1];
3112 ASSERT(start <= end);
3113 Handle<String> substring = Factory::NewSubString(subject,
3114 start,
3115 end);
3116 elements->set(i, *substring);
3117 } else {
3118 ASSERT(register_vector[i * 2 + 1] < 0);
3119 elements->set(i, Heap::undefined_value());
3120 }
3121 }
3122 elements->set(capture_count + 1, Smi::FromInt(match_start));
3123 elements->set(capture_count + 2, *subject);
3124 builder->Add(*Factory::NewJSArrayWithElements(elements));
3125 }
3126 // Swap register vectors, so the last successful match is in
3127 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003128 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003129 prev_register_vector = register_vector;
3130 register_vector = tmp;
3131
3132 if (match_end > match_start) {
3133 pos = match_end;
3134 } else {
3135 pos = match_end + 1;
3136 if (pos > subject_length) {
3137 break;
3138 }
3139 }
3140
3141 result = RegExpImpl::IrregexpExecOnce(regexp,
3142 subject,
3143 pos,
3144 register_vector);
3145 } while (result == RegExpImpl::RE_SUCCESS);
3146
3147 if (result != RegExpImpl::RE_EXCEPTION) {
3148 // Finished matching, with at least one match.
3149 if (match_end < subject_length) {
3150 ReplacementStringBuilder::AddSubjectSlice(builder,
3151 match_end,
3152 subject_length);
3153 }
3154
3155 int last_match_capture_count = (capture_count + 1) * 2;
3156 int last_match_array_size =
3157 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3158 last_match_array->EnsureSize(last_match_array_size);
3159 AssertNoAllocation no_gc;
3160 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3161 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3162 RegExpImpl::SetLastSubject(elements, *subject);
3163 RegExpImpl::SetLastInput(elements, *subject);
3164 for (int i = 0; i < last_match_capture_count; i++) {
3165 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3166 }
3167 return RegExpImpl::RE_SUCCESS;
3168 }
3169 }
3170 // No matches at all, return failure or exception result directly.
3171 return result;
3172}
3173
3174
3175static Object* Runtime_RegExpExecMultiple(Arguments args) {
3176 ASSERT(args.length() == 4);
3177 HandleScope handles;
3178
3179 CONVERT_ARG_CHECKED(String, subject, 1);
3180 if (!subject->IsFlat()) { FlattenString(subject); }
3181 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3182 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3183 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3184
3185 ASSERT(last_match_info->HasFastElements());
3186 ASSERT(regexp->GetFlags().is_global());
3187 Handle<FixedArray> result_elements;
3188 if (result_array->HasFastElements()) {
3189 result_elements =
3190 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3191 } else {
3192 result_elements = Factory::NewFixedArrayWithHoles(16);
3193 }
3194 FixedArrayBuilder builder(result_elements);
3195
3196 if (regexp->TypeTag() == JSRegExp::ATOM) {
3197 Handle<String> pattern(
3198 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003199 if (!pattern->IsFlat()) FlattenString(pattern);
3200 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3201 return *builder.ToJSArray(result_array);
3202 }
3203 return Heap::null_value();
3204 }
3205
3206 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3207
3208 RegExpImpl::IrregexpResult result;
3209 if (regexp->CaptureCount() == 0) {
3210 result = SearchRegExpNoCaptureMultiple(subject,
3211 regexp,
3212 last_match_info,
3213 &builder);
3214 } else {
3215 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3216 }
3217 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3218 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3219 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3220 return Failure::Exception();
3221}
3222
3223
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003224static Object* Runtime_NumberToRadixString(Arguments args) {
3225 NoHandleAllocation ha;
3226 ASSERT(args.length() == 2);
3227
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003228 // Fast case where the result is a one character string.
3229 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3230 int value = Smi::cast(args[0])->value();
3231 int radix = Smi::cast(args[1])->value();
3232 if (value >= 0 && value < radix) {
3233 RUNTIME_ASSERT(radix <= 36);
3234 // Character array used for conversion.
3235 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3236 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3237 }
3238 }
3239
3240 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003241 CONVERT_DOUBLE_CHECKED(value, args[0]);
3242 if (isnan(value)) {
3243 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3244 }
3245 if (isinf(value)) {
3246 if (value < 0) {
3247 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3248 }
3249 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3250 }
3251 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3252 int radix = FastD2I(radix_number);
3253 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3254 char* str = DoubleToRadixCString(value, radix);
3255 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
3256 DeleteArray(str);
3257 return result;
3258}
3259
3260
3261static Object* Runtime_NumberToFixed(Arguments args) {
3262 NoHandleAllocation ha;
3263 ASSERT(args.length() == 2);
3264
3265 CONVERT_DOUBLE_CHECKED(value, args[0]);
3266 if (isnan(value)) {
3267 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3268 }
3269 if (isinf(value)) {
3270 if (value < 0) {
3271 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3272 }
3273 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3274 }
3275 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3276 int f = FastD2I(f_number);
3277 RUNTIME_ASSERT(f >= 0);
3278 char* str = DoubleToFixedCString(value, f);
3279 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
3280 DeleteArray(str);
3281 return res;
3282}
3283
3284
3285static Object* Runtime_NumberToExponential(Arguments args) {
3286 NoHandleAllocation ha;
3287 ASSERT(args.length() == 2);
3288
3289 CONVERT_DOUBLE_CHECKED(value, args[0]);
3290 if (isnan(value)) {
3291 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3292 }
3293 if (isinf(value)) {
3294 if (value < 0) {
3295 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3296 }
3297 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3298 }
3299 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3300 int f = FastD2I(f_number);
3301 RUNTIME_ASSERT(f >= -1 && f <= 20);
3302 char* str = DoubleToExponentialCString(value, f);
3303 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
3304 DeleteArray(str);
3305 return res;
3306}
3307
3308
3309static Object* Runtime_NumberToPrecision(Arguments args) {
3310 NoHandleAllocation ha;
3311 ASSERT(args.length() == 2);
3312
3313 CONVERT_DOUBLE_CHECKED(value, args[0]);
3314 if (isnan(value)) {
3315 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3316 }
3317 if (isinf(value)) {
3318 if (value < 0) {
3319 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3320 }
3321 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3322 }
3323 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3324 int f = FastD2I(f_number);
3325 RUNTIME_ASSERT(f >= 1 && f <= 21);
3326 char* str = DoubleToPrecisionCString(value, f);
3327 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
3328 DeleteArray(str);
3329 return res;
3330}
3331
3332
3333// Returns a single character string where first character equals
3334// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003335static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003336 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003337 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003338 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003339 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003340 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003341 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003342}
3343
3344
3345Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
3346 // Handle [] indexing on Strings
3347 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003348 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3349 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003350 }
3351
3352 // Handle [] indexing on String objects
3353 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003354 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3355 Handle<Object> result =
3356 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3357 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003358 }
3359
3360 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003361 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003362 return prototype->GetElement(index);
3363 }
3364
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003365 return GetElement(object, index);
3366}
3367
3368
3369Object* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370 return object->GetElement(index);
3371}
3372
3373
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003374Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
3375 HandleScope scope;
3376
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003377 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003378 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003379 Handle<Object> error =
3380 Factory::NewTypeError("non_object_property_load",
3381 HandleVector(args, 2));
3382 return Top::Throw(*error);
3383 }
3384
3385 // Check if the given key is an array index.
3386 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003387 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003388 return GetElementOrCharAt(object, index);
3389 }
3390
3391 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003392 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003393 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003394 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003395 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003396 bool has_pending_exception = false;
3397 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003398 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003400 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 }
3402
ager@chromium.org32912102009-01-16 10:38:43 +00003403 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003404 // the element if so.
3405 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003406 return GetElementOrCharAt(object, index);
3407 } else {
3408 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003409 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410 }
3411}
3412
3413
3414static Object* Runtime_GetProperty(Arguments args) {
3415 NoHandleAllocation ha;
3416 ASSERT(args.length() == 2);
3417
3418 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003419 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003420
3421 return Runtime::GetObjectProperty(object, key);
3422}
3423
3424
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003425// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003426static Object* Runtime_KeyedGetProperty(Arguments args) {
3427 NoHandleAllocation ha;
3428 ASSERT(args.length() == 2);
3429
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003430 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003431 // itself.
3432 //
3433 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003434 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003435 // global proxy object never has properties. This is the case
3436 // because the global proxy object forwards everything to its hidden
3437 // prototype including local lookups.
3438 //
3439 // Additionally, we need to make sure that we do not cache results
3440 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003441 if (args[0]->IsJSObject() &&
3442 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003443 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003444 args[1]->IsString()) {
3445 JSObject* receiver = JSObject::cast(args[0]);
3446 String* key = String::cast(args[1]);
3447 if (receiver->HasFastProperties()) {
3448 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003449 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003450 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3451 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003452 Object* value = receiver->FastPropertyAt(offset);
3453 return value->IsTheHole() ? Heap::undefined_value() : value;
3454 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003455 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003456 LookupResult result;
3457 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003458 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003459 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003460 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003461 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003462 }
3463 } else {
3464 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003465 StringDictionary* dictionary = receiver->property_dictionary();
3466 int entry = dictionary->FindEntry(key);
3467 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003468 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003469 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003470 if (!receiver->IsGlobalObject()) return value;
3471 value = JSGlobalPropertyCell::cast(value)->value();
3472 if (!value->IsTheHole()) return value;
3473 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003474 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003475 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003476 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3477 // Fast case for string indexing using [] with a smi index.
3478 HandleScope scope;
3479 Handle<String> str = args.at<String>(0);
3480 int index = Smi::cast(args[1])->value();
3481 Handle<Object> result = GetCharAt(str, index);
3482 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003483 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003484
3485 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003486 return Runtime::GetObjectProperty(args.at<Object>(0),
3487 args.at<Object>(1));
3488}
3489
3490
ager@chromium.org5c838252010-02-19 08:53:10 +00003491static Object* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
3492 ASSERT(args.length() == 5);
3493 HandleScope scope;
3494 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3495 CONVERT_CHECKED(String, name, args[1]);
3496 CONVERT_CHECKED(Smi, flag_setter, args[2]);
3497 CONVERT_CHECKED(JSFunction, fun, args[3]);
3498 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3499 int unchecked = flag_attr->value();
3500 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3501 RUNTIME_ASSERT(!obj->IsNull());
3502 LookupResult result;
3503 obj->LocalLookupRealNamedProperty(name, &result);
3504
3505 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3506 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3507 // delete it to avoid running into trouble in DefineAccessor, which
3508 // handles this incorrectly if the property is readonly (does nothing)
3509 if (result.IsProperty() &&
3510 (result.type() == FIELD || result.type() == NORMAL
3511 || result.type() == CONSTANT_FUNCTION)) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003512 Object* ok = obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3513 if (ok->IsFailure()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00003514 }
3515 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3516}
3517
3518static Object* Runtime_DefineOrRedefineDataProperty(Arguments args) {
3519 ASSERT(args.length() == 4);
3520 HandleScope scope;
3521 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3522 CONVERT_ARG_CHECKED(String, name, 1);
3523 Handle<Object> obj_value = args.at<Object>(2);
3524
3525 CONVERT_CHECKED(Smi, flag, args[3]);
3526 int unchecked = flag->value();
3527 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3528
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003529 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3530
3531 // Check if this is an element.
3532 uint32_t index;
3533 bool is_element = name->AsArrayIndex(&index);
3534
3535 // Special case for elements if any of the flags are true.
3536 // If elements are in fast case we always implicitly assume that:
3537 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3538 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3539 is_element) {
3540 // Normalize the elements to enable attributes on the property.
3541 js_object->NormalizeElements();
3542 NumberDictionary* dictionary = js_object->element_dictionary();
3543 // Make sure that we never go back to fast case.
3544 dictionary->set_requires_slow_elements();
3545 PropertyDetails details = PropertyDetails(attr, NORMAL);
3546 dictionary->Set(index, *obj_value, details);
3547 }
3548
ager@chromium.org5c838252010-02-19 08:53:10 +00003549 LookupResult result;
3550 js_object->LocalLookupRealNamedProperty(*name, &result);
3551
ager@chromium.org5c838252010-02-19 08:53:10 +00003552 // Take special care when attributes are different and there is already
3553 // a property. For simplicity we normalize the property which enables us
3554 // to not worry about changing the instance_descriptor and creating a new
3555 // map. The current version of SetObjectProperty does not handle attributes
3556 // correctly in the case where a property is a field and is reset with
3557 // new attributes.
3558 if (result.IsProperty() && attr != result.GetAttributes()) {
3559 // New attributes - normalize to avoid writing to instance descriptor
3560 js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3561 // Use IgnoreAttributes version since a readonly property may be
3562 // overridden and SetProperty does not allow this.
3563 return js_object->IgnoreAttributesAndSetLocalProperty(*name,
3564 *obj_value,
3565 attr);
3566 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003567
ager@chromium.org5c838252010-02-19 08:53:10 +00003568 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3569}
3570
3571
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572Object* Runtime::SetObjectProperty(Handle<Object> object,
3573 Handle<Object> key,
3574 Handle<Object> value,
3575 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003576 HandleScope scope;
3577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003578 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003579 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580 Handle<Object> error =
3581 Factory::NewTypeError("non_object_property_store",
3582 HandleVector(args, 2));
3583 return Top::Throw(*error);
3584 }
3585
3586 // If the object isn't a JavaScript object, we ignore the store.
3587 if (!object->IsJSObject()) return *value;
3588
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003589 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3590
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 // Check if the given key is an array index.
3592 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003593 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003594 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3595 // of a string using [] notation. We need to support this too in
3596 // JavaScript.
3597 // In the case of a String object we just need to redirect the assignment to
3598 // the underlying string if the index is in range. Since the underlying
3599 // string does nothing with the assignment then we can ignore such
3600 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003601 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003602 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003603 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003605 Handle<Object> result = SetElement(js_object, index, value);
3606 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003607 return *value;
3608 }
3609
3610 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003611 Handle<Object> result;
3612 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003613 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003614 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003615 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003616 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003617 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003619 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 return *value;
3621 }
3622
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003623 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003624 bool has_pending_exception = false;
3625 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3626 if (has_pending_exception) return Failure::Exception();
3627 Handle<String> name = Handle<String>::cast(converted);
3628
3629 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003630 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003632 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003633 }
3634}
3635
3636
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003637Object* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3638 Handle<Object> key,
3639 Handle<Object> value,
3640 PropertyAttributes attr) {
3641 HandleScope scope;
3642
3643 // Check if the given key is an array index.
3644 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003645 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003646 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3647 // of a string using [] notation. We need to support this too in
3648 // JavaScript.
3649 // In the case of a String object we just need to redirect the assignment to
3650 // the underlying string if the index is in range. Since the underlying
3651 // string does nothing with the assignment then we can ignore such
3652 // assignments.
3653 if (js_object->IsStringObjectWithCharacterAt(index)) {
3654 return *value;
3655 }
3656
3657 return js_object->SetElement(index, *value);
3658 }
3659
3660 if (key->IsString()) {
3661 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003662 return js_object->SetElement(index, *value);
3663 } else {
3664 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003665 key_string->TryFlatten();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003666 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
3667 *value,
3668 attr);
3669 }
3670 }
3671
3672 // Call-back into JavaScript to convert the key to a string.
3673 bool has_pending_exception = false;
3674 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3675 if (has_pending_exception) return Failure::Exception();
3676 Handle<String> name = Handle<String>::cast(converted);
3677
3678 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003679 return js_object->SetElement(index, *value);
3680 } else {
3681 return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr);
3682 }
3683}
3684
3685
ager@chromium.orge2902be2009-06-08 12:21:35 +00003686Object* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3687 Handle<Object> key) {
3688 HandleScope scope;
3689
3690 // Check if the given key is an array index.
3691 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003692 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003693 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3694 // characters of a string using [] notation. In the case of a
3695 // String object we just need to redirect the deletion to the
3696 // underlying string if the index is in range. Since the
3697 // underlying string does nothing with the deletion, we can ignore
3698 // such deletions.
3699 if (js_object->IsStringObjectWithCharacterAt(index)) {
3700 return Heap::true_value();
3701 }
3702
3703 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3704 }
3705
3706 Handle<String> key_string;
3707 if (key->IsString()) {
3708 key_string = Handle<String>::cast(key);
3709 } else {
3710 // Call-back into JavaScript to convert the key to a string.
3711 bool has_pending_exception = false;
3712 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3713 if (has_pending_exception) return Failure::Exception();
3714 key_string = Handle<String>::cast(converted);
3715 }
3716
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003717 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003718 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3719}
3720
3721
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003722static Object* Runtime_SetProperty(Arguments args) {
3723 NoHandleAllocation ha;
3724 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3725
3726 Handle<Object> object = args.at<Object>(0);
3727 Handle<Object> key = args.at<Object>(1);
3728 Handle<Object> value = args.at<Object>(2);
3729
3730 // Compute attributes.
3731 PropertyAttributes attributes = NONE;
3732 if (args.length() == 4) {
3733 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003734 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003735 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003736 RUNTIME_ASSERT(
3737 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3738 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003739 }
3740 return Runtime::SetObjectProperty(object, key, value, attributes);
3741}
3742
3743
3744// Set a local property, even if it is READ_ONLY. If the property does not
3745// exist, it will be added with attributes NONE.
3746static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
3747 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003748 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003749 CONVERT_CHECKED(JSObject, object, args[0]);
3750 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003751 // Compute attributes.
3752 PropertyAttributes attributes = NONE;
3753 if (args.length() == 4) {
3754 CONVERT_CHECKED(Smi, value_obj, args[3]);
3755 int unchecked_value = value_obj->value();
3756 // Only attribute bits should be set.
3757 RUNTIME_ASSERT(
3758 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3759 attributes = static_cast<PropertyAttributes>(unchecked_value);
3760 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003761
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003762 return object->
3763 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764}
3765
3766
3767static Object* Runtime_DeleteProperty(Arguments args) {
3768 NoHandleAllocation ha;
3769 ASSERT(args.length() == 2);
3770
3771 CONVERT_CHECKED(JSObject, object, args[0]);
3772 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003773 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774}
3775
3776
ager@chromium.org9085a012009-05-11 19:22:57 +00003777static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3778 Handle<String> key) {
3779 if (object->HasLocalProperty(*key)) return Heap::true_value();
3780 // Handle hidden prototypes. If there's a hidden prototype above this thing
3781 // then we have to check it for properties, because they are supposed to
3782 // look like they are on this object.
3783 Handle<Object> proto(object->GetPrototype());
3784 if (proto->IsJSObject() &&
3785 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3786 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3787 }
3788 return Heap::false_value();
3789}
3790
3791
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003792static Object* Runtime_HasLocalProperty(Arguments args) {
3793 NoHandleAllocation ha;
3794 ASSERT(args.length() == 2);
3795 CONVERT_CHECKED(String, key, args[1]);
3796
ager@chromium.org9085a012009-05-11 19:22:57 +00003797 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003799 if (obj->IsJSObject()) {
3800 JSObject* object = JSObject::cast(obj);
3801 // Fast case - no interceptors.
3802 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3803 // Slow case. Either it's not there or we have an interceptor. We should
3804 // have handles for this kind of deal.
3805 HandleScope scope;
3806 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3807 Handle<String>(key));
3808 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003809 // Well, there is one exception: Handle [] on strings.
3810 uint32_t index;
3811 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003812 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003813 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003814 return Heap::true_value();
3815 }
3816 }
3817 return Heap::false_value();
3818}
3819
3820
3821static Object* Runtime_HasProperty(Arguments args) {
3822 NoHandleAllocation na;
3823 ASSERT(args.length() == 2);
3824
3825 // Only JS objects can have properties.
3826 if (args[0]->IsJSObject()) {
3827 JSObject* object = JSObject::cast(args[0]);
3828 CONVERT_CHECKED(String, key, args[1]);
3829 if (object->HasProperty(key)) return Heap::true_value();
3830 }
3831 return Heap::false_value();
3832}
3833
3834
3835static Object* Runtime_HasElement(Arguments args) {
3836 NoHandleAllocation na;
3837 ASSERT(args.length() == 2);
3838
3839 // Only JS objects can have elements.
3840 if (args[0]->IsJSObject()) {
3841 JSObject* object = JSObject::cast(args[0]);
3842 CONVERT_CHECKED(Smi, index_obj, args[1]);
3843 uint32_t index = index_obj->value();
3844 if (object->HasElement(index)) return Heap::true_value();
3845 }
3846 return Heap::false_value();
3847}
3848
3849
3850static Object* Runtime_IsPropertyEnumerable(Arguments args) {
3851 NoHandleAllocation ha;
3852 ASSERT(args.length() == 2);
3853
3854 CONVERT_CHECKED(JSObject, object, args[0]);
3855 CONVERT_CHECKED(String, key, args[1]);
3856
3857 uint32_t index;
3858 if (key->AsArrayIndex(&index)) {
3859 return Heap::ToBoolean(object->HasElement(index));
3860 }
3861
ager@chromium.org870a0b62008-11-04 11:43:05 +00003862 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3863 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003864}
3865
3866
3867static Object* Runtime_GetPropertyNames(Arguments args) {
3868 HandleScope scope;
3869 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003870 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003871 return *GetKeysFor(object);
3872}
3873
3874
3875// Returns either a FixedArray as Runtime_GetPropertyNames,
3876// or, if the given object has an enum cache that contains
3877// all enumerable properties of the object and its prototypes
3878// have none, the map of the object. This is used to speed up
3879// the check for deletions during a for-in.
3880static Object* Runtime_GetPropertyNamesFast(Arguments args) {
3881 ASSERT(args.length() == 1);
3882
3883 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3884
3885 if (raw_object->IsSimpleEnum()) return raw_object->map();
3886
3887 HandleScope scope;
3888 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003889 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3890 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003891
3892 // Test again, since cache may have been built by preceding call.
3893 if (object->IsSimpleEnum()) return object->map();
3894
3895 return *content;
3896}
3897
3898
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003899// Find the length of the prototype chain that is to to handled as one. If a
3900// prototype object is hidden it is to be viewed as part of the the object it
3901// is prototype for.
3902static int LocalPrototypeChainLength(JSObject* obj) {
3903 int count = 1;
3904 Object* proto = obj->GetPrototype();
3905 while (proto->IsJSObject() &&
3906 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3907 count++;
3908 proto = JSObject::cast(proto)->GetPrototype();
3909 }
3910 return count;
3911}
3912
3913
3914// Return the names of the local named properties.
3915// args[0]: object
3916static Object* Runtime_GetLocalPropertyNames(Arguments args) {
3917 HandleScope scope;
3918 ASSERT(args.length() == 1);
3919 if (!args[0]->IsJSObject()) {
3920 return Heap::undefined_value();
3921 }
3922 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3923
3924 // Skip the global proxy as it has no properties and always delegates to the
3925 // real global object.
3926 if (obj->IsJSGlobalProxy()) {
3927 // Only collect names if access is permitted.
3928 if (obj->IsAccessCheckNeeded() &&
3929 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3930 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3931 return *Factory::NewJSArray(0);
3932 }
3933 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3934 }
3935
3936 // Find the number of objects making up this.
3937 int length = LocalPrototypeChainLength(*obj);
3938
3939 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003940 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003941 int total_property_count = 0;
3942 Handle<JSObject> jsproto = obj;
3943 for (int i = 0; i < length; i++) {
3944 // Only collect names if access is permitted.
3945 if (jsproto->IsAccessCheckNeeded() &&
3946 !Top::MayNamedAccess(*jsproto,
3947 Heap::undefined_value(),
3948 v8::ACCESS_KEYS)) {
3949 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
3950 return *Factory::NewJSArray(0);
3951 }
3952 int n;
3953 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3954 local_property_count[i] = n;
3955 total_property_count += n;
3956 if (i < length - 1) {
3957 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3958 }
3959 }
3960
3961 // Allocate an array with storage for all the property names.
3962 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
3963
3964 // Get the property names.
3965 jsproto = obj;
3966 int proto_with_hidden_properties = 0;
3967 for (int i = 0; i < length; i++) {
3968 jsproto->GetLocalPropertyNames(*names,
3969 i == 0 ? 0 : local_property_count[i - 1]);
3970 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
3971 proto_with_hidden_properties++;
3972 }
3973 if (i < length - 1) {
3974 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3975 }
3976 }
3977
3978 // Filter out name of hidden propeties object.
3979 if (proto_with_hidden_properties > 0) {
3980 Handle<FixedArray> old_names = names;
3981 names = Factory::NewFixedArray(
3982 names->length() - proto_with_hidden_properties);
3983 int dest_pos = 0;
3984 for (int i = 0; i < total_property_count; i++) {
3985 Object* name = old_names->get(i);
3986 if (name == Heap::hidden_symbol()) {
3987 continue;
3988 }
3989 names->set(dest_pos++, name);
3990 }
3991 }
3992
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003993 return *Factory::NewJSArrayWithElements(names);
3994}
3995
3996
3997// Return the names of the local indexed properties.
3998// args[0]: object
3999static Object* Runtime_GetLocalElementNames(Arguments args) {
4000 HandleScope scope;
4001 ASSERT(args.length() == 1);
4002 if (!args[0]->IsJSObject()) {
4003 return Heap::undefined_value();
4004 }
4005 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4006
4007 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4008 Handle<FixedArray> names = Factory::NewFixedArray(n);
4009 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4010 return *Factory::NewJSArrayWithElements(names);
4011}
4012
4013
4014// Return information on whether an object has a named or indexed interceptor.
4015// args[0]: object
4016static Object* Runtime_GetInterceptorInfo(Arguments args) {
4017 HandleScope scope;
4018 ASSERT(args.length() == 1);
4019 if (!args[0]->IsJSObject()) {
4020 return Smi::FromInt(0);
4021 }
4022 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4023
4024 int result = 0;
4025 if (obj->HasNamedInterceptor()) result |= 2;
4026 if (obj->HasIndexedInterceptor()) result |= 1;
4027
4028 return Smi::FromInt(result);
4029}
4030
4031
4032// Return property names from named interceptor.
4033// args[0]: object
4034static Object* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
4035 HandleScope scope;
4036 ASSERT(args.length() == 1);
4037 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4038
4039 if (obj->HasNamedInterceptor()) {
4040 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4041 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4042 }
4043 return Heap::undefined_value();
4044}
4045
4046
4047// Return element names from indexed interceptor.
4048// args[0]: object
4049static Object* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
4050 HandleScope scope;
4051 ASSERT(args.length() == 1);
4052 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4053
4054 if (obj->HasIndexedInterceptor()) {
4055 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4056 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4057 }
4058 return Heap::undefined_value();
4059}
4060
4061
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004062static Object* Runtime_LocalKeys(Arguments args) {
4063 ASSERT_EQ(args.length(), 1);
4064 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4065 HandleScope scope;
4066 Handle<JSObject> object(raw_object);
4067 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4068 LOCAL_ONLY);
4069 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4070 // property array and since the result is mutable we have to create
4071 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004072 int length = contents->length();
4073 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4074 for (int i = 0; i < length; i++) {
4075 Object* entry = contents->get(i);
4076 if (entry->IsString()) {
4077 copy->set(i, entry);
4078 } else {
4079 ASSERT(entry->IsNumber());
4080 HandleScope scope;
4081 Handle<Object> entry_handle(entry);
4082 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4083 copy->set(i, *entry_str);
4084 }
4085 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004086 return *Factory::NewJSArrayWithElements(copy);
4087}
4088
4089
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090static Object* Runtime_GetArgumentsProperty(Arguments args) {
4091 NoHandleAllocation ha;
4092 ASSERT(args.length() == 1);
4093
4094 // Compute the frame holding the arguments.
4095 JavaScriptFrameIterator it;
4096 it.AdvanceToArgumentsFrame();
4097 JavaScriptFrame* frame = it.frame();
4098
4099 // Get the actual number of provided arguments.
4100 const uint32_t n = frame->GetProvidedParametersCount();
4101
4102 // Try to convert the key to an index. If successful and within
4103 // index return the the argument from the frame.
4104 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004105 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106 return frame->GetParameter(index);
4107 }
4108
4109 // Convert the key to a string.
4110 HandleScope scope;
4111 bool exception = false;
4112 Handle<Object> converted =
4113 Execution::ToString(args.at<Object>(0), &exception);
4114 if (exception) return Failure::Exception();
4115 Handle<String> key = Handle<String>::cast(converted);
4116
4117 // Try to convert the string key into an array index.
4118 if (key->AsArrayIndex(&index)) {
4119 if (index < n) {
4120 return frame->GetParameter(index);
4121 } else {
4122 return Top::initial_object_prototype()->GetElement(index);
4123 }
4124 }
4125
4126 // Handle special arguments properties.
4127 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4128 if (key->Equals(Heap::callee_symbol())) return frame->function();
4129
4130 // Lookup in the initial Object.prototype object.
4131 return Top::initial_object_prototype()->GetProperty(*key);
4132}
4133
4134
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004135static Object* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004136 HandleScope scope;
4137
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004138 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004139 Handle<Object> object = args.at<Object>(0);
4140 if (object->IsJSObject()) {
4141 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004142 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
4143 js_object->TransformToFastProperties(0);
4144 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004145 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004146 return *object;
4147}
4148
4149
4150static Object* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004151 HandleScope scope;
4152
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004153 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004154 Handle<Object> object = args.at<Object>(0);
4155 if (object->IsJSObject()) {
4156 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004157 js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004158 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004159 return *object;
4160}
4161
4162
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004163static Object* Runtime_ToBool(Arguments args) {
4164 NoHandleAllocation ha;
4165 ASSERT(args.length() == 1);
4166
4167 return args[0]->ToBoolean();
4168}
4169
4170
4171// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4172// Possible optimizations: put the type string into the oddballs.
4173static Object* Runtime_Typeof(Arguments args) {
4174 NoHandleAllocation ha;
4175
4176 Object* obj = args[0];
4177 if (obj->IsNumber()) return Heap::number_symbol();
4178 HeapObject* heap_obj = HeapObject::cast(obj);
4179
4180 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004181 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004182
4183 InstanceType instance_type = heap_obj->map()->instance_type();
4184 if (instance_type < FIRST_NONSTRING_TYPE) {
4185 return Heap::string_symbol();
4186 }
4187
4188 switch (instance_type) {
4189 case ODDBALL_TYPE:
4190 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4191 return Heap::boolean_symbol();
4192 }
4193 if (heap_obj->IsNull()) {
4194 return Heap::object_symbol();
4195 }
4196 ASSERT(heap_obj->IsUndefined());
4197 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004198 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004199 return Heap::function_symbol();
4200 default:
4201 // For any kind of object not handled above, the spec rule for
4202 // host objects gives that it is okay to return "object"
4203 return Heap::object_symbol();
4204 }
4205}
4206
4207
lrn@chromium.org25156de2010-04-06 13:10:27 +00004208static bool AreDigits(const char*s, int from, int to) {
4209 for (int i = from; i < to; i++) {
4210 if (s[i] < '0' || s[i] > '9') return false;
4211 }
4212
4213 return true;
4214}
4215
4216
4217static int ParseDecimalInteger(const char*s, int from, int to) {
4218 ASSERT(to - from < 10); // Overflow is not possible.
4219 ASSERT(from < to);
4220 int d = s[from] - '0';
4221
4222 for (int i = from + 1; i < to; i++) {
4223 d = 10 * d + (s[i] - '0');
4224 }
4225
4226 return d;
4227}
4228
4229
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230static Object* Runtime_StringToNumber(Arguments args) {
4231 NoHandleAllocation ha;
4232 ASSERT(args.length() == 1);
4233 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004234 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004235
4236 // Fast case: short integer or some sorts of junk values.
4237 int len = subject->length();
4238 if (subject->IsSeqAsciiString()) {
4239 if (len == 0) return Smi::FromInt(0);
4240
4241 char const* data = SeqAsciiString::cast(subject)->GetChars();
4242 bool minus = (data[0] == '-');
4243 int start_pos = (minus ? 1 : 0);
4244
4245 if (start_pos == len) {
4246 return Heap::nan_value();
4247 } else if (data[start_pos] > '9') {
4248 // Fast check for a junk value. A valid string may start from a
4249 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4250 // the 'I' character ('Infinity'). All of that have codes not greater than
4251 // '9' except 'I'.
4252 if (data[start_pos] != 'I') {
4253 return Heap::nan_value();
4254 }
4255 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4256 // The maximal/minimal smi has 10 digits. If the string has less digits we
4257 // know it will fit into the smi-data type.
4258 int d = ParseDecimalInteger(data, start_pos, len);
4259 if (minus) {
4260 if (d == 0) return Heap::minus_zero_value();
4261 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004262 } else if (!subject->HasHashCode() &&
4263 len <= String::kMaxArrayIndexSize &&
4264 (len == 1 || data[0] != '0')) {
4265 // String hash is not calculated yet but all the data are present.
4266 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004267 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004268#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004269 subject->Hash(); // Force hash calculation.
4270 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4271 static_cast<int>(hash));
4272#endif
4273 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004274 }
4275 return Smi::FromInt(d);
4276 }
4277 }
4278
4279 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004280 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4281}
4282
4283
4284static Object* Runtime_StringFromCharCodeArray(Arguments args) {
4285 NoHandleAllocation ha;
4286 ASSERT(args.length() == 1);
4287
4288 CONVERT_CHECKED(JSArray, codes, args[0]);
4289 int length = Smi::cast(codes->length())->value();
4290
4291 // Check if the string can be ASCII.
4292 int i;
4293 for (i = 0; i < length; i++) {
4294 Object* element = codes->GetElement(i);
4295 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4296 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4297 break;
4298 }
4299
4300 Object* object = NULL;
4301 if (i == length) { // The string is ASCII.
4302 object = Heap::AllocateRawAsciiString(length);
4303 } else { // The string is not ASCII.
4304 object = Heap::AllocateRawTwoByteString(length);
4305 }
4306
4307 if (object->IsFailure()) return object;
4308 String* result = String::cast(object);
4309 for (int i = 0; i < length; i++) {
4310 Object* element = codes->GetElement(i);
4311 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004312 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004313 }
4314 return result;
4315}
4316
4317
4318// kNotEscaped is generated by the following:
4319//
4320// #!/bin/perl
4321// for (my $i = 0; $i < 256; $i++) {
4322// print "\n" if $i % 16 == 0;
4323// my $c = chr($i);
4324// my $escaped = 1;
4325// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4326// print $escaped ? "0, " : "1, ";
4327// }
4328
4329
4330static bool IsNotEscaped(uint16_t character) {
4331 // Only for 8 bit characters, the rest are always escaped (in a different way)
4332 ASSERT(character < 256);
4333 static const char kNotEscaped[256] = {
4334 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4335 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4336 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4337 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4338 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4339 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4340 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4341 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4342 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4343 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4344 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4345 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4346 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4347 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4350 };
4351 return kNotEscaped[character] != 0;
4352}
4353
4354
4355static Object* Runtime_URIEscape(Arguments args) {
4356 const char hex_chars[] = "0123456789ABCDEF";
4357 NoHandleAllocation ha;
4358 ASSERT(args.length() == 1);
4359 CONVERT_CHECKED(String, source, args[0]);
4360
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004361 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004362
4363 int escaped_length = 0;
4364 int length = source->length();
4365 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004366 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004367 buffer->Reset(source);
4368 while (buffer->has_more()) {
4369 uint16_t character = buffer->GetNext();
4370 if (character >= 256) {
4371 escaped_length += 6;
4372 } else if (IsNotEscaped(character)) {
4373 escaped_length++;
4374 } else {
4375 escaped_length += 3;
4376 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004377 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004378 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004379 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004380 Top::context()->mark_out_of_memory();
4381 return Failure::OutOfMemoryException();
4382 }
4383 }
4384 }
4385 // No length change implies no change. Return original string if no change.
4386 if (escaped_length == length) {
4387 return source;
4388 }
4389 Object* o = Heap::AllocateRawAsciiString(escaped_length);
4390 if (o->IsFailure()) return o;
4391 String* destination = String::cast(o);
4392 int dest_position = 0;
4393
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004394 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004395 buffer->Rewind();
4396 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004397 uint16_t chr = buffer->GetNext();
4398 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004399 destination->Set(dest_position, '%');
4400 destination->Set(dest_position+1, 'u');
4401 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4402 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4403 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4404 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004405 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004406 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004407 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004408 dest_position++;
4409 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004410 destination->Set(dest_position, '%');
4411 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4412 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004413 dest_position += 3;
4414 }
4415 }
4416 return destination;
4417}
4418
4419
4420static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4421 static const signed char kHexValue['g'] = {
4422 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4423 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4424 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4425 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4426 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4427 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4428 -1, 10, 11, 12, 13, 14, 15 };
4429
4430 if (character1 > 'f') return -1;
4431 int hi = kHexValue[character1];
4432 if (hi == -1) return -1;
4433 if (character2 > 'f') return -1;
4434 int lo = kHexValue[character2];
4435 if (lo == -1) return -1;
4436 return (hi << 4) + lo;
4437}
4438
4439
ager@chromium.org870a0b62008-11-04 11:43:05 +00004440static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004441 int i,
4442 int length,
4443 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004444 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004445 int32_t hi = 0;
4446 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447 if (character == '%' &&
4448 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004449 source->Get(i + 1) == 'u' &&
4450 (hi = TwoDigitHex(source->Get(i + 2),
4451 source->Get(i + 3))) != -1 &&
4452 (lo = TwoDigitHex(source->Get(i + 4),
4453 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004454 *step = 6;
4455 return (hi << 8) + lo;
4456 } else if (character == '%' &&
4457 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004458 (lo = TwoDigitHex(source->Get(i + 1),
4459 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004460 *step = 3;
4461 return lo;
4462 } else {
4463 *step = 1;
4464 return character;
4465 }
4466}
4467
4468
4469static Object* Runtime_URIUnescape(Arguments args) {
4470 NoHandleAllocation ha;
4471 ASSERT(args.length() == 1);
4472 CONVERT_CHECKED(String, source, args[0]);
4473
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004474 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004475
4476 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004477 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004478
4479 int unescaped_length = 0;
4480 for (int i = 0; i < length; unescaped_length++) {
4481 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004482 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004484 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 i += step;
4486 }
4487
4488 // No length change implies no change. Return original string if no change.
4489 if (unescaped_length == length)
4490 return source;
4491
4492 Object* o = ascii ?
4493 Heap::AllocateRawAsciiString(unescaped_length) :
4494 Heap::AllocateRawTwoByteString(unescaped_length);
4495 if (o->IsFailure()) return o;
4496 String* destination = String::cast(o);
4497
4498 int dest_position = 0;
4499 for (int i = 0; i < length; dest_position++) {
4500 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004501 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004502 i += step;
4503 }
4504 return destination;
4505}
4506
4507
4508static Object* Runtime_StringParseInt(Arguments args) {
4509 NoHandleAllocation ha;
4510
4511 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004512 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004514 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004515
lrn@chromium.org25156de2010-04-06 13:10:27 +00004516 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4517 double value = StringToInt(s, radix);
4518 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004519}
4520
4521
4522static Object* Runtime_StringParseFloat(Arguments args) {
4523 NoHandleAllocation ha;
4524 CONVERT_CHECKED(String, str, args[0]);
4525
4526 // ECMA-262 section 15.1.2.3, empty string is NaN
4527 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4528
4529 // Create a number object from the value.
4530 return Heap::NumberFromDouble(value);
4531}
4532
4533
4534static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4535static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4536
4537
4538template <class Converter>
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004539static Object* ConvertCaseHelper(String* s,
4540 int length,
4541 int input_string_length,
4542 unibrow::Mapping<Converter, 128>* mapping) {
4543 // We try this twice, once with the assumption that the result is no longer
4544 // than the input and, if that assumption breaks, again with the exact
4545 // length. This may not be pretty, but it is nicer than what was here before
4546 // and I hereby claim my vaffel-is.
4547 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004548 // Allocate the resulting string.
4549 //
4550 // NOTE: This assumes that the upper/lower case of an ascii
4551 // character is also ascii. This is currently the case, but it
4552 // might break in the future if we implement more context and locale
4553 // dependent upper/lower conversions.
ager@chromium.org5ec48922009-05-05 07:25:34 +00004554 Object* o = s->IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004555 ? Heap::AllocateRawAsciiString(length)
4556 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004557 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004558 String* result = String::cast(o);
4559 bool has_changed_character = false;
4560
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004561 // Convert all characters to upper case, assuming that they will fit
4562 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004563 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004564 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004565 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004566 // We can assume that the string is not empty
4567 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004568 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004569 bool has_next = buffer->has_more();
4570 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004571 int char_length = mapping->get(current, next, chars);
4572 if (char_length == 0) {
4573 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004574 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004575 i++;
4576 } else if (char_length == 1) {
4577 // Common case: converting the letter resulted in one character.
4578 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004579 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004580 has_changed_character = true;
4581 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004582 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004583 // We've assumed that the result would be as long as the
4584 // input but here is a character that converts to several
4585 // characters. No matter, we calculate the exact length
4586 // of the result and try the whole thing again.
4587 //
4588 // Note that this leaves room for optimization. We could just
4589 // memcpy what we already have to the result string. Also,
4590 // the result string is the last object allocated we could
4591 // "realloc" it and probably, in the vast majority of cases,
4592 // extend the existing string to be able to hold the full
4593 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004594 int next_length = 0;
4595 if (has_next) {
4596 next_length = mapping->get(next, 0, chars);
4597 if (next_length == 0) next_length = 1;
4598 }
4599 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004600 while (buffer->has_more()) {
4601 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004602 // NOTE: we use 0 as the next character here because, while
4603 // the next character may affect what a character converts to,
4604 // it does not in any case affect the length of what it convert
4605 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004606 int char_length = mapping->get(current, 0, chars);
4607 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004608 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004609 if (current_length > Smi::kMaxValue) {
4610 Top::context()->mark_out_of_memory();
4611 return Failure::OutOfMemoryException();
4612 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004613 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004614 // Try again with the real length.
4615 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616 } else {
4617 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004618 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004619 i++;
4620 }
4621 has_changed_character = true;
4622 }
4623 current = next;
4624 }
4625 if (has_changed_character) {
4626 return result;
4627 } else {
4628 // If we didn't actually change anything in doing the conversion
4629 // we simple return the result and let the converted string
4630 // become garbage; there is no reason to keep two identical strings
4631 // alive.
4632 return s;
4633 }
4634}
4635
4636
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004637namespace {
4638
4639struct ToLowerTraits {
4640 typedef unibrow::ToLowercase UnibrowConverter;
4641
4642 static bool ConvertAscii(char* dst, char* src, int length) {
4643 bool changed = false;
4644 for (int i = 0; i < length; ++i) {
4645 char c = src[i];
4646 if ('A' <= c && c <= 'Z') {
4647 c += ('a' - 'A');
4648 changed = true;
4649 }
4650 dst[i] = c;
4651 }
4652 return changed;
4653 }
4654};
4655
4656
4657struct ToUpperTraits {
4658 typedef unibrow::ToUppercase UnibrowConverter;
4659
4660 static bool ConvertAscii(char* dst, char* src, int length) {
4661 bool changed = false;
4662 for (int i = 0; i < length; ++i) {
4663 char c = src[i];
4664 if ('a' <= c && c <= 'z') {
4665 c -= ('a' - 'A');
4666 changed = true;
4667 }
4668 dst[i] = c;
4669 }
4670 return changed;
4671 }
4672};
4673
4674} // namespace
4675
4676
4677template <typename ConvertTraits>
4678static Object* ConvertCase(
4679 Arguments args,
4680 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004681 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004682 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004683 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004684
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004685 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004686 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004687 if (length == 0) return s;
4688
4689 // Simpler handling of ascii strings.
4690 //
4691 // NOTE: This assumes that the upper/lower case of an ascii
4692 // character is also ascii. This is currently the case, but it
4693 // might break in the future if we implement more context and locale
4694 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004695 if (s->IsSeqAsciiString()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004696 Object* o = Heap::AllocateRawAsciiString(length);
4697 if (o->IsFailure()) return o;
4698 SeqAsciiString* result = SeqAsciiString::cast(o);
4699 bool has_changed_character = ConvertTraits::ConvertAscii(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004700 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004701 return has_changed_character ? result : s;
4702 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004703
4704 Object* answer = ConvertCaseHelper(s, length, length, mapping);
4705 if (answer->IsSmi()) {
4706 // Retry with correct length.
4707 answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
4708 }
4709 return answer; // This may be a failure.
4710}
4711
4712
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004713static Object* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004714 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004715}
4716
4717
4718static Object* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004719 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004720}
4721
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004722
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004723static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
4724 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
4725}
4726
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004727
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004728static Object* Runtime_StringTrim(Arguments args) {
4729 NoHandleAllocation ha;
4730 ASSERT(args.length() == 3);
4731
4732 CONVERT_CHECKED(String, s, args[0]);
4733 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
4734 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
4735
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004736 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004737 int length = s->length();
4738
4739 int left = 0;
4740 if (trimLeft) {
4741 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
4742 left++;
4743 }
4744 }
4745
4746 int right = length;
4747 if (trimRight) {
4748 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
4749 right--;
4750 }
4751 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004752 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004753}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004754
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004755
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004756template <typename SubjectChar, typename PatternChar>
4757void FindStringIndices(Vector<const SubjectChar> subject,
4758 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004759 ZoneList<int>* indices,
4760 unsigned int limit) {
4761 ASSERT(limit > 0);
4762 // Collect indices of pattern in subject, and the end-of-string index.
4763 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004764 StringSearch<PatternChar, SubjectChar> search(pattern);
4765 int pattern_length = pattern.length();
4766 int index = 0;
4767 while (limit > 0) {
4768 index = search.Search(subject, index);
4769 if (index < 0) return;
4770 indices->Add(index);
4771 index += pattern_length;
4772 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004773 }
4774}
4775
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004776
4777static Object* Runtime_StringSplit(Arguments args) {
4778 ASSERT(args.length() == 3);
4779 HandleScope handle_scope;
4780 CONVERT_ARG_CHECKED(String, subject, 0);
4781 CONVERT_ARG_CHECKED(String, pattern, 1);
4782 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
4783
4784 int subject_length = subject->length();
4785 int pattern_length = pattern->length();
4786 RUNTIME_ASSERT(pattern_length > 0);
4787
4788 // The limit can be very large (0xffffffffu), but since the pattern
4789 // isn't empty, we can never create more parts than ~half the length
4790 // of the subject.
4791
4792 if (!subject->IsFlat()) FlattenString(subject);
4793
4794 static const int kMaxInitialListCapacity = 16;
4795
4796 ZoneScope scope(DELETE_ON_EXIT);
4797
4798 // Find (up to limit) indices of separator and end-of-string in subject
4799 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
4800 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004801 if (!pattern->IsFlat()) FlattenString(pattern);
4802
4803 // No allocation block.
4804 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004805 AssertNoAllocation nogc;
4806 if (subject->IsAsciiRepresentation()) {
4807 Vector<const char> subject_vector = subject->ToAsciiVector();
4808 if (pattern->IsAsciiRepresentation()) {
4809 FindStringIndices(subject_vector,
4810 pattern->ToAsciiVector(),
4811 &indices,
4812 limit);
4813 } else {
4814 FindStringIndices(subject_vector,
4815 pattern->ToUC16Vector(),
4816 &indices,
4817 limit);
4818 }
4819 } else {
4820 Vector<const uc16> subject_vector = subject->ToUC16Vector();
4821 if (pattern->IsAsciiRepresentation()) {
4822 FindStringIndices(subject_vector,
4823 pattern->ToAsciiVector(),
4824 &indices,
4825 limit);
4826 } else {
4827 FindStringIndices(subject_vector,
4828 pattern->ToUC16Vector(),
4829 &indices,
4830 limit);
4831 }
4832 }
4833 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004834
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004835 if (static_cast<uint32_t>(indices.length()) < limit) {
4836 indices.Add(subject_length);
4837 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004838
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004839 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004840
4841 // Create JSArray of substrings separated by separator.
4842 int part_count = indices.length();
4843
4844 Handle<JSArray> result = Factory::NewJSArray(part_count);
4845 result->set_length(Smi::FromInt(part_count));
4846
4847 ASSERT(result->HasFastElements());
4848
4849 if (part_count == 1 && indices.at(0) == subject_length) {
4850 FixedArray::cast(result->elements())->set(0, *subject);
4851 return *result;
4852 }
4853
4854 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
4855 int part_start = 0;
4856 for (int i = 0; i < part_count; i++) {
4857 HandleScope local_loop_handle;
4858 int part_end = indices.at(i);
4859 Handle<String> substring =
4860 Factory::NewSubString(subject, part_start, part_end);
4861 elements->set(i, *substring);
4862 part_start = part_end + pattern_length;
4863 }
4864
4865 return *result;
4866}
4867
4868
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004869// Copies ascii characters to the given fixed array looking up
4870// one-char strings in the cache. Gives up on the first char that is
4871// not in the cache and fills the remainder with smi zeros. Returns
4872// the length of the successfully copied prefix.
4873static int CopyCachedAsciiCharsToArray(const char* chars,
4874 FixedArray* elements,
4875 int length) {
4876 AssertNoAllocation nogc;
4877 FixedArray* ascii_cache = Heap::single_character_string_cache();
4878 Object* undefined = Heap::undefined_value();
4879 int i;
4880 for (i = 0; i < length; ++i) {
4881 Object* value = ascii_cache->get(chars[i]);
4882 if (value == undefined) break;
4883 ASSERT(!Heap::InNewSpace(value));
4884 elements->set(i, value, SKIP_WRITE_BARRIER);
4885 }
4886 if (i < length) {
4887 ASSERT(Smi::FromInt(0) == 0);
4888 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
4889 }
4890#ifdef DEBUG
4891 for (int j = 0; j < length; ++j) {
4892 Object* element = elements->get(j);
4893 ASSERT(element == Smi::FromInt(0) ||
4894 (element->IsString() && String::cast(element)->LooksValid()));
4895 }
4896#endif
4897 return i;
4898}
4899
4900
4901// Converts a String to JSArray.
4902// For example, "foo" => ["f", "o", "o"].
4903static Object* Runtime_StringToArray(Arguments args) {
4904 HandleScope scope;
4905 ASSERT(args.length() == 1);
4906 CONVERT_ARG_CHECKED(String, s, 0);
4907
4908 s->TryFlatten();
4909 const int length = s->length();
4910
4911 Handle<FixedArray> elements;
4912 if (s->IsFlat() && s->IsAsciiRepresentation()) {
4913 Object* obj = Heap::AllocateUninitializedFixedArray(length);
4914 if (obj->IsFailure()) return obj;
4915 elements = Handle<FixedArray>(FixedArray::cast(obj));
4916
4917 Vector<const char> chars = s->ToAsciiVector();
4918 // Note, this will initialize all elements (not only the prefix)
4919 // to prevent GC from seeing partially initialized array.
4920 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
4921 *elements,
4922 length);
4923
4924 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004925 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
4926 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004927 }
4928 } else {
4929 elements = Factory::NewFixedArray(length);
4930 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004931 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
4932 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004933 }
4934 }
4935
4936#ifdef DEBUG
4937 for (int i = 0; i < length; ++i) {
4938 ASSERT(String::cast(elements->get(i))->length() == 1);
4939 }
4940#endif
4941
4942 return *Factory::NewJSArrayWithElements(elements);
4943}
4944
4945
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004946static Object* Runtime_NewStringWrapper(Arguments args) {
4947 NoHandleAllocation ha;
4948 ASSERT(args.length() == 1);
4949 CONVERT_CHECKED(String, value, args[0]);
4950 return value->ToObject();
4951}
4952
4953
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00004954bool Runtime::IsUpperCaseChar(uint16_t ch) {
4955 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
4956 int char_length = to_upper_mapping.get(ch, 0, chars);
4957 return char_length == 0;
4958}
4959
4960
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004961static Object* Runtime_NumberToString(Arguments args) {
4962 NoHandleAllocation ha;
4963 ASSERT(args.length() == 1);
4964
4965 Object* number = args[0];
4966 RUNTIME_ASSERT(number->IsNumber());
4967
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004968 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004969}
4970
4971
ager@chromium.org357bf652010-04-12 11:30:10 +00004972static Object* Runtime_NumberToStringSkipCache(Arguments args) {
4973 NoHandleAllocation ha;
4974 ASSERT(args.length() == 1);
4975
4976 Object* number = args[0];
4977 RUNTIME_ASSERT(number->IsNumber());
4978
4979 return Heap::NumberToString(number, false);
4980}
4981
4982
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004983static Object* Runtime_NumberToInteger(Arguments args) {
4984 NoHandleAllocation ha;
4985 ASSERT(args.length() == 1);
4986
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004987 CONVERT_DOUBLE_CHECKED(number, args[0]);
4988
4989 // We do not include 0 so that we don't have to treat +0 / -0 cases.
4990 if (number > 0 && number <= Smi::kMaxValue) {
4991 return Smi::FromInt(static_cast<int>(number));
4992 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004993 return Heap::NumberFromDouble(DoubleToInteger(number));
4994}
4995
4996
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004997static Object* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
4998 NoHandleAllocation ha;
4999 ASSERT(args.length() == 1);
5000
5001 CONVERT_DOUBLE_CHECKED(number, args[0]);
5002
5003 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5004 if (number > 0 && number <= Smi::kMaxValue) {
5005 return Smi::FromInt(static_cast<int>(number));
5006 }
5007
5008 double double_value = DoubleToInteger(number);
5009 // Map both -0 and +0 to +0.
5010 if (double_value == 0) double_value = 0;
5011
5012 return Heap::NumberFromDouble(double_value);
5013}
5014
5015
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005016static Object* Runtime_NumberToJSUint32(Arguments args) {
5017 NoHandleAllocation ha;
5018 ASSERT(args.length() == 1);
5019
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005020 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005021 return Heap::NumberFromUint32(number);
5022}
5023
5024
5025static Object* Runtime_NumberToJSInt32(Arguments args) {
5026 NoHandleAllocation ha;
5027 ASSERT(args.length() == 1);
5028
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005029 CONVERT_DOUBLE_CHECKED(number, args[0]);
5030
5031 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5032 if (number > 0 && number <= Smi::kMaxValue) {
5033 return Smi::FromInt(static_cast<int>(number));
5034 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005035 return Heap::NumberFromInt32(DoubleToInt32(number));
5036}
5037
5038
ager@chromium.org870a0b62008-11-04 11:43:05 +00005039// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5040// a small integer.
5041static Object* Runtime_NumberToSmi(Arguments args) {
5042 NoHandleAllocation ha;
5043 ASSERT(args.length() == 1);
5044
5045 Object* obj = args[0];
5046 if (obj->IsSmi()) {
5047 return obj;
5048 }
5049 if (obj->IsHeapNumber()) {
5050 double value = HeapNumber::cast(obj)->value();
5051 int int_value = FastD2I(value);
5052 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5053 return Smi::FromInt(int_value);
5054 }
5055 }
5056 return Heap::nan_value();
5057}
5058
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005059
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005060static Object* Runtime_NumberAdd(Arguments args) {
5061 NoHandleAllocation ha;
5062 ASSERT(args.length() == 2);
5063
5064 CONVERT_DOUBLE_CHECKED(x, args[0]);
5065 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005066 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005067}
5068
5069
5070static Object* Runtime_NumberSub(Arguments args) {
5071 NoHandleAllocation ha;
5072 ASSERT(args.length() == 2);
5073
5074 CONVERT_DOUBLE_CHECKED(x, args[0]);
5075 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005076 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005077}
5078
5079
5080static Object* Runtime_NumberMul(Arguments args) {
5081 NoHandleAllocation ha;
5082 ASSERT(args.length() == 2);
5083
5084 CONVERT_DOUBLE_CHECKED(x, args[0]);
5085 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005086 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005087}
5088
5089
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005090static Object* Runtime_NumberUnaryMinus(Arguments args) {
5091 NoHandleAllocation ha;
5092 ASSERT(args.length() == 1);
5093
5094 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005095 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005096}
5097
5098
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005099static Object* Runtime_NumberAlloc(Arguments args) {
5100 NoHandleAllocation ha;
5101 ASSERT(args.length() == 0);
5102
5103 return Heap::NumberFromDouble(9876543210.0);
5104}
5105
5106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005107static Object* Runtime_NumberDiv(Arguments args) {
5108 NoHandleAllocation ha;
5109 ASSERT(args.length() == 2);
5110
5111 CONVERT_DOUBLE_CHECKED(x, args[0]);
5112 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005113 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005114}
5115
5116
5117static Object* Runtime_NumberMod(Arguments args) {
5118 NoHandleAllocation ha;
5119 ASSERT(args.length() == 2);
5120
5121 CONVERT_DOUBLE_CHECKED(x, args[0]);
5122 CONVERT_DOUBLE_CHECKED(y, args[1]);
5123
ager@chromium.org3811b432009-10-28 14:53:37 +00005124 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005125 // NumberFromDouble may return a Smi instead of a Number object
5126 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005127}
5128
5129
5130static Object* Runtime_StringAdd(Arguments args) {
5131 NoHandleAllocation ha;
5132 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005133 CONVERT_CHECKED(String, str1, args[0]);
5134 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005135 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005136 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005137}
5138
5139
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005140template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005141static inline void StringBuilderConcatHelper(String* special,
5142 sinkchar* sink,
5143 FixedArray* fixed_array,
5144 int array_length) {
5145 int position = 0;
5146 for (int i = 0; i < array_length; i++) {
5147 Object* element = fixed_array->get(i);
5148 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005149 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005150 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005151 int pos;
5152 int len;
5153 if (encoded_slice > 0) {
5154 // Position and length encoded in one smi.
5155 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5156 len = StringBuilderSubstringLength::decode(encoded_slice);
5157 } else {
5158 // Position and length encoded in two smis.
5159 Object* obj = fixed_array->get(++i);
5160 ASSERT(obj->IsSmi());
5161 pos = Smi::cast(obj)->value();
5162 len = -encoded_slice;
5163 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005164 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005165 sink + position,
5166 pos,
5167 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005168 position += len;
5169 } else {
5170 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005171 int element_length = string->length();
5172 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005173 position += element_length;
5174 }
5175 }
5176}
5177
5178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005179static Object* Runtime_StringBuilderConcat(Arguments args) {
5180 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005181 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005182 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005183 if (!args[1]->IsSmi()) {
5184 Top::context()->mark_out_of_memory();
5185 return Failure::OutOfMemoryException();
5186 }
5187 int array_length = Smi::cast(args[1])->value();
5188 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005189
5190 // This assumption is used by the slice encoding in one or two smis.
5191 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5192
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005193 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005194 if (!array->HasFastElements()) {
5195 return Top::Throw(Heap::illegal_argument_symbol());
5196 }
5197 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005198 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005199 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005200 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201
5202 if (array_length == 0) {
5203 return Heap::empty_string();
5204 } else if (array_length == 1) {
5205 Object* first = fixed_array->get(0);
5206 if (first->IsString()) return first;
5207 }
5208
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005209 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005210 int position = 0;
5211 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005212 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005213 Object* elt = fixed_array->get(i);
5214 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005215 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005216 int smi_value = Smi::cast(elt)->value();
5217 int pos;
5218 int len;
5219 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005220 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005221 pos = StringBuilderSubstringPosition::decode(smi_value);
5222 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005223 } else {
5224 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005225 len = -smi_value;
5226 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005227 i++;
5228 if (i >= array_length) {
5229 return Top::Throw(Heap::illegal_argument_symbol());
5230 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005231 Object* next_smi = fixed_array->get(i);
5232 if (!next_smi->IsSmi()) {
5233 return Top::Throw(Heap::illegal_argument_symbol());
5234 }
5235 pos = Smi::cast(next_smi)->value();
5236 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005237 return Top::Throw(Heap::illegal_argument_symbol());
5238 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005239 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005240 ASSERT(pos >= 0);
5241 ASSERT(len >= 0);
5242 if (pos > special_length || len > special_length - pos) {
5243 return Top::Throw(Heap::illegal_argument_symbol());
5244 }
5245 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005246 } else if (elt->IsString()) {
5247 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005248 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005249 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005250 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005252 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005253 } else {
5254 return Top::Throw(Heap::illegal_argument_symbol());
5255 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005256 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005257 Top::context()->mark_out_of_memory();
5258 return Failure::OutOfMemoryException();
5259 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005260 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005261 }
5262
5263 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005264 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005266 if (ascii) {
5267 object = Heap::AllocateRawAsciiString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005268 if (object->IsFailure()) return object;
5269 SeqAsciiString* answer = SeqAsciiString::cast(object);
5270 StringBuilderConcatHelper(special,
5271 answer->GetChars(),
5272 fixed_array,
5273 array_length);
5274 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005275 } else {
5276 object = Heap::AllocateRawTwoByteString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005277 if (object->IsFailure()) return object;
5278 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5279 StringBuilderConcatHelper(special,
5280 answer->GetChars(),
5281 fixed_array,
5282 array_length);
5283 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005284 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005285}
5286
5287
5288static Object* Runtime_NumberOr(Arguments args) {
5289 NoHandleAllocation ha;
5290 ASSERT(args.length() == 2);
5291
5292 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5293 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5294 return Heap::NumberFromInt32(x | y);
5295}
5296
5297
5298static Object* Runtime_NumberAnd(Arguments args) {
5299 NoHandleAllocation ha;
5300 ASSERT(args.length() == 2);
5301
5302 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5303 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5304 return Heap::NumberFromInt32(x & y);
5305}
5306
5307
5308static Object* Runtime_NumberXor(Arguments args) {
5309 NoHandleAllocation ha;
5310 ASSERT(args.length() == 2);
5311
5312 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5313 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5314 return Heap::NumberFromInt32(x ^ y);
5315}
5316
5317
5318static Object* Runtime_NumberNot(Arguments args) {
5319 NoHandleAllocation ha;
5320 ASSERT(args.length() == 1);
5321
5322 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5323 return Heap::NumberFromInt32(~x);
5324}
5325
5326
5327static Object* Runtime_NumberShl(Arguments args) {
5328 NoHandleAllocation ha;
5329 ASSERT(args.length() == 2);
5330
5331 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5332 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5333 return Heap::NumberFromInt32(x << (y & 0x1f));
5334}
5335
5336
5337static Object* Runtime_NumberShr(Arguments args) {
5338 NoHandleAllocation ha;
5339 ASSERT(args.length() == 2);
5340
5341 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5342 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5343 return Heap::NumberFromUint32(x >> (y & 0x1f));
5344}
5345
5346
5347static Object* Runtime_NumberSar(Arguments args) {
5348 NoHandleAllocation ha;
5349 ASSERT(args.length() == 2);
5350
5351 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5352 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5353 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5354}
5355
5356
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005357static Object* Runtime_NumberEquals(Arguments args) {
5358 NoHandleAllocation ha;
5359 ASSERT(args.length() == 2);
5360
5361 CONVERT_DOUBLE_CHECKED(x, args[0]);
5362 CONVERT_DOUBLE_CHECKED(y, args[1]);
5363 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5364 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5365 if (x == y) return Smi::FromInt(EQUAL);
5366 Object* result;
5367 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5368 result = Smi::FromInt(EQUAL);
5369 } else {
5370 result = Smi::FromInt(NOT_EQUAL);
5371 }
5372 return result;
5373}
5374
5375
5376static Object* Runtime_StringEquals(Arguments args) {
5377 NoHandleAllocation ha;
5378 ASSERT(args.length() == 2);
5379
5380 CONVERT_CHECKED(String, x, args[0]);
5381 CONVERT_CHECKED(String, y, args[1]);
5382
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005383 bool not_equal = !x->Equals(y);
5384 // This is slightly convoluted because the value that signifies
5385 // equality is 0 and inequality is 1 so we have to negate the result
5386 // from String::Equals.
5387 ASSERT(not_equal == 0 || not_equal == 1);
5388 STATIC_CHECK(EQUAL == 0);
5389 STATIC_CHECK(NOT_EQUAL == 1);
5390 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005391}
5392
5393
5394static Object* Runtime_NumberCompare(Arguments args) {
5395 NoHandleAllocation ha;
5396 ASSERT(args.length() == 3);
5397
5398 CONVERT_DOUBLE_CHECKED(x, args[0]);
5399 CONVERT_DOUBLE_CHECKED(y, args[1]);
5400 if (isnan(x) || isnan(y)) return args[2];
5401 if (x == y) return Smi::FromInt(EQUAL);
5402 if (isless(x, y)) return Smi::FromInt(LESS);
5403 return Smi::FromInt(GREATER);
5404}
5405
5406
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005407// Compare two Smis as if they were converted to strings and then
5408// compared lexicographically.
5409static Object* Runtime_SmiLexicographicCompare(Arguments args) {
5410 NoHandleAllocation ha;
5411 ASSERT(args.length() == 2);
5412
5413 // Arrays for the individual characters of the two Smis. Smis are
5414 // 31 bit integers and 10 decimal digits are therefore enough.
5415 static int x_elms[10];
5416 static int y_elms[10];
5417
5418 // Extract the integer values from the Smis.
5419 CONVERT_CHECKED(Smi, x, args[0]);
5420 CONVERT_CHECKED(Smi, y, args[1]);
5421 int x_value = x->value();
5422 int y_value = y->value();
5423
5424 // If the integers are equal so are the string representations.
5425 if (x_value == y_value) return Smi::FromInt(EQUAL);
5426
5427 // If one of the integers are zero the normal integer order is the
5428 // same as the lexicographic order of the string representations.
5429 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5430
ager@chromium.org32912102009-01-16 10:38:43 +00005431 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005432 // smallest because the char code of '-' is less than the char code
5433 // of any digit. Otherwise, we make both values positive.
5434 if (x_value < 0 || y_value < 0) {
5435 if (y_value >= 0) return Smi::FromInt(LESS);
5436 if (x_value >= 0) return Smi::FromInt(GREATER);
5437 x_value = -x_value;
5438 y_value = -y_value;
5439 }
5440
5441 // Convert the integers to arrays of their decimal digits.
5442 int x_index = 0;
5443 int y_index = 0;
5444 while (x_value > 0) {
5445 x_elms[x_index++] = x_value % 10;
5446 x_value /= 10;
5447 }
5448 while (y_value > 0) {
5449 y_elms[y_index++] = y_value % 10;
5450 y_value /= 10;
5451 }
5452
5453 // Loop through the arrays of decimal digits finding the first place
5454 // where they differ.
5455 while (--x_index >= 0 && --y_index >= 0) {
5456 int diff = x_elms[x_index] - y_elms[y_index];
5457 if (diff != 0) return Smi::FromInt(diff);
5458 }
5459
5460 // If one array is a suffix of the other array, the longest array is
5461 // the representation of the largest of the Smis in the
5462 // lexicographic ordering.
5463 return Smi::FromInt(x_index - y_index);
5464}
5465
5466
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005467static Object* StringInputBufferCompare(String* x, String* y) {
5468 static StringInputBuffer bufx;
5469 static StringInputBuffer bufy;
5470 bufx.Reset(x);
5471 bufy.Reset(y);
5472 while (bufx.has_more() && bufy.has_more()) {
5473 int d = bufx.GetNext() - bufy.GetNext();
5474 if (d < 0) return Smi::FromInt(LESS);
5475 else if (d > 0) return Smi::FromInt(GREATER);
5476 }
5477
5478 // x is (non-trivial) prefix of y:
5479 if (bufy.has_more()) return Smi::FromInt(LESS);
5480 // y is prefix of x:
5481 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5482}
5483
5484
5485static Object* FlatStringCompare(String* x, String* y) {
5486 ASSERT(x->IsFlat());
5487 ASSERT(y->IsFlat());
5488 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5489 int prefix_length = x->length();
5490 if (y->length() < prefix_length) {
5491 prefix_length = y->length();
5492 equal_prefix_result = Smi::FromInt(GREATER);
5493 } else if (y->length() > prefix_length) {
5494 equal_prefix_result = Smi::FromInt(LESS);
5495 }
5496 int r;
5497 if (x->IsAsciiRepresentation()) {
5498 Vector<const char> x_chars = x->ToAsciiVector();
5499 if (y->IsAsciiRepresentation()) {
5500 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005501 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005502 } else {
5503 Vector<const uc16> y_chars = y->ToUC16Vector();
5504 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5505 }
5506 } else {
5507 Vector<const uc16> x_chars = x->ToUC16Vector();
5508 if (y->IsAsciiRepresentation()) {
5509 Vector<const char> y_chars = y->ToAsciiVector();
5510 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5511 } else {
5512 Vector<const uc16> y_chars = y->ToUC16Vector();
5513 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5514 }
5515 }
5516 Object* result;
5517 if (r == 0) {
5518 result = equal_prefix_result;
5519 } else {
5520 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5521 }
5522 ASSERT(result == StringInputBufferCompare(x, y));
5523 return result;
5524}
5525
5526
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005527static Object* Runtime_StringCompare(Arguments args) {
5528 NoHandleAllocation ha;
5529 ASSERT(args.length() == 2);
5530
5531 CONVERT_CHECKED(String, x, args[0]);
5532 CONVERT_CHECKED(String, y, args[1]);
5533
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005534 Counters::string_compare_runtime.Increment();
5535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005536 // A few fast case tests before we flatten.
5537 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005538 if (y->length() == 0) {
5539 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005540 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005541 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005542 return Smi::FromInt(LESS);
5543 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005544
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005545 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005546 if (d < 0) return Smi::FromInt(LESS);
5547 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005548
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005549 Object* obj = Heap::PrepareForCompare(x);
5550 if (obj->IsFailure()) return obj;
5551 obj = Heap::PrepareForCompare(y);
5552 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005553
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005554 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5555 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005556}
5557
5558
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005559static Object* Runtime_Math_acos(Arguments args) {
5560 NoHandleAllocation ha;
5561 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005562 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005563
5564 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005565 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005566}
5567
5568
5569static Object* Runtime_Math_asin(Arguments args) {
5570 NoHandleAllocation ha;
5571 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005572 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005573
5574 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005575 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005576}
5577
5578
5579static Object* Runtime_Math_atan(Arguments args) {
5580 NoHandleAllocation ha;
5581 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005582 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005583
5584 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005585 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005586}
5587
5588
5589static Object* Runtime_Math_atan2(Arguments args) {
5590 NoHandleAllocation ha;
5591 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005592 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005593
5594 CONVERT_DOUBLE_CHECKED(x, args[0]);
5595 CONVERT_DOUBLE_CHECKED(y, args[1]);
5596 double result;
5597 if (isinf(x) && isinf(y)) {
5598 // Make sure that the result in case of two infinite arguments
5599 // is a multiple of Pi / 4. The sign of the result is determined
5600 // by the first argument (x) and the sign of the second argument
5601 // determines the multiplier: one or three.
5602 static double kPiDividedBy4 = 0.78539816339744830962;
5603 int multiplier = (x < 0) ? -1 : 1;
5604 if (y < 0) multiplier *= 3;
5605 result = multiplier * kPiDividedBy4;
5606 } else {
5607 result = atan2(x, y);
5608 }
5609 return Heap::AllocateHeapNumber(result);
5610}
5611
5612
5613static Object* Runtime_Math_ceil(Arguments args) {
5614 NoHandleAllocation ha;
5615 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005616 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005617
5618 CONVERT_DOUBLE_CHECKED(x, args[0]);
5619 return Heap::NumberFromDouble(ceiling(x));
5620}
5621
5622
5623static Object* Runtime_Math_cos(Arguments args) {
5624 NoHandleAllocation ha;
5625 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005626 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005627
5628 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005629 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005630}
5631
5632
5633static Object* Runtime_Math_exp(Arguments args) {
5634 NoHandleAllocation ha;
5635 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005636 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005637
5638 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005639 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005640}
5641
5642
5643static Object* Runtime_Math_floor(Arguments args) {
5644 NoHandleAllocation ha;
5645 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005646 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005647
5648 CONVERT_DOUBLE_CHECKED(x, args[0]);
5649 return Heap::NumberFromDouble(floor(x));
5650}
5651
5652
5653static Object* Runtime_Math_log(Arguments args) {
5654 NoHandleAllocation ha;
5655 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005656 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005657
5658 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005659 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005660}
5661
5662
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005663// Helper function to compute x^y, where y is known to be an
5664// integer. Uses binary decomposition to limit the number of
5665// multiplications; see the discussion in "Hacker's Delight" by Henry
5666// S. Warren, Jr., figure 11-6, page 213.
5667static double powi(double x, int y) {
5668 ASSERT(y != kMinInt);
5669 unsigned n = (y < 0) ? -y : y;
5670 double m = x;
5671 double p = 1;
5672 while (true) {
5673 if ((n & 1) != 0) p *= m;
5674 n >>= 1;
5675 if (n == 0) {
5676 if (y < 0) {
5677 // Unfortunately, we have to be careful when p has reached
5678 // infinity in the computation, because sometimes the higher
5679 // internal precision in the pow() implementation would have
5680 // given us a finite p. This happens very rarely.
5681 double result = 1.0 / p;
5682 return (result == 0 && isinf(p))
5683 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
5684 : result;
5685 } else {
5686 return p;
5687 }
5688 }
5689 m *= m;
5690 }
5691}
5692
5693
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005694static Object* Runtime_Math_pow(Arguments args) {
5695 NoHandleAllocation ha;
5696 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005697 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005698
5699 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005700
5701 // If the second argument is a smi, it is much faster to call the
5702 // custom powi() function than the generic pow().
5703 if (args[1]->IsSmi()) {
5704 int y = Smi::cast(args[1])->value();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005705 return Heap::NumberFromDouble(powi(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005706 }
5707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005708 CONVERT_DOUBLE_CHECKED(y, args[1]);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005709
5710 if (!isinf(x)) {
5711 if (y == 0.5) {
5712 // It's not uncommon to use Math.pow(x, 0.5) to compute the
5713 // square root of a number. To speed up such computations, we
5714 // explictly check for this case and use the sqrt() function
5715 // which is faster than pow().
5716 return Heap::AllocateHeapNumber(sqrt(x));
5717 } else if (y == -0.5) {
5718 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
5719 return Heap::AllocateHeapNumber(1.0 / sqrt(x));
5720 }
5721 }
5722
5723 if (y == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005724 return Smi::FromInt(1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005725 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5726 return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005727 } else {
5728 return Heap::AllocateHeapNumber(pow(x, y));
5729 }
5730}
5731
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005732// Fast version of Math.pow if we know that y is not an integer and
5733// y is not -0.5 or 0.5. Used as slowcase from codegen.
5734static Object* Runtime_Math_pow_cfunction(Arguments args) {
5735 NoHandleAllocation ha;
5736 ASSERT(args.length() == 2);
5737 CONVERT_DOUBLE_CHECKED(x, args[0]);
5738 CONVERT_DOUBLE_CHECKED(y, args[1]);
5739 if (y == 0) {
5740 return Smi::FromInt(1);
5741 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5742 return Heap::nan_value();
5743 } else {
5744 return Heap::AllocateHeapNumber(pow(x, y));
5745 }
5746}
5747
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005748
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005749static Object* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005750 NoHandleAllocation ha;
5751 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005752 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005753
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005754 if (!args[0]->IsHeapNumber()) {
5755 // Must be smi. Return the argument unchanged for all the other types
5756 // to make fuzz-natives test happy.
5757 return args[0];
5758 }
5759
5760 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
5761
5762 double value = number->value();
5763 int exponent = number->get_exponent();
5764 int sign = number->get_sign();
5765
5766 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
5767 // should be rounded to 2^30, which is not smi.
5768 if (!sign && exponent <= kSmiValueSize - 3) {
5769 return Smi::FromInt(static_cast<int>(value + 0.5));
5770 }
5771
5772 // If the magnitude is big enough, there's no place for fraction part. If we
5773 // try to add 0.5 to this number, 1.0 will be added instead.
5774 if (exponent >= 52) {
5775 return number;
5776 }
5777
5778 if (sign && value >= -0.5) return Heap::minus_zero_value();
5779
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005780 // Do not call NumberFromDouble() to avoid extra checks.
5781 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005782}
5783
5784
5785static Object* Runtime_Math_sin(Arguments args) {
5786 NoHandleAllocation ha;
5787 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005788 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005789
5790 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005791 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005792}
5793
5794
5795static Object* Runtime_Math_sqrt(Arguments args) {
5796 NoHandleAllocation ha;
5797 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005798 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005799
5800 CONVERT_DOUBLE_CHECKED(x, args[0]);
5801 return Heap::AllocateHeapNumber(sqrt(x));
5802}
5803
5804
5805static Object* Runtime_Math_tan(Arguments args) {
5806 NoHandleAllocation ha;
5807 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005808 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005809
5810 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005811 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005812}
5813
5814
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005815static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005816 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
5817 181, 212, 243, 273, 304, 334};
5818 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
5819 182, 213, 244, 274, 305, 335};
5820
5821 year += month / 12;
5822 month %= 12;
5823 if (month < 0) {
5824 year--;
5825 month += 12;
5826 }
5827
5828 ASSERT(month >= 0);
5829 ASSERT(month < 12);
5830
5831 // year_delta is an arbitrary number such that:
5832 // a) year_delta = -1 (mod 400)
5833 // b) year + year_delta > 0 for years in the range defined by
5834 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
5835 // Jan 1 1970. This is required so that we don't run into integer
5836 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005837 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005838 // operations.
5839 static const int year_delta = 399999;
5840 static const int base_day = 365 * (1970 + year_delta) +
5841 (1970 + year_delta) / 4 -
5842 (1970 + year_delta) / 100 +
5843 (1970 + year_delta) / 400;
5844
5845 int year1 = year + year_delta;
5846 int day_from_year = 365 * year1 +
5847 year1 / 4 -
5848 year1 / 100 +
5849 year1 / 400 -
5850 base_day;
5851
5852 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005853 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005854 }
5855
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005856 return day_from_year + day_from_month_leap[month] + day - 1;
5857}
5858
5859
5860static Object* Runtime_DateMakeDay(Arguments args) {
5861 NoHandleAllocation ha;
5862 ASSERT(args.length() == 3);
5863
5864 CONVERT_SMI_CHECKED(year, args[0]);
5865 CONVERT_SMI_CHECKED(month, args[1]);
5866 CONVERT_SMI_CHECKED(date, args[2]);
5867
5868 return Smi::FromInt(MakeDay(year, month, date));
5869}
5870
5871
5872static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
5873static const int kDaysIn4Years = 4 * 365 + 1;
5874static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
5875static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
5876static const int kDays1970to2000 = 30 * 365 + 7;
5877static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
5878 kDays1970to2000;
5879static const int kYearsOffset = 400000;
5880
5881static const char kDayInYear[] = {
5882 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5883 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5884 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5885 22, 23, 24, 25, 26, 27, 28,
5886 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5887 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5888 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5889 22, 23, 24, 25, 26, 27, 28, 29, 30,
5890 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5891 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5892 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5893 22, 23, 24, 25, 26, 27, 28, 29, 30,
5894 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5895 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5896 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5897 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5898 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5899 22, 23, 24, 25, 26, 27, 28, 29, 30,
5900 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5901 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5902 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5903 22, 23, 24, 25, 26, 27, 28, 29, 30,
5904 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5905 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5906
5907 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5908 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5909 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5910 22, 23, 24, 25, 26, 27, 28,
5911 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5912 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5913 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5914 22, 23, 24, 25, 26, 27, 28, 29, 30,
5915 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5916 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5917 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5918 22, 23, 24, 25, 26, 27, 28, 29, 30,
5919 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5920 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5921 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5922 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5923 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5924 22, 23, 24, 25, 26, 27, 28, 29, 30,
5925 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5926 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5927 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5928 22, 23, 24, 25, 26, 27, 28, 29, 30,
5929 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5930 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5931
5932 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5933 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5934 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5935 22, 23, 24, 25, 26, 27, 28, 29,
5936 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5937 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5938 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5939 22, 23, 24, 25, 26, 27, 28, 29, 30,
5940 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5941 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5942 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5943 22, 23, 24, 25, 26, 27, 28, 29, 30,
5944 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5945 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5946 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5947 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5948 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5949 22, 23, 24, 25, 26, 27, 28, 29, 30,
5950 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5951 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5952 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5953 22, 23, 24, 25, 26, 27, 28, 29, 30,
5954 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5955 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5956
5957 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5958 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5959 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5960 22, 23, 24, 25, 26, 27, 28,
5961 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5962 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5963 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5964 22, 23, 24, 25, 26, 27, 28, 29, 30,
5965 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5966 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5967 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5968 22, 23, 24, 25, 26, 27, 28, 29, 30,
5969 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5970 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5971 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5972 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5973 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5974 22, 23, 24, 25, 26, 27, 28, 29, 30,
5975 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5976 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5977 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5978 22, 23, 24, 25, 26, 27, 28, 29, 30,
5979 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5980 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
5981
5982static const char kMonthInYear[] = {
5983 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5984 0, 0, 0, 0, 0, 0,
5985 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5986 1, 1, 1,
5987 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
5988 2, 2, 2, 2, 2, 2,
5989 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
5990 3, 3, 3, 3, 3,
5991 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5992 4, 4, 4, 4, 4, 4,
5993 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5994 5, 5, 5, 5, 5,
5995 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
5996 6, 6, 6, 6, 6, 6,
5997 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
5998 7, 7, 7, 7, 7, 7,
5999 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6000 8, 8, 8, 8, 8,
6001 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6002 9, 9, 9, 9, 9, 9,
6003 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6004 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6005 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6006 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6007
6008 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6009 0, 0, 0, 0, 0, 0,
6010 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6011 1, 1, 1,
6012 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6013 2, 2, 2, 2, 2, 2,
6014 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6015 3, 3, 3, 3, 3,
6016 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6017 4, 4, 4, 4, 4, 4,
6018 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6019 5, 5, 5, 5, 5,
6020 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6021 6, 6, 6, 6, 6, 6,
6022 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6023 7, 7, 7, 7, 7, 7,
6024 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6025 8, 8, 8, 8, 8,
6026 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6027 9, 9, 9, 9, 9, 9,
6028 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6029 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6030 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6031 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6032
6033 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6034 0, 0, 0, 0, 0, 0,
6035 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6036 1, 1, 1, 1,
6037 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6038 2, 2, 2, 2, 2, 2,
6039 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6040 3, 3, 3, 3, 3,
6041 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6042 4, 4, 4, 4, 4, 4,
6043 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6044 5, 5, 5, 5, 5,
6045 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6046 6, 6, 6, 6, 6, 6,
6047 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6048 7, 7, 7, 7, 7, 7,
6049 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6050 8, 8, 8, 8, 8,
6051 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6052 9, 9, 9, 9, 9, 9,
6053 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6054 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6055 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6056 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6057
6058 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6059 0, 0, 0, 0, 0, 0,
6060 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6061 1, 1, 1,
6062 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6063 2, 2, 2, 2, 2, 2,
6064 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6065 3, 3, 3, 3, 3,
6066 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6067 4, 4, 4, 4, 4, 4,
6068 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6069 5, 5, 5, 5, 5,
6070 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6071 6, 6, 6, 6, 6, 6,
6072 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6073 7, 7, 7, 7, 7, 7,
6074 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6075 8, 8, 8, 8, 8,
6076 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6077 9, 9, 9, 9, 9, 9,
6078 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6079 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6080 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6081 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6082
6083
6084// This function works for dates from 1970 to 2099.
6085static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006086 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006087#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006088 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006089#endif
6090
6091 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6092 date %= kDaysIn4Years;
6093
6094 month = kMonthInYear[date];
6095 day = kDayInYear[date];
6096
6097 ASSERT(MakeDay(year, month, day) == save_date);
6098}
6099
6100
6101static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006102 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006103#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006104 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006105#endif
6106
6107 date += kDaysOffset;
6108 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6109 date %= kDaysIn400Years;
6110
6111 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6112
6113 date--;
6114 int yd1 = date / kDaysIn100Years;
6115 date %= kDaysIn100Years;
6116 year += 100 * yd1;
6117
6118 date++;
6119 int yd2 = date / kDaysIn4Years;
6120 date %= kDaysIn4Years;
6121 year += 4 * yd2;
6122
6123 date--;
6124 int yd3 = date / 365;
6125 date %= 365;
6126 year += yd3;
6127
6128 bool is_leap = (!yd1 || yd2) && !yd3;
6129
6130 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006131 ASSERT(is_leap || (date >= 0));
6132 ASSERT((date < 365) || (is_leap && (date < 366)));
6133 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6134 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6135 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006136
6137 if (is_leap) {
6138 day = kDayInYear[2*365 + 1 + date];
6139 month = kMonthInYear[2*365 + 1 + date];
6140 } else {
6141 day = kDayInYear[date];
6142 month = kMonthInYear[date];
6143 }
6144
6145 ASSERT(MakeDay(year, month, day) == save_date);
6146}
6147
6148
6149static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006150 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006151 if (date >= 0 && date < 32 * kDaysIn4Years) {
6152 DateYMDFromTimeAfter1970(date, year, month, day);
6153 } else {
6154 DateYMDFromTimeSlow(date, year, month, day);
6155 }
6156}
6157
6158
6159static Object* Runtime_DateYMDFromTime(Arguments args) {
6160 NoHandleAllocation ha;
6161 ASSERT(args.length() == 2);
6162
6163 CONVERT_DOUBLE_CHECKED(t, args[0]);
6164 CONVERT_CHECKED(JSArray, res_array, args[1]);
6165
6166 int year, month, day;
6167 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6168
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006169 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6170 FixedArray* elms = FixedArray::cast(res_array->elements());
6171 RUNTIME_ASSERT(elms->length() == 3);
6172
6173 elms->set(0, Smi::FromInt(year));
6174 elms->set(1, Smi::FromInt(month));
6175 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006176
6177 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006178}
6179
6180
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006181static Object* Runtime_NewArgumentsFast(Arguments args) {
6182 NoHandleAllocation ha;
6183 ASSERT(args.length() == 3);
6184
6185 JSFunction* callee = JSFunction::cast(args[0]);
6186 Object** parameters = reinterpret_cast<Object**>(args[1]);
6187 const int length = Smi::cast(args[2])->value();
6188
6189 Object* result = Heap::AllocateArgumentsObject(callee, length);
6190 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006191 // Allocate the elements if needed.
6192 if (length > 0) {
6193 // Allocate the fixed array.
6194 Object* obj = Heap::AllocateRawFixedArray(length);
6195 if (obj->IsFailure()) return obj;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006196
6197 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006198 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6199 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006200 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006201
6202 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006203 for (int i = 0; i < length; i++) {
6204 array->set(i, *--parameters, mode);
6205 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006206 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006207 }
6208 return result;
6209}
6210
6211
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006212static Object* Runtime_NewClosure(Arguments args) {
6213 HandleScope scope;
6214 ASSERT(args.length() == 2);
ager@chromium.org3811b432009-10-28 14:53:37 +00006215 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006216 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006217
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00006218 PretenureFlag pretenure = (context->global_context() == *context)
6219 ? TENURED // Allocate global closures in old space.
6220 : NOT_TENURED; // Allocate local closures in new space.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006221 Handle<JSFunction> result =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006222 Factory::NewFunctionFromSharedFunctionInfo(shared, context, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006223 return *result;
6224}
6225
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006226static Object* Runtime_NewObjectFromBound(Arguments args) {
6227 HandleScope scope;
6228 ASSERT(args.length() == 2);
6229 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6230 CONVERT_ARG_CHECKED(JSArray, params, 1);
6231
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006232 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006233 FixedArray* fixed = FixedArray::cast(params->elements());
6234
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006235 int fixed_length = Smi::cast(params->length())->value();
6236 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6237 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006238 Handle<Object> val = Handle<Object>(fixed->get(i));
6239 param_data[i] = val.location();
6240 }
6241
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006242 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006243 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006244 function, fixed_length, *param_data, &exception);
6245 if (exception) {
6246 return Failure::Exception();
6247 }
6248 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006249 return *result;
6250}
6251
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006253static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006254 Handle<Object> prototype = Factory::null_value();
6255 if (function->has_instance_prototype()) {
6256 prototype = Handle<Object>(function->instance_prototype());
6257 }
6258 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006259 ConstructStubCompiler compiler;
ager@chromium.org5c838252010-02-19 08:53:10 +00006260 Object* code = compiler.CompileConstructStub(function->shared());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006261 if (!code->IsFailure()) {
6262 function->shared()->set_construct_stub(Code::cast(code));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006263 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006264 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006265}
6266
6267
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006268static Object* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006269 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006270 ASSERT(args.length() == 1);
6271
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006272 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006273
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006274 // If the constructor isn't a proper function we throw a type error.
6275 if (!constructor->IsJSFunction()) {
6276 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6277 Handle<Object> type_error =
6278 Factory::NewTypeError("not_constructor", arguments);
6279 return Top::Throw(*type_error);
6280 }
6281
6282 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006283
6284 // If function should not have prototype, construction is not allowed. In this
6285 // case generated code bailouts here, since function has no initial_map.
6286 if (!function->should_have_prototype()) {
6287 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6288 Handle<Object> type_error =
6289 Factory::NewTypeError("not_constructor", arguments);
6290 return Top::Throw(*type_error);
6291 }
6292
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006293#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006294 // Handle stepping into constructors if step into is active.
6295 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006296 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006297 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006298#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006299
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006300 if (function->has_initial_map()) {
6301 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006302 // The 'Function' function ignores the receiver object when
6303 // called using 'new' and creates a new JSFunction object that
6304 // is returned. The receiver object is only used for error
6305 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006306 // JSFunction. Factory::NewJSObject() should not be used to
6307 // allocate JSFunctions since it does not properly initialize
6308 // the shared part of the function. Since the receiver is
6309 // ignored anyway, we use the global object as the receiver
6310 // instead of a new JSFunction object. This way, errors are
6311 // reported the same way whether or not 'Function' is called
6312 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006313 return Top::context()->global();
6314 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006315 }
6316
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006317 // The function should be compiled for the optimization hints to be available.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006318 Handle<SharedFunctionInfo> shared(function->shared());
6319 EnsureCompiled(shared, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006320
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006321 if (!function->has_initial_map() &&
6322 shared->IsInobjectSlackTrackingInProgress()) {
6323 // The tracking is already in progress for another function. We can only
6324 // track one initial_map at a time, so we force the completion before the
6325 // function is called as a constructor for the first time.
6326 shared->CompleteInobjectSlackTracking();
6327 TrySettingInlineConstructStub(function);
6328 }
6329
6330 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006331 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006332 // Delay setting the stub if inobject slack tracking is in progress.
6333 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6334 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006335 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006336
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006337 Counters::constructed_objects.Increment();
6338 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006339
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006340 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006341}
6342
6343
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006344static Object* Runtime_FinalizeInstanceSize(Arguments args) {
6345 HandleScope scope;
6346 ASSERT(args.length() == 1);
6347
6348 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6349 function->shared()->CompleteInobjectSlackTracking();
6350 TrySettingInlineConstructStub(function);
6351
6352 return Heap::undefined_value();
6353}
6354
6355
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006356static Object* Runtime_LazyCompile(Arguments args) {
6357 HandleScope scope;
6358 ASSERT(args.length() == 1);
6359
6360 Handle<JSFunction> function = args.at<JSFunction>(0);
6361#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006362 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006363 PrintF("[lazy: ");
6364 function->shared()->name()->Print();
6365 PrintF("]\n");
6366 }
6367#endif
6368
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006369 // Compile the target function. Here we compile using CompileLazyInLoop in
6370 // order to get the optimized version. This helps code like delta-blue
6371 // that calls performance-critical routines through constructors. A
6372 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6373 // direct call. Since the in-loop tracking takes place through CallICs
6374 // this means that things called through constructors are never known to
6375 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006376 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006377 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006378 return Failure::Exception();
6379 }
6380
6381 return function->code();
6382}
6383
6384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006385static Object* Runtime_GetFunctionDelegate(Arguments args) {
6386 HandleScope scope;
6387 ASSERT(args.length() == 1);
6388 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6389 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6390}
6391
6392
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006393static Object* Runtime_GetConstructorDelegate(Arguments args) {
6394 HandleScope scope;
6395 ASSERT(args.length() == 1);
6396 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6397 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6398}
6399
6400
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006401static Object* Runtime_NewContext(Arguments args) {
6402 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006403 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006404
kasper.lund7276f142008-07-30 08:49:36 +00006405 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006406 int length = function->shared()->scope_info()->NumberOfContextSlots();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006407 Object* result = Heap::AllocateFunctionContext(length, function);
6408 if (result->IsFailure()) return result;
6409
6410 Top::set_context(Context::cast(result));
6411
kasper.lund7276f142008-07-30 08:49:36 +00006412 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006413}
6414
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006415static Object* PushContextHelper(Object* object, bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006416 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006417 Object* js_object = object;
6418 if (!js_object->IsJSObject()) {
6419 js_object = js_object->ToObject();
6420 if (js_object->IsFailure()) {
6421 if (!Failure::cast(js_object)->IsInternalError()) return js_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006422 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006423 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006424 Handle<Object> result =
6425 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
6426 return Top::Throw(*result);
6427 }
6428 }
6429
6430 Object* result =
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006431 Heap::AllocateWithContext(Top::context(),
6432 JSObject::cast(js_object),
6433 is_catch_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006434 if (result->IsFailure()) return result;
6435
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006436 Context* context = Context::cast(result);
6437 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006438
kasper.lund7276f142008-07-30 08:49:36 +00006439 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006440}
6441
6442
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006443static Object* Runtime_PushContext(Arguments args) {
6444 NoHandleAllocation ha;
6445 ASSERT(args.length() == 1);
6446 return PushContextHelper(args[0], false);
6447}
6448
6449
6450static Object* Runtime_PushCatchContext(Arguments args) {
6451 NoHandleAllocation ha;
6452 ASSERT(args.length() == 1);
6453 return PushContextHelper(args[0], true);
6454}
6455
6456
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457static Object* Runtime_LookupContext(Arguments args) {
6458 HandleScope scope;
6459 ASSERT(args.length() == 2);
6460
6461 CONVERT_ARG_CHECKED(Context, context, 0);
6462 CONVERT_ARG_CHECKED(String, name, 1);
6463
6464 int index;
6465 PropertyAttributes attributes;
6466 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006467 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006468 context->Lookup(name, flags, &index, &attributes);
6469
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006470 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006471 ASSERT(holder->IsJSObject());
6472 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006473 }
6474
6475 // No intermediate context found. Use global object by default.
6476 return Top::context()->global();
6477}
6478
6479
ager@chromium.orga1645e22009-09-09 19:27:10 +00006480// A mechanism to return a pair of Object pointers in registers (if possible).
6481// How this is achieved is calling convention-dependent.
6482// All currently supported x86 compiles uses calling conventions that are cdecl
6483// variants where a 64-bit value is returned in two 32-bit registers
6484// (edx:eax on ia32, r1:r0 on ARM).
6485// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
6486// In Win64 calling convention, a struct of two pointers is returned in memory,
6487// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006488#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006489struct ObjectPair {
6490 Object* x;
6491 Object* y;
6492};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006493
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006494static inline ObjectPair MakePair(Object* x, Object* y) {
6495 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006496 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
6497 // In Win64 they are assigned to a hidden first argument.
6498 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006499}
6500#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006501typedef uint64_t ObjectPair;
6502static inline ObjectPair MakePair(Object* x, Object* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006503 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006504 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006506#endif
6507
6508
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006509static inline Object* Unhole(Object* x, PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006510 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
6511 USE(attributes);
6512 return x->IsTheHole() ? Heap::undefined_value() : x;
6513}
6514
6515
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006516static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
6517 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006518 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006519 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006520 JSFunction* context_extension_function =
6521 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006522 // If the holder isn't a context extension object, we just return it
6523 // as the receiver. This allows arguments objects to be used as
6524 // receivers, but only if they are put in the context scope chain
6525 // explicitly via a with-statement.
6526 Object* constructor = holder->map()->constructor();
6527 if (constructor != context_extension_function) return holder;
6528 // Fall back to using the global object as the receiver if the
6529 // property turns out to be a local variable allocated in a context
6530 // extension object - introduced via eval.
6531 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006532}
6533
6534
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006535static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006536 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006537 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006538
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006539 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00006540 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006541 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006542 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006543 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006544
6545 int index;
6546 PropertyAttributes attributes;
6547 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006548 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006549 context->Lookup(name, flags, &index, &attributes);
6550
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006551 // If the index is non-negative, the slot has been found in a local
6552 // variable or a parameter. Read it from the context object or the
6553 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006554 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006555 // If the "property" we were looking for is a local variable or an
6556 // argument in a context, the receiver is the global object; see
6557 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
6558 JSObject* receiver = Top::context()->global()->global_receiver();
6559 Object* value = (holder->IsContext())
6560 ? Context::cast(*holder)->get(index)
6561 : JSObject::cast(*holder)->GetElement(index);
6562 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006563 }
6564
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006565 // If the holder is found, we read the property from it.
6566 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006567 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006568 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006569 JSObject* receiver;
6570 if (object->IsGlobalObject()) {
6571 receiver = GlobalObject::cast(object)->global_receiver();
6572 } else if (context->is_exception_holder(*holder)) {
6573 receiver = Top::context()->global()->global_receiver();
6574 } else {
6575 receiver = ComputeReceiverForNonGlobal(object);
6576 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006577 // No need to unhole the value here. This is taken care of by the
6578 // GetProperty function.
6579 Object* value = object->GetProperty(*name);
6580 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006581 }
6582
6583 if (throw_error) {
6584 // The property doesn't exist - throw exception.
6585 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006586 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587 return MakePair(Top::Throw(*reference_error), NULL);
6588 } else {
6589 // The property doesn't exist - return undefined
6590 return MakePair(Heap::undefined_value(), Heap::undefined_value());
6591 }
6592}
6593
6594
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006595static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006596 return LoadContextSlotHelper(args, true);
6597}
6598
6599
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006600static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006601 return LoadContextSlotHelper(args, false);
6602}
6603
6604
6605static Object* Runtime_StoreContextSlot(Arguments args) {
6606 HandleScope scope;
6607 ASSERT(args.length() == 3);
6608
6609 Handle<Object> value(args[0]);
6610 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006611 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006612
6613 int index;
6614 PropertyAttributes attributes;
6615 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006616 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617 context->Lookup(name, flags, &index, &attributes);
6618
6619 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006620 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006621 // Ignore if read_only variable.
6622 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006623 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006624 }
6625 } else {
6626 ASSERT((attributes & READ_ONLY) == 0);
6627 Object* result =
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006628 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 USE(result);
6630 ASSERT(!result->IsFailure());
6631 }
6632 return *value;
6633 }
6634
6635 // Slow case: The property is not in a FixedArray context.
6636 // It is either in an JSObject extension context or it was not found.
6637 Handle<JSObject> context_ext;
6638
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006639 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006640 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006641 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642 } else {
6643 // The property was not found. It needs to be stored in the global context.
6644 ASSERT(attributes == ABSENT);
6645 attributes = NONE;
6646 context_ext = Handle<JSObject>(Top::context()->global());
6647 }
6648
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006649 // Set the property, but ignore if read_only variable on the context
6650 // extension object itself.
6651 if ((attributes & READ_ONLY) == 0 ||
6652 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006653 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
6654 if (set.is_null()) {
6655 // Failure::Exception is converted to a null handle in the
6656 // handle-based methods such as SetProperty. We therefore need
6657 // to convert null handles back to exceptions.
6658 ASSERT(Top::has_pending_exception());
6659 return Failure::Exception();
6660 }
6661 }
6662 return *value;
6663}
6664
6665
6666static Object* Runtime_Throw(Arguments args) {
6667 HandleScope scope;
6668 ASSERT(args.length() == 1);
6669
6670 return Top::Throw(args[0]);
6671}
6672
6673
6674static Object* Runtime_ReThrow(Arguments args) {
6675 HandleScope scope;
6676 ASSERT(args.length() == 1);
6677
6678 return Top::ReThrow(args[0]);
6679}
6680
6681
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006682static Object* Runtime_PromoteScheduledException(Arguments args) {
6683 ASSERT_EQ(0, args.length());
6684 return Top::PromoteScheduledException();
6685}
6686
6687
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006688static Object* Runtime_ThrowReferenceError(Arguments args) {
6689 HandleScope scope;
6690 ASSERT(args.length() == 1);
6691
6692 Handle<Object> name(args[0]);
6693 Handle<Object> reference_error =
6694 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
6695 return Top::Throw(*reference_error);
6696}
6697
6698
6699static Object* Runtime_StackOverflow(Arguments args) {
6700 NoHandleAllocation na;
6701 return Top::StackOverflow();
6702}
6703
6704
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705static Object* Runtime_StackGuard(Arguments args) {
6706 ASSERT(args.length() == 1);
6707
6708 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00006709 if (StackGuard::IsStackOverflow()) {
6710 return Runtime_StackOverflow(args);
6711 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006712
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006713 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006714}
6715
6716
6717// NOTE: These PrintXXX functions are defined for all builds (not just
6718// DEBUG builds) because we may want to be able to trace function
6719// calls in all modes.
6720static void PrintString(String* str) {
6721 // not uncommon to have empty strings
6722 if (str->length() > 0) {
6723 SmartPointer<char> s =
6724 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
6725 PrintF("%s", *s);
6726 }
6727}
6728
6729
6730static void PrintObject(Object* obj) {
6731 if (obj->IsSmi()) {
6732 PrintF("%d", Smi::cast(obj)->value());
6733 } else if (obj->IsString() || obj->IsSymbol()) {
6734 PrintString(String::cast(obj));
6735 } else if (obj->IsNumber()) {
6736 PrintF("%g", obj->Number());
6737 } else if (obj->IsFailure()) {
6738 PrintF("<failure>");
6739 } else if (obj->IsUndefined()) {
6740 PrintF("<undefined>");
6741 } else if (obj->IsNull()) {
6742 PrintF("<null>");
6743 } else if (obj->IsTrue()) {
6744 PrintF("<true>");
6745 } else if (obj->IsFalse()) {
6746 PrintF("<false>");
6747 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006748 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006749 }
6750}
6751
6752
6753static int StackSize() {
6754 int n = 0;
6755 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
6756 return n;
6757}
6758
6759
6760static void PrintTransition(Object* result) {
6761 // indentation
6762 { const int nmax = 80;
6763 int n = StackSize();
6764 if (n <= nmax)
6765 PrintF("%4d:%*s", n, n, "");
6766 else
6767 PrintF("%4d:%*s", n, nmax, "...");
6768 }
6769
6770 if (result == NULL) {
6771 // constructor calls
6772 JavaScriptFrameIterator it;
6773 JavaScriptFrame* frame = it.frame();
6774 if (frame->IsConstructor()) PrintF("new ");
6775 // function name
6776 Object* fun = frame->function();
6777 if (fun->IsJSFunction()) {
6778 PrintObject(JSFunction::cast(fun)->shared()->name());
6779 } else {
6780 PrintObject(fun);
6781 }
6782 // function arguments
6783 // (we are intentionally only printing the actually
6784 // supplied parameters, not all parameters required)
6785 PrintF("(this=");
6786 PrintObject(frame->receiver());
6787 const int length = frame->GetProvidedParametersCount();
6788 for (int i = 0; i < length; i++) {
6789 PrintF(", ");
6790 PrintObject(frame->GetParameter(i));
6791 }
6792 PrintF(") {\n");
6793
6794 } else {
6795 // function result
6796 PrintF("} -> ");
6797 PrintObject(result);
6798 PrintF("\n");
6799 }
6800}
6801
6802
6803static Object* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006804 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805 NoHandleAllocation ha;
6806 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006807 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808}
6809
6810
6811static Object* Runtime_TraceExit(Arguments args) {
6812 NoHandleAllocation ha;
6813 PrintTransition(args[0]);
6814 return args[0]; // return TOS
6815}
6816
6817
6818static Object* Runtime_DebugPrint(Arguments args) {
6819 NoHandleAllocation ha;
6820 ASSERT(args.length() == 1);
6821
6822#ifdef DEBUG
6823 if (args[0]->IsString()) {
6824 // If we have a string, assume it's a code "marker"
6825 // and print some interesting cpu debugging info.
6826 JavaScriptFrameIterator it;
6827 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00006828 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
6829 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006830 } else {
6831 PrintF("DebugPrint: ");
6832 }
6833 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006834 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006835 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006836 HeapObject::cast(args[0])->map()->Print();
6837 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006838#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006839 // ShortPrint is available in release mode. Print is not.
6840 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006841#endif
6842 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00006843 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006844
6845 return args[0]; // return TOS
6846}
6847
6848
6849static Object* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006850 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006851 NoHandleAllocation ha;
6852 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006853 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006854}
6855
6856
mads.s.ager31e71382008-08-13 09:32:07 +00006857static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006858 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00006859 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006860
6861 // According to ECMA-262, section 15.9.1, page 117, the precision of
6862 // the number in a Date object representing a particular instant in
6863 // time is milliseconds. Therefore, we floor the result of getting
6864 // the OS time.
6865 double millis = floor(OS::TimeCurrentMillis());
6866 return Heap::NumberFromDouble(millis);
6867}
6868
6869
6870static Object* Runtime_DateParseString(Arguments args) {
6871 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006872 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006873
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006874 CONVERT_ARG_CHECKED(String, str, 0);
6875 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006876
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006877 CONVERT_ARG_CHECKED(JSArray, output, 1);
6878 RUNTIME_ASSERT(output->HasFastElements());
6879
6880 AssertNoAllocation no_allocation;
6881
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006882 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006883 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
6884 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00006885 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006886 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006887 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00006888 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006889 result = DateParser::Parse(str->ToUC16Vector(), output_array);
6890 }
6891
6892 if (result) {
6893 return *output;
6894 } else {
6895 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006896 }
6897}
6898
6899
6900static Object* Runtime_DateLocalTimezone(Arguments args) {
6901 NoHandleAllocation ha;
6902 ASSERT(args.length() == 1);
6903
6904 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00006905 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006906 return Heap::AllocateStringFromUtf8(CStrVector(zone));
6907}
6908
6909
6910static Object* Runtime_DateLocalTimeOffset(Arguments args) {
6911 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00006912 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006913
6914 return Heap::NumberFromDouble(OS::LocalTimeOffset());
6915}
6916
6917
6918static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
6919 NoHandleAllocation ha;
6920 ASSERT(args.length() == 1);
6921
6922 CONVERT_DOUBLE_CHECKED(x, args[0]);
6923 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
6924}
6925
6926
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006927static Object* Runtime_GlobalReceiver(Arguments args) {
6928 ASSERT(args.length() == 1);
6929 Object* global = args[0];
6930 if (!global->IsJSGlobalObject()) return Heap::null_value();
6931 return JSGlobalObject::cast(global)->global_receiver();
6932}
6933
6934
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006935static Object* Runtime_CompileString(Arguments args) {
6936 HandleScope scope;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006937 ASSERT_EQ(2, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006938 CONVERT_ARG_CHECKED(String, source, 0);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006939 CONVERT_ARG_CHECKED(Oddball, is_json, 1)
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006940
ager@chromium.org381abbb2009-02-25 13:23:22 +00006941 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006942 Handle<Context> context(Top::context()->global_context());
ager@chromium.orgadd848f2009-08-13 12:44:13 +00006943 Compiler::ValidationState validate = (is_json->IsTrue())
6944 ? Compiler::VALIDATE_JSON : Compiler::DONT_VALIDATE_JSON;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006945 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
6946 context,
6947 true,
6948 validate);
6949 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006950 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006951 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006952 return *fun;
6953}
6954
6955
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00006956static ObjectPair CompileGlobalEval(Handle<String> source,
6957 Handle<Object> receiver) {
6958 // Deal with a normal eval call with a string argument. Compile it
6959 // and return the compiled function bound in the local context.
6960 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
6961 source,
6962 Handle<Context>(Top::context()),
6963 Top::context()->IsGlobalContext(),
6964 Compiler::DONT_VALIDATE_JSON);
6965 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
6966 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
6967 shared,
6968 Handle<Context>(Top::context()),
6969 NOT_TENURED);
6970 return MakePair(*compiled, *receiver);
6971}
6972
6973
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006974static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
6975 ASSERT(args.length() == 3);
6976 if (!args[0]->IsJSFunction()) {
6977 return MakePair(Top::ThrowIllegalOperation(), NULL);
6978 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006979
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006980 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006981 Handle<JSFunction> callee = args.at<JSFunction>(0);
6982 Handle<Object> receiver; // Will be overwritten.
6983
6984 // Compute the calling context.
6985 Handle<Context> context = Handle<Context>(Top::context());
6986#ifdef DEBUG
6987 // Make sure Top::context() agrees with the old code that traversed
6988 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006989 StackFrameLocator locator;
6990 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006991 ASSERT(Context::cast(frame->context()) == *context);
6992#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006993
6994 // Find where the 'eval' symbol is bound. It is unaliased only if
6995 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006996 int index = -1;
6997 PropertyAttributes attributes = ABSENT;
6998 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006999 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7000 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007001 // Stop search when eval is found or when the global context is
7002 // reached.
7003 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007004 if (context->is_function_context()) {
7005 context = Handle<Context>(Context::cast(context->closure()->context()));
7006 } else {
7007 context = Handle<Context>(context->previous());
7008 }
7009 }
7010
iposva@chromium.org245aa852009-02-10 00:49:54 +00007011 // If eval could not be resolved, it has been deleted and we need to
7012 // throw a reference error.
7013 if (attributes == ABSENT) {
7014 Handle<Object> name = Factory::eval_symbol();
7015 Handle<Object> reference_error =
7016 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007017 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007018 }
7019
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007020 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007021 // 'eval' is not bound in the global context. Just call the function
7022 // with the given arguments. This is not necessarily the global eval.
7023 if (receiver->IsContext()) {
7024 context = Handle<Context>::cast(receiver);
7025 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007026 } else if (receiver->IsJSContextExtensionObject()) {
7027 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007028 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007029 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007030 }
7031
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007032 // 'eval' is bound in the global context, but it may have been overwritten.
7033 // Compare it to the builtin 'GlobalEval' function to make sure.
7034 if (*callee != Top::global_context()->global_eval_fun() ||
7035 !args[1]->IsString()) {
7036 return MakePair(*callee, Top::context()->global()->global_receiver());
7037 }
7038
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007039 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7040}
7041
7042
7043static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7044 ASSERT(args.length() == 3);
7045 if (!args[0]->IsJSFunction()) {
7046 return MakePair(Top::ThrowIllegalOperation(), NULL);
7047 }
7048
7049 HandleScope scope;
7050 Handle<JSFunction> callee = args.at<JSFunction>(0);
7051
7052 // 'eval' is bound in the global context, but it may have been overwritten.
7053 // Compare it to the builtin 'GlobalEval' function to make sure.
7054 if (*callee != Top::global_context()->global_eval_fun() ||
7055 !args[1]->IsString()) {
7056 return MakePair(*callee, Top::context()->global()->global_receiver());
7057 }
7058
7059 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007060}
7061
7062
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007063static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
7064 // This utility adjusts the property attributes for newly created Function
7065 // object ("new Function(...)") by changing the map.
7066 // All it does is changing the prototype property to enumerable
7067 // as specified in ECMA262, 15.3.5.2.
7068 HandleScope scope;
7069 ASSERT(args.length() == 1);
7070 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7071 ASSERT(func->map()->instance_type() ==
7072 Top::function_instance_map()->instance_type());
7073 ASSERT(func->map()->instance_size() ==
7074 Top::function_instance_map()->instance_size());
7075 func->set_map(*Top::function_instance_map());
7076 return *func;
7077}
7078
7079
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007080static Object* Runtime_AllocateInNewSpace(Arguments args) {
7081 // Allocate a block of memory in NewSpace (filled with a filler).
7082 // Use as fallback for allocation in generated code when NewSpace
7083 // is full.
7084 ASSERT(args.length() == 1);
7085 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7086 int size = size_smi->value();
7087 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7088 RUNTIME_ASSERT(size > 0);
7089 static const int kMinFreeNewSpaceAfterGC =
7090 Heap::InitialSemiSpaceSize() * 3/4;
7091 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
7092 Object* allocation = Heap::new_space()->AllocateRaw(size);
7093 if (!allocation->IsFailure()) {
7094 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7095 }
7096 return allocation;
7097}
7098
7099
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007100// Push an array unto an array of arrays if it is not already in the
7101// array. Returns true if the element was pushed on the stack and
7102// false otherwise.
7103static Object* Runtime_PushIfAbsent(Arguments args) {
7104 ASSERT(args.length() == 2);
7105 CONVERT_CHECKED(JSArray, array, args[0]);
7106 CONVERT_CHECKED(JSArray, element, args[1]);
7107 RUNTIME_ASSERT(array->HasFastElements());
7108 int length = Smi::cast(array->length())->value();
7109 FixedArray* elements = FixedArray::cast(array->elements());
7110 for (int i = 0; i < length; i++) {
7111 if (elements->get(i) == element) return Heap::false_value();
7112 }
7113 Object* obj = array->SetFastElement(length, element);
7114 if (obj->IsFailure()) return obj;
7115 return Heap::true_value();
7116}
7117
7118
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007119/**
7120 * A simple visitor visits every element of Array's.
7121 * The backend storage can be a fixed array for fast elements case,
7122 * or a dictionary for sparse array. Since Dictionary is a subtype
7123 * of FixedArray, the class can be used by both fast and slow cases.
7124 * The second parameter of the constructor, fast_elements, specifies
7125 * whether the storage is a FixedArray or Dictionary.
7126 *
7127 * An index limit is used to deal with the situation that a result array
7128 * length overflows 32-bit non-negative integer.
7129 */
7130class ArrayConcatVisitor {
7131 public:
7132 ArrayConcatVisitor(Handle<FixedArray> storage,
7133 uint32_t index_limit,
7134 bool fast_elements) :
7135 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007136 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007137
7138 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007139 if (i >= index_limit_ - index_offset_) return;
7140 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007141
7142 if (fast_elements_) {
7143 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7144 storage_->set(index, *elm);
7145
7146 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007147 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7148 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007149 Factory::DictionaryAtNumberPut(dict, index, elm);
7150 if (!result.is_identical_to(dict))
7151 storage_ = result;
7152 }
7153 }
7154
7155 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007156 if (index_limit_ - index_offset_ < delta) {
7157 index_offset_ = index_limit_;
7158 } else {
7159 index_offset_ += delta;
7160 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007161 }
7162
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007163 Handle<FixedArray> storage() { return storage_; }
7164
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007165 private:
7166 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007167 // Limit on the accepted indices. Elements with indices larger than the
7168 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007169 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007170 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007171 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007172 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007173};
7174
7175
ager@chromium.org3811b432009-10-28 14:53:37 +00007176template<class ExternalArrayClass, class ElementType>
7177static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7178 bool elements_are_ints,
7179 bool elements_are_guaranteed_smis,
7180 uint32_t range,
7181 ArrayConcatVisitor* visitor) {
7182 Handle<ExternalArrayClass> array(
7183 ExternalArrayClass::cast(receiver->elements()));
7184 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7185
7186 if (visitor != NULL) {
7187 if (elements_are_ints) {
7188 if (elements_are_guaranteed_smis) {
7189 for (uint32_t j = 0; j < len; j++) {
7190 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7191 visitor->visit(j, e);
7192 }
7193 } else {
7194 for (uint32_t j = 0; j < len; j++) {
7195 int64_t val = static_cast<int64_t>(array->get(j));
7196 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7197 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7198 visitor->visit(j, e);
7199 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007200 Handle<Object> e =
7201 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007202 visitor->visit(j, e);
7203 }
7204 }
7205 }
7206 } else {
7207 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007208 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007209 visitor->visit(j, e);
7210 }
7211 }
7212 }
7213
7214 return len;
7215}
7216
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007217/**
7218 * A helper function that visits elements of a JSObject. Only elements
7219 * whose index between 0 and range (exclusive) are visited.
7220 *
7221 * If the third parameter, visitor, is not NULL, the visitor is called
7222 * with parameters, 'visitor_index_offset + element index' and the element.
7223 *
7224 * It returns the number of visisted elements.
7225 */
7226static uint32_t IterateElements(Handle<JSObject> receiver,
7227 uint32_t range,
7228 ArrayConcatVisitor* visitor) {
7229 uint32_t num_of_elements = 0;
7230
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007231 switch (receiver->GetElementsKind()) {
7232 case JSObject::FAST_ELEMENTS: {
7233 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7234 uint32_t len = elements->length();
7235 if (range < len) {
7236 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007237 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007238
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007239 for (uint32_t j = 0; j < len; j++) {
7240 Handle<Object> e(elements->get(j));
7241 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007242 num_of_elements++;
7243 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007244 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007245 }
7246 }
7247 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007248 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007249 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007250 case JSObject::PIXEL_ELEMENTS: {
7251 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7252 uint32_t len = pixels->length();
7253 if (range < len) {
7254 len = range;
7255 }
7256
7257 for (uint32_t j = 0; j < len; j++) {
7258 num_of_elements++;
7259 if (visitor != NULL) {
7260 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7261 visitor->visit(j, e);
7262 }
7263 }
7264 break;
7265 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007266 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7267 num_of_elements =
7268 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7269 receiver, true, true, range, visitor);
7270 break;
7271 }
7272 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7273 num_of_elements =
7274 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7275 receiver, true, true, range, visitor);
7276 break;
7277 }
7278 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7279 num_of_elements =
7280 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7281 receiver, true, true, range, visitor);
7282 break;
7283 }
7284 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7285 num_of_elements =
7286 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7287 receiver, true, true, range, visitor);
7288 break;
7289 }
7290 case JSObject::EXTERNAL_INT_ELEMENTS: {
7291 num_of_elements =
7292 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7293 receiver, true, false, range, visitor);
7294 break;
7295 }
7296 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7297 num_of_elements =
7298 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7299 receiver, true, false, range, visitor);
7300 break;
7301 }
7302 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7303 num_of_elements =
7304 IterateExternalArrayElements<ExternalFloatArray, float>(
7305 receiver, false, false, range, visitor);
7306 break;
7307 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007308 case JSObject::DICTIONARY_ELEMENTS: {
7309 Handle<NumberDictionary> dict(receiver->element_dictionary());
7310 uint32_t capacity = dict->Capacity();
7311 for (uint32_t j = 0; j < capacity; j++) {
7312 Handle<Object> k(dict->KeyAt(j));
7313 if (dict->IsKey(*k)) {
7314 ASSERT(k->IsNumber());
7315 uint32_t index = static_cast<uint32_t>(k->Number());
7316 if (index < range) {
7317 num_of_elements++;
7318 if (visitor) {
7319 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7320 }
7321 }
7322 }
7323 }
7324 break;
7325 }
7326 default:
7327 UNREACHABLE();
7328 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007329 }
7330
7331 return num_of_elements;
7332}
7333
7334
7335/**
7336 * A helper function that visits elements of an Array object, and elements
7337 * on its prototypes.
7338 *
7339 * Elements on prototypes are visited first, and only elements whose indices
7340 * less than Array length are visited.
7341 *
7342 * If a ArrayConcatVisitor object is given, the visitor is called with
7343 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007344 *
7345 * The returned number of elements is an upper bound on the actual number
7346 * of elements added. If the same element occurs in more than one object
7347 * in the array's prototype chain, it will be counted more than once, but
7348 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007349 */
7350static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7351 ArrayConcatVisitor* visitor) {
7352 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7353 Handle<Object> obj = array;
7354
7355 static const int kEstimatedPrototypes = 3;
7356 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7357
7358 // Visit prototype first. If an element on the prototype is shadowed by
7359 // the inheritor using the same index, the ArrayConcatVisitor visits
7360 // the prototype element before the shadowing element.
7361 // The visitor can simply overwrite the old value by new value using
7362 // the same index. This follows Array::concat semantics.
7363 while (!obj->IsNull()) {
7364 objects.Add(Handle<JSObject>::cast(obj));
7365 obj = Handle<Object>(obj->GetPrototype());
7366 }
7367
7368 uint32_t nof_elements = 0;
7369 for (int i = objects.length() - 1; i >= 0; i--) {
7370 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007371 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007372 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007373
7374 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7375 nof_elements = JSObject::kMaxElementCount;
7376 } else {
7377 nof_elements += encountered_elements;
7378 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007379 }
7380
7381 return nof_elements;
7382}
7383
7384
7385/**
7386 * A helper function of Runtime_ArrayConcat.
7387 *
7388 * The first argument is an Array of arrays and objects. It is the
7389 * same as the arguments array of Array::concat JS function.
7390 *
7391 * If an argument is an Array object, the function visits array
7392 * elements. If an argument is not an Array object, the function
7393 * visits the object as if it is an one-element array.
7394 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007395 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007396 * non-negative number is used as new length. For example, if one
7397 * array length is 2^32 - 1, second array length is 1, the
7398 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007399 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
7400 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007401 */
7402static uint32_t IterateArguments(Handle<JSArray> arguments,
7403 ArrayConcatVisitor* visitor) {
7404 uint32_t visited_elements = 0;
7405 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7406
7407 for (uint32_t i = 0; i < num_of_args; i++) {
7408 Handle<Object> obj(arguments->GetElement(i));
7409 if (obj->IsJSArray()) {
7410 Handle<JSArray> array = Handle<JSArray>::cast(obj);
7411 uint32_t len = static_cast<uint32_t>(array->length()->Number());
7412 uint32_t nof_elements =
7413 IterateArrayAndPrototypeElements(array, visitor);
7414 // Total elements of array and its prototype chain can be more than
7415 // the array length, but ArrayConcat can only concatenate at most
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007416 // the array length number of elements. We use the length as an estimate
7417 // for the actual number of elements added.
7418 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
7419 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
7420 visited_elements = JSArray::kMaxElementCount;
7421 } else {
7422 visited_elements += added_elements;
7423 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007424 if (visitor) visitor->increase_index_offset(len);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007425 } else {
7426 if (visitor) {
7427 visitor->visit(0, obj);
7428 visitor->increase_index_offset(1);
7429 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007430 if (visited_elements < JSArray::kMaxElementCount) {
7431 visited_elements++;
7432 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007433 }
7434 }
7435 return visited_elements;
7436}
7437
7438
7439/**
7440 * Array::concat implementation.
7441 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007442 * TODO(lrn): Fix non-compliance for very large concatenations and update to
7443 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007444 */
7445static Object* Runtime_ArrayConcat(Arguments args) {
7446 ASSERT(args.length() == 1);
7447 HandleScope handle_scope;
7448
7449 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
7450 Handle<JSArray> arguments(arg_arrays);
7451
7452 // Pass 1: estimate the number of elements of the result
7453 // (it could be more than real numbers if prototype has elements).
7454 uint32_t result_length = 0;
7455 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7456
7457 { AssertNoAllocation nogc;
7458 for (uint32_t i = 0; i < num_of_args; i++) {
7459 Object* obj = arguments->GetElement(i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007460 uint32_t length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007461 if (obj->IsJSArray()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007462 length_estimate =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007463 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
7464 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007465 length_estimate = 1;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007466 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007467 if (JSObject::kMaxElementCount - result_length < length_estimate) {
7468 result_length = JSObject::kMaxElementCount;
7469 break;
7470 }
7471 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007472 }
7473 }
7474
7475 // Allocate an empty array, will set length and content later.
7476 Handle<JSArray> result = Factory::NewJSArray(0);
7477
7478 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
7479 // If estimated number of elements is more than half of length, a
7480 // fixed array (fast case) is more time and space-efficient than a
7481 // dictionary.
7482 bool fast_case = (estimate_nof_elements * 2) >= result_length;
7483
7484 Handle<FixedArray> storage;
7485 if (fast_case) {
7486 // The backing storage array must have non-existing elements to
7487 // preserve holes across concat operations.
7488 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007489 Handle<Map> fast_map =
7490 Factory::GetFastElementsMap(Handle<Map>(result->map()));
7491 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007492 } else {
7493 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
7494 uint32_t at_least_space_for = estimate_nof_elements +
7495 (estimate_nof_elements >> 2);
7496 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007497 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007498 Handle<Map> slow_map =
7499 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
7500 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007501 }
7502
7503 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
7504
7505 ArrayConcatVisitor visitor(storage, result_length, fast_case);
7506
7507 IterateArguments(arguments, &visitor);
7508
7509 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007510 // Please note the storage might have changed in the visitor.
7511 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007512
7513 return *result;
7514}
7515
7516
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007517// This will not allocate (flatten the string), but it may run
7518// very slowly for very deeply nested ConsStrings. For debugging use only.
7519static Object* Runtime_GlobalPrint(Arguments args) {
7520 NoHandleAllocation ha;
7521 ASSERT(args.length() == 1);
7522
7523 CONVERT_CHECKED(String, string, args[0]);
7524 StringInputBuffer buffer(string);
7525 while (buffer.has_more()) {
7526 uint16_t character = buffer.GetNext();
7527 PrintF("%c", character);
7528 }
7529 return string;
7530}
7531
ager@chromium.org5ec48922009-05-05 07:25:34 +00007532// Moves all own elements of an object, that are below a limit, to positions
7533// starting at zero. All undefined values are placed after non-undefined values,
7534// and are followed by non-existing element. Does not change the length
7535// property.
7536// Returns the number of non-undefined elements collected.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007537static Object* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007538 ASSERT(args.length() == 2);
7539 CONVERT_CHECKED(JSObject, object, args[0]);
7540 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
7541 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007542}
7543
7544
7545// Move contents of argument 0 (an array) to argument 1 (an array)
7546static Object* Runtime_MoveArrayContents(Arguments args) {
7547 ASSERT(args.length() == 2);
7548 CONVERT_CHECKED(JSArray, from, args[0]);
7549 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007550 HeapObject* new_elements = from->elements();
7551 Object* new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007552 if (new_elements->map() == Heap::fixed_array_map() ||
7553 new_elements->map() == Heap::fixed_cow_array_map()) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007554 new_map = to->map()->GetFastElementsMap();
7555 } else {
7556 new_map = to->map()->GetSlowElementsMap();
7557 }
7558 if (new_map->IsFailure()) return new_map;
7559 to->set_map(Map::cast(new_map));
7560 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007561 to->set_length(from->length());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007562 Object* obj = from->ResetElements();
7563 if (obj->IsFailure()) return obj;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007564 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007565 return to;
7566}
7567
7568
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007569// How many elements does this object/array have?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007570static Object* Runtime_EstimateNumberOfElements(Arguments args) {
7571 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007572 CONVERT_CHECKED(JSObject, object, args[0]);
7573 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007574 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007575 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007576 } else if (object->IsJSArray()) {
7577 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007578 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007579 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007580 }
7581}
7582
7583
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007584static Object* Runtime_SwapElements(Arguments args) {
7585 HandleScope handle_scope;
7586
7587 ASSERT_EQ(3, args.length());
7588
ager@chromium.orgac091b72010-05-05 07:34:42 +00007589 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007590 Handle<Object> key1 = args.at<Object>(1);
7591 Handle<Object> key2 = args.at<Object>(2);
7592
7593 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007594 if (!key1->ToArrayIndex(&index1)
7595 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00007596 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007597 }
7598
ager@chromium.orgac091b72010-05-05 07:34:42 +00007599 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
7600 Handle<Object> tmp1 = GetElement(jsobject, index1);
7601 Handle<Object> tmp2 = GetElement(jsobject, index2);
7602
7603 SetElement(jsobject, index1, tmp2);
7604 SetElement(jsobject, index2, tmp1);
7605
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007606 return Heap::undefined_value();
7607}
7608
7609
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007610// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007611// might have elements. Can either return keys (positive integers) or
7612// intervals (pair of a negative integer (-start-1) followed by a
7613// positive (length)) or undefined values.
7614// Intervals can span over some keys that are not in the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007615static Object* Runtime_GetArrayKeys(Arguments args) {
7616 ASSERT(args.length() == 2);
7617 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007618 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007619 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007620 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007621 // Create an array and get all the keys into it, then remove all the
7622 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007623 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007624 int keys_length = keys->length();
7625 for (int i = 0; i < keys_length; i++) {
7626 Object* key = keys->get(i);
7627 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007628 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007629 // Zap invalid keys.
7630 keys->set_undefined(i);
7631 }
7632 }
7633 return *Factory::NewJSArrayWithElements(keys);
7634 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007635 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007636 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
7637 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007638 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007639 uint32_t actual_length =
7640 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00007641 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007642 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00007643 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007644 single_interval->set(1, *length_object);
7645 return *Factory::NewJSArrayWithElements(single_interval);
7646 }
7647}
7648
7649
7650// DefineAccessor takes an optional final argument which is the
7651// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
7652// to the way accessors are implemented, it is set for both the getter
7653// and setter on the first call to DefineAccessor and ignored on
7654// subsequent calls.
7655static Object* Runtime_DefineAccessor(Arguments args) {
7656 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
7657 // Compute attributes.
7658 PropertyAttributes attributes = NONE;
7659 if (args.length() == 5) {
7660 CONVERT_CHECKED(Smi, attrs, args[4]);
7661 int value = attrs->value();
7662 // Only attribute bits should be set.
7663 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
7664 attributes = static_cast<PropertyAttributes>(value);
7665 }
7666
7667 CONVERT_CHECKED(JSObject, obj, args[0]);
7668 CONVERT_CHECKED(String, name, args[1]);
7669 CONVERT_CHECKED(Smi, flag, args[2]);
7670 CONVERT_CHECKED(JSFunction, fun, args[3]);
7671 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
7672}
7673
7674
7675static Object* Runtime_LookupAccessor(Arguments args) {
7676 ASSERT(args.length() == 3);
7677 CONVERT_CHECKED(JSObject, obj, args[0]);
7678 CONVERT_CHECKED(String, name, args[1]);
7679 CONVERT_CHECKED(Smi, flag, args[2]);
7680 return obj->LookupAccessor(name, flag->value() == 0);
7681}
7682
7683
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007684#ifdef ENABLE_DEBUGGER_SUPPORT
7685static Object* Runtime_DebugBreak(Arguments args) {
7686 ASSERT(args.length() == 0);
7687 return Execution::DebugBreakHelper();
7688}
7689
7690
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007691// Helper functions for wrapping and unwrapping stack frame ids.
7692static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007693 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007694 return Smi::FromInt(id >> 2);
7695}
7696
7697
7698static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
7699 return static_cast<StackFrame::Id>(wrapped->value() << 2);
7700}
7701
7702
7703// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00007704// args[0]: debug event listener function to set or null or undefined for
7705// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007706// args[1]: object supplied during callback
iposva@chromium.org245aa852009-02-10 00:49:54 +00007707static Object* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007708 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007709 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
7710 args[0]->IsUndefined() ||
7711 args[0]->IsNull());
7712 Handle<Object> callback = args.at<Object>(0);
7713 Handle<Object> data = args.at<Object>(1);
7714 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007715
7716 return Heap::undefined_value();
7717}
7718
7719
7720static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00007721 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007722 StackGuard::DebugBreak();
7723 return Heap::undefined_value();
7724}
7725
7726
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007727static Object* DebugLookupResultValue(Object* receiver, String* name,
7728 LookupResult* result,
ager@chromium.org32912102009-01-16 10:38:43 +00007729 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007730 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007732 case NORMAL:
7733 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007734 if (value->IsTheHole()) {
7735 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007736 }
7737 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007738 case FIELD:
7739 value =
7740 JSObject::cast(
7741 result->holder())->FastPropertyAt(result->GetFieldIndex());
7742 if (value->IsTheHole()) {
7743 return Heap::undefined_value();
7744 }
7745 return value;
7746 case CONSTANT_FUNCTION:
7747 return result->GetConstantFunction();
7748 case CALLBACKS: {
7749 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007750 if (structure->IsProxy() || structure->IsAccessorInfo()) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007751 value = receiver->GetPropertyWithCallback(
7752 receiver, structure, name, result->holder());
ager@chromium.org381abbb2009-02-25 13:23:22 +00007753 if (value->IsException()) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007754 value = Top::pending_exception();
7755 Top::clear_pending_exception();
7756 if (caught_exception != NULL) {
7757 *caught_exception = true;
7758 }
7759 }
7760 return value;
7761 } else {
7762 return Heap::undefined_value();
7763 }
7764 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007765 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007766 case MAP_TRANSITION:
7767 case CONSTANT_TRANSITION:
7768 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007769 return Heap::undefined_value();
7770 default:
7771 UNREACHABLE();
7772 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007773 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007774 return Heap::undefined_value();
7775}
7776
7777
ager@chromium.org32912102009-01-16 10:38:43 +00007778// Get debugger related details for an object property.
7779// args[0]: object holding property
7780// args[1]: name of the property
7781//
7782// The array returned contains the following information:
7783// 0: Property value
7784// 1: Property details
7785// 2: Property value is exception
7786// 3: Getter function if defined
7787// 4: Setter function if defined
7788// Items 2-4 are only filled if the property has either a getter or a setter
7789// defined through __defineGetter__ and/or __defineSetter__.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007790static Object* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007791 HandleScope scope;
7792
7793 ASSERT(args.length() == 2);
7794
7795 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7796 CONVERT_ARG_CHECKED(String, name, 1);
7797
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007798 // Make sure to set the current context to the context before the debugger was
7799 // entered (if the debugger is entered). The reason for switching context here
7800 // is that for some property lookups (accessors and interceptors) callbacks
7801 // into the embedding application can occour, and the embedding application
7802 // could have the assumption that its own global context is the current
7803 // context and not some internal debugger context.
7804 SaveContext save;
7805 if (Debug::InDebugger()) {
7806 Top::set_context(*Debug::debugger_entry()->GetContext());
7807 }
7808
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007809 // Skip the global proxy as it has no properties and always delegates to the
7810 // real global object.
7811 if (obj->IsJSGlobalProxy()) {
7812 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
7813 }
7814
7815
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007816 // Check if the name is trivially convertible to an index and get the element
7817 // if so.
7818 uint32_t index;
7819 if (name->AsArrayIndex(&index)) {
7820 Handle<FixedArray> details = Factory::NewFixedArray(2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007821 Object* element_or_char = Runtime::GetElementOrCharAt(obj, index);
7822 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007823 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
7824 return *Factory::NewJSArrayWithElements(details);
7825 }
7826
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007827 // Find the number of objects making up this.
7828 int length = LocalPrototypeChainLength(*obj);
7829
7830 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007831 Handle<JSObject> jsproto = obj;
7832 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007833 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007834 jsproto->LocalLookup(*name, &result);
7835 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007836 // LookupResult is not GC safe as it holds raw object pointers.
7837 // GC can happen later in this code so put the required fields into
7838 // local variables using handles when required for later use.
7839 PropertyType result_type = result.type();
7840 Handle<Object> result_callback_obj;
7841 if (result_type == CALLBACKS) {
7842 result_callback_obj = Handle<Object>(result.GetCallbackObject());
7843 }
7844 Smi* property_details = result.GetPropertyDetails().AsSmi();
7845 // DebugLookupResultValue can cause GC so details from LookupResult needs
7846 // to be copied to handles before this.
7847 bool caught_exception = false;
7848 Object* raw_value = DebugLookupResultValue(*obj, *name, &result,
7849 &caught_exception);
7850 if (raw_value->IsFailure()) return raw_value;
7851 Handle<Object> value(raw_value);
7852
7853 // If the callback object is a fixed array then it contains JavaScript
7854 // getter and/or setter.
7855 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
7856 result_callback_obj->IsFixedArray();
7857 Handle<FixedArray> details =
7858 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
7859 details->set(0, *value);
7860 details->set(1, property_details);
7861 if (hasJavaScriptAccessors) {
7862 details->set(2,
7863 caught_exception ? Heap::true_value()
7864 : Heap::false_value());
7865 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
7866 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
7867 }
7868
7869 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007870 }
7871 if (i < length - 1) {
7872 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
7873 }
7874 }
7875
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007876 return Heap::undefined_value();
7877}
7878
7879
7880static Object* Runtime_DebugGetProperty(Arguments args) {
7881 HandleScope scope;
7882
7883 ASSERT(args.length() == 2);
7884
7885 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7886 CONVERT_ARG_CHECKED(String, name, 1);
7887
7888 LookupResult result;
7889 obj->Lookup(*name, &result);
7890 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007891 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007892 }
7893 return Heap::undefined_value();
7894}
7895
7896
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007897// Return the property type calculated from the property details.
7898// args[0]: smi with property details.
7899static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
7900 ASSERT(args.length() == 1);
7901 CONVERT_CHECKED(Smi, details, args[0]);
7902 PropertyType type = PropertyDetails(details).type();
7903 return Smi::FromInt(static_cast<int>(type));
7904}
7905
7906
7907// Return the property attribute calculated from the property details.
7908// args[0]: smi with property details.
7909static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
7910 ASSERT(args.length() == 1);
7911 CONVERT_CHECKED(Smi, details, args[0]);
7912 PropertyAttributes attributes = PropertyDetails(details).attributes();
7913 return Smi::FromInt(static_cast<int>(attributes));
7914}
7915
7916
7917// Return the property insertion index calculated from the property details.
7918// args[0]: smi with property details.
7919static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
7920 ASSERT(args.length() == 1);
7921 CONVERT_CHECKED(Smi, details, args[0]);
7922 int index = PropertyDetails(details).index();
7923 return Smi::FromInt(index);
7924}
7925
7926
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007927// Return property value from named interceptor.
7928// args[0]: object
7929// args[1]: property name
7930static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
7931 HandleScope scope;
7932 ASSERT(args.length() == 2);
7933 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7934 RUNTIME_ASSERT(obj->HasNamedInterceptor());
7935 CONVERT_ARG_CHECKED(String, name, 1);
7936
7937 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007938 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007939}
7940
7941
7942// Return element value from indexed interceptor.
7943// args[0]: object
7944// args[1]: index
7945static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
7946 HandleScope scope;
7947 ASSERT(args.length() == 2);
7948 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7949 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
7950 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
7951
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007952 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007953}
7954
7955
7956static Object* Runtime_CheckExecutionState(Arguments args) {
7957 ASSERT(args.length() >= 1);
7958 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007959 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007960 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007961 return Top::Throw(Heap::illegal_execution_state_symbol());
7962 }
7963
7964 return Heap::true_value();
7965}
7966
7967
7968static Object* Runtime_GetFrameCount(Arguments args) {
7969 HandleScope scope;
7970 ASSERT(args.length() == 1);
7971
7972 // Check arguments.
7973 Object* result = Runtime_CheckExecutionState(args);
7974 if (result->IsFailure()) return result;
7975
7976 // Count all frames which are relevant to debugging stack trace.
7977 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007978 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00007979 if (id == StackFrame::NO_ID) {
7980 // If there is no JavaScript stack frame count is 0.
7981 return Smi::FromInt(0);
7982 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007983 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
7984 return Smi::FromInt(n);
7985}
7986
7987
7988static const int kFrameDetailsFrameIdIndex = 0;
7989static const int kFrameDetailsReceiverIndex = 1;
7990static const int kFrameDetailsFunctionIndex = 2;
7991static const int kFrameDetailsArgumentCountIndex = 3;
7992static const int kFrameDetailsLocalCountIndex = 4;
7993static const int kFrameDetailsSourcePositionIndex = 5;
7994static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00007995static const int kFrameDetailsAtReturnIndex = 7;
7996static const int kFrameDetailsDebuggerFrameIndex = 8;
7997static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007998
7999// Return an array with frame details
8000// args[0]: number: break id
8001// args[1]: number: frame index
8002//
8003// The array returned contains the following information:
8004// 0: Frame id
8005// 1: Receiver
8006// 2: Function
8007// 3: Argument count
8008// 4: Local count
8009// 5: Source position
8010// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008011// 7: Is at return
8012// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008013// Arguments name, value
8014// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008015// Return value if any
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008016static Object* Runtime_GetFrameDetails(Arguments args) {
8017 HandleScope scope;
8018 ASSERT(args.length() == 2);
8019
8020 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008021 Object* check = Runtime_CheckExecutionState(args);
8022 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008023 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8024
8025 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008026 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008027 if (id == StackFrame::NO_ID) {
8028 // If there are no JavaScript stack frames return undefined.
8029 return Heap::undefined_value();
8030 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008031 int count = 0;
8032 JavaScriptFrameIterator it(id);
8033 for (; !it.done(); it.Advance()) {
8034 if (count == index) break;
8035 count++;
8036 }
8037 if (it.done()) return Heap::undefined_value();
8038
8039 // Traverse the saved contexts chain to find the active context for the
8040 // selected frame.
8041 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008042 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008043 save = save->prev();
8044 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008045 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008046
8047 // Get the frame id.
8048 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8049
8050 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008051 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008052
8053 // Check for constructor frame.
8054 bool constructor = it.frame()->IsConstructor();
8055
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008056 // Get scope info and read from it for local variable information.
8057 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008058 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008059 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008060
8061 // Get the context.
8062 Handle<Context> context(Context::cast(it.frame()->context()));
8063
8064 // Get the locals names and values into a temporary array.
8065 //
8066 // TODO(1240907): Hide compiler-introduced stack variables
8067 // (e.g. .result)? For users of the debugger, they will probably be
8068 // confusing.
8069 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
8070 for (int i = 0; i < info.NumberOfLocals(); i++) {
8071 // Name of the local.
8072 locals->set(i * 2, *info.LocalName(i));
8073
8074 // Fetch the value of the local - either from the stack or from a
8075 // heap-allocated context.
8076 if (i < info.number_of_stack_slots()) {
8077 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8078 } else {
8079 Handle<String> name = info.LocalName(i);
8080 // Traverse the context chain to the function context as all local
8081 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008082 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008083 context = Handle<Context>(context->previous());
8084 }
8085 ASSERT(context->is_function_context());
8086 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008087 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008088 }
8089 }
8090
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008091 // Check whether this frame is positioned at return.
8092 int at_return = (index == 0) ? Debug::IsBreakAtReturn(it.frame()) : false;
8093
8094 // If positioned just before return find the value to be returned and add it
8095 // to the frame information.
8096 Handle<Object> return_value = Factory::undefined_value();
8097 if (at_return) {
8098 StackFrameIterator it2;
8099 Address internal_frame_sp = NULL;
8100 while (!it2.done()) {
8101 if (it2.frame()->is_internal()) {
8102 internal_frame_sp = it2.frame()->sp();
8103 } else {
8104 if (it2.frame()->is_java_script()) {
8105 if (it2.frame()->id() == it.frame()->id()) {
8106 // The internal frame just before the JavaScript frame contains the
8107 // value to return on top. A debug break at return will create an
8108 // internal frame to store the return value (eax/rax/r0) before
8109 // entering the debug break exit frame.
8110 if (internal_frame_sp != NULL) {
8111 return_value =
8112 Handle<Object>(Memory::Object_at(internal_frame_sp));
8113 break;
8114 }
8115 }
8116 }
8117
8118 // Indicate that the previous frame was not an internal frame.
8119 internal_frame_sp = NULL;
8120 }
8121 it2.Advance();
8122 }
8123 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008124
8125 // Now advance to the arguments adapter frame (if any). It contains all
8126 // the provided parameters whereas the function frame always have the number
8127 // of arguments matching the functions parameters. The rest of the
8128 // information (except for what is collected above) is the same.
8129 it.AdvanceToArgumentsFrame();
8130
8131 // Find the number of arguments to fill. At least fill the number of
8132 // parameters for the function and fill more if more parameters are provided.
8133 int argument_count = info.number_of_parameters();
8134 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8135 argument_count = it.frame()->GetProvidedParametersCount();
8136 }
8137
8138 // Calculate the size of the result.
8139 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008140 2 * (argument_count + info.NumberOfLocals()) +
8141 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008142 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8143
8144 // Add the frame id.
8145 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8146
8147 // Add the function (same as in function frame).
8148 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8149
8150 // Add the arguments count.
8151 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8152
8153 // Add the locals count
8154 details->set(kFrameDetailsLocalCountIndex,
8155 Smi::FromInt(info.NumberOfLocals()));
8156
8157 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008158 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008159 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8160 } else {
8161 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8162 }
8163
8164 // Add the constructor information.
8165 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8166
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008167 // Add the at return information.
8168 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8169
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008170 // Add information on whether this frame is invoked in the debugger context.
8171 details->set(kFrameDetailsDebuggerFrameIndex,
8172 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8173
8174 // Fill the dynamic part.
8175 int details_index = kFrameDetailsFirstDynamicIndex;
8176
8177 // Add arguments name and value.
8178 for (int i = 0; i < argument_count; i++) {
8179 // Name of the argument.
8180 if (i < info.number_of_parameters()) {
8181 details->set(details_index++, *info.parameter_name(i));
8182 } else {
8183 details->set(details_index++, Heap::undefined_value());
8184 }
8185
8186 // Parameter value.
8187 if (i < it.frame()->GetProvidedParametersCount()) {
8188 details->set(details_index++, it.frame()->GetParameter(i));
8189 } else {
8190 details->set(details_index++, Heap::undefined_value());
8191 }
8192 }
8193
8194 // Add locals name and value from the temporary copy from the function frame.
8195 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8196 details->set(details_index++, locals->get(i));
8197 }
8198
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008199 // Add the value being returned.
8200 if (at_return) {
8201 details->set(details_index++, *return_value);
8202 }
8203
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008204 // Add the receiver (same as in function frame).
8205 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8206 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8207 Handle<Object> receiver(it.frame()->receiver());
8208 if (!receiver->IsJSObject()) {
8209 // If the receiver is NOT a JSObject we have hit an optimization
8210 // where a value object is not converted into a wrapped JS objects.
8211 // To hide this optimization from the debugger, we wrap the receiver
8212 // by creating correct wrapper object based on the calling frame's
8213 // global context.
8214 it.Advance();
8215 Handle<Context> calling_frames_global_context(
8216 Context::cast(Context::cast(it.frame()->context())->global_context()));
8217 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8218 }
8219 details->set(kFrameDetailsReceiverIndex, *receiver);
8220
8221 ASSERT_EQ(details_size, details_index);
8222 return *Factory::NewJSArrayWithElements(details);
8223}
8224
8225
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008226// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008227static void CopyContextLocalsToScopeObject(
8228 Handle<SerializedScopeInfo> serialized_scope_info,
8229 ScopeInfo<>& scope_info,
8230 Handle<Context> context,
8231 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008232 // Fill all context locals to the context extension.
8233 for (int i = Context::MIN_CONTEXT_SLOTS;
8234 i < scope_info.number_of_context_slots();
8235 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008236 int context_index = serialized_scope_info->ContextSlotIndex(
8237 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008238
8239 // Don't include the arguments shadow (.arguments) context variable.
8240 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8241 SetProperty(scope_object,
8242 scope_info.context_slot_name(i),
8243 Handle<Object>(context->get(context_index)), NONE);
8244 }
8245 }
8246}
8247
8248
8249// Create a plain JSObject which materializes the local scope for the specified
8250// frame.
8251static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8252 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008253 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008254 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8255 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008256
8257 // Allocate and initialize a JSObject with all the arguments, stack locals
8258 // heap locals and extension properties of the debugged function.
8259 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8260
8261 // First fill all parameters.
8262 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8263 SetProperty(local_scope,
8264 scope_info.parameter_name(i),
8265 Handle<Object>(frame->GetParameter(i)), NONE);
8266 }
8267
8268 // Second fill all stack locals.
8269 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8270 SetProperty(local_scope,
8271 scope_info.stack_slot_name(i),
8272 Handle<Object>(frame->GetExpression(i)), NONE);
8273 }
8274
8275 // Third fill all context locals.
8276 Handle<Context> frame_context(Context::cast(frame->context()));
8277 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008278 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008279 function_context, local_scope);
8280
8281 // Finally copy any properties from the function context extension. This will
8282 // be variables introduced by eval.
8283 if (function_context->closure() == *function) {
8284 if (function_context->has_extension() &&
8285 !function_context->IsGlobalContext()) {
8286 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008287 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008288 for (int i = 0; i < keys->length(); i++) {
8289 // Names of variables introduced by eval are strings.
8290 ASSERT(keys->get(i)->IsString());
8291 Handle<String> key(String::cast(keys->get(i)));
8292 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8293 }
8294 }
8295 }
8296 return local_scope;
8297}
8298
8299
8300// Create a plain JSObject which materializes the closure content for the
8301// context.
8302static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8303 ASSERT(context->is_function_context());
8304
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008305 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008306 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8307 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008308
8309 // Allocate and initialize a JSObject with all the content of theis function
8310 // closure.
8311 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8312
8313 // Check whether the arguments shadow object exists.
8314 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008315 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8316 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008317 if (arguments_shadow_index >= 0) {
8318 // In this case all the arguments are available in the arguments shadow
8319 // object.
8320 Handle<JSObject> arguments_shadow(
8321 JSObject::cast(context->get(arguments_shadow_index)));
8322 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8323 SetProperty(closure_scope,
8324 scope_info.parameter_name(i),
8325 Handle<Object>(arguments_shadow->GetElement(i)), NONE);
8326 }
8327 }
8328
8329 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008330 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8331 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008332
8333 // Finally copy any properties from the function context extension. This will
8334 // be variables introduced by eval.
8335 if (context->has_extension()) {
8336 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008337 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008338 for (int i = 0; i < keys->length(); i++) {
8339 // Names of variables introduced by eval are strings.
8340 ASSERT(keys->get(i)->IsString());
8341 Handle<String> key(String::cast(keys->get(i)));
8342 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
8343 }
8344 }
8345
8346 return closure_scope;
8347}
8348
8349
8350// Iterate over the actual scopes visible from a stack frame. All scopes are
8351// backed by an actual context except the local scope, which is inserted
8352// "artifically" in the context chain.
8353class ScopeIterator {
8354 public:
8355 enum ScopeType {
8356 ScopeTypeGlobal = 0,
8357 ScopeTypeLocal,
8358 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00008359 ScopeTypeClosure,
8360 // Every catch block contains an implicit with block (its parameter is
8361 // a JSContextExtensionObject) that extends current scope with a variable
8362 // holding exception object. Such with blocks are treated as scopes of their
8363 // own type.
8364 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008365 };
8366
8367 explicit ScopeIterator(JavaScriptFrame* frame)
8368 : frame_(frame),
8369 function_(JSFunction::cast(frame->function())),
8370 context_(Context::cast(frame->context())),
8371 local_done_(false),
8372 at_local_(false) {
8373
8374 // Check whether the first scope is actually a local scope.
8375 if (context_->IsGlobalContext()) {
8376 // If there is a stack slot for .result then this local scope has been
8377 // created for evaluating top level code and it is not a real local scope.
8378 // Checking for the existence of .result seems fragile, but the scope info
8379 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008380 int index = function_->shared()->scope_info()->
8381 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008382 at_local_ = index < 0;
8383 } else if (context_->is_function_context()) {
8384 at_local_ = true;
8385 }
8386 }
8387
8388 // More scopes?
8389 bool Done() { return context_.is_null(); }
8390
8391 // Move to the next scope.
8392 void Next() {
8393 // If at a local scope mark the local scope as passed.
8394 if (at_local_) {
8395 at_local_ = false;
8396 local_done_ = true;
8397
8398 // If the current context is not associated with the local scope the
8399 // current context is the next real scope, so don't move to the next
8400 // context in this case.
8401 if (context_->closure() != *function_) {
8402 return;
8403 }
8404 }
8405
8406 // The global scope is always the last in the chain.
8407 if (context_->IsGlobalContext()) {
8408 context_ = Handle<Context>();
8409 return;
8410 }
8411
8412 // Move to the next context.
8413 if (context_->is_function_context()) {
8414 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
8415 } else {
8416 context_ = Handle<Context>(context_->previous());
8417 }
8418
8419 // If passing the local scope indicate that the current scope is now the
8420 // local scope.
8421 if (!local_done_ &&
8422 (context_->IsGlobalContext() || (context_->is_function_context()))) {
8423 at_local_ = true;
8424 }
8425 }
8426
8427 // Return the type of the current scope.
8428 int Type() {
8429 if (at_local_) {
8430 return ScopeTypeLocal;
8431 }
8432 if (context_->IsGlobalContext()) {
8433 ASSERT(context_->global()->IsGlobalObject());
8434 return ScopeTypeGlobal;
8435 }
8436 if (context_->is_function_context()) {
8437 return ScopeTypeClosure;
8438 }
8439 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00008440 // Current scope is either an explicit with statement or a with statement
8441 // implicitely generated for a catch block.
8442 // If the extension object here is a JSContextExtensionObject then
8443 // current with statement is one frome a catch block otherwise it's a
8444 // regular with statement.
8445 if (context_->extension()->IsJSContextExtensionObject()) {
8446 return ScopeTypeCatch;
8447 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008448 return ScopeTypeWith;
8449 }
8450
8451 // Return the JavaScript object with the content of the current scope.
8452 Handle<JSObject> ScopeObject() {
8453 switch (Type()) {
8454 case ScopeIterator::ScopeTypeGlobal:
8455 return Handle<JSObject>(CurrentContext()->global());
8456 break;
8457 case ScopeIterator::ScopeTypeLocal:
8458 // Materialize the content of the local scope into a JSObject.
8459 return MaterializeLocalScope(frame_);
8460 break;
8461 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00008462 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008463 // Return the with object.
8464 return Handle<JSObject>(CurrentContext()->extension());
8465 break;
8466 case ScopeIterator::ScopeTypeClosure:
8467 // Materialize the content of the closure scope into a JSObject.
8468 return MaterializeClosure(CurrentContext());
8469 break;
8470 }
8471 UNREACHABLE();
8472 return Handle<JSObject>();
8473 }
8474
8475 // Return the context for this scope. For the local context there might not
8476 // be an actual context.
8477 Handle<Context> CurrentContext() {
8478 if (at_local_ && context_->closure() != *function_) {
8479 return Handle<Context>();
8480 }
8481 return context_;
8482 }
8483
8484#ifdef DEBUG
8485 // Debug print of the content of the current scope.
8486 void DebugPrint() {
8487 switch (Type()) {
8488 case ScopeIterator::ScopeTypeGlobal:
8489 PrintF("Global:\n");
8490 CurrentContext()->Print();
8491 break;
8492
8493 case ScopeIterator::ScopeTypeLocal: {
8494 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008495 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008496 scope_info.Print();
8497 if (!CurrentContext().is_null()) {
8498 CurrentContext()->Print();
8499 if (CurrentContext()->has_extension()) {
8500 Handle<JSObject> extension =
8501 Handle<JSObject>(CurrentContext()->extension());
8502 if (extension->IsJSContextExtensionObject()) {
8503 extension->Print();
8504 }
8505 }
8506 }
8507 break;
8508 }
8509
8510 case ScopeIterator::ScopeTypeWith: {
8511 PrintF("With:\n");
8512 Handle<JSObject> extension =
8513 Handle<JSObject>(CurrentContext()->extension());
8514 extension->Print();
8515 break;
8516 }
8517
ager@chromium.orga1645e22009-09-09 19:27:10 +00008518 case ScopeIterator::ScopeTypeCatch: {
8519 PrintF("Catch:\n");
8520 Handle<JSObject> extension =
8521 Handle<JSObject>(CurrentContext()->extension());
8522 extension->Print();
8523 break;
8524 }
8525
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008526 case ScopeIterator::ScopeTypeClosure: {
8527 PrintF("Closure:\n");
8528 CurrentContext()->Print();
8529 if (CurrentContext()->has_extension()) {
8530 Handle<JSObject> extension =
8531 Handle<JSObject>(CurrentContext()->extension());
8532 if (extension->IsJSContextExtensionObject()) {
8533 extension->Print();
8534 }
8535 }
8536 break;
8537 }
8538
8539 default:
8540 UNREACHABLE();
8541 }
8542 PrintF("\n");
8543 }
8544#endif
8545
8546 private:
8547 JavaScriptFrame* frame_;
8548 Handle<JSFunction> function_;
8549 Handle<Context> context_;
8550 bool local_done_;
8551 bool at_local_;
8552
8553 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
8554};
8555
8556
8557static Object* Runtime_GetScopeCount(Arguments args) {
8558 HandleScope scope;
8559 ASSERT(args.length() == 2);
8560
8561 // Check arguments.
8562 Object* check = Runtime_CheckExecutionState(args);
8563 if (check->IsFailure()) return check;
8564 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8565
8566 // Get the frame where the debugging is performed.
8567 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8568 JavaScriptFrameIterator it(id);
8569 JavaScriptFrame* frame = it.frame();
8570
8571 // Count the visible scopes.
8572 int n = 0;
8573 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8574 n++;
8575 }
8576
8577 return Smi::FromInt(n);
8578}
8579
8580
8581static const int kScopeDetailsTypeIndex = 0;
8582static const int kScopeDetailsObjectIndex = 1;
8583static const int kScopeDetailsSize = 2;
8584
8585// Return an array with scope details
8586// args[0]: number: break id
8587// args[1]: number: frame index
8588// args[2]: number: scope index
8589//
8590// The array returned contains the following information:
8591// 0: Scope type
8592// 1: Scope object
8593static Object* Runtime_GetScopeDetails(Arguments args) {
8594 HandleScope scope;
8595 ASSERT(args.length() == 3);
8596
8597 // Check arguments.
8598 Object* check = Runtime_CheckExecutionState(args);
8599 if (check->IsFailure()) return check;
8600 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8601 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
8602
8603 // Get the frame where the debugging is performed.
8604 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8605 JavaScriptFrameIterator frame_it(id);
8606 JavaScriptFrame* frame = frame_it.frame();
8607
8608 // Find the requested scope.
8609 int n = 0;
8610 ScopeIterator it(frame);
8611 for (; !it.Done() && n < index; it.Next()) {
8612 n++;
8613 }
8614 if (it.Done()) {
8615 return Heap::undefined_value();
8616 }
8617
8618 // Calculate the size of the result.
8619 int details_size = kScopeDetailsSize;
8620 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8621
8622 // Fill in scope details.
8623 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008624 Handle<JSObject> scope_object = it.ScopeObject();
8625 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008626
8627 return *Factory::NewJSArrayWithElements(details);
8628}
8629
8630
8631static Object* Runtime_DebugPrintScopes(Arguments args) {
8632 HandleScope scope;
8633 ASSERT(args.length() == 0);
8634
8635#ifdef DEBUG
8636 // Print the scopes for the top frame.
8637 StackFrameLocator locator;
8638 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
8639 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8640 it.DebugPrint();
8641 }
8642#endif
8643 return Heap::undefined_value();
8644}
8645
8646
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008647static Object* Runtime_GetCFrames(Arguments args) {
8648 HandleScope scope;
8649 ASSERT(args.length() == 1);
8650 Object* result = Runtime_CheckExecutionState(args);
8651 if (result->IsFailure()) return result;
8652
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00008653#if V8_HOST_ARCH_64_BIT
8654 UNIMPLEMENTED();
8655 return Heap::undefined_value();
8656#else
8657
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008658 static const int kMaxCFramesSize = 200;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008659 ScopedVector<OS::StackFrame> frames(kMaxCFramesSize);
8660 int frames_count = OS::StackWalk(frames);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008661 if (frames_count == OS::kStackWalkError) {
8662 return Heap::undefined_value();
8663 }
8664
8665 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
8666 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
8667 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
8668 for (int i = 0; i < frames_count; i++) {
8669 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008670 Handle<Object> frame_address =
8671 Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address));
8672
8673 frame_value->SetProperty(*address_str, *frame_address, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008674
8675 // Get the stack walk text for this frame.
8676 Handle<String> frame_text;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008677 int frame_text_length = StrLength(frames[i].text);
8678 if (frame_text_length > 0) {
8679 Vector<const char> str(frames[i].text, frame_text_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008680 frame_text = Factory::NewStringFromAscii(str);
8681 }
8682
8683 if (!frame_text.is_null()) {
8684 frame_value->SetProperty(*text_str, *frame_text, NONE);
8685 }
8686
8687 frames_array->set(i, *frame_value);
8688 }
8689 return *Factory::NewJSArrayWithElements(frames_array);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00008690#endif // V8_HOST_ARCH_64_BIT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008691}
8692
8693
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008694static Object* Runtime_GetThreadCount(Arguments args) {
8695 HandleScope scope;
8696 ASSERT(args.length() == 1);
8697
8698 // Check arguments.
8699 Object* result = Runtime_CheckExecutionState(args);
8700 if (result->IsFailure()) return result;
8701
8702 // Count all archived V8 threads.
8703 int n = 0;
8704 for (ThreadState* thread = ThreadState::FirstInUse();
8705 thread != NULL;
8706 thread = thread->Next()) {
8707 n++;
8708 }
8709
8710 // Total number of threads is current thread and archived threads.
8711 return Smi::FromInt(n + 1);
8712}
8713
8714
8715static const int kThreadDetailsCurrentThreadIndex = 0;
8716static const int kThreadDetailsThreadIdIndex = 1;
8717static const int kThreadDetailsSize = 2;
8718
8719// Return an array with thread details
8720// args[0]: number: break id
8721// args[1]: number: thread index
8722//
8723// The array returned contains the following information:
8724// 0: Is current thread?
8725// 1: Thread id
8726static Object* Runtime_GetThreadDetails(Arguments args) {
8727 HandleScope scope;
8728 ASSERT(args.length() == 2);
8729
8730 // Check arguments.
8731 Object* check = Runtime_CheckExecutionState(args);
8732 if (check->IsFailure()) return check;
8733 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8734
8735 // Allocate array for result.
8736 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
8737
8738 // Thread index 0 is current thread.
8739 if (index == 0) {
8740 // Fill the details.
8741 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
8742 details->set(kThreadDetailsThreadIdIndex,
8743 Smi::FromInt(ThreadManager::CurrentId()));
8744 } else {
8745 // Find the thread with the requested index.
8746 int n = 1;
8747 ThreadState* thread = ThreadState::FirstInUse();
8748 while (index != n && thread != NULL) {
8749 thread = thread->Next();
8750 n++;
8751 }
8752 if (thread == NULL) {
8753 return Heap::undefined_value();
8754 }
8755
8756 // Fill the details.
8757 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
8758 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
8759 }
8760
8761 // Convert to JS array and return.
8762 return *Factory::NewJSArrayWithElements(details);
8763}
8764
8765
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008766// Sets the disable break state
8767// args[0]: disable break state
8768static Object* Runtime_SetDisableBreak(Arguments args) {
8769 HandleScope scope;
8770 ASSERT(args.length() == 1);
8771 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
8772 Debug::set_disable_break(disable_break);
8773 return Heap::undefined_value();
8774}
8775
8776
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008777static Object* Runtime_GetBreakLocations(Arguments args) {
8778 HandleScope scope;
8779 ASSERT(args.length() == 1);
8780
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008781 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8782 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008783 // Find the number of break points
8784 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
8785 if (break_locations->IsUndefined()) return Heap::undefined_value();
8786 // Return array as JS array
8787 return *Factory::NewJSArrayWithElements(
8788 Handle<FixedArray>::cast(break_locations));
8789}
8790
8791
8792// Set a break point in a function
8793// args[0]: function
8794// args[1]: number: break source position (within the function source)
8795// args[2]: number: break point object
8796static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
8797 HandleScope scope;
8798 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008799 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8800 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008801 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
8802 RUNTIME_ASSERT(source_position >= 0);
8803 Handle<Object> break_point_object_arg = args.at<Object>(2);
8804
8805 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008806 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008807
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008808 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008809}
8810
8811
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00008812Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
8813 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008814 // Iterate the heap looking for SharedFunctionInfo generated from the
8815 // script. The inner most SharedFunctionInfo containing the source position
8816 // for the requested break point is found.
8817 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
8818 // which is found is not compiled it is compiled and the heap is iterated
8819 // again as the compilation might create inner functions from the newly
8820 // compiled function and the actual requested break point might be in one of
8821 // these functions.
8822 bool done = false;
8823 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00008824 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008826 while (!done) {
8827 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008828 for (HeapObject* obj = iterator.next();
8829 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008830 if (obj->IsSharedFunctionInfo()) {
8831 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
8832 if (shared->script() == *script) {
8833 // If the SharedFunctionInfo found has the requested script data and
8834 // contains the source position it is a candidate.
8835 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00008836 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008837 start_position = shared->start_position();
8838 }
8839 if (start_position <= position &&
8840 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00008841 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008842 // candidate this is the new candidate.
8843 if (target.is_null()) {
8844 target_start_position = start_position;
8845 target = shared;
8846 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00008847 if (target_start_position == start_position &&
8848 shared->end_position() == target->end_position()) {
8849 // If a top-level function contain only one function
8850 // declartion the source for the top-level and the function is
8851 // the same. In that case prefer the non top-level function.
8852 if (!shared->is_toplevel()) {
8853 target_start_position = start_position;
8854 target = shared;
8855 }
8856 } else if (target_start_position <= start_position &&
8857 shared->end_position() <= target->end_position()) {
8858 // This containment check includes equality as a function inside
8859 // a top-level function can share either start or end position
8860 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008861 target_start_position = start_position;
8862 target = shared;
8863 }
8864 }
8865 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008866 }
8867 }
8868 }
8869
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008870 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008871 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008872 }
8873
8874 // If the candidate found is compiled we are done. NOTE: when lazy
8875 // compilation of inner functions is introduced some additional checking
8876 // needs to be done here to compile inner functions.
8877 done = target->is_compiled();
8878 if (!done) {
8879 // If the candidate is not compiled compile it to reveal any inner
8880 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008881 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008882 }
8883 }
8884
8885 return *target;
8886}
8887
8888
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008889// Changes the state of a break point in a script and returns source position
8890// where break point was set. NOTE: Regarding performance see the NOTE for
8891// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008892// args[0]: script to set break point in
8893// args[1]: number: break source position (within the script source)
8894// args[2]: number: break point object
8895static Object* Runtime_SetScriptBreakPoint(Arguments args) {
8896 HandleScope scope;
8897 ASSERT(args.length() == 3);
8898 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
8899 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
8900 RUNTIME_ASSERT(source_position >= 0);
8901 Handle<Object> break_point_object_arg = args.at<Object>(2);
8902
8903 // Get the script from the script wrapper.
8904 RUNTIME_ASSERT(wrapper->value()->IsScript());
8905 Handle<Script> script(Script::cast(wrapper->value()));
8906
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00008907 Object* result = Runtime::FindSharedFunctionInfoInScript(
8908 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008909 if (!result->IsUndefined()) {
8910 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
8911 // Find position within function. The script position might be before the
8912 // source position of the first function.
8913 int position;
8914 if (shared->start_position() > source_position) {
8915 position = 0;
8916 } else {
8917 position = source_position - shared->start_position();
8918 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008919 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
8920 position += shared->start_position();
8921 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008922 }
8923 return Heap::undefined_value();
8924}
8925
8926
8927// Clear a break point
8928// args[0]: number: break point object
8929static Object* Runtime_ClearBreakPoint(Arguments args) {
8930 HandleScope scope;
8931 ASSERT(args.length() == 1);
8932 Handle<Object> break_point_object_arg = args.at<Object>(0);
8933
8934 // Clear break point.
8935 Debug::ClearBreakPoint(break_point_object_arg);
8936
8937 return Heap::undefined_value();
8938}
8939
8940
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00008941// Change the state of break on exceptions.
8942// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
8943// args[1]: Boolean indicating on/off.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008944static Object* Runtime_ChangeBreakOnException(Arguments args) {
8945 HandleScope scope;
8946 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00008947 RUNTIME_ASSERT(args[0]->IsNumber());
8948 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008949
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00008950 // If the number doesn't match an enum value, the ChangeBreakOnException
8951 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008952 ExceptionBreakType type =
8953 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00008954 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008955 Debug::ChangeBreakOnException(type, enable);
8956 return Heap::undefined_value();
8957}
8958
8959
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00008960// Returns the state of break on exceptions
8961// args[0]: boolean indicating uncaught exceptions
8962static Object* Runtime_IsBreakOnException(Arguments args) {
8963 HandleScope scope;
8964 ASSERT(args.length() == 1);
8965 RUNTIME_ASSERT(args[0]->IsNumber());
8966
8967 ExceptionBreakType type =
8968 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
8969 bool result = Debug::IsBreakOnException(type);
8970 return Smi::FromInt(result);
8971}
8972
8973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008974// Prepare for stepping
8975// args[0]: break id for checking execution state
8976// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00008977// args[2]: number of times to perform the step, for step out it is the number
8978// of frames to step down.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008979static Object* Runtime_PrepareStep(Arguments args) {
8980 HandleScope scope;
8981 ASSERT(args.length() == 3);
8982 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008983 Object* check = Runtime_CheckExecutionState(args);
8984 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008985 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
8986 return Top::Throw(Heap::illegal_argument_symbol());
8987 }
8988
8989 // Get the step action and check validity.
8990 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
8991 if (step_action != StepIn &&
8992 step_action != StepNext &&
8993 step_action != StepOut &&
8994 step_action != StepInMin &&
8995 step_action != StepMin) {
8996 return Top::Throw(Heap::illegal_argument_symbol());
8997 }
8998
8999 // Get the number of steps.
9000 int step_count = NumberToInt32(args[2]);
9001 if (step_count < 1) {
9002 return Top::Throw(Heap::illegal_argument_symbol());
9003 }
9004
ager@chromium.orga1645e22009-09-09 19:27:10 +00009005 // Clear all current stepping setup.
9006 Debug::ClearStepping();
9007
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009008 // Prepare step.
9009 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9010 return Heap::undefined_value();
9011}
9012
9013
9014// Clear all stepping set by PrepareStep.
9015static Object* Runtime_ClearStepping(Arguments args) {
9016 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009017 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009018 Debug::ClearStepping();
9019 return Heap::undefined_value();
9020}
9021
9022
9023// Creates a copy of the with context chain. The copy of the context chain is
9024// is linked to the function context supplied.
9025static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9026 Handle<Context> function_context) {
9027 // At the bottom of the chain. Return the function context to link to.
9028 if (context_chain->is_function_context()) {
9029 return function_context;
9030 }
9031
9032 // Recursively copy the with contexts.
9033 Handle<Context> previous(context_chain->previous());
9034 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009035 Handle<Context> context = CopyWithContextChain(function_context, previous);
9036 return Factory::NewWithContext(context,
9037 extension,
9038 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009039}
9040
9041
9042// Helper function to find or create the arguments object for
9043// Runtime_DebugEvaluate.
9044static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9045 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009046 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009047 const ScopeInfo<>* sinfo,
9048 Handle<Context> function_context) {
9049 // Try to find the value of 'arguments' to pass as parameter. If it is not
9050 // found (that is the debugged function does not reference 'arguments' and
9051 // does not support eval) then create an 'arguments' object.
9052 int index;
9053 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009054 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009055 if (index != -1) {
9056 return Handle<Object>(frame->GetExpression(index));
9057 }
9058 }
9059
9060 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009061 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009062 if (index != -1) {
9063 return Handle<Object>(function_context->get(index));
9064 }
9065 }
9066
9067 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009068 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9069 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009070
9071 AssertNoAllocation no_gc;
9072 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009073 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009074 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009075 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009076 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009077 return arguments;
9078}
9079
9080
9081// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009082// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009083// extension part has all the parameters and locals of the function on the
9084// stack frame. A function which calls eval with the code to evaluate is then
9085// compiled in this context and called in this context. As this context
9086// replaces the context of the function on the stack frame a new (empty)
9087// function is created as well to be used as the closure for the context.
9088// This function and the context acts as replacements for the function on the
9089// stack frame presenting the same view of the values of parameters and
9090// local variables as if the piece of JavaScript was evaluated at the point
9091// where the function on the stack frame is currently stopped.
9092static Object* Runtime_DebugEvaluate(Arguments args) {
9093 HandleScope scope;
9094
9095 // Check the execution state and decode arguments frame and source to be
9096 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009097 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098 Object* check_result = Runtime_CheckExecutionState(args);
9099 if (check_result->IsFailure()) return check_result;
9100 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9101 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009102 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
9103
9104 // Handle the processing of break.
9105 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009106
9107 // Get the frame where the debugging is performed.
9108 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9109 JavaScriptFrameIterator it(id);
9110 JavaScriptFrame* frame = it.frame();
9111 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009112 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009113 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009114
9115 // Traverse the saved contexts chain to find the active context for the
9116 // selected frame.
9117 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009118 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119 save = save->prev();
9120 }
9121 ASSERT(save != NULL);
9122 SaveContext savex;
9123 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009124
9125 // Create the (empty) function replacing the function on the stack frame for
9126 // the purpose of evaluating in the context created below. It is important
9127 // that this function does not describe any parameters and local variables
9128 // in the context. If it does then this will cause problems with the lookup
9129 // in Context::Lookup, where context slots for parameters and local variables
9130 // are looked at before the extension object.
9131 Handle<JSFunction> go_between =
9132 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9133 go_between->set_context(function->context());
9134#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009135 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009136 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9137 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9138#endif
9139
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009140 // Materialize the content of the local scope into a JSObject.
9141 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142
9143 // Allocate a new context for the debug evaluation and set the extension
9144 // object build.
9145 Handle<Context> context =
9146 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009147 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009148 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009149 Handle<Context> frame_context(Context::cast(frame->context()));
9150 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009151 context = CopyWithContextChain(frame_context, context);
9152
9153 // Wrap the evaluation statement in a new function compiled in the newly
9154 // created context. The function has one parameter which has to be called
9155 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009156 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009157 // function(arguments,__source__) {return eval(__source__);}
9158 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009159 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009160 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009161 Handle<String> function_source =
9162 Factory::NewStringFromAscii(Vector<const char>(source_str,
9163 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009164 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009165 Compiler::CompileEval(function_source,
9166 context,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00009167 context->IsGlobalContext(),
ager@chromium.orgadd848f2009-08-13 12:44:13 +00009168 Compiler::DONT_VALIDATE_JSON);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009169 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009170 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009171 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009172
9173 // Invoke the result of the compilation to get the evaluation function.
9174 bool has_pending_exception;
9175 Handle<Object> receiver(frame->receiver());
9176 Handle<Object> evaluation_function =
9177 Execution::Call(compiled_function, receiver, 0, NULL,
9178 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009179 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009181 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9182 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009183
9184 // Invoke the evaluation function and return the result.
9185 const int argc = 2;
9186 Object** argv[argc] = { arguments.location(),
9187 Handle<Object>::cast(source).location() };
9188 Handle<Object> result =
9189 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9190 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009191 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009192
9193 // Skip the global proxy as it has no properties and always delegates to the
9194 // real global object.
9195 if (result->IsJSGlobalProxy()) {
9196 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9197 }
9198
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009199 return *result;
9200}
9201
9202
9203static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
9204 HandleScope scope;
9205
9206 // Check the execution state and decode arguments frame and source to be
9207 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009208 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009209 Object* check_result = Runtime_CheckExecutionState(args);
9210 if (check_result->IsFailure()) return check_result;
9211 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009212 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
9213
9214 // Handle the processing of break.
9215 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009216
9217 // Enter the top context from before the debugger was invoked.
9218 SaveContext save;
9219 SaveContext* top = &save;
9220 while (top != NULL && *top->context() == *Debug::debug_context()) {
9221 top = top->prev();
9222 }
9223 if (top != NULL) {
9224 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009225 }
9226
9227 // Get the global context now set to the top context from before the
9228 // debugger was invoked.
9229 Handle<Context> context = Top::global_context();
9230
9231 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009232 Handle<SharedFunctionInfo> shared =
9233 Compiler::CompileEval(source,
9234 context,
9235 true,
9236 Compiler::DONT_VALIDATE_JSON);
9237 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009238 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009239 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9240 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009241
9242 // Invoke the result of the compilation to get the evaluation function.
9243 bool has_pending_exception;
9244 Handle<Object> receiver = Top::global();
9245 Handle<Object> result =
9246 Execution::Call(compiled_function, receiver, 0, NULL,
9247 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009248 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009249 return *result;
9250}
9251
9252
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009253static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
9254 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009255 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009256
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009257 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009258 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009259
9260 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009261 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009262 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9263 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9264 // because using
9265 // instances->set(i, *GetScriptWrapper(script))
9266 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9267 // already have deferenced the instances handle.
9268 Handle<JSValue> wrapper = GetScriptWrapper(script);
9269 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009270 }
9271
9272 // Return result as a JS array.
9273 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9274 Handle<JSArray>::cast(result)->SetContent(*instances);
9275 return *result;
9276}
9277
9278
9279// Helper function used by Runtime_DebugReferencedBy below.
9280static int DebugReferencedBy(JSObject* target,
9281 Object* instance_filter, int max_references,
9282 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009283 JSFunction* arguments_function) {
9284 NoHandleAllocation ha;
9285 AssertNoAllocation no_alloc;
9286
9287 // Iterate the heap.
9288 int count = 0;
9289 JSObject* last = NULL;
9290 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009291 HeapObject* heap_obj = NULL;
9292 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009293 (max_references == 0 || count < max_references)) {
9294 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009295 if (heap_obj->IsJSObject()) {
9296 // Skip context extension objects and argument arrays as these are
9297 // checked in the context of functions using them.
9298 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009299 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009300 obj->map()->constructor() == arguments_function) {
9301 continue;
9302 }
9303
9304 // Check if the JS object has a reference to the object looked for.
9305 if (obj->ReferencesObject(target)) {
9306 // Check instance filter if supplied. This is normally used to avoid
9307 // references from mirror objects (see Runtime_IsInPrototypeChain).
9308 if (!instance_filter->IsUndefined()) {
9309 Object* V = obj;
9310 while (true) {
9311 Object* prototype = V->GetPrototype();
9312 if (prototype->IsNull()) {
9313 break;
9314 }
9315 if (instance_filter == prototype) {
9316 obj = NULL; // Don't add this object.
9317 break;
9318 }
9319 V = prototype;
9320 }
9321 }
9322
9323 if (obj != NULL) {
9324 // Valid reference found add to instance array if supplied an update
9325 // count.
9326 if (instances != NULL && count < instances_size) {
9327 instances->set(count, obj);
9328 }
9329 last = obj;
9330 count++;
9331 }
9332 }
9333 }
9334 }
9335
9336 // Check for circular reference only. This can happen when the object is only
9337 // referenced from mirrors and has a circular reference in which case the
9338 // object is not really alive and would have been garbage collected if not
9339 // referenced from the mirror.
9340 if (count == 1 && last == target) {
9341 count = 0;
9342 }
9343
9344 // Return the number of referencing objects found.
9345 return count;
9346}
9347
9348
9349// Scan the heap for objects with direct references to an object
9350// args[0]: the object to find references to
9351// args[1]: constructor function for instances to exclude (Mirror)
9352// args[2]: the the maximum number of objects to return
9353static Object* Runtime_DebugReferencedBy(Arguments args) {
9354 ASSERT(args.length() == 3);
9355
9356 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009357 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009358
9359 // Check parameters.
9360 CONVERT_CHECKED(JSObject, target, args[0]);
9361 Object* instance_filter = args[1];
9362 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
9363 instance_filter->IsJSObject());
9364 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
9365 RUNTIME_ASSERT(max_references >= 0);
9366
9367 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009368 JSObject* arguments_boilerplate =
9369 Top::context()->global_context()->arguments_boilerplate();
9370 JSFunction* arguments_function =
9371 JSFunction::cast(arguments_boilerplate->map()->constructor());
9372
9373 // Get the number of referencing objects.
9374 int count;
9375 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009376 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009377
9378 // Allocate an array to hold the result.
9379 Object* object = Heap::AllocateFixedArray(count);
9380 if (object->IsFailure()) return object;
9381 FixedArray* instances = FixedArray::cast(object);
9382
9383 // Fill the referencing objects.
9384 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009385 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009386
9387 // Return result as JS array.
9388 Object* result =
9389 Heap::AllocateJSObject(
9390 Top::context()->global_context()->array_function());
9391 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
9392 return result;
9393}
9394
9395
9396// Helper function used by Runtime_DebugConstructedBy below.
9397static int DebugConstructedBy(JSFunction* constructor, int max_references,
9398 FixedArray* instances, int instances_size) {
9399 AssertNoAllocation no_alloc;
9400
9401 // Iterate the heap.
9402 int count = 0;
9403 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009404 HeapObject* heap_obj = NULL;
9405 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009406 (max_references == 0 || count < max_references)) {
9407 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009408 if (heap_obj->IsJSObject()) {
9409 JSObject* obj = JSObject::cast(heap_obj);
9410 if (obj->map()->constructor() == constructor) {
9411 // Valid reference found add to instance array if supplied an update
9412 // count.
9413 if (instances != NULL && count < instances_size) {
9414 instances->set(count, obj);
9415 }
9416 count++;
9417 }
9418 }
9419 }
9420
9421 // Return the number of referencing objects found.
9422 return count;
9423}
9424
9425
9426// Scan the heap for objects constructed by a specific function.
9427// args[0]: the constructor to find instances of
9428// args[1]: the the maximum number of objects to return
9429static Object* Runtime_DebugConstructedBy(Arguments args) {
9430 ASSERT(args.length() == 2);
9431
9432 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009433 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009434
9435 // Check parameters.
9436 CONVERT_CHECKED(JSFunction, constructor, args[0]);
9437 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
9438 RUNTIME_ASSERT(max_references >= 0);
9439
9440 // Get the number of referencing objects.
9441 int count;
9442 count = DebugConstructedBy(constructor, max_references, NULL, 0);
9443
9444 // Allocate an array to hold the result.
9445 Object* object = Heap::AllocateFixedArray(count);
9446 if (object->IsFailure()) return object;
9447 FixedArray* instances = FixedArray::cast(object);
9448
9449 // Fill the referencing objects.
9450 count = DebugConstructedBy(constructor, max_references, instances, count);
9451
9452 // Return result as JS array.
9453 Object* result =
9454 Heap::AllocateJSObject(
9455 Top::context()->global_context()->array_function());
9456 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
9457 return result;
9458}
9459
9460
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009461// Find the effective prototype object as returned by __proto__.
9462// args[0]: the object to find the prototype for.
9463static Object* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009464 ASSERT(args.length() == 1);
9465
9466 CONVERT_CHECKED(JSObject, obj, args[0]);
9467
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009468 // Use the __proto__ accessor.
9469 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009470}
9471
9472
9473static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00009474 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009475 CPU::DebugBreak();
9476 return Heap::undefined_value();
9477}
9478
9479
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009480static Object* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009481#ifdef DEBUG
9482 HandleScope scope;
9483 ASSERT(args.length() == 1);
9484 // Get the function and make sure it is compiled.
9485 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009486 Handle<SharedFunctionInfo> shared(func->shared());
9487 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009488 return Failure::Exception();
9489 }
9490 func->code()->PrintLn();
9491#endif // DEBUG
9492 return Heap::undefined_value();
9493}
ager@chromium.org9085a012009-05-11 19:22:57 +00009494
9495
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009496static Object* Runtime_DebugDisassembleConstructor(Arguments args) {
9497#ifdef DEBUG
9498 HandleScope scope;
9499 ASSERT(args.length() == 1);
9500 // Get the function and make sure it is compiled.
9501 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009502 Handle<SharedFunctionInfo> shared(func->shared());
9503 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009504 return Failure::Exception();
9505 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009506 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009507#endif // DEBUG
9508 return Heap::undefined_value();
9509}
9510
9511
ager@chromium.org9085a012009-05-11 19:22:57 +00009512static Object* Runtime_FunctionGetInferredName(Arguments args) {
9513 NoHandleAllocation ha;
9514 ASSERT(args.length() == 1);
9515
9516 CONVERT_CHECKED(JSFunction, f, args[0]);
9517 return f->shared()->inferred_name();
9518}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009519
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009520
9521static int FindSharedFunctionInfosForScript(Script* script,
9522 FixedArray* buffer) {
9523 AssertNoAllocation no_allocations;
9524
9525 int counter = 0;
9526 int buffer_size = buffer->length();
9527 HeapIterator iterator;
9528 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
9529 ASSERT(obj != NULL);
9530 if (!obj->IsSharedFunctionInfo()) {
9531 continue;
9532 }
9533 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
9534 if (shared->script() != script) {
9535 continue;
9536 }
9537 if (counter < buffer_size) {
9538 buffer->set(counter, shared);
9539 }
9540 counter++;
9541 }
9542 return counter;
9543}
9544
9545// For a script finds all SharedFunctionInfo's in the heap that points
9546// to this script. Returns JSArray of SharedFunctionInfo wrapped
9547// in OpaqueReferences.
9548static Object* Runtime_LiveEditFindSharedFunctionInfosForScript(
9549 Arguments args) {
9550 ASSERT(args.length() == 1);
9551 HandleScope scope;
9552 CONVERT_CHECKED(JSValue, script_value, args[0]);
9553
9554 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
9555
9556 const int kBufferSize = 32;
9557
9558 Handle<FixedArray> array;
9559 array = Factory::NewFixedArray(kBufferSize);
9560 int number = FindSharedFunctionInfosForScript(*script, *array);
9561 if (number > kBufferSize) {
9562 array = Factory::NewFixedArray(number);
9563 FindSharedFunctionInfosForScript(*script, *array);
9564 }
9565
9566 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
9567 result->set_length(Smi::FromInt(number));
9568
9569 LiveEdit::WrapSharedFunctionInfos(result);
9570
9571 return *result;
9572}
9573
9574// For a script calculates compilation information about all its functions.
9575// The script source is explicitly specified by the second argument.
9576// The source of the actual script is not used, however it is important that
9577// all generated code keeps references to this particular instance of script.
9578// Returns a JSArray of compilation infos. The array is ordered so that
9579// each function with all its descendant is always stored in a continues range
9580// with the function itself going first. The root function is a script function.
9581static Object* Runtime_LiveEditGatherCompileInfo(Arguments args) {
9582 ASSERT(args.length() == 2);
9583 HandleScope scope;
9584 CONVERT_CHECKED(JSValue, script, args[0]);
9585 CONVERT_ARG_CHECKED(String, source, 1);
9586 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
9587
9588 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
9589
9590 if (Top::has_pending_exception()) {
9591 return Failure::Exception();
9592 }
9593
9594 return result;
9595}
9596
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009597// Changes the source of the script to a new_source.
9598// If old_script_name is provided (i.e. is a String), also creates a copy of
9599// the script with its original source and sends notification to debugger.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009600static Object* Runtime_LiveEditReplaceScript(Arguments args) {
9601 ASSERT(args.length() == 3);
9602 HandleScope scope;
9603 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
9604 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009605 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009606
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009607 CONVERT_CHECKED(Script, original_script_pointer,
9608 original_script_value->value());
9609 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009610
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009611 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
9612 new_source,
9613 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009614
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009615 if (old_script->IsScript()) {
9616 Handle<Script> script_handle(Script::cast(old_script));
9617 return *(GetScriptWrapper(script_handle));
9618 } else {
9619 return Heap::null_value();
9620 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009621}
9622
9623// Replaces code of SharedFunctionInfo with a new one.
9624static Object* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
9625 ASSERT(args.length() == 2);
9626 HandleScope scope;
9627 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
9628 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
9629
ager@chromium.orgac091b72010-05-05 07:34:42 +00009630 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009631}
9632
9633// Connects SharedFunctionInfo to another script.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009634static Object* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009635 ASSERT(args.length() == 2);
9636 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009637 Handle<Object> function_object(args[0]);
9638 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009639
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009640 if (function_object->IsJSValue()) {
9641 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
9642 if (script_object->IsJSValue()) {
9643 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
9644 script_object = Handle<Object>(script);
9645 }
9646
9647 LiveEdit::SetFunctionScript(function_wrapper, script_object);
9648 } else {
9649 // Just ignore this. We may not have a SharedFunctionInfo for some functions
9650 // and we check it in this function.
9651 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009652
9653 return Heap::undefined_value();
9654}
9655
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009656
9657// In a code of a parent function replaces original function as embedded object
9658// with a substitution one.
9659static Object* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
9660 ASSERT(args.length() == 3);
9661 HandleScope scope;
9662
9663 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
9664 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
9665 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
9666
9667 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
9668 subst_wrapper);
9669
9670 return Heap::undefined_value();
9671}
9672
9673
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009674// Updates positions of a shared function info (first parameter) according
9675// to script source change. Text change is described in second parameter as
9676// array of groups of 3 numbers:
9677// (change_begin, change_end, change_end_new_position).
9678// Each group describes a change in text; groups are sorted by change_begin.
9679static Object* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
9680 ASSERT(args.length() == 2);
9681 HandleScope scope;
9682 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
9683 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
9684
ager@chromium.orgac091b72010-05-05 07:34:42 +00009685 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009686}
9687
9688
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009689// For array of SharedFunctionInfo's (each wrapped in JSValue)
9690// checks that none of them have activations on stacks (of any thread).
9691// Returns array of the same length with corresponding results of
9692// LiveEdit::FunctionPatchabilityStatus type.
ager@chromium.org357bf652010-04-12 11:30:10 +00009693static Object* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
9694 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009695 HandleScope scope;
9696 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +00009697 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009698
ager@chromium.org357bf652010-04-12 11:30:10 +00009699 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009700}
9701
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009702// Compares 2 strings line-by-line and returns diff in form of JSArray of
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00009703// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009704static Object* Runtime_LiveEditCompareStringsLinewise(Arguments args) {
9705 ASSERT(args.length() == 2);
9706 HandleScope scope;
9707 CONVERT_ARG_CHECKED(String, s1, 0);
9708 CONVERT_ARG_CHECKED(String, s2, 1);
9709
9710 return *LiveEdit::CompareStringsLinewise(s1, s2);
9711}
9712
9713
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009714
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009715// A testing entry. Returns statement position which is the closest to
9716// source_position.
9717static Object* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
9718 ASSERT(args.length() == 2);
9719 HandleScope scope;
9720 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9721 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9722
9723 Handle<Code> code(function->code());
9724
9725 RelocIterator it(*code, 1 << RelocInfo::STATEMENT_POSITION);
9726 int closest_pc = 0;
9727 int distance = kMaxInt;
9728 while (!it.done()) {
9729 int statement_position = static_cast<int>(it.rinfo()->data());
9730 // Check if this break point is closer that what was previously found.
9731 if (source_position <= statement_position &&
9732 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00009733 closest_pc =
9734 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009735 distance = statement_position - source_position;
9736 // Check whether we can't get any closer.
9737 if (distance == 0) break;
9738 }
9739 it.next();
9740 }
9741
9742 return Smi::FromInt(closest_pc);
9743}
9744
9745
ager@chromium.org357bf652010-04-12 11:30:10 +00009746// Calls specified function with or without entering the debugger.
9747// This is used in unit tests to run code as if debugger is entered or simply
9748// to have a stack with C++ frame in the middle.
9749static Object* Runtime_ExecuteInDebugContext(Arguments args) {
9750 ASSERT(args.length() == 2);
9751 HandleScope scope;
9752 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9753 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
9754
9755 Handle<Object> result;
9756 bool pending_exception;
9757 {
9758 if (without_debugger) {
9759 result = Execution::Call(function, Top::global(), 0, NULL,
9760 &pending_exception);
9761 } else {
9762 EnterDebugger enter_debugger;
9763 result = Execution::Call(function, Top::global(), 0, NULL,
9764 &pending_exception);
9765 }
9766 }
9767 if (!pending_exception) {
9768 return *result;
9769 } else {
9770 return Failure::Exception();
9771 }
9772}
9773
9774
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009775#endif // ENABLE_DEBUGGER_SUPPORT
9776
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009777#ifdef ENABLE_LOGGING_AND_PROFILING
9778
9779static Object* Runtime_ProfilerResume(Arguments args) {
9780 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009781 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009782
9783 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00009784 CONVERT_CHECKED(Smi, smi_tag, args[1]);
9785 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009786 return Heap::undefined_value();
9787}
9788
9789
9790static Object* Runtime_ProfilerPause(Arguments args) {
9791 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009792 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009793
9794 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00009795 CONVERT_CHECKED(Smi, smi_tag, args[1]);
9796 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009797 return Heap::undefined_value();
9798}
9799
9800#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009801
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009802// Finds the script object from the script data. NOTE: This operation uses
9803// heap traversal to find the function generated for the source position
9804// for the requested break point. For lazily compiled functions several heap
9805// traversals might be required rendering this operation as a rather slow
9806// operation. However for setting break points which is normally done through
9807// some kind of user interaction the performance is not crucial.
9808static Handle<Object> Runtime_GetScriptFromScriptName(
9809 Handle<String> script_name) {
9810 // Scan the heap for Script objects to find the script with the requested
9811 // script data.
9812 Handle<Script> script;
9813 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009814 HeapObject* obj = NULL;
9815 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009816 // If a script is found check if it has the script data requested.
9817 if (obj->IsScript()) {
9818 if (Script::cast(obj)->name()->IsString()) {
9819 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
9820 script = Handle<Script>(Script::cast(obj));
9821 }
9822 }
9823 }
9824 }
9825
9826 // If no script with the requested script data is found return undefined.
9827 if (script.is_null()) return Factory::undefined_value();
9828
9829 // Return the script found.
9830 return GetScriptWrapper(script);
9831}
9832
9833
9834// Get the script object from script data. NOTE: Regarding performance
9835// see the NOTE for GetScriptFromScriptData.
9836// args[0]: script data for the script to find the source for
9837static Object* Runtime_GetScript(Arguments args) {
9838 HandleScope scope;
9839
9840 ASSERT(args.length() == 1);
9841
9842 CONVERT_CHECKED(String, script_name, args[0]);
9843
9844 // Find the requested script.
9845 Handle<Object> result =
9846 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
9847 return *result;
9848}
9849
9850
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009851// Determines whether the given stack frame should be displayed in
9852// a stack trace. The caller is the error constructor that asked
9853// for the stack trace to be collected. The first time a construct
9854// call to this function is encountered it is skipped. The seen_caller
9855// in/out parameter is used to remember if the caller has been seen
9856// yet.
9857static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
9858 bool* seen_caller) {
9859 // Only display JS frames.
9860 if (!raw_frame->is_java_script())
9861 return false;
9862 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
9863 Object* raw_fun = frame->function();
9864 // Not sure when this can happen but skip it just in case.
9865 if (!raw_fun->IsJSFunction())
9866 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009867 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009868 *seen_caller = true;
9869 return false;
9870 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009871 // Skip all frames until we've seen the caller. Also, skip the most
9872 // obvious builtin calls. Some builtin calls (such as Number.ADD
9873 // which is invoked using 'call') are very difficult to recognize
9874 // so we're leaving them in for now.
9875 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009876}
9877
9878
9879// Collect the raw data for a stack trace. Returns an array of three
9880// element segments each containing a receiver, function and native
9881// code offset.
9882static Object* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009883 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009884 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009885 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
9886
9887 HandleScope scope;
9888
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00009889 limit = Max(limit, 0); // Ensure that limit is not negative.
9890 int initial_size = Min(limit, 10);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009891 Handle<JSArray> result = Factory::NewJSArray(initial_size * 3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009892
9893 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009894 // If the caller parameter is a function we skip frames until we're
9895 // under it before starting to collect.
9896 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009897 int cursor = 0;
9898 int frames_seen = 0;
9899 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009900 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009901 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009902 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009903 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009904 Object* recv = frame->receiver();
9905 Object* fun = frame->function();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009906 Address pc = frame->pc();
9907 Address start = frame->code()->address();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009908 Smi* offset = Smi::FromInt(static_cast<int>(pc - start));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009909 FixedArray* elements = FixedArray::cast(result->elements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009910 if (cursor + 2 < elements->length()) {
9911 elements->set(cursor++, recv);
9912 elements->set(cursor++, fun);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009913 elements->set(cursor++, offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009914 } else {
9915 HandleScope scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009916 Handle<Object> recv_handle(recv);
9917 Handle<Object> fun_handle(fun);
9918 SetElement(result, cursor++, recv_handle);
9919 SetElement(result, cursor++, fun_handle);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009920 SetElement(result, cursor++, Handle<Smi>(offset));
9921 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009922 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009923 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009924 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009925
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009926 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009927 return *result;
9928}
9929
9930
ager@chromium.org3811b432009-10-28 14:53:37 +00009931// Returns V8 version as a string.
9932static Object* Runtime_GetV8Version(Arguments args) {
9933 ASSERT_EQ(args.length(), 0);
9934
9935 NoHandleAllocation ha;
9936
9937 const char* version_string = v8::V8::GetVersion();
9938
9939 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
9940}
9941
9942
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009943static Object* Runtime_Abort(Arguments args) {
9944 ASSERT(args.length() == 2);
9945 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
9946 Smi::cast(args[1])->value());
9947 Top::PrintStack();
9948 OS::Abort();
9949 UNREACHABLE();
9950 return NULL;
9951}
9952
9953
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009954static Object* Runtime_DeleteHandleScopeExtensions(Arguments args) {
9955 ASSERT(args.length() == 0);
9956 HandleScope::DeleteExtensions();
9957 return Heap::undefined_value();
9958}
9959
9960
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009961static Object* CacheMiss(FixedArray* cache_obj, int index, Object* key_obj) {
9962 ASSERT(index % 2 == 0); // index of the key
9963 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
9964 ASSERT(index < cache_obj->length());
9965
9966 HandleScope scope;
9967
9968 Handle<FixedArray> cache(cache_obj);
9969 Handle<Object> key(key_obj);
9970 Handle<JSFunction> factory(JSFunction::cast(
9971 cache->get(JSFunctionResultCache::kFactoryIndex)));
9972 // TODO(antonm): consider passing a receiver when constructing a cache.
9973 Handle<Object> receiver(Top::global_context()->global());
9974
9975 Handle<Object> value;
9976 {
9977 // This handle is nor shared, nor used later, so it's safe.
9978 Object** argv[] = { key.location() };
9979 bool pending_exception = false;
9980 value = Execution::Call(factory,
9981 receiver,
9982 1,
9983 argv,
9984 &pending_exception);
9985 if (pending_exception) return Failure::Exception();
9986 }
9987
9988 cache->set(index, *key);
9989 cache->set(index + 1, *value);
9990 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index));
9991
9992 return *value;
9993}
9994
9995
9996static Object* Runtime_GetFromCache(Arguments args) {
9997 // This is only called from codegen, so checks might be more lax.
9998 CONVERT_CHECKED(FixedArray, cache, args[0]);
9999 Object* key = args[1];
10000
10001 const int finger_index =
10002 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value();
10003
10004 Object* o = cache->get(finger_index);
10005 if (o == key) {
10006 // The fastest case: hit the same place again.
10007 return cache->get(finger_index + 1);
10008 }
10009
10010 for (int i = finger_index - 2;
10011 i >= JSFunctionResultCache::kEntriesIndex;
10012 i -= 2) {
10013 o = cache->get(i);
10014 if (o == key) {
10015 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10016 return cache->get(i + 1);
10017 }
10018 }
10019
10020 const int size =
10021 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value();
10022 ASSERT(size <= cache->length());
10023
10024 for (int i = size - 2; i > finger_index; i -= 2) {
10025 o = cache->get(i);
10026 if (o == key) {
10027 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10028 return cache->get(i + 1);
10029 }
10030 }
10031
10032 // Cache miss. If we have spare room, put new data into it, otherwise
10033 // evict post finger entry which must be least recently used.
10034 if (size < cache->length()) {
10035 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2));
10036 return CacheMiss(cache, size, key);
10037 } else {
antonm@chromium.org397e23c2010-04-21 12:00:05 +000010038 int target_index = finger_index + JSFunctionResultCache::kEntrySize;
10039 if (target_index == cache->length()) {
10040 target_index = JSFunctionResultCache::kEntriesIndex;
10041 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010042 return CacheMiss(cache, target_index, key);
10043 }
10044}
10045
kasper.lund44510672008-07-25 07:37:58 +000010046#ifdef DEBUG
10047// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10048// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010049static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010050 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010051 HandleScope scope;
10052 Handle<JSArray> result = Factory::NewJSArray(0);
10053 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010054 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010055#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010056 { \
10057 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010058 Handle<String> name; \
10059 /* Inline runtime functions have an underscore in front of the name. */ \
10060 if (inline_runtime_functions) { \
10061 name = Factory::NewStringFromAscii( \
10062 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10063 } else { \
10064 name = Factory::NewStringFromAscii( \
10065 Vector<const char>(#Name, StrLength(#Name))); \
10066 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010067 Handle<JSArray> pair = Factory::NewJSArray(0); \
10068 SetElement(pair, 0, name); \
10069 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10070 SetElement(result, index++, pair); \
10071 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010072 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010073 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010074 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010075 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010076 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010077#undef ADD_ENTRY
10078 return *result;
10079}
kasper.lund44510672008-07-25 07:37:58 +000010080#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010081
10082
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010083static Object* Runtime_Log(Arguments args) {
10084 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010085 CONVERT_CHECKED(String, format, args[0]);
10086 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010087 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010088 Logger::LogRuntime(chars, elms);
10089 return Heap::undefined_value();
10090}
10091
10092
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010093static Object* Runtime_IS_VAR(Arguments args) {
10094 UNREACHABLE(); // implemented as macro in the parser
10095 return NULL;
10096}
10097
10098
10099// ----------------------------------------------------------------------------
10100// Implementation of Runtime
10101
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010102#define F(name, number_of_args, result_size) \
10103 { Runtime::k##name, Runtime::RUNTIME, #name, \
10104 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010105
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010106
10107#define I(name, number_of_args, result_size) \
10108 { Runtime::kInline##name, Runtime::INLINE, \
10109 "_" #name, NULL, number_of_args, result_size },
10110
10111Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010112 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010113 INLINE_FUNCTION_LIST(I)
10114 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115};
10116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010117
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010118Object* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
10119 ASSERT(dictionary != NULL);
10120 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10121 for (int i = 0; i < kNumFunctions; ++i) {
10122 Object* name_symbol = Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10123 if (name_symbol->IsFailure()) return name_symbol;
10124 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
10125 dictionary = string_dictionary->Add(String::cast(name_symbol),
10126 Smi::FromInt(i),
10127 PropertyDetails(NONE, NORMAL));
10128 // Non-recoverable failure. Calling code must restart heap initialization.
10129 if (dictionary->IsFailure()) return dictionary;
10130 }
10131 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010132}
10133
10134
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010135Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10136 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10137 if (entry != kNotFound) {
10138 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10139 int function_index = Smi::cast(smi_index)->value();
10140 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010141 }
10142 return NULL;
10143}
10144
10145
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010146Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10147 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10148}
10149
10150
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010151void Runtime::PerformGC(Object* result) {
10152 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010153 if (failure->IsRetryAfterGC()) {
10154 // Try to do a garbage collection; ignore it if it fails. The C
10155 // entry stub will throw an out-of-memory exception in that case.
10156 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
10157 } else {
10158 // Handle last resort GC and make sure to allow future allocations
10159 // to grow the heap without causing GCs (if possible).
10160 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010161 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010162 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010163}
10164
10165
10166} } // namespace v8::internal