blob: 627ea1217fdc7b9f39e49cbd66fe021fb083316a [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;
641 CONVERT_CHECKED(JSObject, obj, args[0]);
642 CONVERT_CHECKED(String, name, args[1]);
643
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000644 // This could be an element.
645 uint32_t index;
646 if (name->AsArrayIndex(&index)) {
647 if (!obj->HasLocalElement(index)) {
648 return Heap::undefined_value();
649 }
650
651 // Special handling of string objects according to ECMAScript 5 15.5.5.2.
652 // Note that this might be a string object with elements other than the
653 // actual string value. This is covered by the subsequent cases.
654 if (obj->IsStringObjectWithCharacterAt(index)) {
655 JSValue* js_value = JSValue::cast(obj);
656 String* str = String::cast(js_value->value());
657 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
658 elms->set(VALUE_INDEX, str->SubString(index, index+1));
659 elms->set(WRITABLE_INDEX, Heap::false_value());
660 elms->set(ENUMERABLE_INDEX, Heap::false_value());
661 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
662 return *desc;
663 }
664
665 // This can potentially be an element in the elements dictionary or
666 // a fast element.
667 if (obj->HasDictionaryElements()) {
668 NumberDictionary* dictionary = obj->element_dictionary();
669 int entry = dictionary->FindEntry(index);
670 PropertyDetails details = dictionary->DetailsAt(entry);
671 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
672 elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000673 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000674 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000675 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000676 return *desc;
677 } else {
678 // Elements that are stored as array elements always has:
679 // writable: true, configurable: true, enumerable: true.
680 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
681 elms->set(VALUE_INDEX, obj->GetElement(index));
682 elms->set(WRITABLE_INDEX, Heap::true_value());
683 elms->set(ENUMERABLE_INDEX, Heap::true_value());
684 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
685 return *desc;
686 }
687 }
688
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000689 // Use recursive implementation to also traverse hidden prototypes
690 GetOwnPropertyImplementation(obj, name, &result);
691
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000692 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000693 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000694 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000695 if (result.type() == CALLBACKS) {
696 Object* structure = result.GetCallbackObject();
ager@chromium.org5c838252010-02-19 08:53:10 +0000697 if (structure->IsProxy() || structure->IsAccessorInfo()) {
698 // Property that is internally implemented as a callback or
699 // an API defined callback.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000700 Object* value = obj->GetPropertyWithCallback(
701 obj, structure, name, result.holder());
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000702 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
703 elms->set(VALUE_INDEX, value);
704 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000705 } else if (structure->IsFixedArray()) {
706 // __defineGetter__/__defineSetter__ callback.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000707 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
708 elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
709 elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000710 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000711 return Heap::undefined_value();
712 }
713 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000714 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
715 elms->set(VALUE_INDEX, result.GetLazyValue());
716 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000717 }
718
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000719 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
720 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000721 return *desc;
722}
723
724
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000725static Object* Runtime_PreventExtensions(Arguments args) {
726 ASSERT(args.length() == 1);
727 CONVERT_CHECKED(JSObject, obj, args[0]);
728 return obj->PreventExtensions();
729}
730
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000731static Object* Runtime_IsExtensible(Arguments args) {
732 ASSERT(args.length() == 1);
733 CONVERT_CHECKED(JSObject, obj, args[0]);
734 return obj->map()->is_extensible() ? Heap::true_value()
735 : Heap::false_value();
736}
737
738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739static Object* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000740 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000741 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000742 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
743 CONVERT_ARG_CHECKED(String, pattern, 1);
744 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000745 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
746 if (result.is_null()) return Failure::Exception();
747 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000748}
749
750
751static Object* Runtime_CreateApiFunction(Arguments args) {
752 HandleScope scope;
753 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000754 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000755 return *Factory::CreateApiFunction(data);
756}
757
758
759static Object* Runtime_IsTemplate(Arguments args) {
760 ASSERT(args.length() == 1);
761 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000762 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000763 return Heap::ToBoolean(result);
764}
765
766
767static Object* Runtime_GetTemplateField(Arguments args) {
768 ASSERT(args.length() == 2);
769 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000770 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000771 int index = field->value();
772 int offset = index * kPointerSize + HeapObject::kHeaderSize;
773 InstanceType type = templ->map()->instance_type();
774 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
775 type == OBJECT_TEMPLATE_INFO_TYPE);
776 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000777 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000778 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
779 } else {
780 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
781 }
782 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000783}
784
785
ager@chromium.org870a0b62008-11-04 11:43:05 +0000786static Object* Runtime_DisableAccessChecks(Arguments args) {
787 ASSERT(args.length() == 1);
788 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000789 Map* old_map = object->map();
790 bool needs_access_checks = old_map->is_access_check_needed();
791 if (needs_access_checks) {
792 // Copy map so it won't interfere constructor's initial map.
793 Object* new_map = old_map->CopyDropTransitions();
794 if (new_map->IsFailure()) return new_map;
795
796 Map::cast(new_map)->set_is_access_check_needed(false);
797 object->set_map(Map::cast(new_map));
798 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000799 return needs_access_checks ? Heap::true_value() : Heap::false_value();
800}
801
802
803static Object* Runtime_EnableAccessChecks(Arguments args) {
804 ASSERT(args.length() == 1);
805 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000806 Map* old_map = object->map();
807 if (!old_map->is_access_check_needed()) {
808 // Copy map so it won't interfere constructor's initial map.
809 Object* new_map = old_map->CopyDropTransitions();
810 if (new_map->IsFailure()) return new_map;
811
812 Map::cast(new_map)->set_is_access_check_needed(true);
813 object->set_map(Map::cast(new_map));
814 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000815 return Heap::undefined_value();
816}
817
818
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
820 HandleScope scope;
821 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
822 Handle<Object> args[2] = { type_handle, name };
823 Handle<Object> error =
824 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
825 return Top::Throw(*error);
826}
827
828
829static Object* Runtime_DeclareGlobals(Arguments args) {
830 HandleScope scope;
831 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
832
ager@chromium.org3811b432009-10-28 14:53:37 +0000833 Handle<Context> context = args.at<Context>(0);
834 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835 bool is_eval = Smi::cast(args[2])->value() == 1;
836
837 // Compute the property attributes. According to ECMA-262, section
838 // 13, page 71, the property must be read-only and
839 // non-deletable. However, neither SpiderMonkey nor KJS creates the
840 // property as read-only, so we don't either.
841 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
842
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000843 // Traverse the name/value pairs and set the properties.
844 int length = pairs->length();
845 for (int i = 0; i < length; i += 2) {
846 HandleScope scope;
847 Handle<String> name(String::cast(pairs->get(i)));
848 Handle<Object> value(pairs->get(i + 1));
849
850 // We have to declare a global const property. To capture we only
851 // assign to it when evaluating the assignment for "const x =
852 // <expr>" the initial value is the hole.
853 bool is_const_property = value->IsTheHole();
854
855 if (value->IsUndefined() || is_const_property) {
856 // Lookup the property in the global object, and don't set the
857 // value of the variable if the property is already there.
858 LookupResult lookup;
859 global->Lookup(*name, &lookup);
860 if (lookup.IsProperty()) {
861 // Determine if the property is local by comparing the holder
862 // against the global object. The information will be used to
863 // avoid throwing re-declaration errors when declaring
864 // variables or constants that exist in the prototype chain.
865 bool is_local = (*global == lookup.holder());
866 // Get the property attributes and determine if the property is
867 // read-only.
868 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
869 bool is_read_only = (attributes & READ_ONLY) != 0;
870 if (lookup.type() == INTERCEPTOR) {
871 // If the interceptor says the property is there, we
872 // just return undefined without overwriting the property.
873 // Otherwise, we continue to setting the property.
874 if (attributes != ABSENT) {
875 // Check if the existing property conflicts with regards to const.
876 if (is_local && (is_read_only || is_const_property)) {
877 const char* type = (is_read_only) ? "const" : "var";
878 return ThrowRedeclarationError(type, name);
879 };
880 // The property already exists without conflicting: Go to
881 // the next declaration.
882 continue;
883 }
884 // Fall-through and introduce the absent property by using
885 // SetProperty.
886 } else {
887 if (is_local && (is_read_only || is_const_property)) {
888 const char* type = (is_read_only) ? "const" : "var";
889 return ThrowRedeclarationError(type, name);
890 }
891 // The property already exists without conflicting: Go to
892 // the next declaration.
893 continue;
894 }
895 }
896 } else {
897 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000898 Handle<SharedFunctionInfo> shared =
899 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000901 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902 value = function;
903 }
904
905 LookupResult lookup;
906 global->LocalLookup(*name, &lookup);
907
908 PropertyAttributes attributes = is_const_property
909 ? static_cast<PropertyAttributes>(base | READ_ONLY)
910 : base;
911
912 if (lookup.IsProperty()) {
913 // There's a local property that we need to overwrite because
914 // we're either declaring a function or there's an interceptor
915 // that claims the property is absent.
916
917 // Check for conflicting re-declarations. We cannot have
918 // conflicting types in case of intercepted properties because
919 // they are absent.
920 if (lookup.type() != INTERCEPTOR &&
921 (lookup.IsReadOnly() || is_const_property)) {
922 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
923 return ThrowRedeclarationError(type, name);
924 }
925 SetProperty(global, name, value, attributes);
926 } else {
927 // If a property with this name does not already exist on the
928 // global object add the property locally. We take special
929 // precautions to always add it as a local property even in case
930 // of callbacks in the prototype chain (this rules out using
931 // SetProperty). Also, we must use the handle-based version to
932 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000933 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934 }
935 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000936
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937 return Heap::undefined_value();
938}
939
940
941static Object* Runtime_DeclareContextSlot(Arguments args) {
942 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000943 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000944
ager@chromium.org7c537e22008-10-16 08:43:32 +0000945 CONVERT_ARG_CHECKED(Context, context, 0);
946 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000947 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000948 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000949 ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000950 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000951
952 // Declarations are always done in the function context.
953 context = Handle<Context>(context->fcontext());
954
955 int index;
956 PropertyAttributes attributes;
957 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000958 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959 context->Lookup(name, flags, &index, &attributes);
960
961 if (attributes != ABSENT) {
962 // The name was declared before; check for conflicting
963 // re-declarations: This is similar to the code in parser.cc in
964 // the AstBuildingParser::Declare function.
965 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
966 // Functions are not read-only.
967 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
968 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
969 return ThrowRedeclarationError(type, name);
970 }
971
972 // Initialize it if necessary.
973 if (*initial_value != NULL) {
974 if (index >= 0) {
975 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000976 // the function context or the arguments object.
977 if (holder->IsContext()) {
978 ASSERT(holder.is_identical_to(context));
979 if (((attributes & READ_ONLY) == 0) ||
980 context->get(index)->IsTheHole()) {
981 context->set(index, *initial_value);
982 }
983 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000984 // The holder is an arguments object.
985 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
986 SetElement(arguments, index, initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000987 }
988 } else {
989 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000990 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 SetProperty(context_ext, name, initial_value, mode);
992 }
993 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000995 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000996 // The property is not in the function context. It needs to be
997 // "declared" in the function context's extension context, or in the
998 // global context.
999 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001000 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001001 // The function context's extension context exists - use it.
1002 context_ext = Handle<JSObject>(context->extension());
1003 } else {
1004 // The function context's extension context does not exists - allocate
1005 // it.
1006 context_ext = Factory::NewJSObject(Top::context_extension_function());
1007 // And store it in the extension slot.
1008 context->set_extension(*context_ext);
1009 }
1010 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011
ager@chromium.org7c537e22008-10-16 08:43:32 +00001012 // Declare the property by setting it to the initial value if provided,
1013 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1014 // constant declarations).
1015 ASSERT(!context_ext->HasLocalProperty(*name));
1016 Handle<Object> value(Heap::undefined_value());
1017 if (*initial_value != NULL) value = initial_value;
1018 SetProperty(context_ext, name, value, mode);
1019 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1020 }
1021
1022 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023}
1024
1025
1026static Object* Runtime_InitializeVarGlobal(Arguments args) {
1027 NoHandleAllocation nha;
1028
1029 // Determine if we need to assign to the variable if it already
1030 // exists (based on the number of arguments).
1031 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1032 bool assign = args.length() == 2;
1033
1034 CONVERT_ARG_CHECKED(String, name, 0);
1035 GlobalObject* global = Top::context()->global();
1036
1037 // According to ECMA-262, section 12.2, page 62, the property must
1038 // not be deletable.
1039 PropertyAttributes attributes = DONT_DELETE;
1040
1041 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001042 // there, there is a property with this name in the prototype chain.
1043 // We follow Safari and Firefox behavior and only set the property
1044 // locally if there is an explicit initialization value that we have
1045 // to assign to the property. When adding the property we take
1046 // special precautions to always add it as a local property even in
1047 // case of callbacks in the prototype chain (this rules out using
1048 // SetProperty). We have IgnoreAttributesAndSetLocalProperty for
1049 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001050 // Note that objects can have hidden prototypes, so we need to traverse
1051 // the whole chain of hidden prototypes to do a 'local' lookup.
1052 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001054 while (true) {
1055 real_holder->LocalLookup(*name, &lookup);
1056 if (lookup.IsProperty()) {
1057 // Determine if this is a redeclaration of something read-only.
1058 if (lookup.IsReadOnly()) {
1059 // If we found readonly property on one of hidden prototypes,
1060 // just shadow it.
1061 if (real_holder != Top::context()->global()) break;
1062 return ThrowRedeclarationError("const", name);
1063 }
1064
1065 // Determine if this is a redeclaration of an intercepted read-only
1066 // property and figure out if the property exists at all.
1067 bool found = true;
1068 PropertyType type = lookup.type();
1069 if (type == INTERCEPTOR) {
1070 HandleScope handle_scope;
1071 Handle<JSObject> holder(real_holder);
1072 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1073 real_holder = *holder;
1074 if (intercepted == ABSENT) {
1075 // The interceptor claims the property isn't there. We need to
1076 // make sure to introduce it.
1077 found = false;
1078 } else if ((intercepted & READ_ONLY) != 0) {
1079 // The property is present, but read-only. Since we're trying to
1080 // overwrite it with a variable declaration we must throw a
1081 // re-declaration error. However if we found readonly property
1082 // on one of hidden prototypes, just shadow it.
1083 if (real_holder != Top::context()->global()) break;
1084 return ThrowRedeclarationError("const", name);
1085 }
1086 }
1087
1088 if (found && !assign) {
1089 // The global property is there and we're not assigning any value
1090 // to it. Just return.
1091 return Heap::undefined_value();
1092 }
1093
1094 // Assign the value (or undefined) to the property.
1095 Object* value = (assign) ? args[1] : Heap::undefined_value();
1096 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001097 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001098
1099 Object* proto = real_holder->GetPrototype();
1100 if (!proto->IsJSObject())
1101 break;
1102
1103 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1104 break;
1105
1106 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001107 }
1108
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001109 global = Top::context()->global();
1110 if (assign) {
1111 return global->IgnoreAttributesAndSetLocalProperty(*name,
1112 args[1],
1113 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001114 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001115 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001116}
1117
1118
1119static Object* Runtime_InitializeConstGlobal(Arguments args) {
1120 // All constants are declared with an initial value. The name
1121 // of the constant is the first argument and the initial value
1122 // is the second.
1123 RUNTIME_ASSERT(args.length() == 2);
1124 CONVERT_ARG_CHECKED(String, name, 0);
1125 Handle<Object> value = args.at<Object>(1);
1126
1127 // Get the current global object from top.
1128 GlobalObject* global = Top::context()->global();
1129
1130 // According to ECMA-262, section 12.2, page 62, the property must
1131 // not be deletable. Since it's a const, it must be READ_ONLY too.
1132 PropertyAttributes attributes =
1133 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1134
1135 // Lookup the property locally in the global object. If it isn't
1136 // there, we add the property and take special precautions to always
1137 // add it as a local property even in case of callbacks in the
1138 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001139 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001140 LookupResult lookup;
1141 global->LocalLookup(*name, &lookup);
1142 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001143 return global->IgnoreAttributesAndSetLocalProperty(*name,
1144 *value,
1145 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146 }
1147
1148 // Determine if this is a redeclaration of something not
1149 // read-only. In case the result is hidden behind an interceptor we
1150 // need to ask it for the property attributes.
1151 if (!lookup.IsReadOnly()) {
1152 if (lookup.type() != INTERCEPTOR) {
1153 return ThrowRedeclarationError("var", name);
1154 }
1155
1156 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1157
1158 // Throw re-declaration error if the intercepted property is present
1159 // but not read-only.
1160 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1161 return ThrowRedeclarationError("var", name);
1162 }
1163
1164 // Restore global object from context (in case of GC) and continue
1165 // with setting the value because the property is either absent or
1166 // read-only. We also have to do redo the lookup.
1167 global = Top::context()->global();
1168
1169 // BUG 1213579: Handle the case where we have to set a read-only
1170 // property through an interceptor and only do it if it's
1171 // uninitialized, e.g. the hole. Nirk...
1172 global->SetProperty(*name, *value, attributes);
1173 return *value;
1174 }
1175
1176 // Set the value, but only we're assigning the initial value to a
1177 // constant. For now, we determine this by checking if the
1178 // current value is the hole.
1179 PropertyType type = lookup.type();
1180 if (type == FIELD) {
1181 FixedArray* properties = global->properties();
1182 int index = lookup.GetFieldIndex();
1183 if (properties->get(index)->IsTheHole()) {
1184 properties->set(index, *value);
1185 }
1186 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001187 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1188 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189 }
1190 } else {
1191 // Ignore re-initialization of constants that have already been
1192 // assigned a function value.
1193 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1194 }
1195
1196 // Use the set value as the result of the operation.
1197 return *value;
1198}
1199
1200
1201static Object* Runtime_InitializeConstContextSlot(Arguments args) {
1202 HandleScope scope;
1203 ASSERT(args.length() == 3);
1204
1205 Handle<Object> value(args[0]);
1206 ASSERT(!value->IsTheHole());
1207 CONVERT_ARG_CHECKED(Context, context, 1);
1208 Handle<String> name(String::cast(args[2]));
1209
1210 // Initializations are always done in the function context.
1211 context = Handle<Context>(context->fcontext());
1212
1213 int index;
1214 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001215 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001216 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001217 context->Lookup(name, flags, &index, &attributes);
1218
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001219 // In most situations, the property introduced by the const
1220 // declaration should be present in the context extension object.
1221 // However, because declaration and initialization are separate, the
1222 // property might have been deleted (if it was introduced by eval)
1223 // before we reach the initialization point.
1224 //
1225 // Example:
1226 //
1227 // function f() { eval("delete x; const x;"); }
1228 //
1229 // In that case, the initialization behaves like a normal assignment
1230 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001231 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001232 // Property was found in a context.
1233 if (holder->IsContext()) {
1234 // The holder cannot be the function context. If it is, there
1235 // should have been a const redeclaration error when declaring
1236 // the const property.
1237 ASSERT(!holder.is_identical_to(context));
1238 if ((attributes & READ_ONLY) == 0) {
1239 Handle<Context>::cast(holder)->set(index, *value);
1240 }
1241 } else {
1242 // The holder is an arguments object.
1243 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001244 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1245 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001246 }
1247 return *value;
1248 }
1249
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001250 // The property could not be found, we introduce it in the global
1251 // context.
1252 if (attributes == ABSENT) {
1253 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1254 SetProperty(global, name, value, NONE);
1255 return *value;
1256 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001258 // The property was present in a context extension object.
1259 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001261 if (*context_ext == context->extension()) {
1262 // This is the property that was introduced by the const
1263 // declaration. Set it if it hasn't been set before. NOTE: We
1264 // cannot use GetProperty() to get the current value as it
1265 // 'unholes' the value.
1266 LookupResult lookup;
1267 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1268 ASSERT(lookup.IsProperty()); // the property was declared
1269 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1270
1271 PropertyType type = lookup.type();
1272 if (type == FIELD) {
1273 FixedArray* properties = context_ext->properties();
1274 int index = lookup.GetFieldIndex();
1275 if (properties->get(index)->IsTheHole()) {
1276 properties->set(index, *value);
1277 }
1278 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001279 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1280 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001281 }
1282 } else {
1283 // We should not reach here. Any real, named property should be
1284 // either a field or a dictionary slot.
1285 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 }
1287 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001288 // The property was found in a different context extension object.
1289 // Set it if it is not a read-only property.
1290 if ((attributes & READ_ONLY) == 0) {
1291 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1292 // Setting a property might throw an exception. Exceptions
1293 // are converted to empty handles in handle operations. We
1294 // need to convert back to exceptions here.
1295 if (set.is_null()) {
1296 ASSERT(Top::has_pending_exception());
1297 return Failure::Exception();
1298 }
1299 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001301
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302 return *value;
1303}
1304
1305
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001306static Object* Runtime_OptimizeObjectForAddingMultipleProperties(
1307 Arguments args) {
1308 HandleScope scope;
1309 ASSERT(args.length() == 2);
1310 CONVERT_ARG_CHECKED(JSObject, object, 0);
1311 CONVERT_SMI_CHECKED(properties, args[1]);
1312 if (object->HasFastProperties()) {
1313 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1314 }
1315 return *object;
1316}
1317
1318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319static Object* Runtime_RegExpExec(Arguments args) {
1320 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001321 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001322 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1323 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001324 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001325 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001326 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001327 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001328 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001329 RUNTIME_ASSERT(index >= 0);
1330 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001331 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001332 Handle<Object> result = RegExpImpl::Exec(regexp,
1333 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001334 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001335 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001336 if (result.is_null()) return Failure::Exception();
1337 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338}
1339
1340
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001341static Object* Runtime_RegExpConstructResult(Arguments args) {
1342 ASSERT(args.length() == 3);
1343 CONVERT_SMI_CHECKED(elements_count, args[0]);
1344 if (elements_count > JSArray::kMaxFastElementsLength) {
1345 return Top::ThrowIllegalOperation();
1346 }
1347 Object* new_object = Heap::AllocateFixedArrayWithHoles(elements_count);
1348 if (new_object->IsFailure()) return new_object;
1349 FixedArray* elements = FixedArray::cast(new_object);
1350 new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1351 NEW_SPACE,
1352 OLD_POINTER_SPACE);
1353 if (new_object->IsFailure()) return new_object;
1354 {
1355 AssertNoAllocation no_gc;
1356 HandleScope scope;
1357 reinterpret_cast<HeapObject*>(new_object)->
1358 set_map(Top::global_context()->regexp_result_map());
1359 }
1360 JSArray* array = JSArray::cast(new_object);
1361 array->set_properties(Heap::empty_fixed_array());
1362 array->set_elements(elements);
1363 array->set_length(Smi::FromInt(elements_count));
1364 // Write in-object properties after the length of the array.
1365 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1366 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1367 return array;
1368}
1369
1370
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001371static Object* Runtime_RegExpCloneResult(Arguments args) {
1372 ASSERT(args.length() == 1);
1373 Map* regexp_result_map;
1374 {
1375 AssertNoAllocation no_gc;
1376 HandleScope handles;
1377 regexp_result_map = Top::global_context()->regexp_result_map();
1378 }
1379 if (!args[0]->IsJSArray()) return args[0];
1380
1381 JSArray* result = JSArray::cast(args[0]);
1382 // Arguments to RegExpCloneResult should always be fresh RegExp exec call
1383 // results (either a fresh JSRegExpResult or null).
1384 // If the argument is not a JSRegExpResult, or isn't unmodified, just return
1385 // the argument uncloned.
1386 if (result->map() != regexp_result_map) return result;
1387
1388 // Having the original JSRegExpResult map guarantees that we have
1389 // fast elements and no properties except the two in-object properties.
1390 ASSERT(result->HasFastElements());
1391 ASSERT(result->properties() == Heap::empty_fixed_array());
1392 ASSERT_EQ(2, regexp_result_map->inobject_properties());
1393
1394 Object* new_array_alloc = Heap::AllocateRaw(JSRegExpResult::kSize,
1395 NEW_SPACE,
1396 OLD_POINTER_SPACE);
1397 if (new_array_alloc->IsFailure()) return new_array_alloc;
1398
1399 // Set HeapObject map to JSRegExpResult map.
1400 reinterpret_cast<HeapObject*>(new_array_alloc)->set_map(regexp_result_map);
1401
1402 JSArray* new_array = JSArray::cast(new_array_alloc);
1403
1404 // Copy JSObject properties.
1405 new_array->set_properties(result->properties()); // Empty FixedArray.
1406
1407 // Copy JSObject elements as copy-on-write.
1408 FixedArray* elements = FixedArray::cast(result->elements());
1409 if (elements != Heap::empty_fixed_array()) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001410 elements->set_map(Heap::fixed_cow_array_map());
1411 }
1412 new_array->set_elements(elements);
1413
1414 // Copy JSArray length.
1415 new_array->set_length(result->length());
1416
1417 // Copy JSRegExpResult in-object property fields input and index.
1418 new_array->FastPropertyAtPut(JSRegExpResult::kIndexIndex,
1419 result->FastPropertyAt(
1420 JSRegExpResult::kIndexIndex));
1421 new_array->FastPropertyAtPut(JSRegExpResult::kInputIndex,
1422 result->FastPropertyAt(
1423 JSRegExpResult::kInputIndex));
1424 return new_array;
1425}
1426
1427
lrn@chromium.org25156de2010-04-06 13:10:27 +00001428static Object* Runtime_RegExpInitializeObject(Arguments args) {
1429 AssertNoAllocation no_alloc;
1430 ASSERT(args.length() == 5);
1431 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1432 CONVERT_CHECKED(String, source, args[1]);
1433
1434 Object* global = args[2];
1435 if (!global->IsTrue()) global = Heap::false_value();
1436
1437 Object* ignoreCase = args[3];
1438 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1439
1440 Object* multiline = args[4];
1441 if (!multiline->IsTrue()) multiline = Heap::false_value();
1442
1443 Map* map = regexp->map();
1444 Object* constructor = map->constructor();
1445 if (constructor->IsJSFunction() &&
1446 JSFunction::cast(constructor)->initial_map() == map) {
1447 // If we still have the original map, set in-object properties directly.
1448 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1449 // TODO(lrn): Consider skipping write barrier on booleans as well.
1450 // Both true and false should be in oldspace at all times.
1451 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1452 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1453 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1454 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1455 Smi::FromInt(0),
1456 SKIP_WRITE_BARRIER);
1457 return regexp;
1458 }
1459
1460 // Map has changed, so use generic, but slower, method.
1461 PropertyAttributes final =
1462 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1463 PropertyAttributes writable =
1464 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
1465 regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(),
1466 source,
1467 final);
1468 regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(),
1469 global,
1470 final);
1471 regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(),
1472 ignoreCase,
1473 final);
1474 regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(),
1475 multiline,
1476 final);
1477 regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(),
1478 Smi::FromInt(0),
1479 writable);
1480 return regexp;
1481}
1482
1483
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001484static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) {
1485 HandleScope scope;
1486 ASSERT(args.length() == 1);
1487 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1488 // This is necessary to enable fast checks for absence of elements
1489 // on Array.prototype and below.
1490 prototype->set_elements(Heap::empty_fixed_array());
1491 return Smi::FromInt(0);
1492}
1493
1494
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001495static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1496 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001497 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001498 Handle<String> key = Factory::LookupAsciiSymbol(name);
1499 Handle<Code> code(Builtins::builtin(builtin_name));
1500 Handle<JSFunction> optimized = Factory::NewFunction(key,
1501 JS_OBJECT_TYPE,
1502 JSObject::kHeaderSize,
1503 code,
1504 false);
1505 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001506 SetProperty(holder, key, optimized, NONE);
1507 return optimized;
1508}
1509
1510
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001511static Object* Runtime_SpecialArrayFunctions(Arguments args) {
1512 HandleScope scope;
1513 ASSERT(args.length() == 1);
1514 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1515
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001516 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1517 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001518 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1519 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1520 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1521 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001522 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001523
1524 return *holder;
1525}
1526
1527
ager@chromium.org357bf652010-04-12 11:30:10 +00001528static Object* Runtime_GetGlobalReceiver(Arguments args) {
1529 // Returns a real global receiver, not one of builtins object.
1530 Context* global_context = Top::context()->global()->global_context();
1531 return global_context->global()->global_receiver();
1532}
1533
1534
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
1536 HandleScope scope;
1537 ASSERT(args.length() == 4);
1538 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1539 int index = Smi::cast(args[1])->value();
1540 Handle<String> pattern = args.at<String>(2);
1541 Handle<String> flags = args.at<String>(3);
1542
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001543 // Get the RegExp function from the context in the literals array.
1544 // This is the RegExp function from the context in which the
1545 // function was created. We do not use the RegExp function from the
1546 // current global context because this might be the RegExp function
1547 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001548 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001549 Handle<JSFunction>(
1550 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551 // Compute the regular expression literal.
1552 bool has_pending_exception;
1553 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001554 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1555 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 if (has_pending_exception) {
1557 ASSERT(Top::has_pending_exception());
1558 return Failure::Exception();
1559 }
1560 literals->set(index, *regexp);
1561 return *regexp;
1562}
1563
1564
1565static Object* Runtime_FunctionGetName(Arguments args) {
1566 NoHandleAllocation ha;
1567 ASSERT(args.length() == 1);
1568
1569 CONVERT_CHECKED(JSFunction, f, args[0]);
1570 return f->shared()->name();
1571}
1572
1573
ager@chromium.org236ad962008-09-25 09:45:57 +00001574static Object* Runtime_FunctionSetName(Arguments args) {
1575 NoHandleAllocation ha;
1576 ASSERT(args.length() == 2);
1577
1578 CONVERT_CHECKED(JSFunction, f, args[0]);
1579 CONVERT_CHECKED(String, name, args[1]);
1580 f->shared()->set_name(name);
1581 return Heap::undefined_value();
1582}
1583
1584
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001585static Object* Runtime_FunctionRemovePrototype(Arguments args) {
1586 NoHandleAllocation ha;
1587 ASSERT(args.length() == 1);
1588
1589 CONVERT_CHECKED(JSFunction, f, args[0]);
1590 Object* obj = f->RemovePrototype();
1591 if (obj->IsFailure()) return obj;
1592
1593 return Heap::undefined_value();
1594}
1595
1596
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597static Object* Runtime_FunctionGetScript(Arguments args) {
1598 HandleScope scope;
1599 ASSERT(args.length() == 1);
1600
1601 CONVERT_CHECKED(JSFunction, fun, args[0]);
1602 Handle<Object> script = Handle<Object>(fun->shared()->script());
1603 if (!script->IsScript()) return Heap::undefined_value();
1604
1605 return *GetScriptWrapper(Handle<Script>::cast(script));
1606}
1607
1608
1609static Object* Runtime_FunctionGetSourceCode(Arguments args) {
1610 NoHandleAllocation ha;
1611 ASSERT(args.length() == 1);
1612
1613 CONVERT_CHECKED(JSFunction, f, args[0]);
1614 return f->shared()->GetSourceCode();
1615}
1616
1617
1618static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
1619 NoHandleAllocation ha;
1620 ASSERT(args.length() == 1);
1621
1622 CONVERT_CHECKED(JSFunction, fun, args[0]);
1623 int pos = fun->shared()->start_position();
1624 return Smi::FromInt(pos);
1625}
1626
1627
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001628static Object* Runtime_FunctionGetPositionForOffset(Arguments args) {
1629 ASSERT(args.length() == 2);
1630
1631 CONVERT_CHECKED(JSFunction, fun, args[0]);
1632 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1633
1634 Code* code = fun->code();
1635 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1636
1637 Address pc = code->address() + offset;
1638 return Smi::FromInt(fun->code()->SourcePosition(pc));
1639}
1640
1641
1642
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
1644 NoHandleAllocation ha;
1645 ASSERT(args.length() == 2);
1646
1647 CONVERT_CHECKED(JSFunction, fun, args[0]);
1648 CONVERT_CHECKED(String, name, args[1]);
1649 fun->SetInstanceClassName(name);
1650 return Heap::undefined_value();
1651}
1652
1653
1654static Object* Runtime_FunctionSetLength(Arguments args) {
1655 NoHandleAllocation ha;
1656 ASSERT(args.length() == 2);
1657
1658 CONVERT_CHECKED(JSFunction, fun, args[0]);
1659 CONVERT_CHECKED(Smi, length, args[1]);
1660 fun->shared()->set_length(length->value());
1661 return length;
1662}
1663
1664
1665static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001666 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001667 ASSERT(args.length() == 2);
1668
1669 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001670 ASSERT(fun->should_have_prototype());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001671 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
1672 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673 return args[0]; // return TOS
1674}
1675
1676
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001677static Object* Runtime_FunctionIsAPIFunction(Arguments args) {
1678 NoHandleAllocation ha;
1679 ASSERT(args.length() == 1);
1680
1681 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001682 return f->shared()->IsApiFunction() ? Heap::true_value()
1683 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001684}
1685
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001686static Object* Runtime_FunctionIsBuiltin(Arguments args) {
1687 NoHandleAllocation ha;
1688 ASSERT(args.length() == 1);
1689
1690 CONVERT_CHECKED(JSFunction, f, args[0]);
1691 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1692}
1693
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001694
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001695static Object* Runtime_SetCode(Arguments args) {
1696 HandleScope scope;
1697 ASSERT(args.length() == 2);
1698
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001699 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700 Handle<Object> code = args.at<Object>(1);
1701
1702 Handle<Context> context(target->context());
1703
1704 if (!code->IsNull()) {
1705 RUNTIME_ASSERT(code->IsJSFunction());
1706 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001707 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001708
1709 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001710 return Failure::Exception();
1711 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001712 // Set the code, scope info, formal parameter count,
1713 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001714 target->shared()->set_code(shared->code());
1715 target->set_code(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001716 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001717 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001718 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001719 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001720 // Set the source code of the target function to undefined.
1721 // SetCode is only used for built-in constructors like String,
1722 // Array, and Object, and some web code
1723 // doesn't like seeing source code for constructors.
1724 target->shared()->set_script(Heap::undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001725 // Clear the optimization hints related to the compiled code as these are no
1726 // longer valid when the code is overwritten.
1727 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001728 context = Handle<Context>(fun->context());
1729
1730 // Make sure we get a fresh copy of the literal vector to avoid
1731 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001732 int number_of_literals = fun->NumberOfLiterals();
1733 Handle<FixedArray> literals =
1734 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001735 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001736 // Insert the object, regexp and array functions in the literals
1737 // array prefix. These are the functions that will be used when
1738 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001739 literals->set(JSFunction::kLiteralGlobalContextIndex,
1740 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001741 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001742 // It's okay to skip the write barrier here because the literals
1743 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001744 target->set_literals(*literals, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001745 }
1746
1747 target->set_context(*context);
1748 return *target;
1749}
1750
1751
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001752static Object* Runtime_SetExpectedNumberOfProperties(Arguments args) {
1753 HandleScope scope;
1754 ASSERT(args.length() == 2);
1755 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1756 CONVERT_SMI_CHECKED(num, args[1]);
1757 RUNTIME_ASSERT(num >= 0);
1758 SetExpectedNofProperties(function, num);
1759 return Heap::undefined_value();
1760}
1761
1762
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001763static Object* CharFromCode(Object* char_code) {
1764 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001765 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001766 if (code <= 0xffff) {
1767 return Heap::LookupSingleCharacterStringFromCode(code);
1768 }
1769 }
1770 return Heap::empty_string();
1771}
1772
1773
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001774static Object* Runtime_StringCharCodeAt(Arguments args) {
1775 NoHandleAllocation ha;
1776 ASSERT(args.length() == 2);
1777
1778 CONVERT_CHECKED(String, subject, args[0]);
1779 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001780 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001781
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001782 uint32_t i = 0;
1783 if (index->IsSmi()) {
1784 int value = Smi::cast(index)->value();
1785 if (value < 0) return Heap::nan_value();
1786 i = value;
1787 } else {
1788 ASSERT(index->IsHeapNumber());
1789 double value = HeapNumber::cast(index)->value();
1790 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001791 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001792
1793 // Flatten the string. If someone wants to get a char at an index
1794 // in a cons string, it is likely that more indices will be
1795 // accessed.
1796 Object* flat = subject->TryFlatten();
1797 if (flat->IsFailure()) return flat;
1798 subject = String::cast(flat);
1799
1800 if (i >= static_cast<uint32_t>(subject->length())) {
1801 return Heap::nan_value();
1802 }
1803
1804 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001805}
1806
1807
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001808static Object* Runtime_CharFromCode(Arguments args) {
1809 NoHandleAllocation ha;
1810 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001811 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001812}
1813
lrn@chromium.org25156de2010-04-06 13:10:27 +00001814
1815class FixedArrayBuilder {
1816 public:
1817 explicit FixedArrayBuilder(int initial_capacity)
1818 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1819 length_(0) {
1820 // Require a non-zero initial size. Ensures that doubling the size to
1821 // extend the array will work.
1822 ASSERT(initial_capacity > 0);
1823 }
1824
1825 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1826 : array_(backing_store),
1827 length_(0) {
1828 // Require a non-zero initial size. Ensures that doubling the size to
1829 // extend the array will work.
1830 ASSERT(backing_store->length() > 0);
1831 }
1832
1833 bool HasCapacity(int elements) {
1834 int length = array_->length();
1835 int required_length = length_ + elements;
1836 return (length >= required_length);
1837 }
1838
1839 void EnsureCapacity(int elements) {
1840 int length = array_->length();
1841 int required_length = length_ + elements;
1842 if (length < required_length) {
1843 int new_length = length;
1844 do {
1845 new_length *= 2;
1846 } while (new_length < required_length);
1847 Handle<FixedArray> extended_array =
1848 Factory::NewFixedArrayWithHoles(new_length);
1849 array_->CopyTo(0, *extended_array, 0, length_);
1850 array_ = extended_array;
1851 }
1852 }
1853
1854 void Add(Object* value) {
1855 ASSERT(length_ < capacity());
1856 array_->set(length_, value);
1857 length_++;
1858 }
1859
1860 void Add(Smi* value) {
1861 ASSERT(length_ < capacity());
1862 array_->set(length_, value);
1863 length_++;
1864 }
1865
1866 Handle<FixedArray> array() {
1867 return array_;
1868 }
1869
1870 int length() {
1871 return length_;
1872 }
1873
1874 int capacity() {
1875 return array_->length();
1876 }
1877
1878 Handle<JSArray> ToJSArray() {
1879 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1880 result_array->set_length(Smi::FromInt(length_));
1881 return result_array;
1882 }
1883
1884 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1885 target_array->set_elements(*array_);
1886 target_array->set_length(Smi::FromInt(length_));
1887 return target_array;
1888 }
1889
1890 private:
1891 Handle<FixedArray> array_;
1892 int length_;
1893};
1894
1895
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001896// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001897const int kStringBuilderConcatHelperLengthBits = 11;
1898const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001899
1900template <typename schar>
1901static inline void StringBuilderConcatHelper(String*,
1902 schar*,
1903 FixedArray*,
1904 int);
1905
lrn@chromium.org25156de2010-04-06 13:10:27 +00001906typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1907 StringBuilderSubstringLength;
1908typedef BitField<int,
1909 kStringBuilderConcatHelperLengthBits,
1910 kStringBuilderConcatHelperPositionBits>
1911 StringBuilderSubstringPosition;
1912
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001913
1914class ReplacementStringBuilder {
1915 public:
1916 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00001917 : array_builder_(estimated_part_count),
1918 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001919 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001920 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001921 // Require a non-zero initial size. Ensures that doubling the size to
1922 // extend the array will work.
1923 ASSERT(estimated_part_count > 0);
1924 }
1925
lrn@chromium.org25156de2010-04-06 13:10:27 +00001926 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
1927 int from,
1928 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001929 ASSERT(from >= 0);
1930 int length = to - from;
1931 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001932 if (StringBuilderSubstringLength::is_valid(length) &&
1933 StringBuilderSubstringPosition::is_valid(from)) {
1934 int encoded_slice = StringBuilderSubstringLength::encode(length) |
1935 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001936 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001937 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001938 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001939 builder->Add(Smi::FromInt(-length));
1940 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001941 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001942 }
1943
1944
1945 void EnsureCapacity(int elements) {
1946 array_builder_.EnsureCapacity(elements);
1947 }
1948
1949
1950 void AddSubjectSlice(int from, int to) {
1951 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001952 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001953 }
1954
1955
1956 void AddString(Handle<String> string) {
1957 int length = string->length();
1958 ASSERT(length > 0);
1959 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00001960 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001961 is_ascii_ = false;
1962 }
1963 IncrementCharacterCount(length);
1964 }
1965
1966
1967 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001968 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001969 return Factory::empty_string();
1970 }
1971
1972 Handle<String> joined_string;
1973 if (is_ascii_) {
1974 joined_string = NewRawAsciiString(character_count_);
1975 AssertNoAllocation no_alloc;
1976 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
1977 char* char_buffer = seq->GetChars();
1978 StringBuilderConcatHelper(*subject_,
1979 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00001980 *array_builder_.array(),
1981 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001982 } else {
1983 // Non-ASCII.
1984 joined_string = NewRawTwoByteString(character_count_);
1985 AssertNoAllocation no_alloc;
1986 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
1987 uc16* char_buffer = seq->GetChars();
1988 StringBuilderConcatHelper(*subject_,
1989 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00001990 *array_builder_.array(),
1991 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001992 }
1993 return joined_string;
1994 }
1995
1996
1997 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001998 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001999 V8::FatalProcessOutOfMemory("String.replace result too large.");
2000 }
2001 character_count_ += by;
2002 }
2003
lrn@chromium.org25156de2010-04-06 13:10:27 +00002004 Handle<JSArray> GetParts() {
2005 Handle<JSArray> result =
2006 Factory::NewJSArrayWithElements(array_builder_.array());
2007 result->set_length(Smi::FromInt(array_builder_.length()));
2008 return result;
2009 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002010
lrn@chromium.org25156de2010-04-06 13:10:27 +00002011 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002012 Handle<String> NewRawAsciiString(int size) {
2013 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2014 }
2015
2016
2017 Handle<String> NewRawTwoByteString(int size) {
2018 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2019 }
2020
2021
2022 void AddElement(Object* element) {
2023 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002024 ASSERT(array_builder_.capacity() > array_builder_.length());
2025 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002026 }
2027
lrn@chromium.org25156de2010-04-06 13:10:27 +00002028 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002029 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002030 int character_count_;
2031 bool is_ascii_;
2032};
2033
2034
2035class CompiledReplacement {
2036 public:
2037 CompiledReplacement()
2038 : parts_(1), replacement_substrings_(0) {}
2039
2040 void Compile(Handle<String> replacement,
2041 int capture_count,
2042 int subject_length);
2043
2044 void Apply(ReplacementStringBuilder* builder,
2045 int match_from,
2046 int match_to,
2047 Handle<JSArray> last_match_info);
2048
2049 // Number of distinct parts of the replacement pattern.
2050 int parts() {
2051 return parts_.length();
2052 }
2053 private:
2054 enum PartType {
2055 SUBJECT_PREFIX = 1,
2056 SUBJECT_SUFFIX,
2057 SUBJECT_CAPTURE,
2058 REPLACEMENT_SUBSTRING,
2059 REPLACEMENT_STRING,
2060
2061 NUMBER_OF_PART_TYPES
2062 };
2063
2064 struct ReplacementPart {
2065 static inline ReplacementPart SubjectMatch() {
2066 return ReplacementPart(SUBJECT_CAPTURE, 0);
2067 }
2068 static inline ReplacementPart SubjectCapture(int capture_index) {
2069 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2070 }
2071 static inline ReplacementPart SubjectPrefix() {
2072 return ReplacementPart(SUBJECT_PREFIX, 0);
2073 }
2074 static inline ReplacementPart SubjectSuffix(int subject_length) {
2075 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2076 }
2077 static inline ReplacementPart ReplacementString() {
2078 return ReplacementPart(REPLACEMENT_STRING, 0);
2079 }
2080 static inline ReplacementPart ReplacementSubString(int from, int to) {
2081 ASSERT(from >= 0);
2082 ASSERT(to > from);
2083 return ReplacementPart(-from, to);
2084 }
2085
2086 // If tag <= 0 then it is the negation of a start index of a substring of
2087 // the replacement pattern, otherwise it's a value from PartType.
2088 ReplacementPart(int tag, int data)
2089 : tag(tag), data(data) {
2090 // Must be non-positive or a PartType value.
2091 ASSERT(tag < NUMBER_OF_PART_TYPES);
2092 }
2093 // Either a value of PartType or a non-positive number that is
2094 // the negation of an index into the replacement string.
2095 int tag;
2096 // The data value's interpretation depends on the value of tag:
2097 // tag == SUBJECT_PREFIX ||
2098 // tag == SUBJECT_SUFFIX: data is unused.
2099 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2100 // tag == REPLACEMENT_SUBSTRING ||
2101 // tag == REPLACEMENT_STRING: data is index into array of substrings
2102 // of the replacement string.
2103 // tag <= 0: Temporary representation of the substring of the replacement
2104 // string ranging over -tag .. data.
2105 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2106 // substring objects.
2107 int data;
2108 };
2109
2110 template<typename Char>
2111 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2112 Vector<Char> characters,
2113 int capture_count,
2114 int subject_length) {
2115 int length = characters.length();
2116 int last = 0;
2117 for (int i = 0; i < length; i++) {
2118 Char c = characters[i];
2119 if (c == '$') {
2120 int next_index = i + 1;
2121 if (next_index == length) { // No next character!
2122 break;
2123 }
2124 Char c2 = characters[next_index];
2125 switch (c2) {
2126 case '$':
2127 if (i > last) {
2128 // There is a substring before. Include the first "$".
2129 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2130 last = next_index + 1; // Continue after the second "$".
2131 } else {
2132 // Let the next substring start with the second "$".
2133 last = next_index;
2134 }
2135 i = next_index;
2136 break;
2137 case '`':
2138 if (i > last) {
2139 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2140 }
2141 parts->Add(ReplacementPart::SubjectPrefix());
2142 i = next_index;
2143 last = i + 1;
2144 break;
2145 case '\'':
2146 if (i > last) {
2147 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2148 }
2149 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2150 i = next_index;
2151 last = i + 1;
2152 break;
2153 case '&':
2154 if (i > last) {
2155 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2156 }
2157 parts->Add(ReplacementPart::SubjectMatch());
2158 i = next_index;
2159 last = i + 1;
2160 break;
2161 case '0':
2162 case '1':
2163 case '2':
2164 case '3':
2165 case '4':
2166 case '5':
2167 case '6':
2168 case '7':
2169 case '8':
2170 case '9': {
2171 int capture_ref = c2 - '0';
2172 if (capture_ref > capture_count) {
2173 i = next_index;
2174 continue;
2175 }
2176 int second_digit_index = next_index + 1;
2177 if (second_digit_index < length) {
2178 // Peek ahead to see if we have two digits.
2179 Char c3 = characters[second_digit_index];
2180 if ('0' <= c3 && c3 <= '9') { // Double digits.
2181 int double_digit_ref = capture_ref * 10 + c3 - '0';
2182 if (double_digit_ref <= capture_count) {
2183 next_index = second_digit_index;
2184 capture_ref = double_digit_ref;
2185 }
2186 }
2187 }
2188 if (capture_ref > 0) {
2189 if (i > last) {
2190 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2191 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002192 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002193 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2194 last = next_index + 1;
2195 }
2196 i = next_index;
2197 break;
2198 }
2199 default:
2200 i = next_index;
2201 break;
2202 }
2203 }
2204 }
2205 if (length > last) {
2206 if (last == 0) {
2207 parts->Add(ReplacementPart::ReplacementString());
2208 } else {
2209 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2210 }
2211 }
2212 }
2213
2214 ZoneList<ReplacementPart> parts_;
2215 ZoneList<Handle<String> > replacement_substrings_;
2216};
2217
2218
2219void CompiledReplacement::Compile(Handle<String> replacement,
2220 int capture_count,
2221 int subject_length) {
2222 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002223 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002224 AssertNoAllocation no_alloc;
2225 ParseReplacementPattern(&parts_,
2226 replacement->ToAsciiVector(),
2227 capture_count,
2228 subject_length);
2229 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002230 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002231 AssertNoAllocation no_alloc;
2232
2233 ParseReplacementPattern(&parts_,
2234 replacement->ToUC16Vector(),
2235 capture_count,
2236 subject_length);
2237 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002238 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002239 int substring_index = 0;
2240 for (int i = 0, n = parts_.length(); i < n; i++) {
2241 int tag = parts_[i].tag;
2242 if (tag <= 0) { // A replacement string slice.
2243 int from = -tag;
2244 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002245 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002246 parts_[i].tag = REPLACEMENT_SUBSTRING;
2247 parts_[i].data = substring_index;
2248 substring_index++;
2249 } else if (tag == REPLACEMENT_STRING) {
2250 replacement_substrings_.Add(replacement);
2251 parts_[i].data = substring_index;
2252 substring_index++;
2253 }
2254 }
2255}
2256
2257
2258void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2259 int match_from,
2260 int match_to,
2261 Handle<JSArray> last_match_info) {
2262 for (int i = 0, n = parts_.length(); i < n; i++) {
2263 ReplacementPart part = parts_[i];
2264 switch (part.tag) {
2265 case SUBJECT_PREFIX:
2266 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2267 break;
2268 case SUBJECT_SUFFIX: {
2269 int subject_length = part.data;
2270 if (match_to < subject_length) {
2271 builder->AddSubjectSlice(match_to, subject_length);
2272 }
2273 break;
2274 }
2275 case SUBJECT_CAPTURE: {
2276 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002277 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002278 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2279 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2280 if (from >= 0 && to > from) {
2281 builder->AddSubjectSlice(from, to);
2282 }
2283 break;
2284 }
2285 case REPLACEMENT_SUBSTRING:
2286 case REPLACEMENT_STRING:
2287 builder->AddString(replacement_substrings_[part.data]);
2288 break;
2289 default:
2290 UNREACHABLE();
2291 }
2292 }
2293}
2294
2295
2296
2297static Object* StringReplaceRegExpWithString(String* subject,
2298 JSRegExp* regexp,
2299 String* replacement,
2300 JSArray* last_match_info) {
2301 ASSERT(subject->IsFlat());
2302 ASSERT(replacement->IsFlat());
2303
2304 HandleScope handles;
2305
2306 int length = subject->length();
2307 Handle<String> subject_handle(subject);
2308 Handle<JSRegExp> regexp_handle(regexp);
2309 Handle<String> replacement_handle(replacement);
2310 Handle<JSArray> last_match_info_handle(last_match_info);
2311 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2312 subject_handle,
2313 0,
2314 last_match_info_handle);
2315 if (match.is_null()) {
2316 return Failure::Exception();
2317 }
2318 if (match->IsNull()) {
2319 return *subject_handle;
2320 }
2321
2322 int capture_count = regexp_handle->CaptureCount();
2323
2324 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002325 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002326 CompiledReplacement compiled_replacement;
2327 compiled_replacement.Compile(replacement_handle,
2328 capture_count,
2329 length);
2330
2331 bool is_global = regexp_handle->GetFlags().is_global();
2332
2333 // Guessing the number of parts that the final result string is built
2334 // from. Global regexps can match any number of times, so we guess
2335 // conservatively.
2336 int expected_parts =
2337 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2338 ReplacementStringBuilder builder(subject_handle, expected_parts);
2339
2340 // Index of end of last match.
2341 int prev = 0;
2342
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002343 // Number of parts added by compiled replacement plus preceeding
2344 // string and possibly suffix after last match. It is possible for
2345 // all components to use two elements when encoded as two smis.
2346 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002347 bool matched = true;
2348 do {
2349 ASSERT(last_match_info_handle->HasFastElements());
2350 // Increase the capacity of the builder before entering local handle-scope,
2351 // so its internal buffer can safely allocate a new handle if it grows.
2352 builder.EnsureCapacity(parts_added_per_loop);
2353
2354 HandleScope loop_scope;
2355 int start, end;
2356 {
2357 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002358 FixedArray* match_info_array =
2359 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002360
2361 ASSERT_EQ(capture_count * 2 + 2,
2362 RegExpImpl::GetLastCaptureCount(match_info_array));
2363 start = RegExpImpl::GetCapture(match_info_array, 0);
2364 end = RegExpImpl::GetCapture(match_info_array, 1);
2365 }
2366
2367 if (prev < start) {
2368 builder.AddSubjectSlice(prev, start);
2369 }
2370 compiled_replacement.Apply(&builder,
2371 start,
2372 end,
2373 last_match_info_handle);
2374 prev = end;
2375
2376 // Only continue checking for global regexps.
2377 if (!is_global) break;
2378
2379 // Continue from where the match ended, unless it was an empty match.
2380 int next = end;
2381 if (start == end) {
2382 next = end + 1;
2383 if (next > length) break;
2384 }
2385
2386 match = RegExpImpl::Exec(regexp_handle,
2387 subject_handle,
2388 next,
2389 last_match_info_handle);
2390 if (match.is_null()) {
2391 return Failure::Exception();
2392 }
2393 matched = !match->IsNull();
2394 } while (matched);
2395
2396 if (prev < length) {
2397 builder.AddSubjectSlice(prev, length);
2398 }
2399
2400 return *(builder.ToString());
2401}
2402
2403
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002404template <typename ResultSeqString>
2405static Object* StringReplaceRegExpWithEmptyString(String* subject,
2406 JSRegExp* regexp,
2407 JSArray* last_match_info) {
2408 ASSERT(subject->IsFlat());
2409
2410 HandleScope handles;
2411
2412 Handle<String> subject_handle(subject);
2413 Handle<JSRegExp> regexp_handle(regexp);
2414 Handle<JSArray> last_match_info_handle(last_match_info);
2415 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2416 subject_handle,
2417 0,
2418 last_match_info_handle);
2419 if (match.is_null()) return Failure::Exception();
2420 if (match->IsNull()) return *subject_handle;
2421
2422 ASSERT(last_match_info_handle->HasFastElements());
2423
2424 HandleScope loop_scope;
2425 int start, end;
2426 {
2427 AssertNoAllocation match_info_array_is_not_in_a_handle;
2428 FixedArray* match_info_array =
2429 FixedArray::cast(last_match_info_handle->elements());
2430
2431 start = RegExpImpl::GetCapture(match_info_array, 0);
2432 end = RegExpImpl::GetCapture(match_info_array, 1);
2433 }
2434
2435 int length = subject->length();
2436 int new_length = length - (end - start);
2437 if (new_length == 0) {
2438 return Heap::empty_string();
2439 }
2440 Handle<ResultSeqString> answer;
2441 if (ResultSeqString::kHasAsciiEncoding) {
2442 answer =
2443 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2444 } else {
2445 answer =
2446 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2447 }
2448
2449 // If the regexp isn't global, only match once.
2450 if (!regexp_handle->GetFlags().is_global()) {
2451 if (start > 0) {
2452 String::WriteToFlat(*subject_handle,
2453 answer->GetChars(),
2454 0,
2455 start);
2456 }
2457 if (end < length) {
2458 String::WriteToFlat(*subject_handle,
2459 answer->GetChars() + start,
2460 end,
2461 length);
2462 }
2463 return *answer;
2464 }
2465
2466 int prev = 0; // Index of end of last match.
2467 int next = 0; // Start of next search (prev unless last match was empty).
2468 int position = 0;
2469
2470 do {
2471 if (prev < start) {
2472 // Add substring subject[prev;start] to answer string.
2473 String::WriteToFlat(*subject_handle,
2474 answer->GetChars() + position,
2475 prev,
2476 start);
2477 position += start - prev;
2478 }
2479 prev = end;
2480 next = end;
2481 // Continue from where the match ended, unless it was an empty match.
2482 if (start == end) {
2483 next++;
2484 if (next > length) break;
2485 }
2486 match = RegExpImpl::Exec(regexp_handle,
2487 subject_handle,
2488 next,
2489 last_match_info_handle);
2490 if (match.is_null()) return Failure::Exception();
2491 if (match->IsNull()) break;
2492
2493 ASSERT(last_match_info_handle->HasFastElements());
2494 HandleScope loop_scope;
2495 {
2496 AssertNoAllocation match_info_array_is_not_in_a_handle;
2497 FixedArray* match_info_array =
2498 FixedArray::cast(last_match_info_handle->elements());
2499 start = RegExpImpl::GetCapture(match_info_array, 0);
2500 end = RegExpImpl::GetCapture(match_info_array, 1);
2501 }
2502 } while (true);
2503
2504 if (prev < length) {
2505 // Add substring subject[prev;length] to answer string.
2506 String::WriteToFlat(*subject_handle,
2507 answer->GetChars() + position,
2508 prev,
2509 length);
2510 position += length - prev;
2511 }
2512
2513 if (position == 0) {
2514 return Heap::empty_string();
2515 }
2516
2517 // Shorten string and fill
2518 int string_size = ResultSeqString::SizeFor(position);
2519 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2520 int delta = allocated_string_size - string_size;
2521
2522 answer->set_length(position);
2523 if (delta == 0) return *answer;
2524
2525 Address end_of_string = answer->address() + string_size;
2526 Heap::CreateFillerObjectAt(end_of_string, delta);
2527
2528 return *answer;
2529}
2530
2531
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002532static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
2533 ASSERT(args.length() == 4);
2534
2535 CONVERT_CHECKED(String, subject, args[0]);
2536 if (!subject->IsFlat()) {
2537 Object* flat_subject = subject->TryFlatten();
2538 if (flat_subject->IsFailure()) {
2539 return flat_subject;
2540 }
2541 subject = String::cast(flat_subject);
2542 }
2543
2544 CONVERT_CHECKED(String, replacement, args[2]);
2545 if (!replacement->IsFlat()) {
2546 Object* flat_replacement = replacement->TryFlatten();
2547 if (flat_replacement->IsFailure()) {
2548 return flat_replacement;
2549 }
2550 replacement = String::cast(flat_replacement);
2551 }
2552
2553 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2554 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2555
2556 ASSERT(last_match_info->HasFastElements());
2557
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002558 if (replacement->length() == 0) {
2559 if (subject->HasOnlyAsciiChars()) {
2560 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2561 subject, regexp, last_match_info);
2562 } else {
2563 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2564 subject, regexp, last_match_info);
2565 }
2566 }
2567
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002568 return StringReplaceRegExpWithString(subject,
2569 regexp,
2570 replacement,
2571 last_match_info);
2572}
2573
2574
ager@chromium.org7c537e22008-10-16 08:43:32 +00002575// Perform string match of pattern on subject, starting at start index.
2576// Caller must ensure that 0 <= start_index <= sub->length(),
2577// and should check that pat->length() + start_index <= sub->length()
2578int Runtime::StringMatch(Handle<String> sub,
2579 Handle<String> pat,
2580 int start_index) {
2581 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002582 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002583
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002584 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002585 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002586
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002587 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002588 if (start_index + pattern_length > subject_length) return -1;
2589
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002590 if (!sub->IsFlat()) FlattenString(sub);
2591 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002592
ager@chromium.org7c537e22008-10-16 08:43:32 +00002593 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002594 // Extract flattened substrings of cons strings before determining asciiness.
2595 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002596 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002597 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002598 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002599
ager@chromium.org7c537e22008-10-16 08:43:32 +00002600 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002601 if (seq_pat->IsAsciiRepresentation()) {
2602 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2603 if (seq_sub->IsAsciiRepresentation()) {
2604 return StringSearch(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002605 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002606 return StringSearch(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002607 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002608 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2609 if (seq_sub->IsAsciiRepresentation()) {
2610 return StringSearch(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002611 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002612 return StringSearch(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002613}
2614
2615
2616static Object* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002617 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002618 ASSERT(args.length() == 3);
2619
ager@chromium.org7c537e22008-10-16 08:43:32 +00002620 CONVERT_ARG_CHECKED(String, sub, 0);
2621 CONVERT_ARG_CHECKED(String, pat, 1);
2622
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002623 Object* index = args[2];
2624 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002625 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002626
ager@chromium.org870a0b62008-11-04 11:43:05 +00002627 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002628 int position = Runtime::StringMatch(sub, pat, start_index);
2629 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002630}
2631
2632
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002633template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002634static int StringMatchBackwards(Vector<const schar> subject,
2635 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002636 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002637 int pattern_length = pattern.length();
2638 ASSERT(pattern_length >= 1);
2639 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002640
2641 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002642 for (int i = 0; i < pattern_length; i++) {
2643 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002644 if (c > String::kMaxAsciiCharCode) {
2645 return -1;
2646 }
2647 }
2648 }
2649
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002650 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002651 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002652 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002653 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002654 while (j < pattern_length) {
2655 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002656 break;
2657 }
2658 j++;
2659 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002660 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002661 return i;
2662 }
2663 }
2664 return -1;
2665}
2666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002667static Object* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002668 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002669 ASSERT(args.length() == 3);
2670
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002671 CONVERT_ARG_CHECKED(String, sub, 0);
2672 CONVERT_ARG_CHECKED(String, pat, 1);
2673
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002674 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002675 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002676 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002677
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002678 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002679 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002680
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002681 if (start_index + pat_length > sub_length) {
2682 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002683 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002684
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002685 if (pat_length == 0) {
2686 return Smi::FromInt(start_index);
2687 }
2688
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002689 if (!sub->IsFlat()) FlattenString(sub);
2690 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002691
2692 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2693
2694 int position = -1;
2695
2696 if (pat->IsAsciiRepresentation()) {
2697 Vector<const char> pat_vector = pat->ToAsciiVector();
2698 if (sub->IsAsciiRepresentation()) {
2699 position = StringMatchBackwards(sub->ToAsciiVector(),
2700 pat_vector,
2701 start_index);
2702 } else {
2703 position = StringMatchBackwards(sub->ToUC16Vector(),
2704 pat_vector,
2705 start_index);
2706 }
2707 } else {
2708 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2709 if (sub->IsAsciiRepresentation()) {
2710 position = StringMatchBackwards(sub->ToAsciiVector(),
2711 pat_vector,
2712 start_index);
2713 } else {
2714 position = StringMatchBackwards(sub->ToUC16Vector(),
2715 pat_vector,
2716 start_index);
2717 }
2718 }
2719
2720 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002721}
2722
2723
2724static Object* Runtime_StringLocaleCompare(Arguments args) {
2725 NoHandleAllocation ha;
2726 ASSERT(args.length() == 2);
2727
2728 CONVERT_CHECKED(String, str1, args[0]);
2729 CONVERT_CHECKED(String, str2, args[1]);
2730
2731 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002732 int str1_length = str1->length();
2733 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002734
2735 // Decide trivial cases without flattening.
2736 if (str1_length == 0) {
2737 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2738 return Smi::FromInt(-str2_length);
2739 } else {
2740 if (str2_length == 0) return Smi::FromInt(str1_length);
2741 }
2742
2743 int end = str1_length < str2_length ? str1_length : str2_length;
2744
2745 // No need to flatten if we are going to find the answer on the first
2746 // character. At this point we know there is at least one character
2747 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002748 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002749 if (d != 0) return Smi::FromInt(d);
2750
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002751 str1->TryFlatten();
2752 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002753
2754 static StringInputBuffer buf1;
2755 static StringInputBuffer buf2;
2756
2757 buf1.Reset(str1);
2758 buf2.Reset(str2);
2759
2760 for (int i = 0; i < end; i++) {
2761 uint16_t char1 = buf1.GetNext();
2762 uint16_t char2 = buf2.GetNext();
2763 if (char1 != char2) return Smi::FromInt(char1 - char2);
2764 }
2765
2766 return Smi::FromInt(str1_length - str2_length);
2767}
2768
2769
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002770static Object* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002771 NoHandleAllocation ha;
2772 ASSERT(args.length() == 3);
2773
2774 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002775 Object* from = args[1];
2776 Object* to = args[2];
2777 int start, end;
2778 // We have a fast integer-only case here to avoid a conversion to double in
2779 // the common case where from and to are Smis.
2780 if (from->IsSmi() && to->IsSmi()) {
2781 start = Smi::cast(from)->value();
2782 end = Smi::cast(to)->value();
2783 } else {
2784 CONVERT_DOUBLE_CHECKED(from_number, from);
2785 CONVERT_DOUBLE_CHECKED(to_number, to);
2786 start = FastD2I(from_number);
2787 end = FastD2I(to_number);
2788 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002789 RUNTIME_ASSERT(end >= start);
2790 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002791 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002792 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002793 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002794}
2795
2796
ager@chromium.org41826e72009-03-30 13:30:57 +00002797static Object* Runtime_StringMatch(Arguments args) {
2798 ASSERT_EQ(3, args.length());
2799
2800 CONVERT_ARG_CHECKED(String, subject, 0);
2801 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2802 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2803 HandleScope handles;
2804
2805 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2806
2807 if (match.is_null()) {
2808 return Failure::Exception();
2809 }
2810 if (match->IsNull()) {
2811 return Heap::null_value();
2812 }
2813 int length = subject->length();
2814
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002815 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002816 ZoneList<int> offsets(8);
2817 do {
2818 int start;
2819 int end;
2820 {
2821 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002822 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002823 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2824 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2825 }
2826 offsets.Add(start);
2827 offsets.Add(end);
2828 int index = start < end ? end : end + 1;
2829 if (index > length) break;
2830 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2831 if (match.is_null()) {
2832 return Failure::Exception();
2833 }
2834 } while (!match->IsNull());
2835 int matches = offsets.length() / 2;
2836 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2837 for (int i = 0; i < matches ; i++) {
2838 int from = offsets.at(i * 2);
2839 int to = offsets.at(i * 2 + 1);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002840 elements->set(i, *Factory::NewSubString(subject, from, to));
ager@chromium.org41826e72009-03-30 13:30:57 +00002841 }
2842 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2843 result->set_length(Smi::FromInt(matches));
2844 return *result;
2845}
2846
2847
lrn@chromium.org25156de2010-04-06 13:10:27 +00002848// Two smis before and after the match, for very long strings.
2849const int kMaxBuilderEntriesPerRegExpMatch = 5;
2850
2851
2852static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2853 Handle<JSArray> last_match_info,
2854 int match_start,
2855 int match_end) {
2856 // Fill last_match_info with a single capture.
2857 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2858 AssertNoAllocation no_gc;
2859 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2860 RegExpImpl::SetLastCaptureCount(elements, 2);
2861 RegExpImpl::SetLastInput(elements, *subject);
2862 RegExpImpl::SetLastSubject(elements, *subject);
2863 RegExpImpl::SetCapture(elements, 0, match_start);
2864 RegExpImpl::SetCapture(elements, 1, match_end);
2865}
2866
2867
lrn@chromium.org25156de2010-04-06 13:10:27 +00002868template <typename schar, typename pchar>
2869static bool SearchStringMultiple(Vector<schar> subject,
2870 String* pattern,
2871 Vector<pchar> pattern_string,
2872 FixedArrayBuilder* builder,
2873 int* match_pos) {
2874 int pos = *match_pos;
2875 int subject_length = subject.length();
2876 int pattern_length = pattern_string.length();
2877 int max_search_start = subject_length - pattern_length;
2878 bool is_ascii = (sizeof(schar) == 1);
2879 StringSearchStrategy strategy =
2880 InitializeStringSearch(pattern_string, is_ascii);
2881 switch (strategy) {
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002882 case SEARCH_FAIL: break;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002883 case SEARCH_SHORT:
2884 while (pos <= max_search_start) {
2885 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2886 *match_pos = pos;
2887 return false;
2888 }
2889 // Position of end of previous match.
2890 int match_end = pos + pattern_length;
2891 int new_pos = SimpleIndexOf(subject, pattern_string, match_end);
2892 if (new_pos >= 0) {
2893 // A match.
2894 if (new_pos > match_end) {
2895 ReplacementStringBuilder::AddSubjectSlice(builder,
2896 match_end,
2897 new_pos);
2898 }
2899 pos = new_pos;
2900 builder->Add(pattern);
2901 } else {
2902 break;
2903 }
2904 }
2905 break;
2906 case SEARCH_LONG:
2907 while (pos <= max_search_start) {
2908 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002909 *match_pos = pos;
2910 return false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002911 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002912 int match_end = pos + pattern_length;
2913 int new_pos = ComplexIndexOf(subject, pattern_string, match_end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002914 if (new_pos >= 0) {
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002915 // A match has been found.
2916 if (new_pos > match_end) {
2917 ReplacementStringBuilder::AddSubjectSlice(builder,
2918 match_end,
2919 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002920 }
2921 pos = new_pos;
2922 builder->Add(pattern);
2923 } else {
2924 break;
2925 }
2926 }
2927 break;
2928 }
2929 if (pos < max_search_start) {
2930 ReplacementStringBuilder::AddSubjectSlice(builder,
2931 pos + pattern_length,
2932 subject_length);
2933 }
2934 *match_pos = pos;
2935 return true;
2936}
2937
2938
2939static bool SearchStringMultiple(Handle<String> subject,
2940 Handle<String> pattern,
2941 Handle<JSArray> last_match_info,
2942 FixedArrayBuilder* builder) {
2943 ASSERT(subject->IsFlat());
2944 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002945
2946 // Treating as if a previous match was before first character.
2947 int match_pos = -pattern->length();
2948
2949 for (;;) { // Break when search complete.
2950 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
2951 AssertNoAllocation no_gc;
2952 if (subject->IsAsciiRepresentation()) {
2953 Vector<const char> subject_vector = subject->ToAsciiVector();
2954 if (pattern->IsAsciiRepresentation()) {
2955 if (SearchStringMultiple(subject_vector,
2956 *pattern,
2957 pattern->ToAsciiVector(),
2958 builder,
2959 &match_pos)) break;
2960 } else {
2961 if (SearchStringMultiple(subject_vector,
2962 *pattern,
2963 pattern->ToUC16Vector(),
2964 builder,
2965 &match_pos)) break;
2966 }
2967 } else {
2968 Vector<const uc16> subject_vector = subject->ToUC16Vector();
2969 if (pattern->IsAsciiRepresentation()) {
2970 if (SearchStringMultiple(subject_vector,
2971 *pattern,
2972 pattern->ToAsciiVector(),
2973 builder,
2974 &match_pos)) break;
2975 } else {
2976 if (SearchStringMultiple(subject_vector,
2977 *pattern,
2978 pattern->ToUC16Vector(),
2979 builder,
2980 &match_pos)) break;
2981 }
2982 }
2983 }
2984
2985 if (match_pos >= 0) {
2986 SetLastMatchInfoNoCaptures(subject,
2987 last_match_info,
2988 match_pos,
2989 match_pos + pattern->length());
2990 return true;
2991 }
2992 return false; // No matches at all.
2993}
2994
2995
2996static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
2997 Handle<String> subject,
2998 Handle<JSRegExp> regexp,
2999 Handle<JSArray> last_match_array,
3000 FixedArrayBuilder* builder) {
3001 ASSERT(subject->IsFlat());
3002 int match_start = -1;
3003 int match_end = 0;
3004 int pos = 0;
3005 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3006 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3007
3008 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003009 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003010 int subject_length = subject->length();
3011
3012 for (;;) { // Break on failure, return on exception.
3013 RegExpImpl::IrregexpResult result =
3014 RegExpImpl::IrregexpExecOnce(regexp,
3015 subject,
3016 pos,
3017 register_vector);
3018 if (result == RegExpImpl::RE_SUCCESS) {
3019 match_start = register_vector[0];
3020 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3021 if (match_end < match_start) {
3022 ReplacementStringBuilder::AddSubjectSlice(builder,
3023 match_end,
3024 match_start);
3025 }
3026 match_end = register_vector[1];
3027 HandleScope loop_scope;
3028 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3029 if (match_start != match_end) {
3030 pos = match_end;
3031 } else {
3032 pos = match_end + 1;
3033 if (pos > subject_length) break;
3034 }
3035 } else if (result == RegExpImpl::RE_FAILURE) {
3036 break;
3037 } else {
3038 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3039 return result;
3040 }
3041 }
3042
3043 if (match_start >= 0) {
3044 if (match_end < subject_length) {
3045 ReplacementStringBuilder::AddSubjectSlice(builder,
3046 match_end,
3047 subject_length);
3048 }
3049 SetLastMatchInfoNoCaptures(subject,
3050 last_match_array,
3051 match_start,
3052 match_end);
3053 return RegExpImpl::RE_SUCCESS;
3054 } else {
3055 return RegExpImpl::RE_FAILURE; // No matches at all.
3056 }
3057}
3058
3059
3060static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3061 Handle<String> subject,
3062 Handle<JSRegExp> regexp,
3063 Handle<JSArray> last_match_array,
3064 FixedArrayBuilder* builder) {
3065
3066 ASSERT(subject->IsFlat());
3067 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3068 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3069
3070 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003071 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003072
3073 RegExpImpl::IrregexpResult result =
3074 RegExpImpl::IrregexpExecOnce(regexp,
3075 subject,
3076 0,
3077 register_vector);
3078
3079 int capture_count = regexp->CaptureCount();
3080 int subject_length = subject->length();
3081
3082 // Position to search from.
3083 int pos = 0;
3084 // End of previous match. Differs from pos if match was empty.
3085 int match_end = 0;
3086 if (result == RegExpImpl::RE_SUCCESS) {
3087 // Need to keep a copy of the previous match for creating last_match_info
3088 // at the end, so we have two vectors that we swap between.
3089 OffsetsVector registers2(required_registers);
3090 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3091
3092 do {
3093 int match_start = register_vector[0];
3094 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3095 if (match_end < match_start) {
3096 ReplacementStringBuilder::AddSubjectSlice(builder,
3097 match_end,
3098 match_start);
3099 }
3100 match_end = register_vector[1];
3101
3102 {
3103 // Avoid accumulating new handles inside loop.
3104 HandleScope temp_scope;
3105 // Arguments array to replace function is match, captures, index and
3106 // subject, i.e., 3 + capture count in total.
3107 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
3108 elements->set(0, *Factory::NewSubString(subject,
3109 match_start,
3110 match_end));
3111 for (int i = 1; i <= capture_count; i++) {
3112 int start = register_vector[i * 2];
3113 if (start >= 0) {
3114 int end = register_vector[i * 2 + 1];
3115 ASSERT(start <= end);
3116 Handle<String> substring = Factory::NewSubString(subject,
3117 start,
3118 end);
3119 elements->set(i, *substring);
3120 } else {
3121 ASSERT(register_vector[i * 2 + 1] < 0);
3122 elements->set(i, Heap::undefined_value());
3123 }
3124 }
3125 elements->set(capture_count + 1, Smi::FromInt(match_start));
3126 elements->set(capture_count + 2, *subject);
3127 builder->Add(*Factory::NewJSArrayWithElements(elements));
3128 }
3129 // Swap register vectors, so the last successful match is in
3130 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003131 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003132 prev_register_vector = register_vector;
3133 register_vector = tmp;
3134
3135 if (match_end > match_start) {
3136 pos = match_end;
3137 } else {
3138 pos = match_end + 1;
3139 if (pos > subject_length) {
3140 break;
3141 }
3142 }
3143
3144 result = RegExpImpl::IrregexpExecOnce(regexp,
3145 subject,
3146 pos,
3147 register_vector);
3148 } while (result == RegExpImpl::RE_SUCCESS);
3149
3150 if (result != RegExpImpl::RE_EXCEPTION) {
3151 // Finished matching, with at least one match.
3152 if (match_end < subject_length) {
3153 ReplacementStringBuilder::AddSubjectSlice(builder,
3154 match_end,
3155 subject_length);
3156 }
3157
3158 int last_match_capture_count = (capture_count + 1) * 2;
3159 int last_match_array_size =
3160 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3161 last_match_array->EnsureSize(last_match_array_size);
3162 AssertNoAllocation no_gc;
3163 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3164 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3165 RegExpImpl::SetLastSubject(elements, *subject);
3166 RegExpImpl::SetLastInput(elements, *subject);
3167 for (int i = 0; i < last_match_capture_count; i++) {
3168 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3169 }
3170 return RegExpImpl::RE_SUCCESS;
3171 }
3172 }
3173 // No matches at all, return failure or exception result directly.
3174 return result;
3175}
3176
3177
3178static Object* Runtime_RegExpExecMultiple(Arguments args) {
3179 ASSERT(args.length() == 4);
3180 HandleScope handles;
3181
3182 CONVERT_ARG_CHECKED(String, subject, 1);
3183 if (!subject->IsFlat()) { FlattenString(subject); }
3184 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3185 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3186 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3187
3188 ASSERT(last_match_info->HasFastElements());
3189 ASSERT(regexp->GetFlags().is_global());
3190 Handle<FixedArray> result_elements;
3191 if (result_array->HasFastElements()) {
3192 result_elements =
3193 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3194 } else {
3195 result_elements = Factory::NewFixedArrayWithHoles(16);
3196 }
3197 FixedArrayBuilder builder(result_elements);
3198
3199 if (regexp->TypeTag() == JSRegExp::ATOM) {
3200 Handle<String> pattern(
3201 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003202 if (!pattern->IsFlat()) FlattenString(pattern);
3203 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3204 return *builder.ToJSArray(result_array);
3205 }
3206 return Heap::null_value();
3207 }
3208
3209 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3210
3211 RegExpImpl::IrregexpResult result;
3212 if (regexp->CaptureCount() == 0) {
3213 result = SearchRegExpNoCaptureMultiple(subject,
3214 regexp,
3215 last_match_info,
3216 &builder);
3217 } else {
3218 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3219 }
3220 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3221 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3222 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3223 return Failure::Exception();
3224}
3225
3226
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003227static Object* Runtime_NumberToRadixString(Arguments args) {
3228 NoHandleAllocation ha;
3229 ASSERT(args.length() == 2);
3230
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003231 // Fast case where the result is a one character string.
3232 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3233 int value = Smi::cast(args[0])->value();
3234 int radix = Smi::cast(args[1])->value();
3235 if (value >= 0 && value < radix) {
3236 RUNTIME_ASSERT(radix <= 36);
3237 // Character array used for conversion.
3238 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3239 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3240 }
3241 }
3242
3243 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003244 CONVERT_DOUBLE_CHECKED(value, args[0]);
3245 if (isnan(value)) {
3246 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3247 }
3248 if (isinf(value)) {
3249 if (value < 0) {
3250 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3251 }
3252 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3253 }
3254 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3255 int radix = FastD2I(radix_number);
3256 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3257 char* str = DoubleToRadixCString(value, radix);
3258 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
3259 DeleteArray(str);
3260 return result;
3261}
3262
3263
3264static Object* Runtime_NumberToFixed(Arguments args) {
3265 NoHandleAllocation ha;
3266 ASSERT(args.length() == 2);
3267
3268 CONVERT_DOUBLE_CHECKED(value, args[0]);
3269 if (isnan(value)) {
3270 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3271 }
3272 if (isinf(value)) {
3273 if (value < 0) {
3274 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3275 }
3276 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3277 }
3278 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3279 int f = FastD2I(f_number);
3280 RUNTIME_ASSERT(f >= 0);
3281 char* str = DoubleToFixedCString(value, f);
3282 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
3283 DeleteArray(str);
3284 return res;
3285}
3286
3287
3288static Object* Runtime_NumberToExponential(Arguments args) {
3289 NoHandleAllocation ha;
3290 ASSERT(args.length() == 2);
3291
3292 CONVERT_DOUBLE_CHECKED(value, args[0]);
3293 if (isnan(value)) {
3294 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3295 }
3296 if (isinf(value)) {
3297 if (value < 0) {
3298 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3299 }
3300 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3301 }
3302 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3303 int f = FastD2I(f_number);
3304 RUNTIME_ASSERT(f >= -1 && f <= 20);
3305 char* str = DoubleToExponentialCString(value, f);
3306 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
3307 DeleteArray(str);
3308 return res;
3309}
3310
3311
3312static Object* Runtime_NumberToPrecision(Arguments args) {
3313 NoHandleAllocation ha;
3314 ASSERT(args.length() == 2);
3315
3316 CONVERT_DOUBLE_CHECKED(value, args[0]);
3317 if (isnan(value)) {
3318 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3319 }
3320 if (isinf(value)) {
3321 if (value < 0) {
3322 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3323 }
3324 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3325 }
3326 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3327 int f = FastD2I(f_number);
3328 RUNTIME_ASSERT(f >= 1 && f <= 21);
3329 char* str = DoubleToPrecisionCString(value, f);
3330 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
3331 DeleteArray(str);
3332 return res;
3333}
3334
3335
3336// Returns a single character string where first character equals
3337// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003338static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003339 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003340 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003341 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003342 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003343 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003344 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003345}
3346
3347
3348Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
3349 // Handle [] indexing on Strings
3350 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003351 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3352 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353 }
3354
3355 // Handle [] indexing on String objects
3356 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003357 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3358 Handle<Object> result =
3359 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3360 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003361 }
3362
3363 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003364 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003365 return prototype->GetElement(index);
3366 }
3367
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003368 return GetElement(object, index);
3369}
3370
3371
3372Object* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003373 return object->GetElement(index);
3374}
3375
3376
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003377Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
3378 HandleScope scope;
3379
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003380 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003381 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003382 Handle<Object> error =
3383 Factory::NewTypeError("non_object_property_load",
3384 HandleVector(args, 2));
3385 return Top::Throw(*error);
3386 }
3387
3388 // Check if the given key is an array index.
3389 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003390 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003391 return GetElementOrCharAt(object, index);
3392 }
3393
3394 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003395 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003396 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003397 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003398 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399 bool has_pending_exception = false;
3400 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003401 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003403 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003404 }
3405
ager@chromium.org32912102009-01-16 10:38:43 +00003406 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407 // the element if so.
3408 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409 return GetElementOrCharAt(object, index);
3410 } else {
3411 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003412 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003413 }
3414}
3415
3416
3417static Object* Runtime_GetProperty(Arguments args) {
3418 NoHandleAllocation ha;
3419 ASSERT(args.length() == 2);
3420
3421 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003422 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003423
3424 return Runtime::GetObjectProperty(object, key);
3425}
3426
3427
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003428// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003429static Object* Runtime_KeyedGetProperty(Arguments args) {
3430 NoHandleAllocation ha;
3431 ASSERT(args.length() == 2);
3432
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003433 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003434 // itself.
3435 //
3436 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003437 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003438 // global proxy object never has properties. This is the case
3439 // because the global proxy object forwards everything to its hidden
3440 // prototype including local lookups.
3441 //
3442 // Additionally, we need to make sure that we do not cache results
3443 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003444 if (args[0]->IsJSObject() &&
3445 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003446 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003447 args[1]->IsString()) {
3448 JSObject* receiver = JSObject::cast(args[0]);
3449 String* key = String::cast(args[1]);
3450 if (receiver->HasFastProperties()) {
3451 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003452 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003453 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3454 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003455 Object* value = receiver->FastPropertyAt(offset);
3456 return value->IsTheHole() ? Heap::undefined_value() : value;
3457 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003458 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003459 LookupResult result;
3460 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003461 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003462 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003463 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003464 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003465 }
3466 } else {
3467 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003468 StringDictionary* dictionary = receiver->property_dictionary();
3469 int entry = dictionary->FindEntry(key);
3470 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003471 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003472 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003473 if (!receiver->IsGlobalObject()) return value;
3474 value = JSGlobalPropertyCell::cast(value)->value();
3475 if (!value->IsTheHole()) return value;
3476 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003477 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003478 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003479 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3480 // Fast case for string indexing using [] with a smi index.
3481 HandleScope scope;
3482 Handle<String> str = args.at<String>(0);
3483 int index = Smi::cast(args[1])->value();
3484 Handle<Object> result = GetCharAt(str, index);
3485 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003486 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003487
3488 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003489 return Runtime::GetObjectProperty(args.at<Object>(0),
3490 args.at<Object>(1));
3491}
3492
3493
ager@chromium.org5c838252010-02-19 08:53:10 +00003494static Object* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
3495 ASSERT(args.length() == 5);
3496 HandleScope scope;
3497 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3498 CONVERT_CHECKED(String, name, args[1]);
3499 CONVERT_CHECKED(Smi, flag_setter, args[2]);
3500 CONVERT_CHECKED(JSFunction, fun, args[3]);
3501 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3502 int unchecked = flag_attr->value();
3503 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3504 RUNTIME_ASSERT(!obj->IsNull());
3505 LookupResult result;
3506 obj->LocalLookupRealNamedProperty(name, &result);
3507
3508 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3509 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3510 // delete it to avoid running into trouble in DefineAccessor, which
3511 // handles this incorrectly if the property is readonly (does nothing)
3512 if (result.IsProperty() &&
3513 (result.type() == FIELD || result.type() == NORMAL
3514 || result.type() == CONSTANT_FUNCTION)) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003515 Object* ok = obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3516 if (ok->IsFailure()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00003517 }
3518 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3519}
3520
3521static Object* Runtime_DefineOrRedefineDataProperty(Arguments args) {
3522 ASSERT(args.length() == 4);
3523 HandleScope scope;
3524 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3525 CONVERT_ARG_CHECKED(String, name, 1);
3526 Handle<Object> obj_value = args.at<Object>(2);
3527
3528 CONVERT_CHECKED(Smi, flag, args[3]);
3529 int unchecked = flag->value();
3530 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3531
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003532 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3533
3534 // Check if this is an element.
3535 uint32_t index;
3536 bool is_element = name->AsArrayIndex(&index);
3537
3538 // Special case for elements if any of the flags are true.
3539 // If elements are in fast case we always implicitly assume that:
3540 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3541 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3542 is_element) {
3543 // Normalize the elements to enable attributes on the property.
3544 js_object->NormalizeElements();
3545 NumberDictionary* dictionary = js_object->element_dictionary();
3546 // Make sure that we never go back to fast case.
3547 dictionary->set_requires_slow_elements();
3548 PropertyDetails details = PropertyDetails(attr, NORMAL);
3549 dictionary->Set(index, *obj_value, details);
3550 }
3551
ager@chromium.org5c838252010-02-19 08:53:10 +00003552 LookupResult result;
3553 js_object->LocalLookupRealNamedProperty(*name, &result);
3554
ager@chromium.org5c838252010-02-19 08:53:10 +00003555 // Take special care when attributes are different and there is already
3556 // a property. For simplicity we normalize the property which enables us
3557 // to not worry about changing the instance_descriptor and creating a new
3558 // map. The current version of SetObjectProperty does not handle attributes
3559 // correctly in the case where a property is a field and is reset with
3560 // new attributes.
3561 if (result.IsProperty() && attr != result.GetAttributes()) {
3562 // New attributes - normalize to avoid writing to instance descriptor
3563 js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3564 // Use IgnoreAttributes version since a readonly property may be
3565 // overridden and SetProperty does not allow this.
3566 return js_object->IgnoreAttributesAndSetLocalProperty(*name,
3567 *obj_value,
3568 attr);
3569 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003570
ager@chromium.org5c838252010-02-19 08:53:10 +00003571 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3572}
3573
3574
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003575Object* Runtime::SetObjectProperty(Handle<Object> object,
3576 Handle<Object> key,
3577 Handle<Object> value,
3578 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003579 HandleScope scope;
3580
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003582 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003583 Handle<Object> error =
3584 Factory::NewTypeError("non_object_property_store",
3585 HandleVector(args, 2));
3586 return Top::Throw(*error);
3587 }
3588
3589 // If the object isn't a JavaScript object, we ignore the store.
3590 if (!object->IsJSObject()) return *value;
3591
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003592 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3593
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003594 // Check if the given key is an array index.
3595 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003596 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3598 // of a string using [] notation. We need to support this too in
3599 // JavaScript.
3600 // In the case of a String object we just need to redirect the assignment to
3601 // the underlying string if the index is in range. Since the underlying
3602 // string does nothing with the assignment then we can ignore such
3603 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003604 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003606 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003607
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003608 Handle<Object> result = SetElement(js_object, index, value);
3609 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 return *value;
3611 }
3612
3613 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003614 Handle<Object> result;
3615 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003616 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003617 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003618 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003619 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003620 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003621 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003622 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003623 return *value;
3624 }
3625
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003626 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003627 bool has_pending_exception = false;
3628 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3629 if (has_pending_exception) return Failure::Exception();
3630 Handle<String> name = Handle<String>::cast(converted);
3631
3632 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003633 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003635 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003636 }
3637}
3638
3639
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003640Object* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3641 Handle<Object> key,
3642 Handle<Object> value,
3643 PropertyAttributes attr) {
3644 HandleScope scope;
3645
3646 // Check if the given key is an array index.
3647 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003648 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003649 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3650 // of a string using [] notation. We need to support this too in
3651 // JavaScript.
3652 // In the case of a String object we just need to redirect the assignment to
3653 // the underlying string if the index is in range. Since the underlying
3654 // string does nothing with the assignment then we can ignore such
3655 // assignments.
3656 if (js_object->IsStringObjectWithCharacterAt(index)) {
3657 return *value;
3658 }
3659
3660 return js_object->SetElement(index, *value);
3661 }
3662
3663 if (key->IsString()) {
3664 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003665 return js_object->SetElement(index, *value);
3666 } else {
3667 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003668 key_string->TryFlatten();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003669 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
3670 *value,
3671 attr);
3672 }
3673 }
3674
3675 // Call-back into JavaScript to convert the key to a string.
3676 bool has_pending_exception = false;
3677 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3678 if (has_pending_exception) return Failure::Exception();
3679 Handle<String> name = Handle<String>::cast(converted);
3680
3681 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003682 return js_object->SetElement(index, *value);
3683 } else {
3684 return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr);
3685 }
3686}
3687
3688
ager@chromium.orge2902be2009-06-08 12:21:35 +00003689Object* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3690 Handle<Object> key) {
3691 HandleScope scope;
3692
3693 // Check if the given key is an array index.
3694 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003695 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003696 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3697 // characters of a string using [] notation. In the case of a
3698 // String object we just need to redirect the deletion to the
3699 // underlying string if the index is in range. Since the
3700 // underlying string does nothing with the deletion, we can ignore
3701 // such deletions.
3702 if (js_object->IsStringObjectWithCharacterAt(index)) {
3703 return Heap::true_value();
3704 }
3705
3706 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3707 }
3708
3709 Handle<String> key_string;
3710 if (key->IsString()) {
3711 key_string = Handle<String>::cast(key);
3712 } else {
3713 // Call-back into JavaScript to convert the key to a string.
3714 bool has_pending_exception = false;
3715 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3716 if (has_pending_exception) return Failure::Exception();
3717 key_string = Handle<String>::cast(converted);
3718 }
3719
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003720 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003721 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3722}
3723
3724
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725static Object* Runtime_SetProperty(Arguments args) {
3726 NoHandleAllocation ha;
3727 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3728
3729 Handle<Object> object = args.at<Object>(0);
3730 Handle<Object> key = args.at<Object>(1);
3731 Handle<Object> value = args.at<Object>(2);
3732
3733 // Compute attributes.
3734 PropertyAttributes attributes = NONE;
3735 if (args.length() == 4) {
3736 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003737 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003738 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003739 RUNTIME_ASSERT(
3740 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3741 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003742 }
3743 return Runtime::SetObjectProperty(object, key, value, attributes);
3744}
3745
3746
3747// Set a local property, even if it is READ_ONLY. If the property does not
3748// exist, it will be added with attributes NONE.
3749static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
3750 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003751 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752 CONVERT_CHECKED(JSObject, object, args[0]);
3753 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003754 // Compute attributes.
3755 PropertyAttributes attributes = NONE;
3756 if (args.length() == 4) {
3757 CONVERT_CHECKED(Smi, value_obj, args[3]);
3758 int unchecked_value = value_obj->value();
3759 // Only attribute bits should be set.
3760 RUNTIME_ASSERT(
3761 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3762 attributes = static_cast<PropertyAttributes>(unchecked_value);
3763 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003765 return object->
3766 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767}
3768
3769
3770static Object* Runtime_DeleteProperty(Arguments args) {
3771 NoHandleAllocation ha;
3772 ASSERT(args.length() == 2);
3773
3774 CONVERT_CHECKED(JSObject, object, args[0]);
3775 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003776 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777}
3778
3779
ager@chromium.org9085a012009-05-11 19:22:57 +00003780static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3781 Handle<String> key) {
3782 if (object->HasLocalProperty(*key)) return Heap::true_value();
3783 // Handle hidden prototypes. If there's a hidden prototype above this thing
3784 // then we have to check it for properties, because they are supposed to
3785 // look like they are on this object.
3786 Handle<Object> proto(object->GetPrototype());
3787 if (proto->IsJSObject() &&
3788 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3789 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3790 }
3791 return Heap::false_value();
3792}
3793
3794
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003795static Object* Runtime_HasLocalProperty(Arguments args) {
3796 NoHandleAllocation ha;
3797 ASSERT(args.length() == 2);
3798 CONVERT_CHECKED(String, key, args[1]);
3799
ager@chromium.org9085a012009-05-11 19:22:57 +00003800 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003801 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003802 if (obj->IsJSObject()) {
3803 JSObject* object = JSObject::cast(obj);
3804 // Fast case - no interceptors.
3805 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3806 // Slow case. Either it's not there or we have an interceptor. We should
3807 // have handles for this kind of deal.
3808 HandleScope scope;
3809 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3810 Handle<String>(key));
3811 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812 // Well, there is one exception: Handle [] on strings.
3813 uint32_t index;
3814 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003815 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003816 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003817 return Heap::true_value();
3818 }
3819 }
3820 return Heap::false_value();
3821}
3822
3823
3824static Object* Runtime_HasProperty(Arguments args) {
3825 NoHandleAllocation na;
3826 ASSERT(args.length() == 2);
3827
3828 // Only JS objects can have properties.
3829 if (args[0]->IsJSObject()) {
3830 JSObject* object = JSObject::cast(args[0]);
3831 CONVERT_CHECKED(String, key, args[1]);
3832 if (object->HasProperty(key)) return Heap::true_value();
3833 }
3834 return Heap::false_value();
3835}
3836
3837
3838static Object* Runtime_HasElement(Arguments args) {
3839 NoHandleAllocation na;
3840 ASSERT(args.length() == 2);
3841
3842 // Only JS objects can have elements.
3843 if (args[0]->IsJSObject()) {
3844 JSObject* object = JSObject::cast(args[0]);
3845 CONVERT_CHECKED(Smi, index_obj, args[1]);
3846 uint32_t index = index_obj->value();
3847 if (object->HasElement(index)) return Heap::true_value();
3848 }
3849 return Heap::false_value();
3850}
3851
3852
3853static Object* Runtime_IsPropertyEnumerable(Arguments args) {
3854 NoHandleAllocation ha;
3855 ASSERT(args.length() == 2);
3856
3857 CONVERT_CHECKED(JSObject, object, args[0]);
3858 CONVERT_CHECKED(String, key, args[1]);
3859
3860 uint32_t index;
3861 if (key->AsArrayIndex(&index)) {
3862 return Heap::ToBoolean(object->HasElement(index));
3863 }
3864
ager@chromium.org870a0b62008-11-04 11:43:05 +00003865 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3866 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003867}
3868
3869
3870static Object* Runtime_GetPropertyNames(Arguments args) {
3871 HandleScope scope;
3872 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003873 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003874 return *GetKeysFor(object);
3875}
3876
3877
3878// Returns either a FixedArray as Runtime_GetPropertyNames,
3879// or, if the given object has an enum cache that contains
3880// all enumerable properties of the object and its prototypes
3881// have none, the map of the object. This is used to speed up
3882// the check for deletions during a for-in.
3883static Object* Runtime_GetPropertyNamesFast(Arguments args) {
3884 ASSERT(args.length() == 1);
3885
3886 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3887
3888 if (raw_object->IsSimpleEnum()) return raw_object->map();
3889
3890 HandleScope scope;
3891 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003892 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3893 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003894
3895 // Test again, since cache may have been built by preceding call.
3896 if (object->IsSimpleEnum()) return object->map();
3897
3898 return *content;
3899}
3900
3901
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003902// Find the length of the prototype chain that is to to handled as one. If a
3903// prototype object is hidden it is to be viewed as part of the the object it
3904// is prototype for.
3905static int LocalPrototypeChainLength(JSObject* obj) {
3906 int count = 1;
3907 Object* proto = obj->GetPrototype();
3908 while (proto->IsJSObject() &&
3909 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3910 count++;
3911 proto = JSObject::cast(proto)->GetPrototype();
3912 }
3913 return count;
3914}
3915
3916
3917// Return the names of the local named properties.
3918// args[0]: object
3919static Object* Runtime_GetLocalPropertyNames(Arguments args) {
3920 HandleScope scope;
3921 ASSERT(args.length() == 1);
3922 if (!args[0]->IsJSObject()) {
3923 return Heap::undefined_value();
3924 }
3925 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3926
3927 // Skip the global proxy as it has no properties and always delegates to the
3928 // real global object.
3929 if (obj->IsJSGlobalProxy()) {
3930 // Only collect names if access is permitted.
3931 if (obj->IsAccessCheckNeeded() &&
3932 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3933 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3934 return *Factory::NewJSArray(0);
3935 }
3936 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3937 }
3938
3939 // Find the number of objects making up this.
3940 int length = LocalPrototypeChainLength(*obj);
3941
3942 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003943 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003944 int total_property_count = 0;
3945 Handle<JSObject> jsproto = obj;
3946 for (int i = 0; i < length; i++) {
3947 // Only collect names if access is permitted.
3948 if (jsproto->IsAccessCheckNeeded() &&
3949 !Top::MayNamedAccess(*jsproto,
3950 Heap::undefined_value(),
3951 v8::ACCESS_KEYS)) {
3952 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
3953 return *Factory::NewJSArray(0);
3954 }
3955 int n;
3956 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3957 local_property_count[i] = n;
3958 total_property_count += n;
3959 if (i < length - 1) {
3960 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3961 }
3962 }
3963
3964 // Allocate an array with storage for all the property names.
3965 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
3966
3967 // Get the property names.
3968 jsproto = obj;
3969 int proto_with_hidden_properties = 0;
3970 for (int i = 0; i < length; i++) {
3971 jsproto->GetLocalPropertyNames(*names,
3972 i == 0 ? 0 : local_property_count[i - 1]);
3973 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
3974 proto_with_hidden_properties++;
3975 }
3976 if (i < length - 1) {
3977 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3978 }
3979 }
3980
3981 // Filter out name of hidden propeties object.
3982 if (proto_with_hidden_properties > 0) {
3983 Handle<FixedArray> old_names = names;
3984 names = Factory::NewFixedArray(
3985 names->length() - proto_with_hidden_properties);
3986 int dest_pos = 0;
3987 for (int i = 0; i < total_property_count; i++) {
3988 Object* name = old_names->get(i);
3989 if (name == Heap::hidden_symbol()) {
3990 continue;
3991 }
3992 names->set(dest_pos++, name);
3993 }
3994 }
3995
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003996 return *Factory::NewJSArrayWithElements(names);
3997}
3998
3999
4000// Return the names of the local indexed properties.
4001// args[0]: object
4002static Object* Runtime_GetLocalElementNames(Arguments args) {
4003 HandleScope scope;
4004 ASSERT(args.length() == 1);
4005 if (!args[0]->IsJSObject()) {
4006 return Heap::undefined_value();
4007 }
4008 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4009
4010 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4011 Handle<FixedArray> names = Factory::NewFixedArray(n);
4012 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4013 return *Factory::NewJSArrayWithElements(names);
4014}
4015
4016
4017// Return information on whether an object has a named or indexed interceptor.
4018// args[0]: object
4019static Object* Runtime_GetInterceptorInfo(Arguments args) {
4020 HandleScope scope;
4021 ASSERT(args.length() == 1);
4022 if (!args[0]->IsJSObject()) {
4023 return Smi::FromInt(0);
4024 }
4025 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4026
4027 int result = 0;
4028 if (obj->HasNamedInterceptor()) result |= 2;
4029 if (obj->HasIndexedInterceptor()) result |= 1;
4030
4031 return Smi::FromInt(result);
4032}
4033
4034
4035// Return property names from named interceptor.
4036// args[0]: object
4037static Object* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
4038 HandleScope scope;
4039 ASSERT(args.length() == 1);
4040 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4041
4042 if (obj->HasNamedInterceptor()) {
4043 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4044 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4045 }
4046 return Heap::undefined_value();
4047}
4048
4049
4050// Return element names from indexed interceptor.
4051// args[0]: object
4052static Object* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
4053 HandleScope scope;
4054 ASSERT(args.length() == 1);
4055 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4056
4057 if (obj->HasIndexedInterceptor()) {
4058 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4059 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4060 }
4061 return Heap::undefined_value();
4062}
4063
4064
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004065static Object* Runtime_LocalKeys(Arguments args) {
4066 ASSERT_EQ(args.length(), 1);
4067 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4068 HandleScope scope;
4069 Handle<JSObject> object(raw_object);
4070 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4071 LOCAL_ONLY);
4072 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4073 // property array and since the result is mutable we have to create
4074 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004075 int length = contents->length();
4076 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4077 for (int i = 0; i < length; i++) {
4078 Object* entry = contents->get(i);
4079 if (entry->IsString()) {
4080 copy->set(i, entry);
4081 } else {
4082 ASSERT(entry->IsNumber());
4083 HandleScope scope;
4084 Handle<Object> entry_handle(entry);
4085 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4086 copy->set(i, *entry_str);
4087 }
4088 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004089 return *Factory::NewJSArrayWithElements(copy);
4090}
4091
4092
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093static Object* Runtime_GetArgumentsProperty(Arguments args) {
4094 NoHandleAllocation ha;
4095 ASSERT(args.length() == 1);
4096
4097 // Compute the frame holding the arguments.
4098 JavaScriptFrameIterator it;
4099 it.AdvanceToArgumentsFrame();
4100 JavaScriptFrame* frame = it.frame();
4101
4102 // Get the actual number of provided arguments.
4103 const uint32_t n = frame->GetProvidedParametersCount();
4104
4105 // Try to convert the key to an index. If successful and within
4106 // index return the the argument from the frame.
4107 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004108 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 return frame->GetParameter(index);
4110 }
4111
4112 // Convert the key to a string.
4113 HandleScope scope;
4114 bool exception = false;
4115 Handle<Object> converted =
4116 Execution::ToString(args.at<Object>(0), &exception);
4117 if (exception) return Failure::Exception();
4118 Handle<String> key = Handle<String>::cast(converted);
4119
4120 // Try to convert the string key into an array index.
4121 if (key->AsArrayIndex(&index)) {
4122 if (index < n) {
4123 return frame->GetParameter(index);
4124 } else {
4125 return Top::initial_object_prototype()->GetElement(index);
4126 }
4127 }
4128
4129 // Handle special arguments properties.
4130 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4131 if (key->Equals(Heap::callee_symbol())) return frame->function();
4132
4133 // Lookup in the initial Object.prototype object.
4134 return Top::initial_object_prototype()->GetProperty(*key);
4135}
4136
4137
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004138static Object* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004139 HandleScope scope;
4140
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004141 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004142 Handle<Object> object = args.at<Object>(0);
4143 if (object->IsJSObject()) {
4144 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004145 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
4146 js_object->TransformToFastProperties(0);
4147 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004148 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004149 return *object;
4150}
4151
4152
4153static Object* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004154 HandleScope scope;
4155
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004156 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004157 Handle<Object> object = args.at<Object>(0);
4158 if (object->IsJSObject()) {
4159 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004160 js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004161 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004162 return *object;
4163}
4164
4165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166static Object* Runtime_ToBool(Arguments args) {
4167 NoHandleAllocation ha;
4168 ASSERT(args.length() == 1);
4169
4170 return args[0]->ToBoolean();
4171}
4172
4173
4174// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4175// Possible optimizations: put the type string into the oddballs.
4176static Object* Runtime_Typeof(Arguments args) {
4177 NoHandleAllocation ha;
4178
4179 Object* obj = args[0];
4180 if (obj->IsNumber()) return Heap::number_symbol();
4181 HeapObject* heap_obj = HeapObject::cast(obj);
4182
4183 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004184 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185
4186 InstanceType instance_type = heap_obj->map()->instance_type();
4187 if (instance_type < FIRST_NONSTRING_TYPE) {
4188 return Heap::string_symbol();
4189 }
4190
4191 switch (instance_type) {
4192 case ODDBALL_TYPE:
4193 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4194 return Heap::boolean_symbol();
4195 }
4196 if (heap_obj->IsNull()) {
4197 return Heap::object_symbol();
4198 }
4199 ASSERT(heap_obj->IsUndefined());
4200 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004201 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 return Heap::function_symbol();
4203 default:
4204 // For any kind of object not handled above, the spec rule for
4205 // host objects gives that it is okay to return "object"
4206 return Heap::object_symbol();
4207 }
4208}
4209
4210
lrn@chromium.org25156de2010-04-06 13:10:27 +00004211static bool AreDigits(const char*s, int from, int to) {
4212 for (int i = from; i < to; i++) {
4213 if (s[i] < '0' || s[i] > '9') return false;
4214 }
4215
4216 return true;
4217}
4218
4219
4220static int ParseDecimalInteger(const char*s, int from, int to) {
4221 ASSERT(to - from < 10); // Overflow is not possible.
4222 ASSERT(from < to);
4223 int d = s[from] - '0';
4224
4225 for (int i = from + 1; i < to; i++) {
4226 d = 10 * d + (s[i] - '0');
4227 }
4228
4229 return d;
4230}
4231
4232
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004233static Object* Runtime_StringToNumber(Arguments args) {
4234 NoHandleAllocation ha;
4235 ASSERT(args.length() == 1);
4236 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004237 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004238
4239 // Fast case: short integer or some sorts of junk values.
4240 int len = subject->length();
4241 if (subject->IsSeqAsciiString()) {
4242 if (len == 0) return Smi::FromInt(0);
4243
4244 char const* data = SeqAsciiString::cast(subject)->GetChars();
4245 bool minus = (data[0] == '-');
4246 int start_pos = (minus ? 1 : 0);
4247
4248 if (start_pos == len) {
4249 return Heap::nan_value();
4250 } else if (data[start_pos] > '9') {
4251 // Fast check for a junk value. A valid string may start from a
4252 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4253 // the 'I' character ('Infinity'). All of that have codes not greater than
4254 // '9' except 'I'.
4255 if (data[start_pos] != 'I') {
4256 return Heap::nan_value();
4257 }
4258 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4259 // The maximal/minimal smi has 10 digits. If the string has less digits we
4260 // know it will fit into the smi-data type.
4261 int d = ParseDecimalInteger(data, start_pos, len);
4262 if (minus) {
4263 if (d == 0) return Heap::minus_zero_value();
4264 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004265 } else if (!subject->HasHashCode() &&
4266 len <= String::kMaxArrayIndexSize &&
4267 (len == 1 || data[0] != '0')) {
4268 // String hash is not calculated yet but all the data are present.
4269 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004270 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004271#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004272 subject->Hash(); // Force hash calculation.
4273 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4274 static_cast<int>(hash));
4275#endif
4276 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004277 }
4278 return Smi::FromInt(d);
4279 }
4280 }
4281
4282 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004283 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4284}
4285
4286
4287static Object* Runtime_StringFromCharCodeArray(Arguments args) {
4288 NoHandleAllocation ha;
4289 ASSERT(args.length() == 1);
4290
4291 CONVERT_CHECKED(JSArray, codes, args[0]);
4292 int length = Smi::cast(codes->length())->value();
4293
4294 // Check if the string can be ASCII.
4295 int i;
4296 for (i = 0; i < length; i++) {
4297 Object* element = codes->GetElement(i);
4298 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4299 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4300 break;
4301 }
4302
4303 Object* object = NULL;
4304 if (i == length) { // The string is ASCII.
4305 object = Heap::AllocateRawAsciiString(length);
4306 } else { // The string is not ASCII.
4307 object = Heap::AllocateRawTwoByteString(length);
4308 }
4309
4310 if (object->IsFailure()) return object;
4311 String* result = String::cast(object);
4312 for (int i = 0; i < length; i++) {
4313 Object* element = codes->GetElement(i);
4314 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004315 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004316 }
4317 return result;
4318}
4319
4320
4321// kNotEscaped is generated by the following:
4322//
4323// #!/bin/perl
4324// for (my $i = 0; $i < 256; $i++) {
4325// print "\n" if $i % 16 == 0;
4326// my $c = chr($i);
4327// my $escaped = 1;
4328// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4329// print $escaped ? "0, " : "1, ";
4330// }
4331
4332
4333static bool IsNotEscaped(uint16_t character) {
4334 // Only for 8 bit characters, the rest are always escaped (in a different way)
4335 ASSERT(character < 256);
4336 static const char kNotEscaped[256] = {
4337 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4338 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4339 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4340 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4341 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4342 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4343 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4344 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4352 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4353 };
4354 return kNotEscaped[character] != 0;
4355}
4356
4357
4358static Object* Runtime_URIEscape(Arguments args) {
4359 const char hex_chars[] = "0123456789ABCDEF";
4360 NoHandleAllocation ha;
4361 ASSERT(args.length() == 1);
4362 CONVERT_CHECKED(String, source, args[0]);
4363
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004364 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004365
4366 int escaped_length = 0;
4367 int length = source->length();
4368 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004369 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004370 buffer->Reset(source);
4371 while (buffer->has_more()) {
4372 uint16_t character = buffer->GetNext();
4373 if (character >= 256) {
4374 escaped_length += 6;
4375 } else if (IsNotEscaped(character)) {
4376 escaped_length++;
4377 } else {
4378 escaped_length += 3;
4379 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004380 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004381 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004382 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004383 Top::context()->mark_out_of_memory();
4384 return Failure::OutOfMemoryException();
4385 }
4386 }
4387 }
4388 // No length change implies no change. Return original string if no change.
4389 if (escaped_length == length) {
4390 return source;
4391 }
4392 Object* o = Heap::AllocateRawAsciiString(escaped_length);
4393 if (o->IsFailure()) return o;
4394 String* destination = String::cast(o);
4395 int dest_position = 0;
4396
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004397 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004398 buffer->Rewind();
4399 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004400 uint16_t chr = buffer->GetNext();
4401 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004402 destination->Set(dest_position, '%');
4403 destination->Set(dest_position+1, 'u');
4404 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4405 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4406 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4407 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004408 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004409 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004410 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004411 dest_position++;
4412 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004413 destination->Set(dest_position, '%');
4414 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4415 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004416 dest_position += 3;
4417 }
4418 }
4419 return destination;
4420}
4421
4422
4423static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4424 static const signed char kHexValue['g'] = {
4425 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4426 -1, -1, -1, -1, -1, -1, -1, -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 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4429 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4430 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4431 -1, 10, 11, 12, 13, 14, 15 };
4432
4433 if (character1 > 'f') return -1;
4434 int hi = kHexValue[character1];
4435 if (hi == -1) return -1;
4436 if (character2 > 'f') return -1;
4437 int lo = kHexValue[character2];
4438 if (lo == -1) return -1;
4439 return (hi << 4) + lo;
4440}
4441
4442
ager@chromium.org870a0b62008-11-04 11:43:05 +00004443static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004444 int i,
4445 int length,
4446 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004447 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004448 int32_t hi = 0;
4449 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004450 if (character == '%' &&
4451 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004452 source->Get(i + 1) == 'u' &&
4453 (hi = TwoDigitHex(source->Get(i + 2),
4454 source->Get(i + 3))) != -1 &&
4455 (lo = TwoDigitHex(source->Get(i + 4),
4456 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004457 *step = 6;
4458 return (hi << 8) + lo;
4459 } else if (character == '%' &&
4460 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004461 (lo = TwoDigitHex(source->Get(i + 1),
4462 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004463 *step = 3;
4464 return lo;
4465 } else {
4466 *step = 1;
4467 return character;
4468 }
4469}
4470
4471
4472static Object* Runtime_URIUnescape(Arguments args) {
4473 NoHandleAllocation ha;
4474 ASSERT(args.length() == 1);
4475 CONVERT_CHECKED(String, source, args[0]);
4476
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004477 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004478
4479 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004480 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481
4482 int unescaped_length = 0;
4483 for (int i = 0; i < length; unescaped_length++) {
4484 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004485 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004486 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004487 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 i += step;
4489 }
4490
4491 // No length change implies no change. Return original string if no change.
4492 if (unescaped_length == length)
4493 return source;
4494
4495 Object* o = ascii ?
4496 Heap::AllocateRawAsciiString(unescaped_length) :
4497 Heap::AllocateRawTwoByteString(unescaped_length);
4498 if (o->IsFailure()) return o;
4499 String* destination = String::cast(o);
4500
4501 int dest_position = 0;
4502 for (int i = 0; i < length; dest_position++) {
4503 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004504 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004505 i += step;
4506 }
4507 return destination;
4508}
4509
4510
4511static Object* Runtime_StringParseInt(Arguments args) {
4512 NoHandleAllocation ha;
4513
4514 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004515 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004516
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004517 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004518
lrn@chromium.org25156de2010-04-06 13:10:27 +00004519 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4520 double value = StringToInt(s, radix);
4521 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004522}
4523
4524
4525static Object* Runtime_StringParseFloat(Arguments args) {
4526 NoHandleAllocation ha;
4527 CONVERT_CHECKED(String, str, args[0]);
4528
4529 // ECMA-262 section 15.1.2.3, empty string is NaN
4530 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4531
4532 // Create a number object from the value.
4533 return Heap::NumberFromDouble(value);
4534}
4535
4536
4537static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4538static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4539
4540
4541template <class Converter>
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004542static Object* ConvertCaseHelper(String* s,
4543 int length,
4544 int input_string_length,
4545 unibrow::Mapping<Converter, 128>* mapping) {
4546 // We try this twice, once with the assumption that the result is no longer
4547 // than the input and, if that assumption breaks, again with the exact
4548 // length. This may not be pretty, but it is nicer than what was here before
4549 // and I hereby claim my vaffel-is.
4550 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004551 // Allocate the resulting string.
4552 //
4553 // NOTE: This assumes that the upper/lower case of an ascii
4554 // character is also ascii. This is currently the case, but it
4555 // might break in the future if we implement more context and locale
4556 // dependent upper/lower conversions.
ager@chromium.org5ec48922009-05-05 07:25:34 +00004557 Object* o = s->IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004558 ? Heap::AllocateRawAsciiString(length)
4559 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004560 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004561 String* result = String::cast(o);
4562 bool has_changed_character = false;
4563
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004564 // Convert all characters to upper case, assuming that they will fit
4565 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004566 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004567 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004568 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004569 // We can assume that the string is not empty
4570 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004571 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004572 bool has_next = buffer->has_more();
4573 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004574 int char_length = mapping->get(current, next, chars);
4575 if (char_length == 0) {
4576 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004577 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004578 i++;
4579 } else if (char_length == 1) {
4580 // Common case: converting the letter resulted in one character.
4581 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004582 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004583 has_changed_character = true;
4584 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004585 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586 // We've assumed that the result would be as long as the
4587 // input but here is a character that converts to several
4588 // characters. No matter, we calculate the exact length
4589 // of the result and try the whole thing again.
4590 //
4591 // Note that this leaves room for optimization. We could just
4592 // memcpy what we already have to the result string. Also,
4593 // the result string is the last object allocated we could
4594 // "realloc" it and probably, in the vast majority of cases,
4595 // extend the existing string to be able to hold the full
4596 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004597 int next_length = 0;
4598 if (has_next) {
4599 next_length = mapping->get(next, 0, chars);
4600 if (next_length == 0) next_length = 1;
4601 }
4602 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 while (buffer->has_more()) {
4604 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004605 // NOTE: we use 0 as the next character here because, while
4606 // the next character may affect what a character converts to,
4607 // it does not in any case affect the length of what it convert
4608 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004609 int char_length = mapping->get(current, 0, chars);
4610 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004611 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004612 if (current_length > Smi::kMaxValue) {
4613 Top::context()->mark_out_of_memory();
4614 return Failure::OutOfMemoryException();
4615 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004617 // Try again with the real length.
4618 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004619 } else {
4620 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004621 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004622 i++;
4623 }
4624 has_changed_character = true;
4625 }
4626 current = next;
4627 }
4628 if (has_changed_character) {
4629 return result;
4630 } else {
4631 // If we didn't actually change anything in doing the conversion
4632 // we simple return the result and let the converted string
4633 // become garbage; there is no reason to keep two identical strings
4634 // alive.
4635 return s;
4636 }
4637}
4638
4639
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004640namespace {
4641
4642struct ToLowerTraits {
4643 typedef unibrow::ToLowercase UnibrowConverter;
4644
4645 static bool ConvertAscii(char* dst, char* src, int length) {
4646 bool changed = false;
4647 for (int i = 0; i < length; ++i) {
4648 char c = src[i];
4649 if ('A' <= c && c <= 'Z') {
4650 c += ('a' - 'A');
4651 changed = true;
4652 }
4653 dst[i] = c;
4654 }
4655 return changed;
4656 }
4657};
4658
4659
4660struct ToUpperTraits {
4661 typedef unibrow::ToUppercase UnibrowConverter;
4662
4663 static bool ConvertAscii(char* dst, char* src, int length) {
4664 bool changed = false;
4665 for (int i = 0; i < length; ++i) {
4666 char c = src[i];
4667 if ('a' <= c && c <= 'z') {
4668 c -= ('a' - 'A');
4669 changed = true;
4670 }
4671 dst[i] = c;
4672 }
4673 return changed;
4674 }
4675};
4676
4677} // namespace
4678
4679
4680template <typename ConvertTraits>
4681static Object* ConvertCase(
4682 Arguments args,
4683 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004684 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004685 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004686 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004687
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004688 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004689 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004690 if (length == 0) return s;
4691
4692 // Simpler handling of ascii strings.
4693 //
4694 // NOTE: This assumes that the upper/lower case of an ascii
4695 // character is also ascii. This is currently the case, but it
4696 // might break in the future if we implement more context and locale
4697 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004698 if (s->IsSeqAsciiString()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004699 Object* o = Heap::AllocateRawAsciiString(length);
4700 if (o->IsFailure()) return o;
4701 SeqAsciiString* result = SeqAsciiString::cast(o);
4702 bool has_changed_character = ConvertTraits::ConvertAscii(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004703 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004704 return has_changed_character ? result : s;
4705 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004706
4707 Object* answer = ConvertCaseHelper(s, length, length, mapping);
4708 if (answer->IsSmi()) {
4709 // Retry with correct length.
4710 answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
4711 }
4712 return answer; // This may be a failure.
4713}
4714
4715
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004716static Object* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004717 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718}
4719
4720
4721static Object* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004722 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004723}
4724
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004725
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004726static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
4727 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
4728}
4729
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004730
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004731static Object* Runtime_StringTrim(Arguments args) {
4732 NoHandleAllocation ha;
4733 ASSERT(args.length() == 3);
4734
4735 CONVERT_CHECKED(String, s, args[0]);
4736 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
4737 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
4738
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004739 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004740 int length = s->length();
4741
4742 int left = 0;
4743 if (trimLeft) {
4744 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
4745 left++;
4746 }
4747 }
4748
4749 int right = length;
4750 if (trimRight) {
4751 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
4752 right--;
4753 }
4754 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004755 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004756}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004758
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004759// Define storage for buffers declared in header file.
4760// TODO(lrn): Remove these when rewriting search code.
4761int BMBuffers::bad_char_occurrence[kBMAlphabetSize];
4762BMGoodSuffixBuffers BMBuffers::bmgs_buffers;
4763
4764
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004765template <typename schar, typename pchar>
4766void FindStringIndices(Vector<const schar> subject,
4767 Vector<const pchar> pattern,
4768 ZoneList<int>* indices,
4769 unsigned int limit) {
4770 ASSERT(limit > 0);
4771 // Collect indices of pattern in subject, and the end-of-string index.
4772 // Stop after finding at most limit values.
4773 StringSearchStrategy strategy =
4774 InitializeStringSearch(pattern, sizeof(schar) == 1);
4775 switch (strategy) {
4776 case SEARCH_FAIL: return;
4777 case SEARCH_SHORT: {
4778 int pattern_length = pattern.length();
4779 int index = 0;
4780 while (limit > 0) {
4781 index = SimpleIndexOf(subject, pattern, index);
4782 if (index < 0) return;
4783 indices->Add(index);
4784 index += pattern_length;
4785 limit--;
4786 }
4787 return;
4788 }
4789 case SEARCH_LONG: {
4790 int pattern_length = pattern.length();
4791 int index = 0;
4792 while (limit > 0) {
4793 index = ComplexIndexOf(subject, pattern, index);
4794 if (index < 0) return;
4795 indices->Add(index);
4796 index += pattern_length;
4797 limit--;
4798 }
4799 return;
4800 }
4801 default:
4802 UNREACHABLE();
4803 return;
4804 }
4805}
4806
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004807
4808static Object* Runtime_StringSplit(Arguments args) {
4809 ASSERT(args.length() == 3);
4810 HandleScope handle_scope;
4811 CONVERT_ARG_CHECKED(String, subject, 0);
4812 CONVERT_ARG_CHECKED(String, pattern, 1);
4813 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
4814
4815 int subject_length = subject->length();
4816 int pattern_length = pattern->length();
4817 RUNTIME_ASSERT(pattern_length > 0);
4818
4819 // The limit can be very large (0xffffffffu), but since the pattern
4820 // isn't empty, we can never create more parts than ~half the length
4821 // of the subject.
4822
4823 if (!subject->IsFlat()) FlattenString(subject);
4824
4825 static const int kMaxInitialListCapacity = 16;
4826
4827 ZoneScope scope(DELETE_ON_EXIT);
4828
4829 // Find (up to limit) indices of separator and end-of-string in subject
4830 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
4831 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004832 if (!pattern->IsFlat()) FlattenString(pattern);
4833
4834 // No allocation block.
4835 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004836 AssertNoAllocation nogc;
4837 if (subject->IsAsciiRepresentation()) {
4838 Vector<const char> subject_vector = subject->ToAsciiVector();
4839 if (pattern->IsAsciiRepresentation()) {
4840 FindStringIndices(subject_vector,
4841 pattern->ToAsciiVector(),
4842 &indices,
4843 limit);
4844 } else {
4845 FindStringIndices(subject_vector,
4846 pattern->ToUC16Vector(),
4847 &indices,
4848 limit);
4849 }
4850 } else {
4851 Vector<const uc16> subject_vector = subject->ToUC16Vector();
4852 if (pattern->IsAsciiRepresentation()) {
4853 FindStringIndices(subject_vector,
4854 pattern->ToAsciiVector(),
4855 &indices,
4856 limit);
4857 } else {
4858 FindStringIndices(subject_vector,
4859 pattern->ToUC16Vector(),
4860 &indices,
4861 limit);
4862 }
4863 }
4864 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004865
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004866 if (static_cast<uint32_t>(indices.length()) < limit) {
4867 indices.Add(subject_length);
4868 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004869
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004870 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004871
4872 // Create JSArray of substrings separated by separator.
4873 int part_count = indices.length();
4874
4875 Handle<JSArray> result = Factory::NewJSArray(part_count);
4876 result->set_length(Smi::FromInt(part_count));
4877
4878 ASSERT(result->HasFastElements());
4879
4880 if (part_count == 1 && indices.at(0) == subject_length) {
4881 FixedArray::cast(result->elements())->set(0, *subject);
4882 return *result;
4883 }
4884
4885 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
4886 int part_start = 0;
4887 for (int i = 0; i < part_count; i++) {
4888 HandleScope local_loop_handle;
4889 int part_end = indices.at(i);
4890 Handle<String> substring =
4891 Factory::NewSubString(subject, part_start, part_end);
4892 elements->set(i, *substring);
4893 part_start = part_end + pattern_length;
4894 }
4895
4896 return *result;
4897}
4898
4899
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004900// Copies ascii characters to the given fixed array looking up
4901// one-char strings in the cache. Gives up on the first char that is
4902// not in the cache and fills the remainder with smi zeros. Returns
4903// the length of the successfully copied prefix.
4904static int CopyCachedAsciiCharsToArray(const char* chars,
4905 FixedArray* elements,
4906 int length) {
4907 AssertNoAllocation nogc;
4908 FixedArray* ascii_cache = Heap::single_character_string_cache();
4909 Object* undefined = Heap::undefined_value();
4910 int i;
4911 for (i = 0; i < length; ++i) {
4912 Object* value = ascii_cache->get(chars[i]);
4913 if (value == undefined) break;
4914 ASSERT(!Heap::InNewSpace(value));
4915 elements->set(i, value, SKIP_WRITE_BARRIER);
4916 }
4917 if (i < length) {
4918 ASSERT(Smi::FromInt(0) == 0);
4919 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
4920 }
4921#ifdef DEBUG
4922 for (int j = 0; j < length; ++j) {
4923 Object* element = elements->get(j);
4924 ASSERT(element == Smi::FromInt(0) ||
4925 (element->IsString() && String::cast(element)->LooksValid()));
4926 }
4927#endif
4928 return i;
4929}
4930
4931
4932// Converts a String to JSArray.
4933// For example, "foo" => ["f", "o", "o"].
4934static Object* Runtime_StringToArray(Arguments args) {
4935 HandleScope scope;
4936 ASSERT(args.length() == 1);
4937 CONVERT_ARG_CHECKED(String, s, 0);
4938
4939 s->TryFlatten();
4940 const int length = s->length();
4941
4942 Handle<FixedArray> elements;
4943 if (s->IsFlat() && s->IsAsciiRepresentation()) {
4944 Object* obj = Heap::AllocateUninitializedFixedArray(length);
4945 if (obj->IsFailure()) return obj;
4946 elements = Handle<FixedArray>(FixedArray::cast(obj));
4947
4948 Vector<const char> chars = s->ToAsciiVector();
4949 // Note, this will initialize all elements (not only the prefix)
4950 // to prevent GC from seeing partially initialized array.
4951 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
4952 *elements,
4953 length);
4954
4955 for (int i = num_copied_from_cache; i < length; ++i) {
4956 elements->set(i, *LookupSingleCharacterStringFromCode(chars[i]));
4957 }
4958 } else {
4959 elements = Factory::NewFixedArray(length);
4960 for (int i = 0; i < length; ++i) {
4961 elements->set(i, *LookupSingleCharacterStringFromCode(s->Get(i)));
4962 }
4963 }
4964
4965#ifdef DEBUG
4966 for (int i = 0; i < length; ++i) {
4967 ASSERT(String::cast(elements->get(i))->length() == 1);
4968 }
4969#endif
4970
4971 return *Factory::NewJSArrayWithElements(elements);
4972}
4973
4974
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004975static Object* Runtime_NewStringWrapper(Arguments args) {
4976 NoHandleAllocation ha;
4977 ASSERT(args.length() == 1);
4978 CONVERT_CHECKED(String, value, args[0]);
4979 return value->ToObject();
4980}
4981
4982
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00004983bool Runtime::IsUpperCaseChar(uint16_t ch) {
4984 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
4985 int char_length = to_upper_mapping.get(ch, 0, chars);
4986 return char_length == 0;
4987}
4988
4989
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004990static Object* Runtime_NumberToString(Arguments args) {
4991 NoHandleAllocation ha;
4992 ASSERT(args.length() == 1);
4993
4994 Object* number = args[0];
4995 RUNTIME_ASSERT(number->IsNumber());
4996
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004997 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004998}
4999
5000
ager@chromium.org357bf652010-04-12 11:30:10 +00005001static Object* Runtime_NumberToStringSkipCache(Arguments args) {
5002 NoHandleAllocation ha;
5003 ASSERT(args.length() == 1);
5004
5005 Object* number = args[0];
5006 RUNTIME_ASSERT(number->IsNumber());
5007
5008 return Heap::NumberToString(number, false);
5009}
5010
5011
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005012static Object* Runtime_NumberToInteger(Arguments args) {
5013 NoHandleAllocation ha;
5014 ASSERT(args.length() == 1);
5015
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005016 CONVERT_DOUBLE_CHECKED(number, args[0]);
5017
5018 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5019 if (number > 0 && number <= Smi::kMaxValue) {
5020 return Smi::FromInt(static_cast<int>(number));
5021 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005022 return Heap::NumberFromDouble(DoubleToInteger(number));
5023}
5024
5025
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005026static Object* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
5027 NoHandleAllocation ha;
5028 ASSERT(args.length() == 1);
5029
5030 CONVERT_DOUBLE_CHECKED(number, args[0]);
5031
5032 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5033 if (number > 0 && number <= Smi::kMaxValue) {
5034 return Smi::FromInt(static_cast<int>(number));
5035 }
5036
5037 double double_value = DoubleToInteger(number);
5038 // Map both -0 and +0 to +0.
5039 if (double_value == 0) double_value = 0;
5040
5041 return Heap::NumberFromDouble(double_value);
5042}
5043
5044
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005045static Object* Runtime_NumberToJSUint32(Arguments args) {
5046 NoHandleAllocation ha;
5047 ASSERT(args.length() == 1);
5048
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005049 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005050 return Heap::NumberFromUint32(number);
5051}
5052
5053
5054static Object* Runtime_NumberToJSInt32(Arguments args) {
5055 NoHandleAllocation ha;
5056 ASSERT(args.length() == 1);
5057
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005058 CONVERT_DOUBLE_CHECKED(number, args[0]);
5059
5060 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5061 if (number > 0 && number <= Smi::kMaxValue) {
5062 return Smi::FromInt(static_cast<int>(number));
5063 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005064 return Heap::NumberFromInt32(DoubleToInt32(number));
5065}
5066
5067
ager@chromium.org870a0b62008-11-04 11:43:05 +00005068// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5069// a small integer.
5070static Object* Runtime_NumberToSmi(Arguments args) {
5071 NoHandleAllocation ha;
5072 ASSERT(args.length() == 1);
5073
5074 Object* obj = args[0];
5075 if (obj->IsSmi()) {
5076 return obj;
5077 }
5078 if (obj->IsHeapNumber()) {
5079 double value = HeapNumber::cast(obj)->value();
5080 int int_value = FastD2I(value);
5081 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5082 return Smi::FromInt(int_value);
5083 }
5084 }
5085 return Heap::nan_value();
5086}
5087
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005088
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005089static Object* Runtime_NumberAdd(Arguments args) {
5090 NoHandleAllocation ha;
5091 ASSERT(args.length() == 2);
5092
5093 CONVERT_DOUBLE_CHECKED(x, args[0]);
5094 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005095 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005096}
5097
5098
5099static Object* Runtime_NumberSub(Arguments args) {
5100 NoHandleAllocation ha;
5101 ASSERT(args.length() == 2);
5102
5103 CONVERT_DOUBLE_CHECKED(x, args[0]);
5104 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005105 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005106}
5107
5108
5109static Object* Runtime_NumberMul(Arguments args) {
5110 NoHandleAllocation ha;
5111 ASSERT(args.length() == 2);
5112
5113 CONVERT_DOUBLE_CHECKED(x, args[0]);
5114 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005115 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005116}
5117
5118
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005119static Object* Runtime_NumberUnaryMinus(Arguments args) {
5120 NoHandleAllocation ha;
5121 ASSERT(args.length() == 1);
5122
5123 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005124 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005125}
5126
5127
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005128static Object* Runtime_NumberAlloc(Arguments args) {
5129 NoHandleAllocation ha;
5130 ASSERT(args.length() == 0);
5131
5132 return Heap::NumberFromDouble(9876543210.0);
5133}
5134
5135
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005136static Object* Runtime_NumberDiv(Arguments args) {
5137 NoHandleAllocation ha;
5138 ASSERT(args.length() == 2);
5139
5140 CONVERT_DOUBLE_CHECKED(x, args[0]);
5141 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005142 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005143}
5144
5145
5146static Object* Runtime_NumberMod(Arguments args) {
5147 NoHandleAllocation ha;
5148 ASSERT(args.length() == 2);
5149
5150 CONVERT_DOUBLE_CHECKED(x, args[0]);
5151 CONVERT_DOUBLE_CHECKED(y, args[1]);
5152
ager@chromium.org3811b432009-10-28 14:53:37 +00005153 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005154 // NumberFromDouble may return a Smi instead of a Number object
5155 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005156}
5157
5158
5159static Object* Runtime_StringAdd(Arguments args) {
5160 NoHandleAllocation ha;
5161 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005162 CONVERT_CHECKED(String, str1, args[0]);
5163 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005164 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005165 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005166}
5167
5168
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005169template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005170static inline void StringBuilderConcatHelper(String* special,
5171 sinkchar* sink,
5172 FixedArray* fixed_array,
5173 int array_length) {
5174 int position = 0;
5175 for (int i = 0; i < array_length; i++) {
5176 Object* element = fixed_array->get(i);
5177 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005178 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005179 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005180 int pos;
5181 int len;
5182 if (encoded_slice > 0) {
5183 // Position and length encoded in one smi.
5184 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5185 len = StringBuilderSubstringLength::decode(encoded_slice);
5186 } else {
5187 // Position and length encoded in two smis.
5188 Object* obj = fixed_array->get(++i);
5189 ASSERT(obj->IsSmi());
5190 pos = Smi::cast(obj)->value();
5191 len = -encoded_slice;
5192 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005193 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005194 sink + position,
5195 pos,
5196 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005197 position += len;
5198 } else {
5199 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005200 int element_length = string->length();
5201 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005202 position += element_length;
5203 }
5204 }
5205}
5206
5207
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005208static Object* Runtime_StringBuilderConcat(Arguments args) {
5209 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005210 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005211 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005212 if (!args[1]->IsSmi()) {
5213 Top::context()->mark_out_of_memory();
5214 return Failure::OutOfMemoryException();
5215 }
5216 int array_length = Smi::cast(args[1])->value();
5217 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005218
5219 // This assumption is used by the slice encoding in one or two smis.
5220 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5221
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005222 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005223 if (!array->HasFastElements()) {
5224 return Top::Throw(Heap::illegal_argument_symbol());
5225 }
5226 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005227 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005229 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005230
5231 if (array_length == 0) {
5232 return Heap::empty_string();
5233 } else if (array_length == 1) {
5234 Object* first = fixed_array->get(0);
5235 if (first->IsString()) return first;
5236 }
5237
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005238 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005239 int position = 0;
5240 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005241 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005242 Object* elt = fixed_array->get(i);
5243 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005244 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005245 int smi_value = Smi::cast(elt)->value();
5246 int pos;
5247 int len;
5248 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005249 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005250 pos = StringBuilderSubstringPosition::decode(smi_value);
5251 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005252 } else {
5253 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005254 len = -smi_value;
5255 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005256 i++;
5257 if (i >= array_length) {
5258 return Top::Throw(Heap::illegal_argument_symbol());
5259 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005260 Object* next_smi = fixed_array->get(i);
5261 if (!next_smi->IsSmi()) {
5262 return Top::Throw(Heap::illegal_argument_symbol());
5263 }
5264 pos = Smi::cast(next_smi)->value();
5265 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005266 return Top::Throw(Heap::illegal_argument_symbol());
5267 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005268 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005269 ASSERT(pos >= 0);
5270 ASSERT(len >= 0);
5271 if (pos > special_length || len > special_length - pos) {
5272 return Top::Throw(Heap::illegal_argument_symbol());
5273 }
5274 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005275 } else if (elt->IsString()) {
5276 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005277 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005278 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005279 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005280 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005281 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005282 } else {
5283 return Top::Throw(Heap::illegal_argument_symbol());
5284 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005285 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005286 Top::context()->mark_out_of_memory();
5287 return Failure::OutOfMemoryException();
5288 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005289 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005290 }
5291
5292 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005293 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005294
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005295 if (ascii) {
5296 object = Heap::AllocateRawAsciiString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005297 if (object->IsFailure()) return object;
5298 SeqAsciiString* answer = SeqAsciiString::cast(object);
5299 StringBuilderConcatHelper(special,
5300 answer->GetChars(),
5301 fixed_array,
5302 array_length);
5303 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005304 } else {
5305 object = Heap::AllocateRawTwoByteString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005306 if (object->IsFailure()) return object;
5307 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5308 StringBuilderConcatHelper(special,
5309 answer->GetChars(),
5310 fixed_array,
5311 array_length);
5312 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005313 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005314}
5315
5316
5317static Object* Runtime_NumberOr(Arguments args) {
5318 NoHandleAllocation ha;
5319 ASSERT(args.length() == 2);
5320
5321 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5322 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5323 return Heap::NumberFromInt32(x | y);
5324}
5325
5326
5327static Object* Runtime_NumberAnd(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);
5334}
5335
5336
5337static Object* Runtime_NumberXor(Arguments args) {
5338 NoHandleAllocation ha;
5339 ASSERT(args.length() == 2);
5340
5341 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5342 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5343 return Heap::NumberFromInt32(x ^ y);
5344}
5345
5346
5347static Object* Runtime_NumberNot(Arguments args) {
5348 NoHandleAllocation ha;
5349 ASSERT(args.length() == 1);
5350
5351 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5352 return Heap::NumberFromInt32(~x);
5353}
5354
5355
5356static Object* Runtime_NumberShl(Arguments args) {
5357 NoHandleAllocation ha;
5358 ASSERT(args.length() == 2);
5359
5360 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5361 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5362 return Heap::NumberFromInt32(x << (y & 0x1f));
5363}
5364
5365
5366static Object* Runtime_NumberShr(Arguments args) {
5367 NoHandleAllocation ha;
5368 ASSERT(args.length() == 2);
5369
5370 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5371 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5372 return Heap::NumberFromUint32(x >> (y & 0x1f));
5373}
5374
5375
5376static Object* Runtime_NumberSar(Arguments args) {
5377 NoHandleAllocation ha;
5378 ASSERT(args.length() == 2);
5379
5380 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5381 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5382 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5383}
5384
5385
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005386static Object* Runtime_NumberEquals(Arguments args) {
5387 NoHandleAllocation ha;
5388 ASSERT(args.length() == 2);
5389
5390 CONVERT_DOUBLE_CHECKED(x, args[0]);
5391 CONVERT_DOUBLE_CHECKED(y, args[1]);
5392 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5393 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5394 if (x == y) return Smi::FromInt(EQUAL);
5395 Object* result;
5396 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5397 result = Smi::FromInt(EQUAL);
5398 } else {
5399 result = Smi::FromInt(NOT_EQUAL);
5400 }
5401 return result;
5402}
5403
5404
5405static Object* Runtime_StringEquals(Arguments args) {
5406 NoHandleAllocation ha;
5407 ASSERT(args.length() == 2);
5408
5409 CONVERT_CHECKED(String, x, args[0]);
5410 CONVERT_CHECKED(String, y, args[1]);
5411
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005412 bool not_equal = !x->Equals(y);
5413 // This is slightly convoluted because the value that signifies
5414 // equality is 0 and inequality is 1 so we have to negate the result
5415 // from String::Equals.
5416 ASSERT(not_equal == 0 || not_equal == 1);
5417 STATIC_CHECK(EQUAL == 0);
5418 STATIC_CHECK(NOT_EQUAL == 1);
5419 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005420}
5421
5422
5423static Object* Runtime_NumberCompare(Arguments args) {
5424 NoHandleAllocation ha;
5425 ASSERT(args.length() == 3);
5426
5427 CONVERT_DOUBLE_CHECKED(x, args[0]);
5428 CONVERT_DOUBLE_CHECKED(y, args[1]);
5429 if (isnan(x) || isnan(y)) return args[2];
5430 if (x == y) return Smi::FromInt(EQUAL);
5431 if (isless(x, y)) return Smi::FromInt(LESS);
5432 return Smi::FromInt(GREATER);
5433}
5434
5435
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005436// Compare two Smis as if they were converted to strings and then
5437// compared lexicographically.
5438static Object* Runtime_SmiLexicographicCompare(Arguments args) {
5439 NoHandleAllocation ha;
5440 ASSERT(args.length() == 2);
5441
5442 // Arrays for the individual characters of the two Smis. Smis are
5443 // 31 bit integers and 10 decimal digits are therefore enough.
5444 static int x_elms[10];
5445 static int y_elms[10];
5446
5447 // Extract the integer values from the Smis.
5448 CONVERT_CHECKED(Smi, x, args[0]);
5449 CONVERT_CHECKED(Smi, y, args[1]);
5450 int x_value = x->value();
5451 int y_value = y->value();
5452
5453 // If the integers are equal so are the string representations.
5454 if (x_value == y_value) return Smi::FromInt(EQUAL);
5455
5456 // If one of the integers are zero the normal integer order is the
5457 // same as the lexicographic order of the string representations.
5458 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5459
ager@chromium.org32912102009-01-16 10:38:43 +00005460 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005461 // smallest because the char code of '-' is less than the char code
5462 // of any digit. Otherwise, we make both values positive.
5463 if (x_value < 0 || y_value < 0) {
5464 if (y_value >= 0) return Smi::FromInt(LESS);
5465 if (x_value >= 0) return Smi::FromInt(GREATER);
5466 x_value = -x_value;
5467 y_value = -y_value;
5468 }
5469
5470 // Convert the integers to arrays of their decimal digits.
5471 int x_index = 0;
5472 int y_index = 0;
5473 while (x_value > 0) {
5474 x_elms[x_index++] = x_value % 10;
5475 x_value /= 10;
5476 }
5477 while (y_value > 0) {
5478 y_elms[y_index++] = y_value % 10;
5479 y_value /= 10;
5480 }
5481
5482 // Loop through the arrays of decimal digits finding the first place
5483 // where they differ.
5484 while (--x_index >= 0 && --y_index >= 0) {
5485 int diff = x_elms[x_index] - y_elms[y_index];
5486 if (diff != 0) return Smi::FromInt(diff);
5487 }
5488
5489 // If one array is a suffix of the other array, the longest array is
5490 // the representation of the largest of the Smis in the
5491 // lexicographic ordering.
5492 return Smi::FromInt(x_index - y_index);
5493}
5494
5495
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005496static Object* StringInputBufferCompare(String* x, String* y) {
5497 static StringInputBuffer bufx;
5498 static StringInputBuffer bufy;
5499 bufx.Reset(x);
5500 bufy.Reset(y);
5501 while (bufx.has_more() && bufy.has_more()) {
5502 int d = bufx.GetNext() - bufy.GetNext();
5503 if (d < 0) return Smi::FromInt(LESS);
5504 else if (d > 0) return Smi::FromInt(GREATER);
5505 }
5506
5507 // x is (non-trivial) prefix of y:
5508 if (bufy.has_more()) return Smi::FromInt(LESS);
5509 // y is prefix of x:
5510 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5511}
5512
5513
5514static Object* FlatStringCompare(String* x, String* y) {
5515 ASSERT(x->IsFlat());
5516 ASSERT(y->IsFlat());
5517 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5518 int prefix_length = x->length();
5519 if (y->length() < prefix_length) {
5520 prefix_length = y->length();
5521 equal_prefix_result = Smi::FromInt(GREATER);
5522 } else if (y->length() > prefix_length) {
5523 equal_prefix_result = Smi::FromInt(LESS);
5524 }
5525 int r;
5526 if (x->IsAsciiRepresentation()) {
5527 Vector<const char> x_chars = x->ToAsciiVector();
5528 if (y->IsAsciiRepresentation()) {
5529 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005530 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005531 } else {
5532 Vector<const uc16> y_chars = y->ToUC16Vector();
5533 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5534 }
5535 } else {
5536 Vector<const uc16> x_chars = x->ToUC16Vector();
5537 if (y->IsAsciiRepresentation()) {
5538 Vector<const char> y_chars = y->ToAsciiVector();
5539 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5540 } else {
5541 Vector<const uc16> y_chars = y->ToUC16Vector();
5542 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5543 }
5544 }
5545 Object* result;
5546 if (r == 0) {
5547 result = equal_prefix_result;
5548 } else {
5549 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5550 }
5551 ASSERT(result == StringInputBufferCompare(x, y));
5552 return result;
5553}
5554
5555
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005556static Object* Runtime_StringCompare(Arguments args) {
5557 NoHandleAllocation ha;
5558 ASSERT(args.length() == 2);
5559
5560 CONVERT_CHECKED(String, x, args[0]);
5561 CONVERT_CHECKED(String, y, args[1]);
5562
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005563 Counters::string_compare_runtime.Increment();
5564
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005565 // A few fast case tests before we flatten.
5566 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005567 if (y->length() == 0) {
5568 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005569 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005570 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005571 return Smi::FromInt(LESS);
5572 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005573
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005574 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005575 if (d < 0) return Smi::FromInt(LESS);
5576 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005578 Object* obj = Heap::PrepareForCompare(x);
5579 if (obj->IsFailure()) return obj;
5580 obj = Heap::PrepareForCompare(y);
5581 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005582
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005583 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5584 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005585}
5586
5587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005588static Object* Runtime_Math_acos(Arguments args) {
5589 NoHandleAllocation ha;
5590 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005591 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005592
5593 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005594 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005595}
5596
5597
5598static Object* Runtime_Math_asin(Arguments args) {
5599 NoHandleAllocation ha;
5600 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005601 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005602
5603 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005604 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005605}
5606
5607
5608static Object* Runtime_Math_atan(Arguments args) {
5609 NoHandleAllocation ha;
5610 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005611 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005612
5613 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005614 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005615}
5616
5617
5618static Object* Runtime_Math_atan2(Arguments args) {
5619 NoHandleAllocation ha;
5620 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005621 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005622
5623 CONVERT_DOUBLE_CHECKED(x, args[0]);
5624 CONVERT_DOUBLE_CHECKED(y, args[1]);
5625 double result;
5626 if (isinf(x) && isinf(y)) {
5627 // Make sure that the result in case of two infinite arguments
5628 // is a multiple of Pi / 4. The sign of the result is determined
5629 // by the first argument (x) and the sign of the second argument
5630 // determines the multiplier: one or three.
5631 static double kPiDividedBy4 = 0.78539816339744830962;
5632 int multiplier = (x < 0) ? -1 : 1;
5633 if (y < 0) multiplier *= 3;
5634 result = multiplier * kPiDividedBy4;
5635 } else {
5636 result = atan2(x, y);
5637 }
5638 return Heap::AllocateHeapNumber(result);
5639}
5640
5641
5642static Object* Runtime_Math_ceil(Arguments args) {
5643 NoHandleAllocation ha;
5644 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005645 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005646
5647 CONVERT_DOUBLE_CHECKED(x, args[0]);
5648 return Heap::NumberFromDouble(ceiling(x));
5649}
5650
5651
5652static Object* Runtime_Math_cos(Arguments args) {
5653 NoHandleAllocation ha;
5654 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005655 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005656
5657 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005658 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005659}
5660
5661
5662static Object* Runtime_Math_exp(Arguments args) {
5663 NoHandleAllocation ha;
5664 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005665 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005666
5667 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005668 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005669}
5670
5671
5672static Object* Runtime_Math_floor(Arguments args) {
5673 NoHandleAllocation ha;
5674 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005675 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005676
5677 CONVERT_DOUBLE_CHECKED(x, args[0]);
5678 return Heap::NumberFromDouble(floor(x));
5679}
5680
5681
5682static Object* Runtime_Math_log(Arguments args) {
5683 NoHandleAllocation ha;
5684 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005685 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005686
5687 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005688 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005689}
5690
5691
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005692// Helper function to compute x^y, where y is known to be an
5693// integer. Uses binary decomposition to limit the number of
5694// multiplications; see the discussion in "Hacker's Delight" by Henry
5695// S. Warren, Jr., figure 11-6, page 213.
5696static double powi(double x, int y) {
5697 ASSERT(y != kMinInt);
5698 unsigned n = (y < 0) ? -y : y;
5699 double m = x;
5700 double p = 1;
5701 while (true) {
5702 if ((n & 1) != 0) p *= m;
5703 n >>= 1;
5704 if (n == 0) {
5705 if (y < 0) {
5706 // Unfortunately, we have to be careful when p has reached
5707 // infinity in the computation, because sometimes the higher
5708 // internal precision in the pow() implementation would have
5709 // given us a finite p. This happens very rarely.
5710 double result = 1.0 / p;
5711 return (result == 0 && isinf(p))
5712 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
5713 : result;
5714 } else {
5715 return p;
5716 }
5717 }
5718 m *= m;
5719 }
5720}
5721
5722
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005723static Object* Runtime_Math_pow(Arguments args) {
5724 NoHandleAllocation ha;
5725 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005726 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005727
5728 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005729
5730 // If the second argument is a smi, it is much faster to call the
5731 // custom powi() function than the generic pow().
5732 if (args[1]->IsSmi()) {
5733 int y = Smi::cast(args[1])->value();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005734 return Heap::NumberFromDouble(powi(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005735 }
5736
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005737 CONVERT_DOUBLE_CHECKED(y, args[1]);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005738
5739 if (!isinf(x)) {
5740 if (y == 0.5) {
5741 // It's not uncommon to use Math.pow(x, 0.5) to compute the
5742 // square root of a number. To speed up such computations, we
5743 // explictly check for this case and use the sqrt() function
5744 // which is faster than pow().
5745 return Heap::AllocateHeapNumber(sqrt(x));
5746 } else if (y == -0.5) {
5747 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
5748 return Heap::AllocateHeapNumber(1.0 / sqrt(x));
5749 }
5750 }
5751
5752 if (y == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005753 return Smi::FromInt(1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005754 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5755 return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005756 } else {
5757 return Heap::AllocateHeapNumber(pow(x, y));
5758 }
5759}
5760
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005761// Fast version of Math.pow if we know that y is not an integer and
5762// y is not -0.5 or 0.5. Used as slowcase from codegen.
5763static Object* Runtime_Math_pow_cfunction(Arguments args) {
5764 NoHandleAllocation ha;
5765 ASSERT(args.length() == 2);
5766 CONVERT_DOUBLE_CHECKED(x, args[0]);
5767 CONVERT_DOUBLE_CHECKED(y, args[1]);
5768 if (y == 0) {
5769 return Smi::FromInt(1);
5770 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5771 return Heap::nan_value();
5772 } else {
5773 return Heap::AllocateHeapNumber(pow(x, y));
5774 }
5775}
5776
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005777
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005778static Object* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005779 NoHandleAllocation ha;
5780 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005781 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005782
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005783 if (!args[0]->IsHeapNumber()) {
5784 // Must be smi. Return the argument unchanged for all the other types
5785 // to make fuzz-natives test happy.
5786 return args[0];
5787 }
5788
5789 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
5790
5791 double value = number->value();
5792 int exponent = number->get_exponent();
5793 int sign = number->get_sign();
5794
5795 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
5796 // should be rounded to 2^30, which is not smi.
5797 if (!sign && exponent <= kSmiValueSize - 3) {
5798 return Smi::FromInt(static_cast<int>(value + 0.5));
5799 }
5800
5801 // If the magnitude is big enough, there's no place for fraction part. If we
5802 // try to add 0.5 to this number, 1.0 will be added instead.
5803 if (exponent >= 52) {
5804 return number;
5805 }
5806
5807 if (sign && value >= -0.5) return Heap::minus_zero_value();
5808
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005809 // Do not call NumberFromDouble() to avoid extra checks.
5810 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005811}
5812
5813
5814static Object* Runtime_Math_sin(Arguments args) {
5815 NoHandleAllocation ha;
5816 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005817 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005818
5819 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005820 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005821}
5822
5823
5824static Object* Runtime_Math_sqrt(Arguments args) {
5825 NoHandleAllocation ha;
5826 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005827 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005828
5829 CONVERT_DOUBLE_CHECKED(x, args[0]);
5830 return Heap::AllocateHeapNumber(sqrt(x));
5831}
5832
5833
5834static Object* Runtime_Math_tan(Arguments args) {
5835 NoHandleAllocation ha;
5836 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005837 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005838
5839 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005840 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005841}
5842
5843
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005844static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005845 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
5846 181, 212, 243, 273, 304, 334};
5847 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
5848 182, 213, 244, 274, 305, 335};
5849
5850 year += month / 12;
5851 month %= 12;
5852 if (month < 0) {
5853 year--;
5854 month += 12;
5855 }
5856
5857 ASSERT(month >= 0);
5858 ASSERT(month < 12);
5859
5860 // year_delta is an arbitrary number such that:
5861 // a) year_delta = -1 (mod 400)
5862 // b) year + year_delta > 0 for years in the range defined by
5863 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
5864 // Jan 1 1970. This is required so that we don't run into integer
5865 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005866 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005867 // operations.
5868 static const int year_delta = 399999;
5869 static const int base_day = 365 * (1970 + year_delta) +
5870 (1970 + year_delta) / 4 -
5871 (1970 + year_delta) / 100 +
5872 (1970 + year_delta) / 400;
5873
5874 int year1 = year + year_delta;
5875 int day_from_year = 365 * year1 +
5876 year1 / 4 -
5877 year1 / 100 +
5878 year1 / 400 -
5879 base_day;
5880
5881 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005882 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005883 }
5884
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005885 return day_from_year + day_from_month_leap[month] + day - 1;
5886}
5887
5888
5889static Object* Runtime_DateMakeDay(Arguments args) {
5890 NoHandleAllocation ha;
5891 ASSERT(args.length() == 3);
5892
5893 CONVERT_SMI_CHECKED(year, args[0]);
5894 CONVERT_SMI_CHECKED(month, args[1]);
5895 CONVERT_SMI_CHECKED(date, args[2]);
5896
5897 return Smi::FromInt(MakeDay(year, month, date));
5898}
5899
5900
5901static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
5902static const int kDaysIn4Years = 4 * 365 + 1;
5903static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
5904static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
5905static const int kDays1970to2000 = 30 * 365 + 7;
5906static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
5907 kDays1970to2000;
5908static const int kYearsOffset = 400000;
5909
5910static const char kDayInYear[] = {
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,
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,
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, 31,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5932 22, 23, 24, 25, 26, 27, 28, 29, 30,
5933 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5934 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5935
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,
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,
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, 31,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5957 22, 23, 24, 25, 26, 27, 28, 29, 30,
5958 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5959 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5960
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,
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,
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, 31,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5982 22, 23, 24, 25, 26, 27, 28, 29, 30,
5983 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5984 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5985
5986 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5987 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5988 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5989 22, 23, 24, 25, 26, 27, 28,
5990 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5991 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5992 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5993 22, 23, 24, 25, 26, 27, 28, 29, 30,
5994 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5995 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5996 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5997 22, 23, 24, 25, 26, 27, 28, 29, 30,
5998 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5999 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6000 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6001 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6002 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6003 22, 23, 24, 25, 26, 27, 28, 29, 30,
6004 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6005 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6006 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6007 22, 23, 24, 25, 26, 27, 28, 29, 30,
6008 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6009 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6010
6011static const char kMonthInYear[] = {
6012 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,
6013 0, 0, 0, 0, 0, 0,
6014 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,
6015 1, 1, 1,
6016 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,
6017 2, 2, 2, 2, 2, 2,
6018 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,
6019 3, 3, 3, 3, 3,
6020 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,
6021 4, 4, 4, 4, 4, 4,
6022 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,
6023 5, 5, 5, 5, 5,
6024 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,
6025 6, 6, 6, 6, 6, 6,
6026 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,
6027 7, 7, 7, 7, 7, 7,
6028 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,
6029 8, 8, 8, 8, 8,
6030 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,
6031 9, 9, 9, 9, 9, 9,
6032 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6033 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6034 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6035 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6036
6037 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,
6038 0, 0, 0, 0, 0, 0,
6039 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,
6040 1, 1, 1,
6041 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,
6042 2, 2, 2, 2, 2, 2,
6043 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,
6044 3, 3, 3, 3, 3,
6045 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,
6046 4, 4, 4, 4, 4, 4,
6047 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,
6048 5, 5, 5, 5, 5,
6049 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,
6050 6, 6, 6, 6, 6, 6,
6051 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,
6052 7, 7, 7, 7, 7, 7,
6053 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,
6054 8, 8, 8, 8, 8,
6055 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,
6056 9, 9, 9, 9, 9, 9,
6057 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6058 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6059 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6060 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6061
6062 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,
6063 0, 0, 0, 0, 0, 0,
6064 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,
6065 1, 1, 1, 1,
6066 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,
6067 2, 2, 2, 2, 2, 2,
6068 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,
6069 3, 3, 3, 3, 3,
6070 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,
6071 4, 4, 4, 4, 4, 4,
6072 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,
6073 5, 5, 5, 5, 5,
6074 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,
6075 6, 6, 6, 6, 6, 6,
6076 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,
6077 7, 7, 7, 7, 7, 7,
6078 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,
6079 8, 8, 8, 8, 8,
6080 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,
6081 9, 9, 9, 9, 9, 9,
6082 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6083 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6084 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6085 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6086
6087 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,
6088 0, 0, 0, 0, 0, 0,
6089 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,
6090 1, 1, 1,
6091 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,
6092 2, 2, 2, 2, 2, 2,
6093 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,
6094 3, 3, 3, 3, 3,
6095 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,
6096 4, 4, 4, 4, 4, 4,
6097 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,
6098 5, 5, 5, 5, 5,
6099 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,
6100 6, 6, 6, 6, 6, 6,
6101 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,
6102 7, 7, 7, 7, 7, 7,
6103 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,
6104 8, 8, 8, 8, 8,
6105 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,
6106 9, 9, 9, 9, 9, 9,
6107 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6108 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6109 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6110 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6111
6112
6113// This function works for dates from 1970 to 2099.
6114static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006115 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006116#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006117 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006118#endif
6119
6120 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6121 date %= kDaysIn4Years;
6122
6123 month = kMonthInYear[date];
6124 day = kDayInYear[date];
6125
6126 ASSERT(MakeDay(year, month, day) == save_date);
6127}
6128
6129
6130static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006131 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006132#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006133 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006134#endif
6135
6136 date += kDaysOffset;
6137 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6138 date %= kDaysIn400Years;
6139
6140 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6141
6142 date--;
6143 int yd1 = date / kDaysIn100Years;
6144 date %= kDaysIn100Years;
6145 year += 100 * yd1;
6146
6147 date++;
6148 int yd2 = date / kDaysIn4Years;
6149 date %= kDaysIn4Years;
6150 year += 4 * yd2;
6151
6152 date--;
6153 int yd3 = date / 365;
6154 date %= 365;
6155 year += yd3;
6156
6157 bool is_leap = (!yd1 || yd2) && !yd3;
6158
6159 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006160 ASSERT(is_leap || (date >= 0));
6161 ASSERT((date < 365) || (is_leap && (date < 366)));
6162 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6163 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6164 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006165
6166 if (is_leap) {
6167 day = kDayInYear[2*365 + 1 + date];
6168 month = kMonthInYear[2*365 + 1 + date];
6169 } else {
6170 day = kDayInYear[date];
6171 month = kMonthInYear[date];
6172 }
6173
6174 ASSERT(MakeDay(year, month, day) == save_date);
6175}
6176
6177
6178static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006179 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006180 if (date >= 0 && date < 32 * kDaysIn4Years) {
6181 DateYMDFromTimeAfter1970(date, year, month, day);
6182 } else {
6183 DateYMDFromTimeSlow(date, year, month, day);
6184 }
6185}
6186
6187
6188static Object* Runtime_DateYMDFromTime(Arguments args) {
6189 NoHandleAllocation ha;
6190 ASSERT(args.length() == 2);
6191
6192 CONVERT_DOUBLE_CHECKED(t, args[0]);
6193 CONVERT_CHECKED(JSArray, res_array, args[1]);
6194
6195 int year, month, day;
6196 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6197
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006198 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6199 FixedArray* elms = FixedArray::cast(res_array->elements());
6200 RUNTIME_ASSERT(elms->length() == 3);
6201
6202 elms->set(0, Smi::FromInt(year));
6203 elms->set(1, Smi::FromInt(month));
6204 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006205
6206 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006207}
6208
6209
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006210static Object* Runtime_NewArgumentsFast(Arguments args) {
6211 NoHandleAllocation ha;
6212 ASSERT(args.length() == 3);
6213
6214 JSFunction* callee = JSFunction::cast(args[0]);
6215 Object** parameters = reinterpret_cast<Object**>(args[1]);
6216 const int length = Smi::cast(args[2])->value();
6217
6218 Object* result = Heap::AllocateArgumentsObject(callee, length);
6219 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006220 // Allocate the elements if needed.
6221 if (length > 0) {
6222 // Allocate the fixed array.
6223 Object* obj = Heap::AllocateRawFixedArray(length);
6224 if (obj->IsFailure()) return obj;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006225
6226 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006227 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6228 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006229 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006230
6231 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006232 for (int i = 0; i < length; i++) {
6233 array->set(i, *--parameters, mode);
6234 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006235 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006236 }
6237 return result;
6238}
6239
6240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006241static Object* Runtime_NewClosure(Arguments args) {
6242 HandleScope scope;
6243 ASSERT(args.length() == 2);
ager@chromium.org3811b432009-10-28 14:53:37 +00006244 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006245 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006246
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00006247 PretenureFlag pretenure = (context->global_context() == *context)
6248 ? TENURED // Allocate global closures in old space.
6249 : NOT_TENURED; // Allocate local closures in new space.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006250 Handle<JSFunction> result =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006251 Factory::NewFunctionFromSharedFunctionInfo(shared, context, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252 return *result;
6253}
6254
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006255static Object* Runtime_NewObjectFromBound(Arguments args) {
6256 HandleScope scope;
6257 ASSERT(args.length() == 2);
6258 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6259 CONVERT_ARG_CHECKED(JSArray, params, 1);
6260
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006261 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006262 FixedArray* fixed = FixedArray::cast(params->elements());
6263
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006264 int fixed_length = Smi::cast(params->length())->value();
6265 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6266 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006267 Handle<Object> val = Handle<Object>(fixed->get(i));
6268 param_data[i] = val.location();
6269 }
6270
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006271 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006272 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006273 function, fixed_length, *param_data, &exception);
6274 if (exception) {
6275 return Failure::Exception();
6276 }
6277 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006278 return *result;
6279}
6280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006281
ager@chromium.org5c838252010-02-19 08:53:10 +00006282static Code* ComputeConstructStub(Handle<JSFunction> function) {
6283 Handle<Object> prototype = Factory::null_value();
6284 if (function->has_instance_prototype()) {
6285 prototype = Handle<Object>(function->instance_prototype());
6286 }
6287 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006288 ConstructStubCompiler compiler;
ager@chromium.org5c838252010-02-19 08:53:10 +00006289 Object* code = compiler.CompileConstructStub(function->shared());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006290 if (code->IsFailure()) {
6291 return Builtins::builtin(Builtins::JSConstructStubGeneric);
6292 }
6293 return Code::cast(code);
6294 }
6295
ager@chromium.org5c838252010-02-19 08:53:10 +00006296 return function->shared()->construct_stub();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006297}
6298
6299
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006300static Object* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006301 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006302 ASSERT(args.length() == 1);
6303
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006304 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006305
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006306 // If the constructor isn't a proper function we throw a type error.
6307 if (!constructor->IsJSFunction()) {
6308 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6309 Handle<Object> type_error =
6310 Factory::NewTypeError("not_constructor", arguments);
6311 return Top::Throw(*type_error);
6312 }
6313
6314 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006315
6316 // If function should not have prototype, construction is not allowed. In this
6317 // case generated code bailouts here, since function has no initial_map.
6318 if (!function->should_have_prototype()) {
6319 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6320 Handle<Object> type_error =
6321 Factory::NewTypeError("not_constructor", arguments);
6322 return Top::Throw(*type_error);
6323 }
6324
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006325#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006326 // Handle stepping into constructors if step into is active.
6327 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006328 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006329 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006330#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006331
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006332 if (function->has_initial_map()) {
6333 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006334 // The 'Function' function ignores the receiver object when
6335 // called using 'new' and creates a new JSFunction object that
6336 // is returned. The receiver object is only used for error
6337 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006338 // JSFunction. Factory::NewJSObject() should not be used to
6339 // allocate JSFunctions since it does not properly initialize
6340 // the shared part of the function. Since the receiver is
6341 // ignored anyway, we use the global object as the receiver
6342 // instead of a new JSFunction object. This way, errors are
6343 // reported the same way whether or not 'Function' is called
6344 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006345 return Top::context()->global();
6346 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006347 }
6348
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006349 // The function should be compiled for the optimization hints to be available.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006350 Handle<SharedFunctionInfo> shared(function->shared());
6351 EnsureCompiled(shared, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006352
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006353 bool first_allocation = !function->has_initial_map();
6354 Handle<JSObject> result = Factory::NewJSObject(function);
6355 if (first_allocation) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006356 Handle<Code> stub = Handle<Code>(
ager@chromium.org5c838252010-02-19 08:53:10 +00006357 ComputeConstructStub(Handle<JSFunction>(function)));
6358 shared->set_construct_stub(*stub);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006359 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006360
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006361 Counters::constructed_objects.Increment();
6362 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006363
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006364 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006365}
6366
6367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006368static Object* Runtime_LazyCompile(Arguments args) {
6369 HandleScope scope;
6370 ASSERT(args.length() == 1);
6371
6372 Handle<JSFunction> function = args.at<JSFunction>(0);
6373#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006374 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006375 PrintF("[lazy: ");
6376 function->shared()->name()->Print();
6377 PrintF("]\n");
6378 }
6379#endif
6380
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006381 // Compile the target function. Here we compile using CompileLazyInLoop in
6382 // order to get the optimized version. This helps code like delta-blue
6383 // that calls performance-critical routines through constructors. A
6384 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6385 // direct call. Since the in-loop tracking takes place through CallICs
6386 // this means that things called through constructors are never known to
6387 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006388 ASSERT(!function->is_compiled());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006389 if (!CompileLazyInLoop(function, Handle<Object>::null(), KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006390 return Failure::Exception();
6391 }
6392
6393 return function->code();
6394}
6395
6396
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006397static Object* Runtime_GetFunctionDelegate(Arguments args) {
6398 HandleScope scope;
6399 ASSERT(args.length() == 1);
6400 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6401 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6402}
6403
6404
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006405static Object* Runtime_GetConstructorDelegate(Arguments args) {
6406 HandleScope scope;
6407 ASSERT(args.length() == 1);
6408 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6409 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6410}
6411
6412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006413static Object* Runtime_NewContext(Arguments args) {
6414 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006415 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006416
kasper.lund7276f142008-07-30 08:49:36 +00006417 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006418 int length = function->shared()->scope_info()->NumberOfContextSlots();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006419 Object* result = Heap::AllocateFunctionContext(length, function);
6420 if (result->IsFailure()) return result;
6421
6422 Top::set_context(Context::cast(result));
6423
kasper.lund7276f142008-07-30 08:49:36 +00006424 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006425}
6426
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006427static Object* PushContextHelper(Object* object, bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006428 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006429 Object* js_object = object;
6430 if (!js_object->IsJSObject()) {
6431 js_object = js_object->ToObject();
6432 if (js_object->IsFailure()) {
6433 if (!Failure::cast(js_object)->IsInternalError()) return js_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006434 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006435 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006436 Handle<Object> result =
6437 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
6438 return Top::Throw(*result);
6439 }
6440 }
6441
6442 Object* result =
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006443 Heap::AllocateWithContext(Top::context(),
6444 JSObject::cast(js_object),
6445 is_catch_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006446 if (result->IsFailure()) return result;
6447
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006448 Context* context = Context::cast(result);
6449 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006450
kasper.lund7276f142008-07-30 08:49:36 +00006451 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006452}
6453
6454
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006455static Object* Runtime_PushContext(Arguments args) {
6456 NoHandleAllocation ha;
6457 ASSERT(args.length() == 1);
6458 return PushContextHelper(args[0], false);
6459}
6460
6461
6462static Object* Runtime_PushCatchContext(Arguments args) {
6463 NoHandleAllocation ha;
6464 ASSERT(args.length() == 1);
6465 return PushContextHelper(args[0], true);
6466}
6467
6468
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006469static Object* Runtime_LookupContext(Arguments args) {
6470 HandleScope scope;
6471 ASSERT(args.length() == 2);
6472
6473 CONVERT_ARG_CHECKED(Context, context, 0);
6474 CONVERT_ARG_CHECKED(String, name, 1);
6475
6476 int index;
6477 PropertyAttributes attributes;
6478 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006479 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006480 context->Lookup(name, flags, &index, &attributes);
6481
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006482 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006483 ASSERT(holder->IsJSObject());
6484 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006485 }
6486
6487 // No intermediate context found. Use global object by default.
6488 return Top::context()->global();
6489}
6490
6491
ager@chromium.orga1645e22009-09-09 19:27:10 +00006492// A mechanism to return a pair of Object pointers in registers (if possible).
6493// How this is achieved is calling convention-dependent.
6494// All currently supported x86 compiles uses calling conventions that are cdecl
6495// variants where a 64-bit value is returned in two 32-bit registers
6496// (edx:eax on ia32, r1:r0 on ARM).
6497// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
6498// In Win64 calling convention, a struct of two pointers is returned in memory,
6499// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006500#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006501struct ObjectPair {
6502 Object* x;
6503 Object* y;
6504};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006505
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006506static inline ObjectPair MakePair(Object* x, Object* y) {
6507 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006508 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
6509 // In Win64 they are assigned to a hidden first argument.
6510 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006511}
6512#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006513typedef uint64_t ObjectPair;
6514static inline ObjectPair MakePair(Object* x, Object* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006516 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006517}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006518#endif
6519
6520
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006521static inline Object* Unhole(Object* x, PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006522 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
6523 USE(attributes);
6524 return x->IsTheHole() ? Heap::undefined_value() : x;
6525}
6526
6527
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006528static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
6529 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006530 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006531 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006532 JSFunction* context_extension_function =
6533 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006534 // If the holder isn't a context extension object, we just return it
6535 // as the receiver. This allows arguments objects to be used as
6536 // receivers, but only if they are put in the context scope chain
6537 // explicitly via a with-statement.
6538 Object* constructor = holder->map()->constructor();
6539 if (constructor != context_extension_function) return holder;
6540 // Fall back to using the global object as the receiver if the
6541 // property turns out to be a local variable allocated in a context
6542 // extension object - introduced via eval.
6543 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006544}
6545
6546
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006547static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006548 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006549 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006551 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00006552 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006553 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006554 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006555 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006556
6557 int index;
6558 PropertyAttributes attributes;
6559 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006560 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006561 context->Lookup(name, flags, &index, &attributes);
6562
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006563 // If the index is non-negative, the slot has been found in a local
6564 // variable or a parameter. Read it from the context object or the
6565 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006567 // If the "property" we were looking for is a local variable or an
6568 // argument in a context, the receiver is the global object; see
6569 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
6570 JSObject* receiver = Top::context()->global()->global_receiver();
6571 Object* value = (holder->IsContext())
6572 ? Context::cast(*holder)->get(index)
6573 : JSObject::cast(*holder)->GetElement(index);
6574 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575 }
6576
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006577 // If the holder is found, we read the property from it.
6578 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006579 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006580 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006581 JSObject* receiver;
6582 if (object->IsGlobalObject()) {
6583 receiver = GlobalObject::cast(object)->global_receiver();
6584 } else if (context->is_exception_holder(*holder)) {
6585 receiver = Top::context()->global()->global_receiver();
6586 } else {
6587 receiver = ComputeReceiverForNonGlobal(object);
6588 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006589 // No need to unhole the value here. This is taken care of by the
6590 // GetProperty function.
6591 Object* value = object->GetProperty(*name);
6592 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593 }
6594
6595 if (throw_error) {
6596 // The property doesn't exist - throw exception.
6597 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006598 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006599 return MakePair(Top::Throw(*reference_error), NULL);
6600 } else {
6601 // The property doesn't exist - return undefined
6602 return MakePair(Heap::undefined_value(), Heap::undefined_value());
6603 }
6604}
6605
6606
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006607static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006608 return LoadContextSlotHelper(args, true);
6609}
6610
6611
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006612static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006613 return LoadContextSlotHelper(args, false);
6614}
6615
6616
6617static Object* Runtime_StoreContextSlot(Arguments args) {
6618 HandleScope scope;
6619 ASSERT(args.length() == 3);
6620
6621 Handle<Object> value(args[0]);
6622 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006623 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006624
6625 int index;
6626 PropertyAttributes attributes;
6627 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006628 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 context->Lookup(name, flags, &index, &attributes);
6630
6631 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006632 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633 // Ignore if read_only variable.
6634 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006635 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006636 }
6637 } else {
6638 ASSERT((attributes & READ_ONLY) == 0);
6639 Object* result =
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006640 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006641 USE(result);
6642 ASSERT(!result->IsFailure());
6643 }
6644 return *value;
6645 }
6646
6647 // Slow case: The property is not in a FixedArray context.
6648 // It is either in an JSObject extension context or it was not found.
6649 Handle<JSObject> context_ext;
6650
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006651 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006653 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006654 } else {
6655 // The property was not found. It needs to be stored in the global context.
6656 ASSERT(attributes == ABSENT);
6657 attributes = NONE;
6658 context_ext = Handle<JSObject>(Top::context()->global());
6659 }
6660
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006661 // Set the property, but ignore if read_only variable on the context
6662 // extension object itself.
6663 if ((attributes & READ_ONLY) == 0 ||
6664 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006665 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
6666 if (set.is_null()) {
6667 // Failure::Exception is converted to a null handle in the
6668 // handle-based methods such as SetProperty. We therefore need
6669 // to convert null handles back to exceptions.
6670 ASSERT(Top::has_pending_exception());
6671 return Failure::Exception();
6672 }
6673 }
6674 return *value;
6675}
6676
6677
6678static Object* Runtime_Throw(Arguments args) {
6679 HandleScope scope;
6680 ASSERT(args.length() == 1);
6681
6682 return Top::Throw(args[0]);
6683}
6684
6685
6686static Object* Runtime_ReThrow(Arguments args) {
6687 HandleScope scope;
6688 ASSERT(args.length() == 1);
6689
6690 return Top::ReThrow(args[0]);
6691}
6692
6693
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006694static Object* Runtime_PromoteScheduledException(Arguments args) {
6695 ASSERT_EQ(0, args.length());
6696 return Top::PromoteScheduledException();
6697}
6698
6699
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006700static Object* Runtime_ThrowReferenceError(Arguments args) {
6701 HandleScope scope;
6702 ASSERT(args.length() == 1);
6703
6704 Handle<Object> name(args[0]);
6705 Handle<Object> reference_error =
6706 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
6707 return Top::Throw(*reference_error);
6708}
6709
6710
6711static Object* Runtime_StackOverflow(Arguments args) {
6712 NoHandleAllocation na;
6713 return Top::StackOverflow();
6714}
6715
6716
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006717static Object* Runtime_StackGuard(Arguments args) {
6718 ASSERT(args.length() == 1);
6719
6720 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00006721 if (StackGuard::IsStackOverflow()) {
6722 return Runtime_StackOverflow(args);
6723 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006724
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006725 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006726}
6727
6728
6729// NOTE: These PrintXXX functions are defined for all builds (not just
6730// DEBUG builds) because we may want to be able to trace function
6731// calls in all modes.
6732static void PrintString(String* str) {
6733 // not uncommon to have empty strings
6734 if (str->length() > 0) {
6735 SmartPointer<char> s =
6736 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
6737 PrintF("%s", *s);
6738 }
6739}
6740
6741
6742static void PrintObject(Object* obj) {
6743 if (obj->IsSmi()) {
6744 PrintF("%d", Smi::cast(obj)->value());
6745 } else if (obj->IsString() || obj->IsSymbol()) {
6746 PrintString(String::cast(obj));
6747 } else if (obj->IsNumber()) {
6748 PrintF("%g", obj->Number());
6749 } else if (obj->IsFailure()) {
6750 PrintF("<failure>");
6751 } else if (obj->IsUndefined()) {
6752 PrintF("<undefined>");
6753 } else if (obj->IsNull()) {
6754 PrintF("<null>");
6755 } else if (obj->IsTrue()) {
6756 PrintF("<true>");
6757 } else if (obj->IsFalse()) {
6758 PrintF("<false>");
6759 } else {
6760 PrintF("%p", obj);
6761 }
6762}
6763
6764
6765static int StackSize() {
6766 int n = 0;
6767 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
6768 return n;
6769}
6770
6771
6772static void PrintTransition(Object* result) {
6773 // indentation
6774 { const int nmax = 80;
6775 int n = StackSize();
6776 if (n <= nmax)
6777 PrintF("%4d:%*s", n, n, "");
6778 else
6779 PrintF("%4d:%*s", n, nmax, "...");
6780 }
6781
6782 if (result == NULL) {
6783 // constructor calls
6784 JavaScriptFrameIterator it;
6785 JavaScriptFrame* frame = it.frame();
6786 if (frame->IsConstructor()) PrintF("new ");
6787 // function name
6788 Object* fun = frame->function();
6789 if (fun->IsJSFunction()) {
6790 PrintObject(JSFunction::cast(fun)->shared()->name());
6791 } else {
6792 PrintObject(fun);
6793 }
6794 // function arguments
6795 // (we are intentionally only printing the actually
6796 // supplied parameters, not all parameters required)
6797 PrintF("(this=");
6798 PrintObject(frame->receiver());
6799 const int length = frame->GetProvidedParametersCount();
6800 for (int i = 0; i < length; i++) {
6801 PrintF(", ");
6802 PrintObject(frame->GetParameter(i));
6803 }
6804 PrintF(") {\n");
6805
6806 } else {
6807 // function result
6808 PrintF("} -> ");
6809 PrintObject(result);
6810 PrintF("\n");
6811 }
6812}
6813
6814
6815static Object* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006816 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006817 NoHandleAllocation ha;
6818 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006819 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820}
6821
6822
6823static Object* Runtime_TraceExit(Arguments args) {
6824 NoHandleAllocation ha;
6825 PrintTransition(args[0]);
6826 return args[0]; // return TOS
6827}
6828
6829
6830static Object* Runtime_DebugPrint(Arguments args) {
6831 NoHandleAllocation ha;
6832 ASSERT(args.length() == 1);
6833
6834#ifdef DEBUG
6835 if (args[0]->IsString()) {
6836 // If we have a string, assume it's a code "marker"
6837 // and print some interesting cpu debugging info.
6838 JavaScriptFrameIterator it;
6839 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00006840 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
6841 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006842 } else {
6843 PrintF("DebugPrint: ");
6844 }
6845 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006846 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006847 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006848 HeapObject::cast(args[0])->map()->Print();
6849 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006851 // ShortPrint is available in release mode. Print is not.
6852 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006853#endif
6854 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00006855 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006856
6857 return args[0]; // return TOS
6858}
6859
6860
6861static Object* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006862 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006863 NoHandleAllocation ha;
6864 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006865 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006866}
6867
6868
mads.s.ager31e71382008-08-13 09:32:07 +00006869static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006870 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00006871 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006872
6873 // According to ECMA-262, section 15.9.1, page 117, the precision of
6874 // the number in a Date object representing a particular instant in
6875 // time is milliseconds. Therefore, we floor the result of getting
6876 // the OS time.
6877 double millis = floor(OS::TimeCurrentMillis());
6878 return Heap::NumberFromDouble(millis);
6879}
6880
6881
6882static Object* Runtime_DateParseString(Arguments args) {
6883 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006884 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006885
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006886 CONVERT_ARG_CHECKED(String, str, 0);
6887 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006888
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006889 CONVERT_ARG_CHECKED(JSArray, output, 1);
6890 RUNTIME_ASSERT(output->HasFastElements());
6891
6892 AssertNoAllocation no_allocation;
6893
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006894 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006895 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
6896 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00006897 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006898 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006899 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00006900 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006901 result = DateParser::Parse(str->ToUC16Vector(), output_array);
6902 }
6903
6904 if (result) {
6905 return *output;
6906 } else {
6907 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006908 }
6909}
6910
6911
6912static Object* Runtime_DateLocalTimezone(Arguments args) {
6913 NoHandleAllocation ha;
6914 ASSERT(args.length() == 1);
6915
6916 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00006917 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006918 return Heap::AllocateStringFromUtf8(CStrVector(zone));
6919}
6920
6921
6922static Object* Runtime_DateLocalTimeOffset(Arguments args) {
6923 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00006924 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006925
6926 return Heap::NumberFromDouble(OS::LocalTimeOffset());
6927}
6928
6929
6930static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
6931 NoHandleAllocation ha;
6932 ASSERT(args.length() == 1);
6933
6934 CONVERT_DOUBLE_CHECKED(x, args[0]);
6935 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
6936}
6937
6938
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006939static Object* Runtime_GlobalReceiver(Arguments args) {
6940 ASSERT(args.length() == 1);
6941 Object* global = args[0];
6942 if (!global->IsJSGlobalObject()) return Heap::null_value();
6943 return JSGlobalObject::cast(global)->global_receiver();
6944}
6945
6946
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006947static Object* Runtime_CompileString(Arguments args) {
6948 HandleScope scope;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006949 ASSERT_EQ(2, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006950 CONVERT_ARG_CHECKED(String, source, 0);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006951 CONVERT_ARG_CHECKED(Oddball, is_json, 1)
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006952
ager@chromium.org381abbb2009-02-25 13:23:22 +00006953 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006954 Handle<Context> context(Top::context()->global_context());
ager@chromium.orgadd848f2009-08-13 12:44:13 +00006955 Compiler::ValidationState validate = (is_json->IsTrue())
6956 ? Compiler::VALIDATE_JSON : Compiler::DONT_VALIDATE_JSON;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006957 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
6958 context,
6959 true,
6960 validate);
6961 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006962 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006963 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006964 return *fun;
6965}
6966
6967
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00006968static ObjectPair CompileGlobalEval(Handle<String> source,
6969 Handle<Object> receiver) {
6970 // Deal with a normal eval call with a string argument. Compile it
6971 // and return the compiled function bound in the local context.
6972 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
6973 source,
6974 Handle<Context>(Top::context()),
6975 Top::context()->IsGlobalContext(),
6976 Compiler::DONT_VALIDATE_JSON);
6977 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
6978 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
6979 shared,
6980 Handle<Context>(Top::context()),
6981 NOT_TENURED);
6982 return MakePair(*compiled, *receiver);
6983}
6984
6985
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006986static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
6987 ASSERT(args.length() == 3);
6988 if (!args[0]->IsJSFunction()) {
6989 return MakePair(Top::ThrowIllegalOperation(), NULL);
6990 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006991
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006992 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006993 Handle<JSFunction> callee = args.at<JSFunction>(0);
6994 Handle<Object> receiver; // Will be overwritten.
6995
6996 // Compute the calling context.
6997 Handle<Context> context = Handle<Context>(Top::context());
6998#ifdef DEBUG
6999 // Make sure Top::context() agrees with the old code that traversed
7000 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007001 StackFrameLocator locator;
7002 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007003 ASSERT(Context::cast(frame->context()) == *context);
7004#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007005
7006 // Find where the 'eval' symbol is bound. It is unaliased only if
7007 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007008 int index = -1;
7009 PropertyAttributes attributes = ABSENT;
7010 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007011 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7012 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007013 // Stop search when eval is found or when the global context is
7014 // reached.
7015 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007016 if (context->is_function_context()) {
7017 context = Handle<Context>(Context::cast(context->closure()->context()));
7018 } else {
7019 context = Handle<Context>(context->previous());
7020 }
7021 }
7022
iposva@chromium.org245aa852009-02-10 00:49:54 +00007023 // If eval could not be resolved, it has been deleted and we need to
7024 // throw a reference error.
7025 if (attributes == ABSENT) {
7026 Handle<Object> name = Factory::eval_symbol();
7027 Handle<Object> reference_error =
7028 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007029 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007030 }
7031
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007032 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007033 // 'eval' is not bound in the global context. Just call the function
7034 // with the given arguments. This is not necessarily the global eval.
7035 if (receiver->IsContext()) {
7036 context = Handle<Context>::cast(receiver);
7037 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007038 } else if (receiver->IsJSContextExtensionObject()) {
7039 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007040 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007041 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007042 }
7043
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007044 // 'eval' is bound in the global context, but it may have been overwritten.
7045 // Compare it to the builtin 'GlobalEval' function to make sure.
7046 if (*callee != Top::global_context()->global_eval_fun() ||
7047 !args[1]->IsString()) {
7048 return MakePair(*callee, Top::context()->global()->global_receiver());
7049 }
7050
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007051 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7052}
7053
7054
7055static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7056 ASSERT(args.length() == 3);
7057 if (!args[0]->IsJSFunction()) {
7058 return MakePair(Top::ThrowIllegalOperation(), NULL);
7059 }
7060
7061 HandleScope scope;
7062 Handle<JSFunction> callee = args.at<JSFunction>(0);
7063
7064 // 'eval' is bound in the global context, but it may have been overwritten.
7065 // Compare it to the builtin 'GlobalEval' function to make sure.
7066 if (*callee != Top::global_context()->global_eval_fun() ||
7067 !args[1]->IsString()) {
7068 return MakePair(*callee, Top::context()->global()->global_receiver());
7069 }
7070
7071 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007072}
7073
7074
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007075static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
7076 // This utility adjusts the property attributes for newly created Function
7077 // object ("new Function(...)") by changing the map.
7078 // All it does is changing the prototype property to enumerable
7079 // as specified in ECMA262, 15.3.5.2.
7080 HandleScope scope;
7081 ASSERT(args.length() == 1);
7082 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7083 ASSERT(func->map()->instance_type() ==
7084 Top::function_instance_map()->instance_type());
7085 ASSERT(func->map()->instance_size() ==
7086 Top::function_instance_map()->instance_size());
7087 func->set_map(*Top::function_instance_map());
7088 return *func;
7089}
7090
7091
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007092static Object* Runtime_AllocateInNewSpace(Arguments args) {
7093 // Allocate a block of memory in NewSpace (filled with a filler).
7094 // Use as fallback for allocation in generated code when NewSpace
7095 // is full.
7096 ASSERT(args.length() == 1);
7097 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7098 int size = size_smi->value();
7099 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7100 RUNTIME_ASSERT(size > 0);
7101 static const int kMinFreeNewSpaceAfterGC =
7102 Heap::InitialSemiSpaceSize() * 3/4;
7103 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
7104 Object* allocation = Heap::new_space()->AllocateRaw(size);
7105 if (!allocation->IsFailure()) {
7106 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7107 }
7108 return allocation;
7109}
7110
7111
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007112// Push an array unto an array of arrays if it is not already in the
7113// array. Returns true if the element was pushed on the stack and
7114// false otherwise.
7115static Object* Runtime_PushIfAbsent(Arguments args) {
7116 ASSERT(args.length() == 2);
7117 CONVERT_CHECKED(JSArray, array, args[0]);
7118 CONVERT_CHECKED(JSArray, element, args[1]);
7119 RUNTIME_ASSERT(array->HasFastElements());
7120 int length = Smi::cast(array->length())->value();
7121 FixedArray* elements = FixedArray::cast(array->elements());
7122 for (int i = 0; i < length; i++) {
7123 if (elements->get(i) == element) return Heap::false_value();
7124 }
7125 Object* obj = array->SetFastElement(length, element);
7126 if (obj->IsFailure()) return obj;
7127 return Heap::true_value();
7128}
7129
7130
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007131/**
7132 * A simple visitor visits every element of Array's.
7133 * The backend storage can be a fixed array for fast elements case,
7134 * or a dictionary for sparse array. Since Dictionary is a subtype
7135 * of FixedArray, the class can be used by both fast and slow cases.
7136 * The second parameter of the constructor, fast_elements, specifies
7137 * whether the storage is a FixedArray or Dictionary.
7138 *
7139 * An index limit is used to deal with the situation that a result array
7140 * length overflows 32-bit non-negative integer.
7141 */
7142class ArrayConcatVisitor {
7143 public:
7144 ArrayConcatVisitor(Handle<FixedArray> storage,
7145 uint32_t index_limit,
7146 bool fast_elements) :
7147 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007148 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007149
7150 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007151 if (i >= index_limit_ - index_offset_) return;
7152 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007153
7154 if (fast_elements_) {
7155 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7156 storage_->set(index, *elm);
7157
7158 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007159 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7160 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007161 Factory::DictionaryAtNumberPut(dict, index, elm);
7162 if (!result.is_identical_to(dict))
7163 storage_ = result;
7164 }
7165 }
7166
7167 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007168 if (index_limit_ - index_offset_ < delta) {
7169 index_offset_ = index_limit_;
7170 } else {
7171 index_offset_ += delta;
7172 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007173 }
7174
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007175 Handle<FixedArray> storage() { return storage_; }
7176
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007177 private:
7178 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007179 // Limit on the accepted indices. Elements with indices larger than the
7180 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007181 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007182 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007183 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007184 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007185};
7186
7187
ager@chromium.org3811b432009-10-28 14:53:37 +00007188template<class ExternalArrayClass, class ElementType>
7189static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7190 bool elements_are_ints,
7191 bool elements_are_guaranteed_smis,
7192 uint32_t range,
7193 ArrayConcatVisitor* visitor) {
7194 Handle<ExternalArrayClass> array(
7195 ExternalArrayClass::cast(receiver->elements()));
7196 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7197
7198 if (visitor != NULL) {
7199 if (elements_are_ints) {
7200 if (elements_are_guaranteed_smis) {
7201 for (uint32_t j = 0; j < len; j++) {
7202 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7203 visitor->visit(j, e);
7204 }
7205 } else {
7206 for (uint32_t j = 0; j < len; j++) {
7207 int64_t val = static_cast<int64_t>(array->get(j));
7208 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7209 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7210 visitor->visit(j, e);
7211 } else {
7212 Handle<Object> e(
7213 Heap::AllocateHeapNumber(static_cast<ElementType>(val)));
7214 visitor->visit(j, e);
7215 }
7216 }
7217 }
7218 } else {
7219 for (uint32_t j = 0; j < len; j++) {
7220 Handle<Object> e(Heap::AllocateHeapNumber(array->get(j)));
7221 visitor->visit(j, e);
7222 }
7223 }
7224 }
7225
7226 return len;
7227}
7228
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007229/**
7230 * A helper function that visits elements of a JSObject. Only elements
7231 * whose index between 0 and range (exclusive) are visited.
7232 *
7233 * If the third parameter, visitor, is not NULL, the visitor is called
7234 * with parameters, 'visitor_index_offset + element index' and the element.
7235 *
7236 * It returns the number of visisted elements.
7237 */
7238static uint32_t IterateElements(Handle<JSObject> receiver,
7239 uint32_t range,
7240 ArrayConcatVisitor* visitor) {
7241 uint32_t num_of_elements = 0;
7242
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007243 switch (receiver->GetElementsKind()) {
7244 case JSObject::FAST_ELEMENTS: {
7245 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7246 uint32_t len = elements->length();
7247 if (range < len) {
7248 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007249 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007250
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007251 for (uint32_t j = 0; j < len; j++) {
7252 Handle<Object> e(elements->get(j));
7253 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007254 num_of_elements++;
7255 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007256 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007257 }
7258 }
7259 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007260 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007261 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007262 case JSObject::PIXEL_ELEMENTS: {
7263 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7264 uint32_t len = pixels->length();
7265 if (range < len) {
7266 len = range;
7267 }
7268
7269 for (uint32_t j = 0; j < len; j++) {
7270 num_of_elements++;
7271 if (visitor != NULL) {
7272 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7273 visitor->visit(j, e);
7274 }
7275 }
7276 break;
7277 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007278 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7279 num_of_elements =
7280 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7281 receiver, true, true, range, visitor);
7282 break;
7283 }
7284 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7285 num_of_elements =
7286 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7287 receiver, true, true, range, visitor);
7288 break;
7289 }
7290 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7291 num_of_elements =
7292 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7293 receiver, true, true, range, visitor);
7294 break;
7295 }
7296 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7297 num_of_elements =
7298 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7299 receiver, true, true, range, visitor);
7300 break;
7301 }
7302 case JSObject::EXTERNAL_INT_ELEMENTS: {
7303 num_of_elements =
7304 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7305 receiver, true, false, range, visitor);
7306 break;
7307 }
7308 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7309 num_of_elements =
7310 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7311 receiver, true, false, range, visitor);
7312 break;
7313 }
7314 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7315 num_of_elements =
7316 IterateExternalArrayElements<ExternalFloatArray, float>(
7317 receiver, false, false, range, visitor);
7318 break;
7319 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007320 case JSObject::DICTIONARY_ELEMENTS: {
7321 Handle<NumberDictionary> dict(receiver->element_dictionary());
7322 uint32_t capacity = dict->Capacity();
7323 for (uint32_t j = 0; j < capacity; j++) {
7324 Handle<Object> k(dict->KeyAt(j));
7325 if (dict->IsKey(*k)) {
7326 ASSERT(k->IsNumber());
7327 uint32_t index = static_cast<uint32_t>(k->Number());
7328 if (index < range) {
7329 num_of_elements++;
7330 if (visitor) {
7331 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7332 }
7333 }
7334 }
7335 }
7336 break;
7337 }
7338 default:
7339 UNREACHABLE();
7340 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007341 }
7342
7343 return num_of_elements;
7344}
7345
7346
7347/**
7348 * A helper function that visits elements of an Array object, and elements
7349 * on its prototypes.
7350 *
7351 * Elements on prototypes are visited first, and only elements whose indices
7352 * less than Array length are visited.
7353 *
7354 * If a ArrayConcatVisitor object is given, the visitor is called with
7355 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007356 *
7357 * The returned number of elements is an upper bound on the actual number
7358 * of elements added. If the same element occurs in more than one object
7359 * in the array's prototype chain, it will be counted more than once, but
7360 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007361 */
7362static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7363 ArrayConcatVisitor* visitor) {
7364 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7365 Handle<Object> obj = array;
7366
7367 static const int kEstimatedPrototypes = 3;
7368 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7369
7370 // Visit prototype first. If an element on the prototype is shadowed by
7371 // the inheritor using the same index, the ArrayConcatVisitor visits
7372 // the prototype element before the shadowing element.
7373 // The visitor can simply overwrite the old value by new value using
7374 // the same index. This follows Array::concat semantics.
7375 while (!obj->IsNull()) {
7376 objects.Add(Handle<JSObject>::cast(obj));
7377 obj = Handle<Object>(obj->GetPrototype());
7378 }
7379
7380 uint32_t nof_elements = 0;
7381 for (int i = objects.length() - 1; i >= 0; i--) {
7382 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007383 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007384 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007385
7386 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7387 nof_elements = JSObject::kMaxElementCount;
7388 } else {
7389 nof_elements += encountered_elements;
7390 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007391 }
7392
7393 return nof_elements;
7394}
7395
7396
7397/**
7398 * A helper function of Runtime_ArrayConcat.
7399 *
7400 * The first argument is an Array of arrays and objects. It is the
7401 * same as the arguments array of Array::concat JS function.
7402 *
7403 * If an argument is an Array object, the function visits array
7404 * elements. If an argument is not an Array object, the function
7405 * visits the object as if it is an one-element array.
7406 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007407 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007408 * non-negative number is used as new length. For example, if one
7409 * array length is 2^32 - 1, second array length is 1, the
7410 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007411 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
7412 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007413 */
7414static uint32_t IterateArguments(Handle<JSArray> arguments,
7415 ArrayConcatVisitor* visitor) {
7416 uint32_t visited_elements = 0;
7417 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7418
7419 for (uint32_t i = 0; i < num_of_args; i++) {
7420 Handle<Object> obj(arguments->GetElement(i));
7421 if (obj->IsJSArray()) {
7422 Handle<JSArray> array = Handle<JSArray>::cast(obj);
7423 uint32_t len = static_cast<uint32_t>(array->length()->Number());
7424 uint32_t nof_elements =
7425 IterateArrayAndPrototypeElements(array, visitor);
7426 // Total elements of array and its prototype chain can be more than
7427 // the array length, but ArrayConcat can only concatenate at most
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007428 // the array length number of elements. We use the length as an estimate
7429 // for the actual number of elements added.
7430 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
7431 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
7432 visited_elements = JSArray::kMaxElementCount;
7433 } else {
7434 visited_elements += added_elements;
7435 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007436 if (visitor) visitor->increase_index_offset(len);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007437 } else {
7438 if (visitor) {
7439 visitor->visit(0, obj);
7440 visitor->increase_index_offset(1);
7441 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007442 if (visited_elements < JSArray::kMaxElementCount) {
7443 visited_elements++;
7444 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007445 }
7446 }
7447 return visited_elements;
7448}
7449
7450
7451/**
7452 * Array::concat implementation.
7453 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007454 * TODO(lrn): Fix non-compliance for very large concatenations and update to
7455 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007456 */
7457static Object* Runtime_ArrayConcat(Arguments args) {
7458 ASSERT(args.length() == 1);
7459 HandleScope handle_scope;
7460
7461 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
7462 Handle<JSArray> arguments(arg_arrays);
7463
7464 // Pass 1: estimate the number of elements of the result
7465 // (it could be more than real numbers if prototype has elements).
7466 uint32_t result_length = 0;
7467 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7468
7469 { AssertNoAllocation nogc;
7470 for (uint32_t i = 0; i < num_of_args; i++) {
7471 Object* obj = arguments->GetElement(i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007472 uint32_t length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007473 if (obj->IsJSArray()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007474 length_estimate =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007475 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
7476 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007477 length_estimate = 1;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007478 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007479 if (JSObject::kMaxElementCount - result_length < length_estimate) {
7480 result_length = JSObject::kMaxElementCount;
7481 break;
7482 }
7483 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007484 }
7485 }
7486
7487 // Allocate an empty array, will set length and content later.
7488 Handle<JSArray> result = Factory::NewJSArray(0);
7489
7490 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
7491 // If estimated number of elements is more than half of length, a
7492 // fixed array (fast case) is more time and space-efficient than a
7493 // dictionary.
7494 bool fast_case = (estimate_nof_elements * 2) >= result_length;
7495
7496 Handle<FixedArray> storage;
7497 if (fast_case) {
7498 // The backing storage array must have non-existing elements to
7499 // preserve holes across concat operations.
7500 storage = Factory::NewFixedArrayWithHoles(result_length);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007501 result->set_map(*Factory::GetFastElementsMap(Handle<Map>(result->map())));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007502 } else {
7503 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
7504 uint32_t at_least_space_for = estimate_nof_elements +
7505 (estimate_nof_elements >> 2);
7506 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007507 Factory::NewNumberDictionary(at_least_space_for));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007508 result->set_map(*Factory::GetSlowElementsMap(Handle<Map>(result->map())));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007509 }
7510
7511 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
7512
7513 ArrayConcatVisitor visitor(storage, result_length, fast_case);
7514
7515 IterateArguments(arguments, &visitor);
7516
7517 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007518 // Please note the storage might have changed in the visitor.
7519 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007520
7521 return *result;
7522}
7523
7524
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525// This will not allocate (flatten the string), but it may run
7526// very slowly for very deeply nested ConsStrings. For debugging use only.
7527static Object* Runtime_GlobalPrint(Arguments args) {
7528 NoHandleAllocation ha;
7529 ASSERT(args.length() == 1);
7530
7531 CONVERT_CHECKED(String, string, args[0]);
7532 StringInputBuffer buffer(string);
7533 while (buffer.has_more()) {
7534 uint16_t character = buffer.GetNext();
7535 PrintF("%c", character);
7536 }
7537 return string;
7538}
7539
ager@chromium.org5ec48922009-05-05 07:25:34 +00007540// Moves all own elements of an object, that are below a limit, to positions
7541// starting at zero. All undefined values are placed after non-undefined values,
7542// and are followed by non-existing element. Does not change the length
7543// property.
7544// Returns the number of non-undefined elements collected.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007545static Object* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007546 ASSERT(args.length() == 2);
7547 CONVERT_CHECKED(JSObject, object, args[0]);
7548 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
7549 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007550}
7551
7552
7553// Move contents of argument 0 (an array) to argument 1 (an array)
7554static Object* Runtime_MoveArrayContents(Arguments args) {
7555 ASSERT(args.length() == 2);
7556 CONVERT_CHECKED(JSArray, from, args[0]);
7557 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007558 HeapObject* new_elements = from->elements();
7559 Object* new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007560 if (new_elements->map() == Heap::fixed_array_map() ||
7561 new_elements->map() == Heap::fixed_cow_array_map()) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007562 new_map = to->map()->GetFastElementsMap();
7563 } else {
7564 new_map = to->map()->GetSlowElementsMap();
7565 }
7566 if (new_map->IsFailure()) return new_map;
7567 to->set_map(Map::cast(new_map));
7568 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007569 to->set_length(from->length());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007570 Object* obj = from->ResetElements();
7571 if (obj->IsFailure()) return obj;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007572 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007573 return to;
7574}
7575
7576
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007577// How many elements does this object/array have?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007578static Object* Runtime_EstimateNumberOfElements(Arguments args) {
7579 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007580 CONVERT_CHECKED(JSObject, object, args[0]);
7581 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007582 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007583 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007584 } else if (object->IsJSArray()) {
7585 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007586 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007587 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007588 }
7589}
7590
7591
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007592static Object* Runtime_SwapElements(Arguments args) {
7593 HandleScope handle_scope;
7594
7595 ASSERT_EQ(3, args.length());
7596
ager@chromium.orgac091b72010-05-05 07:34:42 +00007597 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007598 Handle<Object> key1 = args.at<Object>(1);
7599 Handle<Object> key2 = args.at<Object>(2);
7600
7601 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007602 if (!key1->ToArrayIndex(&index1)
7603 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00007604 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007605 }
7606
ager@chromium.orgac091b72010-05-05 07:34:42 +00007607 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
7608 Handle<Object> tmp1 = GetElement(jsobject, index1);
7609 Handle<Object> tmp2 = GetElement(jsobject, index2);
7610
7611 SetElement(jsobject, index1, tmp2);
7612 SetElement(jsobject, index2, tmp1);
7613
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007614 return Heap::undefined_value();
7615}
7616
7617
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007618// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007619// might have elements. Can either return keys (positive integers) or
7620// intervals (pair of a negative integer (-start-1) followed by a
7621// positive (length)) or undefined values.
7622// Intervals can span over some keys that are not in the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007623static Object* Runtime_GetArrayKeys(Arguments args) {
7624 ASSERT(args.length() == 2);
7625 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007626 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007627 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007628 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007629 // Create an array and get all the keys into it, then remove all the
7630 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007631 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007632 int keys_length = keys->length();
7633 for (int i = 0; i < keys_length; i++) {
7634 Object* key = keys->get(i);
7635 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007636 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007637 // Zap invalid keys.
7638 keys->set_undefined(i);
7639 }
7640 }
7641 return *Factory::NewJSArrayWithElements(keys);
7642 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007643 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007644 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
7645 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007646 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007647 uint32_t actual_length =
7648 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00007649 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007650 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00007651 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007652 single_interval->set(1, *length_object);
7653 return *Factory::NewJSArrayWithElements(single_interval);
7654 }
7655}
7656
7657
7658// DefineAccessor takes an optional final argument which is the
7659// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
7660// to the way accessors are implemented, it is set for both the getter
7661// and setter on the first call to DefineAccessor and ignored on
7662// subsequent calls.
7663static Object* Runtime_DefineAccessor(Arguments args) {
7664 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
7665 // Compute attributes.
7666 PropertyAttributes attributes = NONE;
7667 if (args.length() == 5) {
7668 CONVERT_CHECKED(Smi, attrs, args[4]);
7669 int value = attrs->value();
7670 // Only attribute bits should be set.
7671 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
7672 attributes = static_cast<PropertyAttributes>(value);
7673 }
7674
7675 CONVERT_CHECKED(JSObject, obj, args[0]);
7676 CONVERT_CHECKED(String, name, args[1]);
7677 CONVERT_CHECKED(Smi, flag, args[2]);
7678 CONVERT_CHECKED(JSFunction, fun, args[3]);
7679 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
7680}
7681
7682
7683static Object* Runtime_LookupAccessor(Arguments args) {
7684 ASSERT(args.length() == 3);
7685 CONVERT_CHECKED(JSObject, obj, args[0]);
7686 CONVERT_CHECKED(String, name, args[1]);
7687 CONVERT_CHECKED(Smi, flag, args[2]);
7688 return obj->LookupAccessor(name, flag->value() == 0);
7689}
7690
7691
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007692#ifdef ENABLE_DEBUGGER_SUPPORT
7693static Object* Runtime_DebugBreak(Arguments args) {
7694 ASSERT(args.length() == 0);
7695 return Execution::DebugBreakHelper();
7696}
7697
7698
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007699// Helper functions for wrapping and unwrapping stack frame ids.
7700static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007701 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007702 return Smi::FromInt(id >> 2);
7703}
7704
7705
7706static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
7707 return static_cast<StackFrame::Id>(wrapped->value() << 2);
7708}
7709
7710
7711// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00007712// args[0]: debug event listener function to set or null or undefined for
7713// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007714// args[1]: object supplied during callback
iposva@chromium.org245aa852009-02-10 00:49:54 +00007715static Object* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007716 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007717 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
7718 args[0]->IsUndefined() ||
7719 args[0]->IsNull());
7720 Handle<Object> callback = args.at<Object>(0);
7721 Handle<Object> data = args.at<Object>(1);
7722 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007723
7724 return Heap::undefined_value();
7725}
7726
7727
7728static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00007729 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007730 StackGuard::DebugBreak();
7731 return Heap::undefined_value();
7732}
7733
7734
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007735static Object* DebugLookupResultValue(Object* receiver, String* name,
7736 LookupResult* result,
ager@chromium.org32912102009-01-16 10:38:43 +00007737 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007738 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007739 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007740 case NORMAL:
7741 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007742 if (value->IsTheHole()) {
7743 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007744 }
7745 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007746 case FIELD:
7747 value =
7748 JSObject::cast(
7749 result->holder())->FastPropertyAt(result->GetFieldIndex());
7750 if (value->IsTheHole()) {
7751 return Heap::undefined_value();
7752 }
7753 return value;
7754 case CONSTANT_FUNCTION:
7755 return result->GetConstantFunction();
7756 case CALLBACKS: {
7757 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007758 if (structure->IsProxy() || structure->IsAccessorInfo()) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007759 value = receiver->GetPropertyWithCallback(
7760 receiver, structure, name, result->holder());
ager@chromium.org381abbb2009-02-25 13:23:22 +00007761 if (value->IsException()) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007762 value = Top::pending_exception();
7763 Top::clear_pending_exception();
7764 if (caught_exception != NULL) {
7765 *caught_exception = true;
7766 }
7767 }
7768 return value;
7769 } else {
7770 return Heap::undefined_value();
7771 }
7772 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007773 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007774 case MAP_TRANSITION:
7775 case CONSTANT_TRANSITION:
7776 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007777 return Heap::undefined_value();
7778 default:
7779 UNREACHABLE();
7780 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007781 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007782 return Heap::undefined_value();
7783}
7784
7785
ager@chromium.org32912102009-01-16 10:38:43 +00007786// Get debugger related details for an object property.
7787// args[0]: object holding property
7788// args[1]: name of the property
7789//
7790// The array returned contains the following information:
7791// 0: Property value
7792// 1: Property details
7793// 2: Property value is exception
7794// 3: Getter function if defined
7795// 4: Setter function if defined
7796// Items 2-4 are only filled if the property has either a getter or a setter
7797// defined through __defineGetter__ and/or __defineSetter__.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007798static Object* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007799 HandleScope scope;
7800
7801 ASSERT(args.length() == 2);
7802
7803 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7804 CONVERT_ARG_CHECKED(String, name, 1);
7805
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007806 // Make sure to set the current context to the context before the debugger was
7807 // entered (if the debugger is entered). The reason for switching context here
7808 // is that for some property lookups (accessors and interceptors) callbacks
7809 // into the embedding application can occour, and the embedding application
7810 // could have the assumption that its own global context is the current
7811 // context and not some internal debugger context.
7812 SaveContext save;
7813 if (Debug::InDebugger()) {
7814 Top::set_context(*Debug::debugger_entry()->GetContext());
7815 }
7816
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007817 // Skip the global proxy as it has no properties and always delegates to the
7818 // real global object.
7819 if (obj->IsJSGlobalProxy()) {
7820 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
7821 }
7822
7823
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007824 // Check if the name is trivially convertible to an index and get the element
7825 // if so.
7826 uint32_t index;
7827 if (name->AsArrayIndex(&index)) {
7828 Handle<FixedArray> details = Factory::NewFixedArray(2);
7829 details->set(0, Runtime::GetElementOrCharAt(obj, index));
7830 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
7831 return *Factory::NewJSArrayWithElements(details);
7832 }
7833
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007834 // Find the number of objects making up this.
7835 int length = LocalPrototypeChainLength(*obj);
7836
7837 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007838 Handle<JSObject> jsproto = obj;
7839 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007840 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007841 jsproto->LocalLookup(*name, &result);
7842 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007843 // LookupResult is not GC safe as it holds raw object pointers.
7844 // GC can happen later in this code so put the required fields into
7845 // local variables using handles when required for later use.
7846 PropertyType result_type = result.type();
7847 Handle<Object> result_callback_obj;
7848 if (result_type == CALLBACKS) {
7849 result_callback_obj = Handle<Object>(result.GetCallbackObject());
7850 }
7851 Smi* property_details = result.GetPropertyDetails().AsSmi();
7852 // DebugLookupResultValue can cause GC so details from LookupResult needs
7853 // to be copied to handles before this.
7854 bool caught_exception = false;
7855 Object* raw_value = DebugLookupResultValue(*obj, *name, &result,
7856 &caught_exception);
7857 if (raw_value->IsFailure()) return raw_value;
7858 Handle<Object> value(raw_value);
7859
7860 // If the callback object is a fixed array then it contains JavaScript
7861 // getter and/or setter.
7862 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
7863 result_callback_obj->IsFixedArray();
7864 Handle<FixedArray> details =
7865 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
7866 details->set(0, *value);
7867 details->set(1, property_details);
7868 if (hasJavaScriptAccessors) {
7869 details->set(2,
7870 caught_exception ? Heap::true_value()
7871 : Heap::false_value());
7872 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
7873 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
7874 }
7875
7876 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007877 }
7878 if (i < length - 1) {
7879 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
7880 }
7881 }
7882
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007883 return Heap::undefined_value();
7884}
7885
7886
7887static Object* Runtime_DebugGetProperty(Arguments args) {
7888 HandleScope scope;
7889
7890 ASSERT(args.length() == 2);
7891
7892 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7893 CONVERT_ARG_CHECKED(String, name, 1);
7894
7895 LookupResult result;
7896 obj->Lookup(*name, &result);
7897 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007898 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007899 }
7900 return Heap::undefined_value();
7901}
7902
7903
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007904// Return the property type calculated from the property details.
7905// args[0]: smi with property details.
7906static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
7907 ASSERT(args.length() == 1);
7908 CONVERT_CHECKED(Smi, details, args[0]);
7909 PropertyType type = PropertyDetails(details).type();
7910 return Smi::FromInt(static_cast<int>(type));
7911}
7912
7913
7914// Return the property attribute calculated from the property details.
7915// args[0]: smi with property details.
7916static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
7917 ASSERT(args.length() == 1);
7918 CONVERT_CHECKED(Smi, details, args[0]);
7919 PropertyAttributes attributes = PropertyDetails(details).attributes();
7920 return Smi::FromInt(static_cast<int>(attributes));
7921}
7922
7923
7924// Return the property insertion index calculated from the property details.
7925// args[0]: smi with property details.
7926static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
7927 ASSERT(args.length() == 1);
7928 CONVERT_CHECKED(Smi, details, args[0]);
7929 int index = PropertyDetails(details).index();
7930 return Smi::FromInt(index);
7931}
7932
7933
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007934// Return property value from named interceptor.
7935// args[0]: object
7936// args[1]: property name
7937static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
7938 HandleScope scope;
7939 ASSERT(args.length() == 2);
7940 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7941 RUNTIME_ASSERT(obj->HasNamedInterceptor());
7942 CONVERT_ARG_CHECKED(String, name, 1);
7943
7944 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007945 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007946}
7947
7948
7949// Return element value from indexed interceptor.
7950// args[0]: object
7951// args[1]: index
7952static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
7953 HandleScope scope;
7954 ASSERT(args.length() == 2);
7955 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7956 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
7957 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
7958
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007959 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007960}
7961
7962
7963static Object* Runtime_CheckExecutionState(Arguments args) {
7964 ASSERT(args.length() >= 1);
7965 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007966 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007967 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007968 return Top::Throw(Heap::illegal_execution_state_symbol());
7969 }
7970
7971 return Heap::true_value();
7972}
7973
7974
7975static Object* Runtime_GetFrameCount(Arguments args) {
7976 HandleScope scope;
7977 ASSERT(args.length() == 1);
7978
7979 // Check arguments.
7980 Object* result = Runtime_CheckExecutionState(args);
7981 if (result->IsFailure()) return result;
7982
7983 // Count all frames which are relevant to debugging stack trace.
7984 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007985 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00007986 if (id == StackFrame::NO_ID) {
7987 // If there is no JavaScript stack frame count is 0.
7988 return Smi::FromInt(0);
7989 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007990 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
7991 return Smi::FromInt(n);
7992}
7993
7994
7995static const int kFrameDetailsFrameIdIndex = 0;
7996static const int kFrameDetailsReceiverIndex = 1;
7997static const int kFrameDetailsFunctionIndex = 2;
7998static const int kFrameDetailsArgumentCountIndex = 3;
7999static const int kFrameDetailsLocalCountIndex = 4;
8000static const int kFrameDetailsSourcePositionIndex = 5;
8001static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008002static const int kFrameDetailsAtReturnIndex = 7;
8003static const int kFrameDetailsDebuggerFrameIndex = 8;
8004static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008005
8006// Return an array with frame details
8007// args[0]: number: break id
8008// args[1]: number: frame index
8009//
8010// The array returned contains the following information:
8011// 0: Frame id
8012// 1: Receiver
8013// 2: Function
8014// 3: Argument count
8015// 4: Local count
8016// 5: Source position
8017// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008018// 7: Is at return
8019// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008020// Arguments name, value
8021// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008022// Return value if any
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008023static Object* Runtime_GetFrameDetails(Arguments args) {
8024 HandleScope scope;
8025 ASSERT(args.length() == 2);
8026
8027 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008028 Object* check = Runtime_CheckExecutionState(args);
8029 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008030 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8031
8032 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008033 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008034 if (id == StackFrame::NO_ID) {
8035 // If there are no JavaScript stack frames return undefined.
8036 return Heap::undefined_value();
8037 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008038 int count = 0;
8039 JavaScriptFrameIterator it(id);
8040 for (; !it.done(); it.Advance()) {
8041 if (count == index) break;
8042 count++;
8043 }
8044 if (it.done()) return Heap::undefined_value();
8045
8046 // Traverse the saved contexts chain to find the active context for the
8047 // selected frame.
8048 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008049 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008050 save = save->prev();
8051 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008052 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008053
8054 // Get the frame id.
8055 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8056
8057 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008058 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008059
8060 // Check for constructor frame.
8061 bool constructor = it.frame()->IsConstructor();
8062
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008063 // Get scope info and read from it for local variable information.
8064 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008065 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008066 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008067
8068 // Get the context.
8069 Handle<Context> context(Context::cast(it.frame()->context()));
8070
8071 // Get the locals names and values into a temporary array.
8072 //
8073 // TODO(1240907): Hide compiler-introduced stack variables
8074 // (e.g. .result)? For users of the debugger, they will probably be
8075 // confusing.
8076 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
8077 for (int i = 0; i < info.NumberOfLocals(); i++) {
8078 // Name of the local.
8079 locals->set(i * 2, *info.LocalName(i));
8080
8081 // Fetch the value of the local - either from the stack or from a
8082 // heap-allocated context.
8083 if (i < info.number_of_stack_slots()) {
8084 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8085 } else {
8086 Handle<String> name = info.LocalName(i);
8087 // Traverse the context chain to the function context as all local
8088 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008089 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008090 context = Handle<Context>(context->previous());
8091 }
8092 ASSERT(context->is_function_context());
8093 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008094 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008095 }
8096 }
8097
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008098 // Check whether this frame is positioned at return.
8099 int at_return = (index == 0) ? Debug::IsBreakAtReturn(it.frame()) : false;
8100
8101 // If positioned just before return find the value to be returned and add it
8102 // to the frame information.
8103 Handle<Object> return_value = Factory::undefined_value();
8104 if (at_return) {
8105 StackFrameIterator it2;
8106 Address internal_frame_sp = NULL;
8107 while (!it2.done()) {
8108 if (it2.frame()->is_internal()) {
8109 internal_frame_sp = it2.frame()->sp();
8110 } else {
8111 if (it2.frame()->is_java_script()) {
8112 if (it2.frame()->id() == it.frame()->id()) {
8113 // The internal frame just before the JavaScript frame contains the
8114 // value to return on top. A debug break at return will create an
8115 // internal frame to store the return value (eax/rax/r0) before
8116 // entering the debug break exit frame.
8117 if (internal_frame_sp != NULL) {
8118 return_value =
8119 Handle<Object>(Memory::Object_at(internal_frame_sp));
8120 break;
8121 }
8122 }
8123 }
8124
8125 // Indicate that the previous frame was not an internal frame.
8126 internal_frame_sp = NULL;
8127 }
8128 it2.Advance();
8129 }
8130 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008131
8132 // Now advance to the arguments adapter frame (if any). It contains all
8133 // the provided parameters whereas the function frame always have the number
8134 // of arguments matching the functions parameters. The rest of the
8135 // information (except for what is collected above) is the same.
8136 it.AdvanceToArgumentsFrame();
8137
8138 // Find the number of arguments to fill. At least fill the number of
8139 // parameters for the function and fill more if more parameters are provided.
8140 int argument_count = info.number_of_parameters();
8141 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8142 argument_count = it.frame()->GetProvidedParametersCount();
8143 }
8144
8145 // Calculate the size of the result.
8146 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008147 2 * (argument_count + info.NumberOfLocals()) +
8148 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008149 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8150
8151 // Add the frame id.
8152 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8153
8154 // Add the function (same as in function frame).
8155 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8156
8157 // Add the arguments count.
8158 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8159
8160 // Add the locals count
8161 details->set(kFrameDetailsLocalCountIndex,
8162 Smi::FromInt(info.NumberOfLocals()));
8163
8164 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008165 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008166 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8167 } else {
8168 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8169 }
8170
8171 // Add the constructor information.
8172 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8173
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008174 // Add the at return information.
8175 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8176
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008177 // Add information on whether this frame is invoked in the debugger context.
8178 details->set(kFrameDetailsDebuggerFrameIndex,
8179 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8180
8181 // Fill the dynamic part.
8182 int details_index = kFrameDetailsFirstDynamicIndex;
8183
8184 // Add arguments name and value.
8185 for (int i = 0; i < argument_count; i++) {
8186 // Name of the argument.
8187 if (i < info.number_of_parameters()) {
8188 details->set(details_index++, *info.parameter_name(i));
8189 } else {
8190 details->set(details_index++, Heap::undefined_value());
8191 }
8192
8193 // Parameter value.
8194 if (i < it.frame()->GetProvidedParametersCount()) {
8195 details->set(details_index++, it.frame()->GetParameter(i));
8196 } else {
8197 details->set(details_index++, Heap::undefined_value());
8198 }
8199 }
8200
8201 // Add locals name and value from the temporary copy from the function frame.
8202 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8203 details->set(details_index++, locals->get(i));
8204 }
8205
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008206 // Add the value being returned.
8207 if (at_return) {
8208 details->set(details_index++, *return_value);
8209 }
8210
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008211 // Add the receiver (same as in function frame).
8212 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8213 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8214 Handle<Object> receiver(it.frame()->receiver());
8215 if (!receiver->IsJSObject()) {
8216 // If the receiver is NOT a JSObject we have hit an optimization
8217 // where a value object is not converted into a wrapped JS objects.
8218 // To hide this optimization from the debugger, we wrap the receiver
8219 // by creating correct wrapper object based on the calling frame's
8220 // global context.
8221 it.Advance();
8222 Handle<Context> calling_frames_global_context(
8223 Context::cast(Context::cast(it.frame()->context())->global_context()));
8224 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8225 }
8226 details->set(kFrameDetailsReceiverIndex, *receiver);
8227
8228 ASSERT_EQ(details_size, details_index);
8229 return *Factory::NewJSArrayWithElements(details);
8230}
8231
8232
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008233// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008234static void CopyContextLocalsToScopeObject(
8235 Handle<SerializedScopeInfo> serialized_scope_info,
8236 ScopeInfo<>& scope_info,
8237 Handle<Context> context,
8238 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008239 // Fill all context locals to the context extension.
8240 for (int i = Context::MIN_CONTEXT_SLOTS;
8241 i < scope_info.number_of_context_slots();
8242 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008243 int context_index = serialized_scope_info->ContextSlotIndex(
8244 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008245
8246 // Don't include the arguments shadow (.arguments) context variable.
8247 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8248 SetProperty(scope_object,
8249 scope_info.context_slot_name(i),
8250 Handle<Object>(context->get(context_index)), NONE);
8251 }
8252 }
8253}
8254
8255
8256// Create a plain JSObject which materializes the local scope for the specified
8257// frame.
8258static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8259 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008260 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008261 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8262 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008263
8264 // Allocate and initialize a JSObject with all the arguments, stack locals
8265 // heap locals and extension properties of the debugged function.
8266 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8267
8268 // First fill all parameters.
8269 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8270 SetProperty(local_scope,
8271 scope_info.parameter_name(i),
8272 Handle<Object>(frame->GetParameter(i)), NONE);
8273 }
8274
8275 // Second fill all stack locals.
8276 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8277 SetProperty(local_scope,
8278 scope_info.stack_slot_name(i),
8279 Handle<Object>(frame->GetExpression(i)), NONE);
8280 }
8281
8282 // Third fill all context locals.
8283 Handle<Context> frame_context(Context::cast(frame->context()));
8284 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008285 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008286 function_context, local_scope);
8287
8288 // Finally copy any properties from the function context extension. This will
8289 // be variables introduced by eval.
8290 if (function_context->closure() == *function) {
8291 if (function_context->has_extension() &&
8292 !function_context->IsGlobalContext()) {
8293 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008294 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008295 for (int i = 0; i < keys->length(); i++) {
8296 // Names of variables introduced by eval are strings.
8297 ASSERT(keys->get(i)->IsString());
8298 Handle<String> key(String::cast(keys->get(i)));
8299 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8300 }
8301 }
8302 }
8303 return local_scope;
8304}
8305
8306
8307// Create a plain JSObject which materializes the closure content for the
8308// context.
8309static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8310 ASSERT(context->is_function_context());
8311
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008312 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008313 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8314 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008315
8316 // Allocate and initialize a JSObject with all the content of theis function
8317 // closure.
8318 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8319
8320 // Check whether the arguments shadow object exists.
8321 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008322 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8323 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008324 if (arguments_shadow_index >= 0) {
8325 // In this case all the arguments are available in the arguments shadow
8326 // object.
8327 Handle<JSObject> arguments_shadow(
8328 JSObject::cast(context->get(arguments_shadow_index)));
8329 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8330 SetProperty(closure_scope,
8331 scope_info.parameter_name(i),
8332 Handle<Object>(arguments_shadow->GetElement(i)), NONE);
8333 }
8334 }
8335
8336 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008337 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8338 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008339
8340 // Finally copy any properties from the function context extension. This will
8341 // be variables introduced by eval.
8342 if (context->has_extension()) {
8343 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008344 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008345 for (int i = 0; i < keys->length(); i++) {
8346 // Names of variables introduced by eval are strings.
8347 ASSERT(keys->get(i)->IsString());
8348 Handle<String> key(String::cast(keys->get(i)));
8349 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
8350 }
8351 }
8352
8353 return closure_scope;
8354}
8355
8356
8357// Iterate over the actual scopes visible from a stack frame. All scopes are
8358// backed by an actual context except the local scope, which is inserted
8359// "artifically" in the context chain.
8360class ScopeIterator {
8361 public:
8362 enum ScopeType {
8363 ScopeTypeGlobal = 0,
8364 ScopeTypeLocal,
8365 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00008366 ScopeTypeClosure,
8367 // Every catch block contains an implicit with block (its parameter is
8368 // a JSContextExtensionObject) that extends current scope with a variable
8369 // holding exception object. Such with blocks are treated as scopes of their
8370 // own type.
8371 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008372 };
8373
8374 explicit ScopeIterator(JavaScriptFrame* frame)
8375 : frame_(frame),
8376 function_(JSFunction::cast(frame->function())),
8377 context_(Context::cast(frame->context())),
8378 local_done_(false),
8379 at_local_(false) {
8380
8381 // Check whether the first scope is actually a local scope.
8382 if (context_->IsGlobalContext()) {
8383 // If there is a stack slot for .result then this local scope has been
8384 // created for evaluating top level code and it is not a real local scope.
8385 // Checking for the existence of .result seems fragile, but the scope info
8386 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008387 int index = function_->shared()->scope_info()->
8388 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008389 at_local_ = index < 0;
8390 } else if (context_->is_function_context()) {
8391 at_local_ = true;
8392 }
8393 }
8394
8395 // More scopes?
8396 bool Done() { return context_.is_null(); }
8397
8398 // Move to the next scope.
8399 void Next() {
8400 // If at a local scope mark the local scope as passed.
8401 if (at_local_) {
8402 at_local_ = false;
8403 local_done_ = true;
8404
8405 // If the current context is not associated with the local scope the
8406 // current context is the next real scope, so don't move to the next
8407 // context in this case.
8408 if (context_->closure() != *function_) {
8409 return;
8410 }
8411 }
8412
8413 // The global scope is always the last in the chain.
8414 if (context_->IsGlobalContext()) {
8415 context_ = Handle<Context>();
8416 return;
8417 }
8418
8419 // Move to the next context.
8420 if (context_->is_function_context()) {
8421 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
8422 } else {
8423 context_ = Handle<Context>(context_->previous());
8424 }
8425
8426 // If passing the local scope indicate that the current scope is now the
8427 // local scope.
8428 if (!local_done_ &&
8429 (context_->IsGlobalContext() || (context_->is_function_context()))) {
8430 at_local_ = true;
8431 }
8432 }
8433
8434 // Return the type of the current scope.
8435 int Type() {
8436 if (at_local_) {
8437 return ScopeTypeLocal;
8438 }
8439 if (context_->IsGlobalContext()) {
8440 ASSERT(context_->global()->IsGlobalObject());
8441 return ScopeTypeGlobal;
8442 }
8443 if (context_->is_function_context()) {
8444 return ScopeTypeClosure;
8445 }
8446 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00008447 // Current scope is either an explicit with statement or a with statement
8448 // implicitely generated for a catch block.
8449 // If the extension object here is a JSContextExtensionObject then
8450 // current with statement is one frome a catch block otherwise it's a
8451 // regular with statement.
8452 if (context_->extension()->IsJSContextExtensionObject()) {
8453 return ScopeTypeCatch;
8454 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008455 return ScopeTypeWith;
8456 }
8457
8458 // Return the JavaScript object with the content of the current scope.
8459 Handle<JSObject> ScopeObject() {
8460 switch (Type()) {
8461 case ScopeIterator::ScopeTypeGlobal:
8462 return Handle<JSObject>(CurrentContext()->global());
8463 break;
8464 case ScopeIterator::ScopeTypeLocal:
8465 // Materialize the content of the local scope into a JSObject.
8466 return MaterializeLocalScope(frame_);
8467 break;
8468 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00008469 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008470 // Return the with object.
8471 return Handle<JSObject>(CurrentContext()->extension());
8472 break;
8473 case ScopeIterator::ScopeTypeClosure:
8474 // Materialize the content of the closure scope into a JSObject.
8475 return MaterializeClosure(CurrentContext());
8476 break;
8477 }
8478 UNREACHABLE();
8479 return Handle<JSObject>();
8480 }
8481
8482 // Return the context for this scope. For the local context there might not
8483 // be an actual context.
8484 Handle<Context> CurrentContext() {
8485 if (at_local_ && context_->closure() != *function_) {
8486 return Handle<Context>();
8487 }
8488 return context_;
8489 }
8490
8491#ifdef DEBUG
8492 // Debug print of the content of the current scope.
8493 void DebugPrint() {
8494 switch (Type()) {
8495 case ScopeIterator::ScopeTypeGlobal:
8496 PrintF("Global:\n");
8497 CurrentContext()->Print();
8498 break;
8499
8500 case ScopeIterator::ScopeTypeLocal: {
8501 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008502 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008503 scope_info.Print();
8504 if (!CurrentContext().is_null()) {
8505 CurrentContext()->Print();
8506 if (CurrentContext()->has_extension()) {
8507 Handle<JSObject> extension =
8508 Handle<JSObject>(CurrentContext()->extension());
8509 if (extension->IsJSContextExtensionObject()) {
8510 extension->Print();
8511 }
8512 }
8513 }
8514 break;
8515 }
8516
8517 case ScopeIterator::ScopeTypeWith: {
8518 PrintF("With:\n");
8519 Handle<JSObject> extension =
8520 Handle<JSObject>(CurrentContext()->extension());
8521 extension->Print();
8522 break;
8523 }
8524
ager@chromium.orga1645e22009-09-09 19:27:10 +00008525 case ScopeIterator::ScopeTypeCatch: {
8526 PrintF("Catch:\n");
8527 Handle<JSObject> extension =
8528 Handle<JSObject>(CurrentContext()->extension());
8529 extension->Print();
8530 break;
8531 }
8532
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008533 case ScopeIterator::ScopeTypeClosure: {
8534 PrintF("Closure:\n");
8535 CurrentContext()->Print();
8536 if (CurrentContext()->has_extension()) {
8537 Handle<JSObject> extension =
8538 Handle<JSObject>(CurrentContext()->extension());
8539 if (extension->IsJSContextExtensionObject()) {
8540 extension->Print();
8541 }
8542 }
8543 break;
8544 }
8545
8546 default:
8547 UNREACHABLE();
8548 }
8549 PrintF("\n");
8550 }
8551#endif
8552
8553 private:
8554 JavaScriptFrame* frame_;
8555 Handle<JSFunction> function_;
8556 Handle<Context> context_;
8557 bool local_done_;
8558 bool at_local_;
8559
8560 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
8561};
8562
8563
8564static Object* Runtime_GetScopeCount(Arguments args) {
8565 HandleScope scope;
8566 ASSERT(args.length() == 2);
8567
8568 // Check arguments.
8569 Object* check = Runtime_CheckExecutionState(args);
8570 if (check->IsFailure()) return check;
8571 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8572
8573 // Get the frame where the debugging is performed.
8574 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8575 JavaScriptFrameIterator it(id);
8576 JavaScriptFrame* frame = it.frame();
8577
8578 // Count the visible scopes.
8579 int n = 0;
8580 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8581 n++;
8582 }
8583
8584 return Smi::FromInt(n);
8585}
8586
8587
8588static const int kScopeDetailsTypeIndex = 0;
8589static const int kScopeDetailsObjectIndex = 1;
8590static const int kScopeDetailsSize = 2;
8591
8592// Return an array with scope details
8593// args[0]: number: break id
8594// args[1]: number: frame index
8595// args[2]: number: scope index
8596//
8597// The array returned contains the following information:
8598// 0: Scope type
8599// 1: Scope object
8600static Object* Runtime_GetScopeDetails(Arguments args) {
8601 HandleScope scope;
8602 ASSERT(args.length() == 3);
8603
8604 // Check arguments.
8605 Object* check = Runtime_CheckExecutionState(args);
8606 if (check->IsFailure()) return check;
8607 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8608 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
8609
8610 // Get the frame where the debugging is performed.
8611 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8612 JavaScriptFrameIterator frame_it(id);
8613 JavaScriptFrame* frame = frame_it.frame();
8614
8615 // Find the requested scope.
8616 int n = 0;
8617 ScopeIterator it(frame);
8618 for (; !it.Done() && n < index; it.Next()) {
8619 n++;
8620 }
8621 if (it.Done()) {
8622 return Heap::undefined_value();
8623 }
8624
8625 // Calculate the size of the result.
8626 int details_size = kScopeDetailsSize;
8627 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8628
8629 // Fill in scope details.
8630 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
8631 details->set(kScopeDetailsObjectIndex, *it.ScopeObject());
8632
8633 return *Factory::NewJSArrayWithElements(details);
8634}
8635
8636
8637static Object* Runtime_DebugPrintScopes(Arguments args) {
8638 HandleScope scope;
8639 ASSERT(args.length() == 0);
8640
8641#ifdef DEBUG
8642 // Print the scopes for the top frame.
8643 StackFrameLocator locator;
8644 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
8645 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8646 it.DebugPrint();
8647 }
8648#endif
8649 return Heap::undefined_value();
8650}
8651
8652
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008653static Object* Runtime_GetCFrames(Arguments args) {
8654 HandleScope scope;
8655 ASSERT(args.length() == 1);
8656 Object* result = Runtime_CheckExecutionState(args);
8657 if (result->IsFailure()) return result;
8658
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00008659#if V8_HOST_ARCH_64_BIT
8660 UNIMPLEMENTED();
8661 return Heap::undefined_value();
8662#else
8663
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008664 static const int kMaxCFramesSize = 200;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008665 ScopedVector<OS::StackFrame> frames(kMaxCFramesSize);
8666 int frames_count = OS::StackWalk(frames);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008667 if (frames_count == OS::kStackWalkError) {
8668 return Heap::undefined_value();
8669 }
8670
8671 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
8672 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
8673 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
8674 for (int i = 0; i < frames_count; i++) {
8675 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
8676 frame_value->SetProperty(
8677 *address_str,
8678 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
8679 NONE);
8680
8681 // Get the stack walk text for this frame.
8682 Handle<String> frame_text;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008683 int frame_text_length = StrLength(frames[i].text);
8684 if (frame_text_length > 0) {
8685 Vector<const char> str(frames[i].text, frame_text_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008686 frame_text = Factory::NewStringFromAscii(str);
8687 }
8688
8689 if (!frame_text.is_null()) {
8690 frame_value->SetProperty(*text_str, *frame_text, NONE);
8691 }
8692
8693 frames_array->set(i, *frame_value);
8694 }
8695 return *Factory::NewJSArrayWithElements(frames_array);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00008696#endif // V8_HOST_ARCH_64_BIT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008697}
8698
8699
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008700static Object* Runtime_GetThreadCount(Arguments args) {
8701 HandleScope scope;
8702 ASSERT(args.length() == 1);
8703
8704 // Check arguments.
8705 Object* result = Runtime_CheckExecutionState(args);
8706 if (result->IsFailure()) return result;
8707
8708 // Count all archived V8 threads.
8709 int n = 0;
8710 for (ThreadState* thread = ThreadState::FirstInUse();
8711 thread != NULL;
8712 thread = thread->Next()) {
8713 n++;
8714 }
8715
8716 // Total number of threads is current thread and archived threads.
8717 return Smi::FromInt(n + 1);
8718}
8719
8720
8721static const int kThreadDetailsCurrentThreadIndex = 0;
8722static const int kThreadDetailsThreadIdIndex = 1;
8723static const int kThreadDetailsSize = 2;
8724
8725// Return an array with thread details
8726// args[0]: number: break id
8727// args[1]: number: thread index
8728//
8729// The array returned contains the following information:
8730// 0: Is current thread?
8731// 1: Thread id
8732static Object* Runtime_GetThreadDetails(Arguments args) {
8733 HandleScope scope;
8734 ASSERT(args.length() == 2);
8735
8736 // Check arguments.
8737 Object* check = Runtime_CheckExecutionState(args);
8738 if (check->IsFailure()) return check;
8739 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8740
8741 // Allocate array for result.
8742 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
8743
8744 // Thread index 0 is current thread.
8745 if (index == 0) {
8746 // Fill the details.
8747 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
8748 details->set(kThreadDetailsThreadIdIndex,
8749 Smi::FromInt(ThreadManager::CurrentId()));
8750 } else {
8751 // Find the thread with the requested index.
8752 int n = 1;
8753 ThreadState* thread = ThreadState::FirstInUse();
8754 while (index != n && thread != NULL) {
8755 thread = thread->Next();
8756 n++;
8757 }
8758 if (thread == NULL) {
8759 return Heap::undefined_value();
8760 }
8761
8762 // Fill the details.
8763 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
8764 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
8765 }
8766
8767 // Convert to JS array and return.
8768 return *Factory::NewJSArrayWithElements(details);
8769}
8770
8771
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008772// Sets the disable break state
8773// args[0]: disable break state
8774static Object* Runtime_SetDisableBreak(Arguments args) {
8775 HandleScope scope;
8776 ASSERT(args.length() == 1);
8777 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
8778 Debug::set_disable_break(disable_break);
8779 return Heap::undefined_value();
8780}
8781
8782
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008783static Object* Runtime_GetBreakLocations(Arguments args) {
8784 HandleScope scope;
8785 ASSERT(args.length() == 1);
8786
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008787 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8788 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008789 // Find the number of break points
8790 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
8791 if (break_locations->IsUndefined()) return Heap::undefined_value();
8792 // Return array as JS array
8793 return *Factory::NewJSArrayWithElements(
8794 Handle<FixedArray>::cast(break_locations));
8795}
8796
8797
8798// Set a break point in a function
8799// args[0]: function
8800// args[1]: number: break source position (within the function source)
8801// args[2]: number: break point object
8802static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
8803 HandleScope scope;
8804 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008805 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8806 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008807 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
8808 RUNTIME_ASSERT(source_position >= 0);
8809 Handle<Object> break_point_object_arg = args.at<Object>(2);
8810
8811 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008812 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008813
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008814 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008815}
8816
8817
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00008818Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
8819 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008820 // Iterate the heap looking for SharedFunctionInfo generated from the
8821 // script. The inner most SharedFunctionInfo containing the source position
8822 // for the requested break point is found.
8823 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
8824 // which is found is not compiled it is compiled and the heap is iterated
8825 // again as the compilation might create inner functions from the newly
8826 // compiled function and the actual requested break point might be in one of
8827 // these functions.
8828 bool done = false;
8829 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00008830 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008831 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008832 while (!done) {
8833 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008834 for (HeapObject* obj = iterator.next();
8835 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008836 if (obj->IsSharedFunctionInfo()) {
8837 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
8838 if (shared->script() == *script) {
8839 // If the SharedFunctionInfo found has the requested script data and
8840 // contains the source position it is a candidate.
8841 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00008842 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008843 start_position = shared->start_position();
8844 }
8845 if (start_position <= position &&
8846 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00008847 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008848 // candidate this is the new candidate.
8849 if (target.is_null()) {
8850 target_start_position = start_position;
8851 target = shared;
8852 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00008853 if (target_start_position == start_position &&
8854 shared->end_position() == target->end_position()) {
8855 // If a top-level function contain only one function
8856 // declartion the source for the top-level and the function is
8857 // the same. In that case prefer the non top-level function.
8858 if (!shared->is_toplevel()) {
8859 target_start_position = start_position;
8860 target = shared;
8861 }
8862 } else if (target_start_position <= start_position &&
8863 shared->end_position() <= target->end_position()) {
8864 // This containment check includes equality as a function inside
8865 // a top-level function can share either start or end position
8866 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008867 target_start_position = start_position;
8868 target = shared;
8869 }
8870 }
8871 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008872 }
8873 }
8874 }
8875
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008876 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008877 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008878 }
8879
8880 // If the candidate found is compiled we are done. NOTE: when lazy
8881 // compilation of inner functions is introduced some additional checking
8882 // needs to be done here to compile inner functions.
8883 done = target->is_compiled();
8884 if (!done) {
8885 // If the candidate is not compiled compile it to reveal any inner
8886 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008887 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008888 }
8889 }
8890
8891 return *target;
8892}
8893
8894
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008895// Changes the state of a break point in a script and returns source position
8896// where break point was set. NOTE: Regarding performance see the NOTE for
8897// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008898// args[0]: script to set break point in
8899// args[1]: number: break source position (within the script source)
8900// args[2]: number: break point object
8901static Object* Runtime_SetScriptBreakPoint(Arguments args) {
8902 HandleScope scope;
8903 ASSERT(args.length() == 3);
8904 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
8905 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
8906 RUNTIME_ASSERT(source_position >= 0);
8907 Handle<Object> break_point_object_arg = args.at<Object>(2);
8908
8909 // Get the script from the script wrapper.
8910 RUNTIME_ASSERT(wrapper->value()->IsScript());
8911 Handle<Script> script(Script::cast(wrapper->value()));
8912
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00008913 Object* result = Runtime::FindSharedFunctionInfoInScript(
8914 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008915 if (!result->IsUndefined()) {
8916 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
8917 // Find position within function. The script position might be before the
8918 // source position of the first function.
8919 int position;
8920 if (shared->start_position() > source_position) {
8921 position = 0;
8922 } else {
8923 position = source_position - shared->start_position();
8924 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008925 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
8926 position += shared->start_position();
8927 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008928 }
8929 return Heap::undefined_value();
8930}
8931
8932
8933// Clear a break point
8934// args[0]: number: break point object
8935static Object* Runtime_ClearBreakPoint(Arguments args) {
8936 HandleScope scope;
8937 ASSERT(args.length() == 1);
8938 Handle<Object> break_point_object_arg = args.at<Object>(0);
8939
8940 // Clear break point.
8941 Debug::ClearBreakPoint(break_point_object_arg);
8942
8943 return Heap::undefined_value();
8944}
8945
8946
8947// Change the state of break on exceptions
8948// args[0]: boolean indicating uncaught exceptions
8949// args[1]: boolean indicating on/off
8950static Object* Runtime_ChangeBreakOnException(Arguments args) {
8951 HandleScope scope;
8952 ASSERT(args.length() == 2);
8953 ASSERT(args[0]->IsNumber());
8954 ASSERT(args[1]->IsBoolean());
8955
8956 // Update break point state
8957 ExceptionBreakType type =
8958 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
8959 bool enable = args[1]->ToBoolean()->IsTrue();
8960 Debug::ChangeBreakOnException(type, enable);
8961 return Heap::undefined_value();
8962}
8963
8964
8965// Prepare for stepping
8966// args[0]: break id for checking execution state
8967// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00008968// args[2]: number of times to perform the step, for step out it is the number
8969// of frames to step down.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008970static Object* Runtime_PrepareStep(Arguments args) {
8971 HandleScope scope;
8972 ASSERT(args.length() == 3);
8973 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008974 Object* check = Runtime_CheckExecutionState(args);
8975 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008976 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
8977 return Top::Throw(Heap::illegal_argument_symbol());
8978 }
8979
8980 // Get the step action and check validity.
8981 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
8982 if (step_action != StepIn &&
8983 step_action != StepNext &&
8984 step_action != StepOut &&
8985 step_action != StepInMin &&
8986 step_action != StepMin) {
8987 return Top::Throw(Heap::illegal_argument_symbol());
8988 }
8989
8990 // Get the number of steps.
8991 int step_count = NumberToInt32(args[2]);
8992 if (step_count < 1) {
8993 return Top::Throw(Heap::illegal_argument_symbol());
8994 }
8995
ager@chromium.orga1645e22009-09-09 19:27:10 +00008996 // Clear all current stepping setup.
8997 Debug::ClearStepping();
8998
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008999 // Prepare step.
9000 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9001 return Heap::undefined_value();
9002}
9003
9004
9005// Clear all stepping set by PrepareStep.
9006static Object* Runtime_ClearStepping(Arguments args) {
9007 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009008 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009009 Debug::ClearStepping();
9010 return Heap::undefined_value();
9011}
9012
9013
9014// Creates a copy of the with context chain. The copy of the context chain is
9015// is linked to the function context supplied.
9016static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9017 Handle<Context> function_context) {
9018 // At the bottom of the chain. Return the function context to link to.
9019 if (context_chain->is_function_context()) {
9020 return function_context;
9021 }
9022
9023 // Recursively copy the with contexts.
9024 Handle<Context> previous(context_chain->previous());
9025 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
9026 return Factory::NewWithContext(
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009027 CopyWithContextChain(function_context, previous),
9028 extension,
9029 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009030}
9031
9032
9033// Helper function to find or create the arguments object for
9034// Runtime_DebugEvaluate.
9035static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9036 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009037 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009038 const ScopeInfo<>* sinfo,
9039 Handle<Context> function_context) {
9040 // Try to find the value of 'arguments' to pass as parameter. If it is not
9041 // found (that is the debugged function does not reference 'arguments' and
9042 // does not support eval) then create an 'arguments' object.
9043 int index;
9044 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009045 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009046 if (index != -1) {
9047 return Handle<Object>(frame->GetExpression(index));
9048 }
9049 }
9050
9051 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009052 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053 if (index != -1) {
9054 return Handle<Object>(function_context->get(index));
9055 }
9056 }
9057
9058 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009059 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9060 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009061
9062 AssertNoAllocation no_gc;
9063 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009064 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009065 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009066 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009067 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068 return arguments;
9069}
9070
9071
9072// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009073// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074// extension part has all the parameters and locals of the function on the
9075// stack frame. A function which calls eval with the code to evaluate is then
9076// compiled in this context and called in this context. As this context
9077// replaces the context of the function on the stack frame a new (empty)
9078// function is created as well to be used as the closure for the context.
9079// This function and the context acts as replacements for the function on the
9080// stack frame presenting the same view of the values of parameters and
9081// local variables as if the piece of JavaScript was evaluated at the point
9082// where the function on the stack frame is currently stopped.
9083static Object* Runtime_DebugEvaluate(Arguments args) {
9084 HandleScope scope;
9085
9086 // Check the execution state and decode arguments frame and source to be
9087 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009088 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009089 Object* check_result = Runtime_CheckExecutionState(args);
9090 if (check_result->IsFailure()) return check_result;
9091 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9092 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009093 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
9094
9095 // Handle the processing of break.
9096 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009097
9098 // Get the frame where the debugging is performed.
9099 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9100 JavaScriptFrameIterator it(id);
9101 JavaScriptFrame* frame = it.frame();
9102 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009103 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009104 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009105
9106 // Traverse the saved contexts chain to find the active context for the
9107 // selected frame.
9108 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009109 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009110 save = save->prev();
9111 }
9112 ASSERT(save != NULL);
9113 SaveContext savex;
9114 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009115
9116 // Create the (empty) function replacing the function on the stack frame for
9117 // the purpose of evaluating in the context created below. It is important
9118 // that this function does not describe any parameters and local variables
9119 // in the context. If it does then this will cause problems with the lookup
9120 // in Context::Lookup, where context slots for parameters and local variables
9121 // are looked at before the extension object.
9122 Handle<JSFunction> go_between =
9123 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9124 go_between->set_context(function->context());
9125#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009126 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009127 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9128 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9129#endif
9130
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009131 // Materialize the content of the local scope into a JSObject.
9132 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009133
9134 // Allocate a new context for the debug evaluation and set the extension
9135 // object build.
9136 Handle<Context> context =
9137 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009138 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009139 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009140 Handle<Context> frame_context(Context::cast(frame->context()));
9141 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142 context = CopyWithContextChain(frame_context, context);
9143
9144 // Wrap the evaluation statement in a new function compiled in the newly
9145 // created context. The function has one parameter which has to be called
9146 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009147 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009148 // function(arguments,__source__) {return eval(__source__);}
9149 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009150 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009151 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009152 Handle<String> function_source =
9153 Factory::NewStringFromAscii(Vector<const char>(source_str,
9154 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009155 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009156 Compiler::CompileEval(function_source,
9157 context,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00009158 context->IsGlobalContext(),
ager@chromium.orgadd848f2009-08-13 12:44:13 +00009159 Compiler::DONT_VALIDATE_JSON);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009160 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009161 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009162 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009163
9164 // Invoke the result of the compilation to get the evaluation function.
9165 bool has_pending_exception;
9166 Handle<Object> receiver(frame->receiver());
9167 Handle<Object> evaluation_function =
9168 Execution::Call(compiled_function, receiver, 0, NULL,
9169 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009170 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009172 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9173 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009174
9175 // Invoke the evaluation function and return the result.
9176 const int argc = 2;
9177 Object** argv[argc] = { arguments.location(),
9178 Handle<Object>::cast(source).location() };
9179 Handle<Object> result =
9180 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9181 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009182 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009183
9184 // Skip the global proxy as it has no properties and always delegates to the
9185 // real global object.
9186 if (result->IsJSGlobalProxy()) {
9187 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9188 }
9189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009190 return *result;
9191}
9192
9193
9194static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
9195 HandleScope scope;
9196
9197 // Check the execution state and decode arguments frame and source to be
9198 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009199 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009200 Object* check_result = Runtime_CheckExecutionState(args);
9201 if (check_result->IsFailure()) return check_result;
9202 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009203 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
9204
9205 // Handle the processing of break.
9206 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009207
9208 // Enter the top context from before the debugger was invoked.
9209 SaveContext save;
9210 SaveContext* top = &save;
9211 while (top != NULL && *top->context() == *Debug::debug_context()) {
9212 top = top->prev();
9213 }
9214 if (top != NULL) {
9215 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009216 }
9217
9218 // Get the global context now set to the top context from before the
9219 // debugger was invoked.
9220 Handle<Context> context = Top::global_context();
9221
9222 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009223 Handle<SharedFunctionInfo> shared =
9224 Compiler::CompileEval(source,
9225 context,
9226 true,
9227 Compiler::DONT_VALIDATE_JSON);
9228 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009229 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009230 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9231 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009232
9233 // Invoke the result of the compilation to get the evaluation function.
9234 bool has_pending_exception;
9235 Handle<Object> receiver = Top::global();
9236 Handle<Object> result =
9237 Execution::Call(compiled_function, receiver, 0, NULL,
9238 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009239 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009240 return *result;
9241}
9242
9243
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
9245 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009246 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009247
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009248 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009249 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009250
9251 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009252 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009253 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9254 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9255 // because using
9256 // instances->set(i, *GetScriptWrapper(script))
9257 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9258 // already have deferenced the instances handle.
9259 Handle<JSValue> wrapper = GetScriptWrapper(script);
9260 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009261 }
9262
9263 // Return result as a JS array.
9264 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9265 Handle<JSArray>::cast(result)->SetContent(*instances);
9266 return *result;
9267}
9268
9269
9270// Helper function used by Runtime_DebugReferencedBy below.
9271static int DebugReferencedBy(JSObject* target,
9272 Object* instance_filter, int max_references,
9273 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009274 JSFunction* arguments_function) {
9275 NoHandleAllocation ha;
9276 AssertNoAllocation no_alloc;
9277
9278 // Iterate the heap.
9279 int count = 0;
9280 JSObject* last = NULL;
9281 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009282 HeapObject* heap_obj = NULL;
9283 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009284 (max_references == 0 || count < max_references)) {
9285 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009286 if (heap_obj->IsJSObject()) {
9287 // Skip context extension objects and argument arrays as these are
9288 // checked in the context of functions using them.
9289 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009290 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009291 obj->map()->constructor() == arguments_function) {
9292 continue;
9293 }
9294
9295 // Check if the JS object has a reference to the object looked for.
9296 if (obj->ReferencesObject(target)) {
9297 // Check instance filter if supplied. This is normally used to avoid
9298 // references from mirror objects (see Runtime_IsInPrototypeChain).
9299 if (!instance_filter->IsUndefined()) {
9300 Object* V = obj;
9301 while (true) {
9302 Object* prototype = V->GetPrototype();
9303 if (prototype->IsNull()) {
9304 break;
9305 }
9306 if (instance_filter == prototype) {
9307 obj = NULL; // Don't add this object.
9308 break;
9309 }
9310 V = prototype;
9311 }
9312 }
9313
9314 if (obj != NULL) {
9315 // Valid reference found add to instance array if supplied an update
9316 // count.
9317 if (instances != NULL && count < instances_size) {
9318 instances->set(count, obj);
9319 }
9320 last = obj;
9321 count++;
9322 }
9323 }
9324 }
9325 }
9326
9327 // Check for circular reference only. This can happen when the object is only
9328 // referenced from mirrors and has a circular reference in which case the
9329 // object is not really alive and would have been garbage collected if not
9330 // referenced from the mirror.
9331 if (count == 1 && last == target) {
9332 count = 0;
9333 }
9334
9335 // Return the number of referencing objects found.
9336 return count;
9337}
9338
9339
9340// Scan the heap for objects with direct references to an object
9341// args[0]: the object to find references to
9342// args[1]: constructor function for instances to exclude (Mirror)
9343// args[2]: the the maximum number of objects to return
9344static Object* Runtime_DebugReferencedBy(Arguments args) {
9345 ASSERT(args.length() == 3);
9346
9347 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009348 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009349
9350 // Check parameters.
9351 CONVERT_CHECKED(JSObject, target, args[0]);
9352 Object* instance_filter = args[1];
9353 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
9354 instance_filter->IsJSObject());
9355 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
9356 RUNTIME_ASSERT(max_references >= 0);
9357
9358 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009359 JSObject* arguments_boilerplate =
9360 Top::context()->global_context()->arguments_boilerplate();
9361 JSFunction* arguments_function =
9362 JSFunction::cast(arguments_boilerplate->map()->constructor());
9363
9364 // Get the number of referencing objects.
9365 int count;
9366 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009367 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009368
9369 // Allocate an array to hold the result.
9370 Object* object = Heap::AllocateFixedArray(count);
9371 if (object->IsFailure()) return object;
9372 FixedArray* instances = FixedArray::cast(object);
9373
9374 // Fill the referencing objects.
9375 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009376 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009377
9378 // Return result as JS array.
9379 Object* result =
9380 Heap::AllocateJSObject(
9381 Top::context()->global_context()->array_function());
9382 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
9383 return result;
9384}
9385
9386
9387// Helper function used by Runtime_DebugConstructedBy below.
9388static int DebugConstructedBy(JSFunction* constructor, int max_references,
9389 FixedArray* instances, int instances_size) {
9390 AssertNoAllocation no_alloc;
9391
9392 // Iterate the heap.
9393 int count = 0;
9394 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009395 HeapObject* heap_obj = NULL;
9396 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009397 (max_references == 0 || count < max_references)) {
9398 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009399 if (heap_obj->IsJSObject()) {
9400 JSObject* obj = JSObject::cast(heap_obj);
9401 if (obj->map()->constructor() == constructor) {
9402 // Valid reference found add to instance array if supplied an update
9403 // count.
9404 if (instances != NULL && count < instances_size) {
9405 instances->set(count, obj);
9406 }
9407 count++;
9408 }
9409 }
9410 }
9411
9412 // Return the number of referencing objects found.
9413 return count;
9414}
9415
9416
9417// Scan the heap for objects constructed by a specific function.
9418// args[0]: the constructor to find instances of
9419// args[1]: the the maximum number of objects to return
9420static Object* Runtime_DebugConstructedBy(Arguments args) {
9421 ASSERT(args.length() == 2);
9422
9423 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009424 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009425
9426 // Check parameters.
9427 CONVERT_CHECKED(JSFunction, constructor, args[0]);
9428 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
9429 RUNTIME_ASSERT(max_references >= 0);
9430
9431 // Get the number of referencing objects.
9432 int count;
9433 count = DebugConstructedBy(constructor, max_references, NULL, 0);
9434
9435 // Allocate an array to hold the result.
9436 Object* object = Heap::AllocateFixedArray(count);
9437 if (object->IsFailure()) return object;
9438 FixedArray* instances = FixedArray::cast(object);
9439
9440 // Fill the referencing objects.
9441 count = DebugConstructedBy(constructor, max_references, instances, count);
9442
9443 // Return result as JS array.
9444 Object* result =
9445 Heap::AllocateJSObject(
9446 Top::context()->global_context()->array_function());
9447 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
9448 return result;
9449}
9450
9451
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009452// Find the effective prototype object as returned by __proto__.
9453// args[0]: the object to find the prototype for.
9454static Object* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009455 ASSERT(args.length() == 1);
9456
9457 CONVERT_CHECKED(JSObject, obj, args[0]);
9458
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009459 // Use the __proto__ accessor.
9460 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009461}
9462
9463
9464static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00009465 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009466 CPU::DebugBreak();
9467 return Heap::undefined_value();
9468}
9469
9470
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009471static Object* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009472#ifdef DEBUG
9473 HandleScope scope;
9474 ASSERT(args.length() == 1);
9475 // Get the function and make sure it is compiled.
9476 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009477 Handle<SharedFunctionInfo> shared(func->shared());
9478 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009479 return Failure::Exception();
9480 }
9481 func->code()->PrintLn();
9482#endif // DEBUG
9483 return Heap::undefined_value();
9484}
ager@chromium.org9085a012009-05-11 19:22:57 +00009485
9486
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009487static Object* Runtime_DebugDisassembleConstructor(Arguments args) {
9488#ifdef DEBUG
9489 HandleScope scope;
9490 ASSERT(args.length() == 1);
9491 // Get the function and make sure it is compiled.
9492 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009493 Handle<SharedFunctionInfo> shared(func->shared());
9494 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009495 return Failure::Exception();
9496 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009497 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009498#endif // DEBUG
9499 return Heap::undefined_value();
9500}
9501
9502
ager@chromium.org9085a012009-05-11 19:22:57 +00009503static Object* Runtime_FunctionGetInferredName(Arguments args) {
9504 NoHandleAllocation ha;
9505 ASSERT(args.length() == 1);
9506
9507 CONVERT_CHECKED(JSFunction, f, args[0]);
9508 return f->shared()->inferred_name();
9509}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009510
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009511
9512static int FindSharedFunctionInfosForScript(Script* script,
9513 FixedArray* buffer) {
9514 AssertNoAllocation no_allocations;
9515
9516 int counter = 0;
9517 int buffer_size = buffer->length();
9518 HeapIterator iterator;
9519 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
9520 ASSERT(obj != NULL);
9521 if (!obj->IsSharedFunctionInfo()) {
9522 continue;
9523 }
9524 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
9525 if (shared->script() != script) {
9526 continue;
9527 }
9528 if (counter < buffer_size) {
9529 buffer->set(counter, shared);
9530 }
9531 counter++;
9532 }
9533 return counter;
9534}
9535
9536// For a script finds all SharedFunctionInfo's in the heap that points
9537// to this script. Returns JSArray of SharedFunctionInfo wrapped
9538// in OpaqueReferences.
9539static Object* Runtime_LiveEditFindSharedFunctionInfosForScript(
9540 Arguments args) {
9541 ASSERT(args.length() == 1);
9542 HandleScope scope;
9543 CONVERT_CHECKED(JSValue, script_value, args[0]);
9544
9545 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
9546
9547 const int kBufferSize = 32;
9548
9549 Handle<FixedArray> array;
9550 array = Factory::NewFixedArray(kBufferSize);
9551 int number = FindSharedFunctionInfosForScript(*script, *array);
9552 if (number > kBufferSize) {
9553 array = Factory::NewFixedArray(number);
9554 FindSharedFunctionInfosForScript(*script, *array);
9555 }
9556
9557 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
9558 result->set_length(Smi::FromInt(number));
9559
9560 LiveEdit::WrapSharedFunctionInfos(result);
9561
9562 return *result;
9563}
9564
9565// For a script calculates compilation information about all its functions.
9566// The script source is explicitly specified by the second argument.
9567// The source of the actual script is not used, however it is important that
9568// all generated code keeps references to this particular instance of script.
9569// Returns a JSArray of compilation infos. The array is ordered so that
9570// each function with all its descendant is always stored in a continues range
9571// with the function itself going first. The root function is a script function.
9572static Object* Runtime_LiveEditGatherCompileInfo(Arguments args) {
9573 ASSERT(args.length() == 2);
9574 HandleScope scope;
9575 CONVERT_CHECKED(JSValue, script, args[0]);
9576 CONVERT_ARG_CHECKED(String, source, 1);
9577 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
9578
9579 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
9580
9581 if (Top::has_pending_exception()) {
9582 return Failure::Exception();
9583 }
9584
9585 return result;
9586}
9587
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009588// Changes the source of the script to a new_source.
9589// If old_script_name is provided (i.e. is a String), also creates a copy of
9590// the script with its original source and sends notification to debugger.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009591static Object* Runtime_LiveEditReplaceScript(Arguments args) {
9592 ASSERT(args.length() == 3);
9593 HandleScope scope;
9594 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
9595 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009596 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009597
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009598 CONVERT_CHECKED(Script, original_script_pointer,
9599 original_script_value->value());
9600 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009601
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009602 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
9603 new_source,
9604 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009605
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009606 if (old_script->IsScript()) {
9607 Handle<Script> script_handle(Script::cast(old_script));
9608 return *(GetScriptWrapper(script_handle));
9609 } else {
9610 return Heap::null_value();
9611 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009612}
9613
9614// Replaces code of SharedFunctionInfo with a new one.
9615static Object* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
9616 ASSERT(args.length() == 2);
9617 HandleScope scope;
9618 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
9619 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
9620
ager@chromium.orgac091b72010-05-05 07:34:42 +00009621 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009622}
9623
9624// Connects SharedFunctionInfo to another script.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009625static Object* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009626 ASSERT(args.length() == 2);
9627 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009628 Handle<Object> function_object(args[0]);
9629 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009630
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009631 if (function_object->IsJSValue()) {
9632 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
9633 if (script_object->IsJSValue()) {
9634 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
9635 script_object = Handle<Object>(script);
9636 }
9637
9638 LiveEdit::SetFunctionScript(function_wrapper, script_object);
9639 } else {
9640 // Just ignore this. We may not have a SharedFunctionInfo for some functions
9641 // and we check it in this function.
9642 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009643
9644 return Heap::undefined_value();
9645}
9646
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009647
9648// In a code of a parent function replaces original function as embedded object
9649// with a substitution one.
9650static Object* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
9651 ASSERT(args.length() == 3);
9652 HandleScope scope;
9653
9654 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
9655 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
9656 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
9657
9658 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
9659 subst_wrapper);
9660
9661 return Heap::undefined_value();
9662}
9663
9664
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009665// Updates positions of a shared function info (first parameter) according
9666// to script source change. Text change is described in second parameter as
9667// array of groups of 3 numbers:
9668// (change_begin, change_end, change_end_new_position).
9669// Each group describes a change in text; groups are sorted by change_begin.
9670static Object* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
9671 ASSERT(args.length() == 2);
9672 HandleScope scope;
9673 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
9674 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
9675
ager@chromium.orgac091b72010-05-05 07:34:42 +00009676 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009677}
9678
9679
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009680// For array of SharedFunctionInfo's (each wrapped in JSValue)
9681// checks that none of them have activations on stacks (of any thread).
9682// Returns array of the same length with corresponding results of
9683// LiveEdit::FunctionPatchabilityStatus type.
ager@chromium.org357bf652010-04-12 11:30:10 +00009684static Object* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
9685 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009686 HandleScope scope;
9687 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +00009688 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009689
ager@chromium.org357bf652010-04-12 11:30:10 +00009690 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009691}
9692
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009693// Compares 2 strings line-by-line and returns diff in form of JSArray of
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00009694// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009695static Object* Runtime_LiveEditCompareStringsLinewise(Arguments args) {
9696 ASSERT(args.length() == 2);
9697 HandleScope scope;
9698 CONVERT_ARG_CHECKED(String, s1, 0);
9699 CONVERT_ARG_CHECKED(String, s2, 1);
9700
9701 return *LiveEdit::CompareStringsLinewise(s1, s2);
9702}
9703
9704
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009705
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009706// A testing entry. Returns statement position which is the closest to
9707// source_position.
9708static Object* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
9709 ASSERT(args.length() == 2);
9710 HandleScope scope;
9711 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9712 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9713
9714 Handle<Code> code(function->code());
9715
9716 RelocIterator it(*code, 1 << RelocInfo::STATEMENT_POSITION);
9717 int closest_pc = 0;
9718 int distance = kMaxInt;
9719 while (!it.done()) {
9720 int statement_position = static_cast<int>(it.rinfo()->data());
9721 // Check if this break point is closer that what was previously found.
9722 if (source_position <= statement_position &&
9723 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00009724 closest_pc =
9725 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009726 distance = statement_position - source_position;
9727 // Check whether we can't get any closer.
9728 if (distance == 0) break;
9729 }
9730 it.next();
9731 }
9732
9733 return Smi::FromInt(closest_pc);
9734}
9735
9736
ager@chromium.org357bf652010-04-12 11:30:10 +00009737// Calls specified function with or without entering the debugger.
9738// This is used in unit tests to run code as if debugger is entered or simply
9739// to have a stack with C++ frame in the middle.
9740static Object* Runtime_ExecuteInDebugContext(Arguments args) {
9741 ASSERT(args.length() == 2);
9742 HandleScope scope;
9743 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9744 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
9745
9746 Handle<Object> result;
9747 bool pending_exception;
9748 {
9749 if (without_debugger) {
9750 result = Execution::Call(function, Top::global(), 0, NULL,
9751 &pending_exception);
9752 } else {
9753 EnterDebugger enter_debugger;
9754 result = Execution::Call(function, Top::global(), 0, NULL,
9755 &pending_exception);
9756 }
9757 }
9758 if (!pending_exception) {
9759 return *result;
9760 } else {
9761 return Failure::Exception();
9762 }
9763}
9764
9765
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009766#endif // ENABLE_DEBUGGER_SUPPORT
9767
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009768#ifdef ENABLE_LOGGING_AND_PROFILING
9769
9770static Object* Runtime_ProfilerResume(Arguments args) {
9771 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009772 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009773
9774 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00009775 CONVERT_CHECKED(Smi, smi_tag, args[1]);
9776 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009777 return Heap::undefined_value();
9778}
9779
9780
9781static Object* Runtime_ProfilerPause(Arguments args) {
9782 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009783 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009784
9785 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00009786 CONVERT_CHECKED(Smi, smi_tag, args[1]);
9787 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009788 return Heap::undefined_value();
9789}
9790
9791#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009792
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009793// Finds the script object from the script data. NOTE: This operation uses
9794// heap traversal to find the function generated for the source position
9795// for the requested break point. For lazily compiled functions several heap
9796// traversals might be required rendering this operation as a rather slow
9797// operation. However for setting break points which is normally done through
9798// some kind of user interaction the performance is not crucial.
9799static Handle<Object> Runtime_GetScriptFromScriptName(
9800 Handle<String> script_name) {
9801 // Scan the heap for Script objects to find the script with the requested
9802 // script data.
9803 Handle<Script> script;
9804 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009805 HeapObject* obj = NULL;
9806 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009807 // If a script is found check if it has the script data requested.
9808 if (obj->IsScript()) {
9809 if (Script::cast(obj)->name()->IsString()) {
9810 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
9811 script = Handle<Script>(Script::cast(obj));
9812 }
9813 }
9814 }
9815 }
9816
9817 // If no script with the requested script data is found return undefined.
9818 if (script.is_null()) return Factory::undefined_value();
9819
9820 // Return the script found.
9821 return GetScriptWrapper(script);
9822}
9823
9824
9825// Get the script object from script data. NOTE: Regarding performance
9826// see the NOTE for GetScriptFromScriptData.
9827// args[0]: script data for the script to find the source for
9828static Object* Runtime_GetScript(Arguments args) {
9829 HandleScope scope;
9830
9831 ASSERT(args.length() == 1);
9832
9833 CONVERT_CHECKED(String, script_name, args[0]);
9834
9835 // Find the requested script.
9836 Handle<Object> result =
9837 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
9838 return *result;
9839}
9840
9841
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009842// Determines whether the given stack frame should be displayed in
9843// a stack trace. The caller is the error constructor that asked
9844// for the stack trace to be collected. The first time a construct
9845// call to this function is encountered it is skipped. The seen_caller
9846// in/out parameter is used to remember if the caller has been seen
9847// yet.
9848static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
9849 bool* seen_caller) {
9850 // Only display JS frames.
9851 if (!raw_frame->is_java_script())
9852 return false;
9853 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
9854 Object* raw_fun = frame->function();
9855 // Not sure when this can happen but skip it just in case.
9856 if (!raw_fun->IsJSFunction())
9857 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009858 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009859 *seen_caller = true;
9860 return false;
9861 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009862 // Skip all frames until we've seen the caller. Also, skip the most
9863 // obvious builtin calls. Some builtin calls (such as Number.ADD
9864 // which is invoked using 'call') are very difficult to recognize
9865 // so we're leaving them in for now.
9866 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009867}
9868
9869
9870// Collect the raw data for a stack trace. Returns an array of three
9871// element segments each containing a receiver, function and native
9872// code offset.
9873static Object* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009874 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009875 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009876 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
9877
9878 HandleScope scope;
9879
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00009880 limit = Max(limit, 0); // Ensure that limit is not negative.
9881 int initial_size = Min(limit, 10);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009882 Handle<JSArray> result = Factory::NewJSArray(initial_size * 3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009883
9884 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009885 // If the caller parameter is a function we skip frames until we're
9886 // under it before starting to collect.
9887 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009888 int cursor = 0;
9889 int frames_seen = 0;
9890 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009891 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009892 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009893 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009894 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009895 Object* recv = frame->receiver();
9896 Object* fun = frame->function();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009897 Address pc = frame->pc();
9898 Address start = frame->code()->address();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009899 Smi* offset = Smi::FromInt(static_cast<int>(pc - start));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009900 FixedArray* elements = FixedArray::cast(result->elements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009901 if (cursor + 2 < elements->length()) {
9902 elements->set(cursor++, recv);
9903 elements->set(cursor++, fun);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009904 elements->set(cursor++, offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009905 } else {
9906 HandleScope scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009907 Handle<Object> recv_handle(recv);
9908 Handle<Object> fun_handle(fun);
9909 SetElement(result, cursor++, recv_handle);
9910 SetElement(result, cursor++, fun_handle);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009911 SetElement(result, cursor++, Handle<Smi>(offset));
9912 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009913 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009914 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009915 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009916
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009917 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009918 return *result;
9919}
9920
9921
ager@chromium.org3811b432009-10-28 14:53:37 +00009922// Returns V8 version as a string.
9923static Object* Runtime_GetV8Version(Arguments args) {
9924 ASSERT_EQ(args.length(), 0);
9925
9926 NoHandleAllocation ha;
9927
9928 const char* version_string = v8::V8::GetVersion();
9929
9930 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
9931}
9932
9933
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009934static Object* Runtime_Abort(Arguments args) {
9935 ASSERT(args.length() == 2);
9936 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
9937 Smi::cast(args[1])->value());
9938 Top::PrintStack();
9939 OS::Abort();
9940 UNREACHABLE();
9941 return NULL;
9942}
9943
9944
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009945static Object* Runtime_DeleteHandleScopeExtensions(Arguments args) {
9946 ASSERT(args.length() == 0);
9947 HandleScope::DeleteExtensions();
9948 return Heap::undefined_value();
9949}
9950
9951
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009952static Object* CacheMiss(FixedArray* cache_obj, int index, Object* key_obj) {
9953 ASSERT(index % 2 == 0); // index of the key
9954 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
9955 ASSERT(index < cache_obj->length());
9956
9957 HandleScope scope;
9958
9959 Handle<FixedArray> cache(cache_obj);
9960 Handle<Object> key(key_obj);
9961 Handle<JSFunction> factory(JSFunction::cast(
9962 cache->get(JSFunctionResultCache::kFactoryIndex)));
9963 // TODO(antonm): consider passing a receiver when constructing a cache.
9964 Handle<Object> receiver(Top::global_context()->global());
9965
9966 Handle<Object> value;
9967 {
9968 // This handle is nor shared, nor used later, so it's safe.
9969 Object** argv[] = { key.location() };
9970 bool pending_exception = false;
9971 value = Execution::Call(factory,
9972 receiver,
9973 1,
9974 argv,
9975 &pending_exception);
9976 if (pending_exception) return Failure::Exception();
9977 }
9978
9979 cache->set(index, *key);
9980 cache->set(index + 1, *value);
9981 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index));
9982
9983 return *value;
9984}
9985
9986
9987static Object* Runtime_GetFromCache(Arguments args) {
9988 // This is only called from codegen, so checks might be more lax.
9989 CONVERT_CHECKED(FixedArray, cache, args[0]);
9990 Object* key = args[1];
9991
9992 const int finger_index =
9993 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value();
9994
9995 Object* o = cache->get(finger_index);
9996 if (o == key) {
9997 // The fastest case: hit the same place again.
9998 return cache->get(finger_index + 1);
9999 }
10000
10001 for (int i = finger_index - 2;
10002 i >= JSFunctionResultCache::kEntriesIndex;
10003 i -= 2) {
10004 o = cache->get(i);
10005 if (o == key) {
10006 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10007 return cache->get(i + 1);
10008 }
10009 }
10010
10011 const int size =
10012 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value();
10013 ASSERT(size <= cache->length());
10014
10015 for (int i = size - 2; i > finger_index; i -= 2) {
10016 o = cache->get(i);
10017 if (o == key) {
10018 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10019 return cache->get(i + 1);
10020 }
10021 }
10022
10023 // Cache miss. If we have spare room, put new data into it, otherwise
10024 // evict post finger entry which must be least recently used.
10025 if (size < cache->length()) {
10026 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2));
10027 return CacheMiss(cache, size, key);
10028 } else {
antonm@chromium.org397e23c2010-04-21 12:00:05 +000010029 int target_index = finger_index + JSFunctionResultCache::kEntrySize;
10030 if (target_index == cache->length()) {
10031 target_index = JSFunctionResultCache::kEntriesIndex;
10032 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010033 return CacheMiss(cache, target_index, key);
10034 }
10035}
10036
kasper.lund44510672008-07-25 07:37:58 +000010037#ifdef DEBUG
10038// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10039// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010040static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010041 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010042 HandleScope scope;
10043 Handle<JSArray> result = Factory::NewJSArray(0);
10044 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010045 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010046#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010047 { \
10048 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010049 Handle<String> name; \
10050 /* Inline runtime functions have an underscore in front of the name. */ \
10051 if (inline_runtime_functions) { \
10052 name = Factory::NewStringFromAscii( \
10053 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10054 } else { \
10055 name = Factory::NewStringFromAscii( \
10056 Vector<const char>(#Name, StrLength(#Name))); \
10057 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010058 Handle<JSArray> pair = Factory::NewJSArray(0); \
10059 SetElement(pair, 0, name); \
10060 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10061 SetElement(result, index++, pair); \
10062 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010063 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010064 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010065 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010066 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010067 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010068#undef ADD_ENTRY
10069 return *result;
10070}
kasper.lund44510672008-07-25 07:37:58 +000010071#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010072
10073
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010074static Object* Runtime_Log(Arguments args) {
10075 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010076 CONVERT_CHECKED(String, format, args[0]);
10077 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010078 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010079 Logger::LogRuntime(chars, elms);
10080 return Heap::undefined_value();
10081}
10082
10083
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010084static Object* Runtime_IS_VAR(Arguments args) {
10085 UNREACHABLE(); // implemented as macro in the parser
10086 return NULL;
10087}
10088
10089
10090// ----------------------------------------------------------------------------
10091// Implementation of Runtime
10092
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010093#define F(name, number_of_args, result_size) \
10094 { Runtime::k##name, Runtime::RUNTIME, #name, \
10095 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010096
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010097
10098#define I(name, number_of_args, result_size) \
10099 { Runtime::kInline##name, Runtime::INLINE, \
10100 "_" #name, NULL, number_of_args, result_size },
10101
10102Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010104 INLINE_FUNCTION_LIST(I)
10105 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010106};
10107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010108
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010109Object* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
10110 ASSERT(dictionary != NULL);
10111 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10112 for (int i = 0; i < kNumFunctions; ++i) {
10113 Object* name_symbol = Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10114 if (name_symbol->IsFailure()) return name_symbol;
10115 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
10116 dictionary = string_dictionary->Add(String::cast(name_symbol),
10117 Smi::FromInt(i),
10118 PropertyDetails(NONE, NORMAL));
10119 // Non-recoverable failure. Calling code must restart heap initialization.
10120 if (dictionary->IsFailure()) return dictionary;
10121 }
10122 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010123}
10124
10125
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010126Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10127 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10128 if (entry != kNotFound) {
10129 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10130 int function_index = Smi::cast(smi_index)->value();
10131 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010132 }
10133 return NULL;
10134}
10135
10136
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010137Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10138 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10139}
10140
10141
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010142void Runtime::PerformGC(Object* result) {
10143 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010144 if (failure->IsRetryAfterGC()) {
10145 // Try to do a garbage collection; ignore it if it fails. The C
10146 // entry stub will throw an out-of-memory exception in that case.
10147 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
10148 } else {
10149 // Handle last resort GC and make sure to allow future allocations
10150 // to grow the heap without causing GCs (if possible).
10151 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010152 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010153 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010154}
10155
10156
10157} } // namespace v8::internal