blob: 8d58db74a017a357d005a22818716976c2e9e5c6 [file] [log] [blame]
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "compiler.h"
37#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000038#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include "debug.h"
40#include "execution.h"
41#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000042#include "liveedit.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000043#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "platform.h"
45#include "runtime.h"
46#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000047#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000048#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000049#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000050#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051
kasperl@chromium.org71affb52009-05-26 05:44:31 +000052namespace v8 {
53namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
55
ager@chromium.org3e875802009-06-29 08:26:34 +000056#define RUNTIME_ASSERT(value) \
57 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
59// Cast the given object to a value of the specified type and store
60// it in a variable with the given name. If the object is not of the
61// expected type call IllegalOperation and return.
62#define CONVERT_CHECKED(Type, name, obj) \
63 RUNTIME_ASSERT(obj->Is##Type()); \
64 Type* name = Type::cast(obj);
65
66#define CONVERT_ARG_CHECKED(Type, name, index) \
67 RUNTIME_ASSERT(args[index]->Is##Type()); \
68 Handle<Type> name = args.at<Type>(index);
69
kasper.lundbd3ec4e2008-07-09 11:06:54 +000070// Cast the given object to a boolean and store it in a variable with
71// the given name. If the object is not a boolean call IllegalOperation
72// and return.
73#define CONVERT_BOOLEAN_CHECKED(name, obj) \
74 RUNTIME_ASSERT(obj->IsBoolean()); \
75 bool name = (obj)->IsTrue();
76
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000077// Cast the given object to a Smi and store its value in an int variable
78// with the given name. If the object is not a Smi call IllegalOperation
79// and return.
80#define CONVERT_SMI_CHECKED(name, obj) \
81 RUNTIME_ASSERT(obj->IsSmi()); \
82 int name = Smi::cast(obj)->value();
83
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000084// Cast the given object to a double and store it in a variable with
85// the given name. If the object is not a number (as opposed to
86// the number not-a-number) call IllegalOperation and return.
87#define CONVERT_DOUBLE_CHECKED(name, obj) \
88 RUNTIME_ASSERT(obj->IsNumber()); \
89 double name = (obj)->Number();
90
91// Call the specified converter on the object *comand store the result in
92// a variable of the specified type with the given name. If the
93// object is not a Number call IllegalOperation and return.
94#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
95 RUNTIME_ASSERT(obj->IsNumber()); \
96 type name = NumberTo##Type(obj);
97
98// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000099static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000102MUST_USE_RESULT static Object* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000103 StackLimitCheck check;
104 if (check.HasOverflowed()) return Top::StackOverflow();
105
106 Object* result = Heap::CopyJSObject(boilerplate);
107 if (result->IsFailure()) return result;
108 JSObject* copy = JSObject::cast(result);
109
110 // Deep copy local properties.
111 if (copy->HasFastProperties()) {
112 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000113 for (int i = 0; i < properties->length(); i++) {
114 Object* value = properties->get(i);
115 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000116 JSObject* js_object = JSObject::cast(value);
117 result = DeepCopyBoilerplate(js_object);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 if (result->IsFailure()) return result;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000119 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000120 }
121 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000122 int nof = copy->map()->inobject_properties();
123 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000124 Object* value = copy->InObjectPropertyAt(i);
125 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 JSObject* js_object = JSObject::cast(value);
127 result = DeepCopyBoilerplate(js_object);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000128 if (result->IsFailure()) return result;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000129 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 }
131 }
132 } else {
133 result = Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
134 if (result->IsFailure()) return result;
135 FixedArray* names = FixedArray::cast(result);
136 copy->GetLocalPropertyNames(names, 0);
137 for (int i = 0; i < names->length(); i++) {
138 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000139 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000142 // Only deep copy fields from the object literal expression.
143 // In particular, don't try to copy the length attribute of
144 // an array.
145 if (attributes != NONE) continue;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000146 Object* value = copy->GetProperty(key_string, &attributes);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000147 ASSERT(!value->IsFailure());
148 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000149 JSObject* js_object = JSObject::cast(value);
150 result = DeepCopyBoilerplate(js_object);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 if (result->IsFailure()) return result;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 result = copy->SetProperty(key_string, result, NONE);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 if (result->IsFailure()) return result;
154 }
155 }
156 }
157
158 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000159 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000160 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000161 switch (copy->GetElementsKind()) {
162 case JSObject::FAST_ELEMENTS: {
163 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000164 if (elements->map() == Heap::fixed_cow_array_map()) {
165 Counters::cow_arrays_created_runtime.Increment();
166#ifdef DEBUG
167 for (int i = 0; i < elements->length(); i++) {
168 ASSERT(!elements->get(i)->IsJSObject());
169 }
170#endif
171 } else {
172 for (int i = 0; i < elements->length(); i++) {
173 Object* value = elements->get(i);
174 if (value->IsJSObject()) {
175 JSObject* js_object = JSObject::cast(value);
176 result = DeepCopyBoilerplate(js_object);
177 if (result->IsFailure()) return result;
178 elements->set(i, result);
179 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000180 }
181 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000182 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000183 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000184 case JSObject::DICTIONARY_ELEMENTS: {
185 NumberDictionary* element_dictionary = copy->element_dictionary();
186 int capacity = element_dictionary->Capacity();
187 for (int i = 0; i < capacity; i++) {
188 Object* k = element_dictionary->KeyAt(i);
189 if (element_dictionary->IsKey(k)) {
190 Object* value = element_dictionary->ValueAt(i);
191 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000192 JSObject* js_object = JSObject::cast(value);
193 result = DeepCopyBoilerplate(js_object);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000194 if (result->IsFailure()) return result;
195 element_dictionary->ValueAtPut(i, result);
196 }
197 }
198 }
199 break;
200 }
201 default:
202 UNREACHABLE();
203 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000204 }
205 return copy;
206}
207
208
209static Object* Runtime_CloneLiteralBoilerplate(Arguments args) {
210 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
211 return DeepCopyBoilerplate(boilerplate);
212}
213
214
215static Object* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000216 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000217 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218}
219
220
ager@chromium.org236ad962008-09-25 09:45:57 +0000221static Handle<Map> ComputeObjectLiteralMap(
222 Handle<Context> context,
223 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000224 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000225 int properties_length = constant_properties->length();
226 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000227 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000228 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000229 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000230 for (int p = 0; p != properties_length; p += 2) {
231 Object* key = constant_properties->get(p);
232 uint32_t element_index = 0;
233 if (key->IsSymbol()) {
234 number_of_symbol_keys++;
235 } else if (key->ToArrayIndex(&element_index)) {
236 // An index key does not require space in the property backing store.
237 number_of_properties--;
238 } else {
239 // Bail out as a non-symbol non-index key makes caching impossible.
240 // ASSERT to make sure that the if condition after the loop is false.
241 ASSERT(number_of_symbol_keys != number_of_properties);
242 break;
243 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000244 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000245 // If we only have symbols and array indices among keys then we can
246 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000247 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000248 if ((number_of_symbol_keys == number_of_properties) &&
249 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000250 // Create the fixed array with the key.
251 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000252 if (number_of_symbol_keys > 0) {
253 int index = 0;
254 for (int p = 0; p < properties_length; p += 2) {
255 Object* key = constant_properties->get(p);
256 if (key->IsSymbol()) {
257 keys->set(index++, key);
258 }
259 }
260 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000262 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 return Factory::ObjectLiteralMapFromCache(context, keys);
264 }
265 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000266 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000267 return Factory::CopyMap(
268 Handle<Map>(context->object_function()->initial_map()),
269 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000270}
271
272
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000273static Handle<Object> CreateLiteralBoilerplate(
274 Handle<FixedArray> literals,
275 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000276
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000277
278static Handle<Object> CreateObjectLiteralBoilerplate(
279 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000280 Handle<FixedArray> constant_properties,
281 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000282 // Get the global context from the literals array. This is the
283 // context in which the function was created and we use the object
284 // function from this context to create the object literal. We do
285 // not use the object function from the current global context
286 // because this might be the object function from another context
287 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000288 Handle<Context> context =
289 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
290
291 bool is_result_from_cache;
292 Handle<Map> map = ComputeObjectLiteralMap(context,
293 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000294 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000295
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000297
298 // Normalize the elements of the boilerplate to save space if needed.
299 if (!should_have_fast_elements) NormalizeElements(boilerplate);
300
ager@chromium.org32912102009-01-16 10:38:43 +0000301 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000302 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000303 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000304 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000305 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000306 for (int index = 0; index < length; index +=2) {
307 Handle<Object> key(constant_properties->get(index+0));
308 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000309 if (value->IsFixedArray()) {
310 // The value contains the constant_properties of a
311 // simple object literal.
312 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
313 value = CreateLiteralBoilerplate(literals, array);
314 if (value.is_null()) return value;
315 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000316 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000318 if (key->IsSymbol()) {
319 // If key is a symbol it is not an array element.
320 Handle<String> name(String::cast(*key));
321 ASSERT(!name->AsArrayIndex(&element_index));
322 result = SetProperty(boilerplate, name, value, NONE);
323 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324 // Array index (uint32).
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000325 result = SetElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326 } else {
327 // Non-uint32 number.
328 ASSERT(key->IsNumber());
329 double num = key->Number();
330 char arr[100];
331 Vector<char> buffer(arr, ARRAY_SIZE(arr));
332 const char* str = DoubleToCString(num, buffer);
333 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000334 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000336 // If setting the property on the boilerplate throws an
337 // exception, the exception is converted to an empty handle in
338 // the handle based operations. In that case, we need to
339 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000340 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000341 }
342 }
343
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000344 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000345}
346
347
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000348static Handle<Object> CreateArrayLiteralBoilerplate(
349 Handle<FixedArray> literals,
350 Handle<FixedArray> elements) {
351 // Create the JSArray.
352 Handle<JSFunction> constructor(
353 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
354 Handle<Object> object = Factory::NewJSObject(constructor);
355
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000356 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
357 Handle<FixedArray> copied_elements =
358 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000359
360 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000361 if (is_cow) {
362#ifdef DEBUG
363 // Copy-on-write arrays must be shallow (and simple).
364 for (int i = 0; i < content->length(); i++) {
365 ASSERT(!content->get(i)->IsFixedArray());
366 }
367#endif
368 } else {
369 for (int i = 0; i < content->length(); i++) {
370 if (content->get(i)->IsFixedArray()) {
371 // The value contains the constant_properties of a
372 // simple object literal.
373 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
374 Handle<Object> result =
375 CreateLiteralBoilerplate(literals, fa);
376 if (result.is_null()) return result;
377 content->set(i, *result);
378 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000379 }
380 }
381
382 // Set the elements.
383 Handle<JSArray>::cast(object)->SetContent(*content);
384 return object;
385}
386
387
388static Handle<Object> CreateLiteralBoilerplate(
389 Handle<FixedArray> literals,
390 Handle<FixedArray> array) {
391 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
392 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000393 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
394 return CreateObjectLiteralBoilerplate(literals, elements, true);
395 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
396 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000397 case CompileTimeValue::ARRAY_LITERAL:
398 return CreateArrayLiteralBoilerplate(literals, elements);
399 default:
400 UNREACHABLE();
401 return Handle<Object>::null();
402 }
403}
404
405
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000407 // Takes a FixedArray of elements containing the literal elements of
408 // the array literal and produces JSArray with those elements.
409 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000410 // which contains the context from which to get the Array function
411 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000412 HandleScope scope;
413 ASSERT(args.length() == 3);
414 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
415 CONVERT_SMI_CHECKED(literals_index, args[1]);
416 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000418 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
419 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421 // Update the functions literal and return the boilerplate.
422 literals->set(literals_index, *object);
423 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000424}
425
426
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000427static Object* Runtime_CreateObjectLiteral(Arguments args) {
428 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000429 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000430 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
431 CONVERT_SMI_CHECKED(literals_index, args[1]);
432 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000433 CONVERT_SMI_CHECKED(fast_elements, args[3]);
434 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000435
436 // Check if boilerplate exists. If not, create it first.
437 Handle<Object> boilerplate(literals->get(literals_index));
438 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000439 boilerplate = CreateObjectLiteralBoilerplate(literals,
440 constant_properties,
441 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000442 if (boilerplate.is_null()) return Failure::Exception();
443 // Update the functions literal and return the boilerplate.
444 literals->set(literals_index, *boilerplate);
445 }
446 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
447}
448
449
450static Object* Runtime_CreateObjectLiteralShallow(Arguments args) {
451 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000452 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000453 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
454 CONVERT_SMI_CHECKED(literals_index, args[1]);
455 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000456 CONVERT_SMI_CHECKED(fast_elements, args[3]);
457 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000458
459 // Check if boilerplate exists. If not, create it first.
460 Handle<Object> boilerplate(literals->get(literals_index));
461 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000462 boilerplate = CreateObjectLiteralBoilerplate(literals,
463 constant_properties,
464 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000465 if (boilerplate.is_null()) return Failure::Exception();
466 // Update the functions literal and return the boilerplate.
467 literals->set(literals_index, *boilerplate);
468 }
469 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
470}
471
472
473static Object* Runtime_CreateArrayLiteral(Arguments args) {
474 HandleScope scope;
475 ASSERT(args.length() == 3);
476 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
477 CONVERT_SMI_CHECKED(literals_index, args[1]);
478 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
479
480 // Check if boilerplate exists. If not, create it first.
481 Handle<Object> boilerplate(literals->get(literals_index));
482 if (*boilerplate == Heap::undefined_value()) {
483 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
484 if (boilerplate.is_null()) return Failure::Exception();
485 // Update the functions literal and return the boilerplate.
486 literals->set(literals_index, *boilerplate);
487 }
488 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
489}
490
491
492static Object* Runtime_CreateArrayLiteralShallow(Arguments args) {
493 HandleScope scope;
494 ASSERT(args.length() == 3);
495 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
496 CONVERT_SMI_CHECKED(literals_index, args[1]);
497 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
498
499 // Check if boilerplate exists. If not, create it first.
500 Handle<Object> boilerplate(literals->get(literals_index));
501 if (*boilerplate == Heap::undefined_value()) {
502 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
503 if (boilerplate.is_null()) return Failure::Exception();
504 // Update the functions literal and return the boilerplate.
505 literals->set(literals_index, *boilerplate);
506 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000507 if (JSObject::cast(*boilerplate)->elements()->map() ==
508 Heap::fixed_cow_array_map()) {
509 Counters::cow_arrays_created_runtime.Increment();
510 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000511 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
512}
513
514
ager@chromium.org32912102009-01-16 10:38:43 +0000515static Object* Runtime_CreateCatchExtensionObject(Arguments args) {
516 ASSERT(args.length() == 2);
517 CONVERT_CHECKED(String, key, args[0]);
518 Object* value = args[1];
519 // Create a catch context extension object.
520 JSFunction* constructor =
521 Top::context()->global_context()->context_extension_function();
522 Object* object = Heap::AllocateJSObject(constructor);
523 if (object->IsFailure()) return object;
524 // Assign the exception value to the catch variable and make sure
525 // that the catch variable is DontDelete.
526 value = JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
527 if (value->IsFailure()) return value;
528 return object;
529}
530
531
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532static Object* Runtime_ClassOf(Arguments args) {
533 NoHandleAllocation ha;
534 ASSERT(args.length() == 1);
535 Object* obj = args[0];
536 if (!obj->IsJSObject()) return Heap::null_value();
537 return JSObject::cast(obj)->class_name();
538}
539
ager@chromium.org7c537e22008-10-16 08:43:32 +0000540
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000541static Object* Runtime_IsInPrototypeChain(Arguments args) {
542 NoHandleAllocation ha;
543 ASSERT(args.length() == 2);
544 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
545 Object* O = args[0];
546 Object* V = args[1];
547 while (true) {
548 Object* prototype = V->GetPrototype();
549 if (prototype->IsNull()) return Heap::false_value();
550 if (O == prototype) return Heap::true_value();
551 V = prototype;
552 }
553}
554
555
ager@chromium.org9085a012009-05-11 19:22:57 +0000556// Inserts an object as the hidden prototype of another object.
557static Object* Runtime_SetHiddenPrototype(Arguments args) {
558 NoHandleAllocation ha;
559 ASSERT(args.length() == 2);
560 CONVERT_CHECKED(JSObject, jsobject, args[0]);
561 CONVERT_CHECKED(JSObject, proto, args[1]);
562
563 // Sanity checks. The old prototype (that we are replacing) could
564 // theoretically be null, but if it is not null then check that we
565 // didn't already install a hidden prototype here.
566 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
567 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
568 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
569
570 // Allocate up front before we start altering state in case we get a GC.
571 Object* map_or_failure = proto->map()->CopyDropTransitions();
572 if (map_or_failure->IsFailure()) return map_or_failure;
573 Map* new_proto_map = Map::cast(map_or_failure);
574
575 map_or_failure = jsobject->map()->CopyDropTransitions();
576 if (map_or_failure->IsFailure()) return map_or_failure;
577 Map* new_map = Map::cast(map_or_failure);
578
579 // Set proto's prototype to be the old prototype of the object.
580 new_proto_map->set_prototype(jsobject->GetPrototype());
581 proto->set_map(new_proto_map);
582 new_proto_map->set_is_hidden_prototype();
583
584 // Set the object's prototype to proto.
585 new_map->set_prototype(proto);
586 jsobject->set_map(new_map);
587
588 return Heap::undefined_value();
589}
590
591
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000592static Object* Runtime_IsConstructCall(Arguments args) {
593 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000594 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000595 JavaScriptFrameIterator it;
596 return Heap::ToBoolean(it.frame()->IsConstructor());
597}
598
599
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000600// Recursively traverses hidden prototypes if property is not found
601static void GetOwnPropertyImplementation(JSObject* obj,
602 String* name,
603 LookupResult* result) {
604 obj->LocalLookupRealNamedProperty(name, result);
605
606 if (!result->IsProperty()) {
607 Object* proto = obj->GetPrototype();
608 if (proto->IsJSObject() &&
609 JSObject::cast(proto)->map()->is_hidden_prototype())
610 GetOwnPropertyImplementation(JSObject::cast(proto),
611 name, result);
612 }
613}
614
615
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000616// Enumerator used as indices into the array returned from GetOwnProperty
617enum PropertyDescriptorIndices {
618 IS_ACCESSOR_INDEX,
619 VALUE_INDEX,
620 GETTER_INDEX,
621 SETTER_INDEX,
622 WRITABLE_INDEX,
623 ENUMERABLE_INDEX,
624 CONFIGURABLE_INDEX,
625 DESCRIPTOR_SIZE
626};
627
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000628// Returns an array with the property description:
629// if args[1] is not a property on args[0]
630// returns undefined
631// if args[1] is a data property on args[0]
632// [false, value, Writeable, Enumerable, Configurable]
633// if args[1] is an accessor on args[0]
634// [true, GetFunction, SetFunction, Enumerable, Configurable]
635static Object* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000636 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000637 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000638 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000639 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
640 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000641 CONVERT_ARG_CHECKED(JSObject, obj, 0);
642 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000643
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000644 // This could be an element.
645 uint32_t index;
646 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000647 switch (obj->HasLocalElement(index)) {
648 case JSObject::UNDEFINED_ELEMENT:
649 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000650
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000651 case JSObject::STRING_CHARACTER_ELEMENT: {
652 // Special handling of string objects according to ECMAScript 5
653 // 15.5.5.2. Note that this might be a string object with elements
654 // other than the actual string value. This is covered by the
655 // subsequent cases.
656 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
657 Handle<String> str(String::cast(js_value->value()));
658 Handle<String> substr = SubString(str, index, index+1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000659
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000660 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
661 elms->set(VALUE_INDEX, *substr);
662 elms->set(WRITABLE_INDEX, Heap::false_value());
663 elms->set(ENUMERABLE_INDEX, Heap::false_value());
664 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
665 return *desc;
666 }
667
668 case JSObject::INTERCEPTED_ELEMENT:
669 case JSObject::FAST_ELEMENT: {
670 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
671 Handle<Object> element = GetElement(Handle<Object>(obj), index);
672 elms->set(VALUE_INDEX, *element);
673 elms->set(WRITABLE_INDEX, Heap::true_value());
674 elms->set(ENUMERABLE_INDEX, Heap::true_value());
675 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
676 return *desc;
677 }
678
679 case JSObject::DICTIONARY_ELEMENT: {
680 NumberDictionary* dictionary = obj->element_dictionary();
681 int entry = dictionary->FindEntry(index);
682 ASSERT(entry != NumberDictionary::kNotFound);
683 PropertyDetails details = dictionary->DetailsAt(entry);
684 switch (details.type()) {
685 case CALLBACKS: {
686 // This is an accessor property with getter and/or setter.
687 FixedArray* callbacks =
688 FixedArray::cast(dictionary->ValueAt(entry));
689 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
690 elms->set(GETTER_INDEX, callbacks->get(0));
691 elms->set(SETTER_INDEX, callbacks->get(1));
692 break;
693 }
694 case NORMAL:
695 // This is a data property.
696 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
697 elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
698 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
699 break;
700 default:
701 UNREACHABLE();
702 break;
703 }
704 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
705 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
706 return *desc;
707 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000708 }
709 }
710
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000711 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000712 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000713
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000714 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000715 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000716 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000717 if (result.type() == CALLBACKS) {
718 Object* structure = result.GetCallbackObject();
ager@chromium.org5c838252010-02-19 08:53:10 +0000719 if (structure->IsProxy() || structure->IsAccessorInfo()) {
720 // Property that is internally implemented as a callback or
721 // an API defined callback.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000722 Object* value = obj->GetPropertyWithCallback(
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000723 *obj, structure, *name, result.holder());
724 if (value->IsFailure()) return value;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000725 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
726 elms->set(VALUE_INDEX, value);
727 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000728 } else if (structure->IsFixedArray()) {
729 // __defineGetter__/__defineSetter__ callback.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000730 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
731 elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
732 elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000733 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000734 return Heap::undefined_value();
735 }
736 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000737 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
738 elms->set(VALUE_INDEX, result.GetLazyValue());
739 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000740 }
741
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000742 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
743 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000744 return *desc;
745}
746
747
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000748static Object* Runtime_PreventExtensions(Arguments args) {
749 ASSERT(args.length() == 1);
750 CONVERT_CHECKED(JSObject, obj, args[0]);
751 return obj->PreventExtensions();
752}
753
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000754static Object* Runtime_IsExtensible(Arguments args) {
755 ASSERT(args.length() == 1);
756 CONVERT_CHECKED(JSObject, obj, args[0]);
757 return obj->map()->is_extensible() ? Heap::true_value()
758 : Heap::false_value();
759}
760
761
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000762static Object* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000763 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000765 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
766 CONVERT_ARG_CHECKED(String, pattern, 1);
767 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000768 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
769 if (result.is_null()) return Failure::Exception();
770 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771}
772
773
774static Object* Runtime_CreateApiFunction(Arguments args) {
775 HandleScope scope;
776 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000777 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778 return *Factory::CreateApiFunction(data);
779}
780
781
782static Object* Runtime_IsTemplate(Arguments args) {
783 ASSERT(args.length() == 1);
784 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000785 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000786 return Heap::ToBoolean(result);
787}
788
789
790static Object* Runtime_GetTemplateField(Arguments args) {
791 ASSERT(args.length() == 2);
792 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000794 int index = field->value();
795 int offset = index * kPointerSize + HeapObject::kHeaderSize;
796 InstanceType type = templ->map()->instance_type();
797 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
798 type == OBJECT_TEMPLATE_INFO_TYPE);
799 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000800 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000801 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
802 } else {
803 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
804 }
805 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806}
807
808
ager@chromium.org870a0b62008-11-04 11:43:05 +0000809static Object* Runtime_DisableAccessChecks(Arguments args) {
810 ASSERT(args.length() == 1);
811 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000812 Map* old_map = object->map();
813 bool needs_access_checks = old_map->is_access_check_needed();
814 if (needs_access_checks) {
815 // Copy map so it won't interfere constructor's initial map.
816 Object* new_map = old_map->CopyDropTransitions();
817 if (new_map->IsFailure()) return new_map;
818
819 Map::cast(new_map)->set_is_access_check_needed(false);
820 object->set_map(Map::cast(new_map));
821 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000822 return needs_access_checks ? Heap::true_value() : Heap::false_value();
823}
824
825
826static Object* Runtime_EnableAccessChecks(Arguments args) {
827 ASSERT(args.length() == 1);
828 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000829 Map* old_map = object->map();
830 if (!old_map->is_access_check_needed()) {
831 // Copy map so it won't interfere constructor's initial map.
832 Object* new_map = old_map->CopyDropTransitions();
833 if (new_map->IsFailure()) return new_map;
834
835 Map::cast(new_map)->set_is_access_check_needed(true);
836 object->set_map(Map::cast(new_map));
837 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000838 return Heap::undefined_value();
839}
840
841
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
843 HandleScope scope;
844 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
845 Handle<Object> args[2] = { type_handle, name };
846 Handle<Object> error =
847 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
848 return Top::Throw(*error);
849}
850
851
852static Object* Runtime_DeclareGlobals(Arguments args) {
853 HandleScope scope;
854 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
855
ager@chromium.org3811b432009-10-28 14:53:37 +0000856 Handle<Context> context = args.at<Context>(0);
857 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000858 bool is_eval = Smi::cast(args[2])->value() == 1;
859
860 // Compute the property attributes. According to ECMA-262, section
861 // 13, page 71, the property must be read-only and
862 // non-deletable. However, neither SpiderMonkey nor KJS creates the
863 // property as read-only, so we don't either.
864 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866 // Traverse the name/value pairs and set the properties.
867 int length = pairs->length();
868 for (int i = 0; i < length; i += 2) {
869 HandleScope scope;
870 Handle<String> name(String::cast(pairs->get(i)));
871 Handle<Object> value(pairs->get(i + 1));
872
873 // We have to declare a global const property. To capture we only
874 // assign to it when evaluating the assignment for "const x =
875 // <expr>" the initial value is the hole.
876 bool is_const_property = value->IsTheHole();
877
878 if (value->IsUndefined() || is_const_property) {
879 // Lookup the property in the global object, and don't set the
880 // value of the variable if the property is already there.
881 LookupResult lookup;
882 global->Lookup(*name, &lookup);
883 if (lookup.IsProperty()) {
884 // Determine if the property is local by comparing the holder
885 // against the global object. The information will be used to
886 // avoid throwing re-declaration errors when declaring
887 // variables or constants that exist in the prototype chain.
888 bool is_local = (*global == lookup.holder());
889 // Get the property attributes and determine if the property is
890 // read-only.
891 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
892 bool is_read_only = (attributes & READ_ONLY) != 0;
893 if (lookup.type() == INTERCEPTOR) {
894 // If the interceptor says the property is there, we
895 // just return undefined without overwriting the property.
896 // Otherwise, we continue to setting the property.
897 if (attributes != ABSENT) {
898 // Check if the existing property conflicts with regards to const.
899 if (is_local && (is_read_only || is_const_property)) {
900 const char* type = (is_read_only) ? "const" : "var";
901 return ThrowRedeclarationError(type, name);
902 };
903 // The property already exists without conflicting: Go to
904 // the next declaration.
905 continue;
906 }
907 // Fall-through and introduce the absent property by using
908 // SetProperty.
909 } else {
910 if (is_local && (is_read_only || is_const_property)) {
911 const char* type = (is_read_only) ? "const" : "var";
912 return ThrowRedeclarationError(type, name);
913 }
914 // The property already exists without conflicting: Go to
915 // the next declaration.
916 continue;
917 }
918 }
919 } else {
920 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000921 Handle<SharedFunctionInfo> shared =
922 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000924 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 value = function;
926 }
927
928 LookupResult lookup;
929 global->LocalLookup(*name, &lookup);
930
931 PropertyAttributes attributes = is_const_property
932 ? static_cast<PropertyAttributes>(base | READ_ONLY)
933 : base;
934
935 if (lookup.IsProperty()) {
936 // There's a local property that we need to overwrite because
937 // we're either declaring a function or there's an interceptor
938 // that claims the property is absent.
939
940 // Check for conflicting re-declarations. We cannot have
941 // conflicting types in case of intercepted properties because
942 // they are absent.
943 if (lookup.type() != INTERCEPTOR &&
944 (lookup.IsReadOnly() || is_const_property)) {
945 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
946 return ThrowRedeclarationError(type, name);
947 }
948 SetProperty(global, name, value, attributes);
949 } else {
950 // If a property with this name does not already exist on the
951 // global object add the property locally. We take special
952 // precautions to always add it as a local property even in case
953 // of callbacks in the prototype chain (this rules out using
954 // SetProperty). Also, we must use the handle-based version to
955 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000956 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000957 }
958 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000959
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960 return Heap::undefined_value();
961}
962
963
964static Object* Runtime_DeclareContextSlot(Arguments args) {
965 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000966 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000967
ager@chromium.org7c537e22008-10-16 08:43:32 +0000968 CONVERT_ARG_CHECKED(Context, context, 0);
969 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000971 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000972 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000973 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000974
975 // Declarations are always done in the function context.
976 context = Handle<Context>(context->fcontext());
977
978 int index;
979 PropertyAttributes attributes;
980 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000981 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982 context->Lookup(name, flags, &index, &attributes);
983
984 if (attributes != ABSENT) {
985 // The name was declared before; check for conflicting
986 // re-declarations: This is similar to the code in parser.cc in
987 // the AstBuildingParser::Declare function.
988 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
989 // Functions are not read-only.
990 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
991 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
992 return ThrowRedeclarationError(type, name);
993 }
994
995 // Initialize it if necessary.
996 if (*initial_value != NULL) {
997 if (index >= 0) {
998 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000999 // the function context or the arguments object.
1000 if (holder->IsContext()) {
1001 ASSERT(holder.is_identical_to(context));
1002 if (((attributes & READ_ONLY) == 0) ||
1003 context->get(index)->IsTheHole()) {
1004 context->set(index, *initial_value);
1005 }
1006 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001007 // The holder is an arguments object.
1008 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1009 SetElement(arguments, index, initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 }
1011 } else {
1012 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001013 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014 SetProperty(context_ext, name, initial_value, mode);
1015 }
1016 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001019 // The property is not in the function context. It needs to be
1020 // "declared" in the function context's extension context, or in the
1021 // global context.
1022 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001023 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001024 // The function context's extension context exists - use it.
1025 context_ext = Handle<JSObject>(context->extension());
1026 } else {
1027 // The function context's extension context does not exists - allocate
1028 // it.
1029 context_ext = Factory::NewJSObject(Top::context_extension_function());
1030 // And store it in the extension slot.
1031 context->set_extension(*context_ext);
1032 }
1033 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034
ager@chromium.org7c537e22008-10-16 08:43:32 +00001035 // Declare the property by setting it to the initial value if provided,
1036 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1037 // constant declarations).
1038 ASSERT(!context_ext->HasLocalProperty(*name));
1039 Handle<Object> value(Heap::undefined_value());
1040 if (*initial_value != NULL) value = initial_value;
1041 SetProperty(context_ext, name, value, mode);
1042 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1043 }
1044
1045 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046}
1047
1048
1049static Object* Runtime_InitializeVarGlobal(Arguments args) {
1050 NoHandleAllocation nha;
1051
1052 // Determine if we need to assign to the variable if it already
1053 // exists (based on the number of arguments).
1054 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1055 bool assign = args.length() == 2;
1056
1057 CONVERT_ARG_CHECKED(String, name, 0);
1058 GlobalObject* global = Top::context()->global();
1059
1060 // According to ECMA-262, section 12.2, page 62, the property must
1061 // not be deletable.
1062 PropertyAttributes attributes = DONT_DELETE;
1063
1064 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001065 // there, there is a property with this name in the prototype chain.
1066 // We follow Safari and Firefox behavior and only set the property
1067 // locally if there is an explicit initialization value that we have
1068 // to assign to the property. When adding the property we take
1069 // special precautions to always add it as a local property even in
1070 // case of callbacks in the prototype chain (this rules out using
1071 // SetProperty). We have IgnoreAttributesAndSetLocalProperty for
1072 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001073 // Note that objects can have hidden prototypes, so we need to traverse
1074 // the whole chain of hidden prototypes to do a 'local' lookup.
1075 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001077 while (true) {
1078 real_holder->LocalLookup(*name, &lookup);
1079 if (lookup.IsProperty()) {
1080 // Determine if this is a redeclaration of something read-only.
1081 if (lookup.IsReadOnly()) {
1082 // If we found readonly property on one of hidden prototypes,
1083 // just shadow it.
1084 if (real_holder != Top::context()->global()) break;
1085 return ThrowRedeclarationError("const", name);
1086 }
1087
1088 // Determine if this is a redeclaration of an intercepted read-only
1089 // property and figure out if the property exists at all.
1090 bool found = true;
1091 PropertyType type = lookup.type();
1092 if (type == INTERCEPTOR) {
1093 HandleScope handle_scope;
1094 Handle<JSObject> holder(real_holder);
1095 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1096 real_holder = *holder;
1097 if (intercepted == ABSENT) {
1098 // The interceptor claims the property isn't there. We need to
1099 // make sure to introduce it.
1100 found = false;
1101 } else if ((intercepted & READ_ONLY) != 0) {
1102 // The property is present, but read-only. Since we're trying to
1103 // overwrite it with a variable declaration we must throw a
1104 // re-declaration error. However if we found readonly property
1105 // on one of hidden prototypes, just shadow it.
1106 if (real_holder != Top::context()->global()) break;
1107 return ThrowRedeclarationError("const", name);
1108 }
1109 }
1110
1111 if (found && !assign) {
1112 // The global property is there and we're not assigning any value
1113 // to it. Just return.
1114 return Heap::undefined_value();
1115 }
1116
1117 // Assign the value (or undefined) to the property.
1118 Object* value = (assign) ? args[1] : Heap::undefined_value();
1119 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001120 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001121
1122 Object* proto = real_holder->GetPrototype();
1123 if (!proto->IsJSObject())
1124 break;
1125
1126 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1127 break;
1128
1129 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130 }
1131
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001132 global = Top::context()->global();
1133 if (assign) {
1134 return global->IgnoreAttributesAndSetLocalProperty(*name,
1135 args[1],
1136 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001138 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001139}
1140
1141
1142static Object* Runtime_InitializeConstGlobal(Arguments args) {
1143 // All constants are declared with an initial value. The name
1144 // of the constant is the first argument and the initial value
1145 // is the second.
1146 RUNTIME_ASSERT(args.length() == 2);
1147 CONVERT_ARG_CHECKED(String, name, 0);
1148 Handle<Object> value = args.at<Object>(1);
1149
1150 // Get the current global object from top.
1151 GlobalObject* global = Top::context()->global();
1152
1153 // According to ECMA-262, section 12.2, page 62, the property must
1154 // not be deletable. Since it's a const, it must be READ_ONLY too.
1155 PropertyAttributes attributes =
1156 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1157
1158 // Lookup the property locally in the global object. If it isn't
1159 // there, we add the property and take special precautions to always
1160 // add it as a local property even in case of callbacks in the
1161 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001162 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 LookupResult lookup;
1164 global->LocalLookup(*name, &lookup);
1165 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001166 return global->IgnoreAttributesAndSetLocalProperty(*name,
1167 *value,
1168 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001169 }
1170
1171 // Determine if this is a redeclaration of something not
1172 // read-only. In case the result is hidden behind an interceptor we
1173 // need to ask it for the property attributes.
1174 if (!lookup.IsReadOnly()) {
1175 if (lookup.type() != INTERCEPTOR) {
1176 return ThrowRedeclarationError("var", name);
1177 }
1178
1179 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1180
1181 // Throw re-declaration error if the intercepted property is present
1182 // but not read-only.
1183 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1184 return ThrowRedeclarationError("var", name);
1185 }
1186
1187 // Restore global object from context (in case of GC) and continue
1188 // with setting the value because the property is either absent or
1189 // read-only. We also have to do redo the lookup.
1190 global = Top::context()->global();
1191
1192 // BUG 1213579: Handle the case where we have to set a read-only
1193 // property through an interceptor and only do it if it's
1194 // uninitialized, e.g. the hole. Nirk...
1195 global->SetProperty(*name, *value, attributes);
1196 return *value;
1197 }
1198
1199 // Set the value, but only we're assigning the initial value to a
1200 // constant. For now, we determine this by checking if the
1201 // current value is the hole.
1202 PropertyType type = lookup.type();
1203 if (type == FIELD) {
1204 FixedArray* properties = global->properties();
1205 int index = lookup.GetFieldIndex();
1206 if (properties->get(index)->IsTheHole()) {
1207 properties->set(index, *value);
1208 }
1209 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001210 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1211 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212 }
1213 } else {
1214 // Ignore re-initialization of constants that have already been
1215 // assigned a function value.
1216 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1217 }
1218
1219 // Use the set value as the result of the operation.
1220 return *value;
1221}
1222
1223
1224static Object* Runtime_InitializeConstContextSlot(Arguments args) {
1225 HandleScope scope;
1226 ASSERT(args.length() == 3);
1227
1228 Handle<Object> value(args[0]);
1229 ASSERT(!value->IsTheHole());
1230 CONVERT_ARG_CHECKED(Context, context, 1);
1231 Handle<String> name(String::cast(args[2]));
1232
1233 // Initializations are always done in the function context.
1234 context = Handle<Context>(context->fcontext());
1235
1236 int index;
1237 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001238 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001239 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240 context->Lookup(name, flags, &index, &attributes);
1241
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001242 // In most situations, the property introduced by the const
1243 // declaration should be present in the context extension object.
1244 // However, because declaration and initialization are separate, the
1245 // property might have been deleted (if it was introduced by eval)
1246 // before we reach the initialization point.
1247 //
1248 // Example:
1249 //
1250 // function f() { eval("delete x; const x;"); }
1251 //
1252 // In that case, the initialization behaves like a normal assignment
1253 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001255 // Property was found in a context.
1256 if (holder->IsContext()) {
1257 // The holder cannot be the function context. If it is, there
1258 // should have been a const redeclaration error when declaring
1259 // the const property.
1260 ASSERT(!holder.is_identical_to(context));
1261 if ((attributes & READ_ONLY) == 0) {
1262 Handle<Context>::cast(holder)->set(index, *value);
1263 }
1264 } else {
1265 // The holder is an arguments object.
1266 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001267 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1268 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269 }
1270 return *value;
1271 }
1272
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001273 // The property could not be found, we introduce it in the global
1274 // context.
1275 if (attributes == ABSENT) {
1276 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1277 SetProperty(global, name, value, NONE);
1278 return *value;
1279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001281 // The property was present in a context extension object.
1282 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001284 if (*context_ext == context->extension()) {
1285 // This is the property that was introduced by the const
1286 // declaration. Set it if it hasn't been set before. NOTE: We
1287 // cannot use GetProperty() to get the current value as it
1288 // 'unholes' the value.
1289 LookupResult lookup;
1290 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1291 ASSERT(lookup.IsProperty()); // the property was declared
1292 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1293
1294 PropertyType type = lookup.type();
1295 if (type == FIELD) {
1296 FixedArray* properties = context_ext->properties();
1297 int index = lookup.GetFieldIndex();
1298 if (properties->get(index)->IsTheHole()) {
1299 properties->set(index, *value);
1300 }
1301 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001302 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1303 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001304 }
1305 } else {
1306 // We should not reach here. Any real, named property should be
1307 // either a field or a dictionary slot.
1308 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309 }
1310 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001311 // The property was found in a different context extension object.
1312 // Set it if it is not a read-only property.
1313 if ((attributes & READ_ONLY) == 0) {
1314 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1315 // Setting a property might throw an exception. Exceptions
1316 // are converted to empty handles in handle operations. We
1317 // need to convert back to exceptions here.
1318 if (set.is_null()) {
1319 ASSERT(Top::has_pending_exception());
1320 return Failure::Exception();
1321 }
1322 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001324
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 return *value;
1326}
1327
1328
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001329static Object* Runtime_OptimizeObjectForAddingMultipleProperties(
1330 Arguments args) {
1331 HandleScope scope;
1332 ASSERT(args.length() == 2);
1333 CONVERT_ARG_CHECKED(JSObject, object, 0);
1334 CONVERT_SMI_CHECKED(properties, args[1]);
1335 if (object->HasFastProperties()) {
1336 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1337 }
1338 return *object;
1339}
1340
1341
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001342static Object* Runtime_RegExpExec(Arguments args) {
1343 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001344 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001345 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1346 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001347 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001348 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001349 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001350 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001351 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001352 RUNTIME_ASSERT(index >= 0);
1353 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001354 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001355 Handle<Object> result = RegExpImpl::Exec(regexp,
1356 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001357 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001358 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001359 if (result.is_null()) return Failure::Exception();
1360 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361}
1362
1363
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001364static Object* Runtime_RegExpConstructResult(Arguments args) {
1365 ASSERT(args.length() == 3);
1366 CONVERT_SMI_CHECKED(elements_count, args[0]);
1367 if (elements_count > JSArray::kMaxFastElementsLength) {
1368 return Top::ThrowIllegalOperation();
1369 }
1370 Object* new_object = Heap::AllocateFixedArrayWithHoles(elements_count);
1371 if (new_object->IsFailure()) return new_object;
1372 FixedArray* elements = FixedArray::cast(new_object);
1373 new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1374 NEW_SPACE,
1375 OLD_POINTER_SPACE);
1376 if (new_object->IsFailure()) return new_object;
1377 {
1378 AssertNoAllocation no_gc;
1379 HandleScope scope;
1380 reinterpret_cast<HeapObject*>(new_object)->
1381 set_map(Top::global_context()->regexp_result_map());
1382 }
1383 JSArray* array = JSArray::cast(new_object);
1384 array->set_properties(Heap::empty_fixed_array());
1385 array->set_elements(elements);
1386 array->set_length(Smi::FromInt(elements_count));
1387 // Write in-object properties after the length of the array.
1388 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1389 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1390 return array;
1391}
1392
1393
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001394static Object* Runtime_RegExpCloneResult(Arguments args) {
1395 ASSERT(args.length() == 1);
1396 Map* regexp_result_map;
1397 {
1398 AssertNoAllocation no_gc;
1399 HandleScope handles;
1400 regexp_result_map = Top::global_context()->regexp_result_map();
1401 }
1402 if (!args[0]->IsJSArray()) return args[0];
1403
1404 JSArray* result = JSArray::cast(args[0]);
1405 // Arguments to RegExpCloneResult should always be fresh RegExp exec call
1406 // results (either a fresh JSRegExpResult or null).
1407 // If the argument is not a JSRegExpResult, or isn't unmodified, just return
1408 // the argument uncloned.
1409 if (result->map() != regexp_result_map) return result;
1410
1411 // Having the original JSRegExpResult map guarantees that we have
1412 // fast elements and no properties except the two in-object properties.
1413 ASSERT(result->HasFastElements());
1414 ASSERT(result->properties() == Heap::empty_fixed_array());
1415 ASSERT_EQ(2, regexp_result_map->inobject_properties());
1416
1417 Object* new_array_alloc = Heap::AllocateRaw(JSRegExpResult::kSize,
1418 NEW_SPACE,
1419 OLD_POINTER_SPACE);
1420 if (new_array_alloc->IsFailure()) return new_array_alloc;
1421
1422 // Set HeapObject map to JSRegExpResult map.
1423 reinterpret_cast<HeapObject*>(new_array_alloc)->set_map(regexp_result_map);
1424
1425 JSArray* new_array = JSArray::cast(new_array_alloc);
1426
1427 // Copy JSObject properties.
1428 new_array->set_properties(result->properties()); // Empty FixedArray.
1429
1430 // Copy JSObject elements as copy-on-write.
1431 FixedArray* elements = FixedArray::cast(result->elements());
1432 if (elements != Heap::empty_fixed_array()) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001433 elements->set_map(Heap::fixed_cow_array_map());
1434 }
1435 new_array->set_elements(elements);
1436
1437 // Copy JSArray length.
1438 new_array->set_length(result->length());
1439
1440 // Copy JSRegExpResult in-object property fields input and index.
1441 new_array->FastPropertyAtPut(JSRegExpResult::kIndexIndex,
1442 result->FastPropertyAt(
1443 JSRegExpResult::kIndexIndex));
1444 new_array->FastPropertyAtPut(JSRegExpResult::kInputIndex,
1445 result->FastPropertyAt(
1446 JSRegExpResult::kInputIndex));
1447 return new_array;
1448}
1449
1450
lrn@chromium.org25156de2010-04-06 13:10:27 +00001451static Object* Runtime_RegExpInitializeObject(Arguments args) {
1452 AssertNoAllocation no_alloc;
1453 ASSERT(args.length() == 5);
1454 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1455 CONVERT_CHECKED(String, source, args[1]);
1456
1457 Object* global = args[2];
1458 if (!global->IsTrue()) global = Heap::false_value();
1459
1460 Object* ignoreCase = args[3];
1461 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1462
1463 Object* multiline = args[4];
1464 if (!multiline->IsTrue()) multiline = Heap::false_value();
1465
1466 Map* map = regexp->map();
1467 Object* constructor = map->constructor();
1468 if (constructor->IsJSFunction() &&
1469 JSFunction::cast(constructor)->initial_map() == map) {
1470 // If we still have the original map, set in-object properties directly.
1471 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1472 // TODO(lrn): Consider skipping write barrier on booleans as well.
1473 // Both true and false should be in oldspace at all times.
1474 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1475 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1476 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1477 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1478 Smi::FromInt(0),
1479 SKIP_WRITE_BARRIER);
1480 return regexp;
1481 }
1482
1483 // Map has changed, so use generic, but slower, method.
1484 PropertyAttributes final =
1485 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1486 PropertyAttributes writable =
1487 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
1488 regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(),
1489 source,
1490 final);
1491 regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(),
1492 global,
1493 final);
1494 regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(),
1495 ignoreCase,
1496 final);
1497 regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(),
1498 multiline,
1499 final);
1500 regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(),
1501 Smi::FromInt(0),
1502 writable);
1503 return regexp;
1504}
1505
1506
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001507static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) {
1508 HandleScope scope;
1509 ASSERT(args.length() == 1);
1510 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1511 // This is necessary to enable fast checks for absence of elements
1512 // on Array.prototype and below.
1513 prototype->set_elements(Heap::empty_fixed_array());
1514 return Smi::FromInt(0);
1515}
1516
1517
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001518static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1519 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001520 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001521 Handle<String> key = Factory::LookupAsciiSymbol(name);
1522 Handle<Code> code(Builtins::builtin(builtin_name));
1523 Handle<JSFunction> optimized = Factory::NewFunction(key,
1524 JS_OBJECT_TYPE,
1525 JSObject::kHeaderSize,
1526 code,
1527 false);
1528 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001529 SetProperty(holder, key, optimized, NONE);
1530 return optimized;
1531}
1532
1533
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001534static Object* Runtime_SpecialArrayFunctions(Arguments args) {
1535 HandleScope scope;
1536 ASSERT(args.length() == 1);
1537 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1538
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001539 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1540 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001541 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1542 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1543 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1544 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001545 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001546
1547 return *holder;
1548}
1549
1550
ager@chromium.org357bf652010-04-12 11:30:10 +00001551static Object* Runtime_GetGlobalReceiver(Arguments args) {
1552 // Returns a real global receiver, not one of builtins object.
1553 Context* global_context = Top::context()->global()->global_context();
1554 return global_context->global()->global_receiver();
1555}
1556
1557
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001558static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
1559 HandleScope scope;
1560 ASSERT(args.length() == 4);
1561 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1562 int index = Smi::cast(args[1])->value();
1563 Handle<String> pattern = args.at<String>(2);
1564 Handle<String> flags = args.at<String>(3);
1565
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001566 // Get the RegExp function from the context in the literals array.
1567 // This is the RegExp function from the context in which the
1568 // function was created. We do not use the RegExp function from the
1569 // current global context because this might be the RegExp function
1570 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001571 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001572 Handle<JSFunction>(
1573 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 // Compute the regular expression literal.
1575 bool has_pending_exception;
1576 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001577 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1578 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001579 if (has_pending_exception) {
1580 ASSERT(Top::has_pending_exception());
1581 return Failure::Exception();
1582 }
1583 literals->set(index, *regexp);
1584 return *regexp;
1585}
1586
1587
1588static Object* Runtime_FunctionGetName(Arguments args) {
1589 NoHandleAllocation ha;
1590 ASSERT(args.length() == 1);
1591
1592 CONVERT_CHECKED(JSFunction, f, args[0]);
1593 return f->shared()->name();
1594}
1595
1596
ager@chromium.org236ad962008-09-25 09:45:57 +00001597static Object* Runtime_FunctionSetName(Arguments args) {
1598 NoHandleAllocation ha;
1599 ASSERT(args.length() == 2);
1600
1601 CONVERT_CHECKED(JSFunction, f, args[0]);
1602 CONVERT_CHECKED(String, name, args[1]);
1603 f->shared()->set_name(name);
1604 return Heap::undefined_value();
1605}
1606
1607
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001608static Object* Runtime_FunctionRemovePrototype(Arguments args) {
1609 NoHandleAllocation ha;
1610 ASSERT(args.length() == 1);
1611
1612 CONVERT_CHECKED(JSFunction, f, args[0]);
1613 Object* obj = f->RemovePrototype();
1614 if (obj->IsFailure()) return obj;
1615
1616 return Heap::undefined_value();
1617}
1618
1619
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620static Object* Runtime_FunctionGetScript(Arguments args) {
1621 HandleScope scope;
1622 ASSERT(args.length() == 1);
1623
1624 CONVERT_CHECKED(JSFunction, fun, args[0]);
1625 Handle<Object> script = Handle<Object>(fun->shared()->script());
1626 if (!script->IsScript()) return Heap::undefined_value();
1627
1628 return *GetScriptWrapper(Handle<Script>::cast(script));
1629}
1630
1631
1632static Object* Runtime_FunctionGetSourceCode(Arguments args) {
1633 NoHandleAllocation ha;
1634 ASSERT(args.length() == 1);
1635
1636 CONVERT_CHECKED(JSFunction, f, args[0]);
1637 return f->shared()->GetSourceCode();
1638}
1639
1640
1641static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
1642 NoHandleAllocation ha;
1643 ASSERT(args.length() == 1);
1644
1645 CONVERT_CHECKED(JSFunction, fun, args[0]);
1646 int pos = fun->shared()->start_position();
1647 return Smi::FromInt(pos);
1648}
1649
1650
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001651static Object* Runtime_FunctionGetPositionForOffset(Arguments args) {
1652 ASSERT(args.length() == 2);
1653
1654 CONVERT_CHECKED(JSFunction, fun, args[0]);
1655 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1656
1657 Code* code = fun->code();
1658 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1659
1660 Address pc = code->address() + offset;
1661 return Smi::FromInt(fun->code()->SourcePosition(pc));
1662}
1663
1664
1665
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001666static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
1667 NoHandleAllocation ha;
1668 ASSERT(args.length() == 2);
1669
1670 CONVERT_CHECKED(JSFunction, fun, args[0]);
1671 CONVERT_CHECKED(String, name, args[1]);
1672 fun->SetInstanceClassName(name);
1673 return Heap::undefined_value();
1674}
1675
1676
1677static Object* Runtime_FunctionSetLength(Arguments args) {
1678 NoHandleAllocation ha;
1679 ASSERT(args.length() == 2);
1680
1681 CONVERT_CHECKED(JSFunction, fun, args[0]);
1682 CONVERT_CHECKED(Smi, length, args[1]);
1683 fun->shared()->set_length(length->value());
1684 return length;
1685}
1686
1687
1688static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001689 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001690 ASSERT(args.length() == 2);
1691
1692 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001693 ASSERT(fun->should_have_prototype());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001694 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
1695 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001696 return args[0]; // return TOS
1697}
1698
1699
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001700static Object* Runtime_FunctionIsAPIFunction(Arguments args) {
1701 NoHandleAllocation ha;
1702 ASSERT(args.length() == 1);
1703
1704 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001705 return f->shared()->IsApiFunction() ? Heap::true_value()
1706 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001707}
1708
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001709static Object* Runtime_FunctionIsBuiltin(Arguments args) {
1710 NoHandleAllocation ha;
1711 ASSERT(args.length() == 1);
1712
1713 CONVERT_CHECKED(JSFunction, f, args[0]);
1714 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1715}
1716
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001717
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001718static Object* Runtime_SetCode(Arguments args) {
1719 HandleScope scope;
1720 ASSERT(args.length() == 2);
1721
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001722 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723 Handle<Object> code = args.at<Object>(1);
1724
1725 Handle<Context> context(target->context());
1726
1727 if (!code->IsNull()) {
1728 RUNTIME_ASSERT(code->IsJSFunction());
1729 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001730 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001731
1732 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 return Failure::Exception();
1734 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001735 // Set the code, scope info, formal parameter count,
1736 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001737 target->shared()->set_code(shared->code());
1738 target->set_code(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001739 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001740 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001741 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001742 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001743 // Set the source code of the target function to undefined.
1744 // SetCode is only used for built-in constructors like String,
1745 // Array, and Object, and some web code
1746 // doesn't like seeing source code for constructors.
1747 target->shared()->set_script(Heap::undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001748 // Clear the optimization hints related to the compiled code as these are no
1749 // longer valid when the code is overwritten.
1750 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001751 context = Handle<Context>(fun->context());
1752
1753 // Make sure we get a fresh copy of the literal vector to avoid
1754 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001755 int number_of_literals = fun->NumberOfLiterals();
1756 Handle<FixedArray> literals =
1757 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001758 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001759 // Insert the object, regexp and array functions in the literals
1760 // array prefix. These are the functions that will be used when
1761 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001762 literals->set(JSFunction::kLiteralGlobalContextIndex,
1763 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001764 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001765 // It's okay to skip the write barrier here because the literals
1766 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001767 target->set_literals(*literals, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768 }
1769
1770 target->set_context(*context);
1771 return *target;
1772}
1773
1774
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001775static Object* Runtime_SetExpectedNumberOfProperties(Arguments args) {
1776 HandleScope scope;
1777 ASSERT(args.length() == 2);
1778 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1779 CONVERT_SMI_CHECKED(num, args[1]);
1780 RUNTIME_ASSERT(num >= 0);
1781 SetExpectedNofProperties(function, num);
1782 return Heap::undefined_value();
1783}
1784
1785
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001786static Object* CharFromCode(Object* char_code) {
1787 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001788 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001789 if (code <= 0xffff) {
1790 return Heap::LookupSingleCharacterStringFromCode(code);
1791 }
1792 }
1793 return Heap::empty_string();
1794}
1795
1796
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797static Object* Runtime_StringCharCodeAt(Arguments args) {
1798 NoHandleAllocation ha;
1799 ASSERT(args.length() == 2);
1800
1801 CONVERT_CHECKED(String, subject, args[0]);
1802 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001803 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001805 uint32_t i = 0;
1806 if (index->IsSmi()) {
1807 int value = Smi::cast(index)->value();
1808 if (value < 0) return Heap::nan_value();
1809 i = value;
1810 } else {
1811 ASSERT(index->IsHeapNumber());
1812 double value = HeapNumber::cast(index)->value();
1813 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001814 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001815
1816 // Flatten the string. If someone wants to get a char at an index
1817 // in a cons string, it is likely that more indices will be
1818 // accessed.
1819 Object* flat = subject->TryFlatten();
1820 if (flat->IsFailure()) return flat;
1821 subject = String::cast(flat);
1822
1823 if (i >= static_cast<uint32_t>(subject->length())) {
1824 return Heap::nan_value();
1825 }
1826
1827 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001828}
1829
1830
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001831static Object* Runtime_CharFromCode(Arguments args) {
1832 NoHandleAllocation ha;
1833 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001834 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001835}
1836
lrn@chromium.org25156de2010-04-06 13:10:27 +00001837
1838class FixedArrayBuilder {
1839 public:
1840 explicit FixedArrayBuilder(int initial_capacity)
1841 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1842 length_(0) {
1843 // Require a non-zero initial size. Ensures that doubling the size to
1844 // extend the array will work.
1845 ASSERT(initial_capacity > 0);
1846 }
1847
1848 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1849 : array_(backing_store),
1850 length_(0) {
1851 // Require a non-zero initial size. Ensures that doubling the size to
1852 // extend the array will work.
1853 ASSERT(backing_store->length() > 0);
1854 }
1855
1856 bool HasCapacity(int elements) {
1857 int length = array_->length();
1858 int required_length = length_ + elements;
1859 return (length >= required_length);
1860 }
1861
1862 void EnsureCapacity(int elements) {
1863 int length = array_->length();
1864 int required_length = length_ + elements;
1865 if (length < required_length) {
1866 int new_length = length;
1867 do {
1868 new_length *= 2;
1869 } while (new_length < required_length);
1870 Handle<FixedArray> extended_array =
1871 Factory::NewFixedArrayWithHoles(new_length);
1872 array_->CopyTo(0, *extended_array, 0, length_);
1873 array_ = extended_array;
1874 }
1875 }
1876
1877 void Add(Object* value) {
1878 ASSERT(length_ < capacity());
1879 array_->set(length_, value);
1880 length_++;
1881 }
1882
1883 void Add(Smi* value) {
1884 ASSERT(length_ < capacity());
1885 array_->set(length_, value);
1886 length_++;
1887 }
1888
1889 Handle<FixedArray> array() {
1890 return array_;
1891 }
1892
1893 int length() {
1894 return length_;
1895 }
1896
1897 int capacity() {
1898 return array_->length();
1899 }
1900
1901 Handle<JSArray> ToJSArray() {
1902 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1903 result_array->set_length(Smi::FromInt(length_));
1904 return result_array;
1905 }
1906
1907 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1908 target_array->set_elements(*array_);
1909 target_array->set_length(Smi::FromInt(length_));
1910 return target_array;
1911 }
1912
1913 private:
1914 Handle<FixedArray> array_;
1915 int length_;
1916};
1917
1918
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001919// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001920const int kStringBuilderConcatHelperLengthBits = 11;
1921const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001922
1923template <typename schar>
1924static inline void StringBuilderConcatHelper(String*,
1925 schar*,
1926 FixedArray*,
1927 int);
1928
lrn@chromium.org25156de2010-04-06 13:10:27 +00001929typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1930 StringBuilderSubstringLength;
1931typedef BitField<int,
1932 kStringBuilderConcatHelperLengthBits,
1933 kStringBuilderConcatHelperPositionBits>
1934 StringBuilderSubstringPosition;
1935
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001936
1937class ReplacementStringBuilder {
1938 public:
1939 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00001940 : array_builder_(estimated_part_count),
1941 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001942 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001943 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001944 // Require a non-zero initial size. Ensures that doubling the size to
1945 // extend the array will work.
1946 ASSERT(estimated_part_count > 0);
1947 }
1948
lrn@chromium.org25156de2010-04-06 13:10:27 +00001949 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
1950 int from,
1951 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001952 ASSERT(from >= 0);
1953 int length = to - from;
1954 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001955 if (StringBuilderSubstringLength::is_valid(length) &&
1956 StringBuilderSubstringPosition::is_valid(from)) {
1957 int encoded_slice = StringBuilderSubstringLength::encode(length) |
1958 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001959 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001960 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001961 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001962 builder->Add(Smi::FromInt(-length));
1963 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001964 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001965 }
1966
1967
1968 void EnsureCapacity(int elements) {
1969 array_builder_.EnsureCapacity(elements);
1970 }
1971
1972
1973 void AddSubjectSlice(int from, int to) {
1974 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001975 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001976 }
1977
1978
1979 void AddString(Handle<String> string) {
1980 int length = string->length();
1981 ASSERT(length > 0);
1982 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00001983 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001984 is_ascii_ = false;
1985 }
1986 IncrementCharacterCount(length);
1987 }
1988
1989
1990 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001991 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001992 return Factory::empty_string();
1993 }
1994
1995 Handle<String> joined_string;
1996 if (is_ascii_) {
1997 joined_string = NewRawAsciiString(character_count_);
1998 AssertNoAllocation no_alloc;
1999 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2000 char* char_buffer = seq->GetChars();
2001 StringBuilderConcatHelper(*subject_,
2002 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002003 *array_builder_.array(),
2004 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002005 } else {
2006 // Non-ASCII.
2007 joined_string = NewRawTwoByteString(character_count_);
2008 AssertNoAllocation no_alloc;
2009 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2010 uc16* char_buffer = seq->GetChars();
2011 StringBuilderConcatHelper(*subject_,
2012 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002013 *array_builder_.array(),
2014 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002015 }
2016 return joined_string;
2017 }
2018
2019
2020 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002021 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002022 V8::FatalProcessOutOfMemory("String.replace result too large.");
2023 }
2024 character_count_ += by;
2025 }
2026
lrn@chromium.org25156de2010-04-06 13:10:27 +00002027 Handle<JSArray> GetParts() {
2028 Handle<JSArray> result =
2029 Factory::NewJSArrayWithElements(array_builder_.array());
2030 result->set_length(Smi::FromInt(array_builder_.length()));
2031 return result;
2032 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002033
lrn@chromium.org25156de2010-04-06 13:10:27 +00002034 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002035 Handle<String> NewRawAsciiString(int size) {
2036 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2037 }
2038
2039
2040 Handle<String> NewRawTwoByteString(int size) {
2041 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2042 }
2043
2044
2045 void AddElement(Object* element) {
2046 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002047 ASSERT(array_builder_.capacity() > array_builder_.length());
2048 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002049 }
2050
lrn@chromium.org25156de2010-04-06 13:10:27 +00002051 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002052 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002053 int character_count_;
2054 bool is_ascii_;
2055};
2056
2057
2058class CompiledReplacement {
2059 public:
2060 CompiledReplacement()
2061 : parts_(1), replacement_substrings_(0) {}
2062
2063 void Compile(Handle<String> replacement,
2064 int capture_count,
2065 int subject_length);
2066
2067 void Apply(ReplacementStringBuilder* builder,
2068 int match_from,
2069 int match_to,
2070 Handle<JSArray> last_match_info);
2071
2072 // Number of distinct parts of the replacement pattern.
2073 int parts() {
2074 return parts_.length();
2075 }
2076 private:
2077 enum PartType {
2078 SUBJECT_PREFIX = 1,
2079 SUBJECT_SUFFIX,
2080 SUBJECT_CAPTURE,
2081 REPLACEMENT_SUBSTRING,
2082 REPLACEMENT_STRING,
2083
2084 NUMBER_OF_PART_TYPES
2085 };
2086
2087 struct ReplacementPart {
2088 static inline ReplacementPart SubjectMatch() {
2089 return ReplacementPart(SUBJECT_CAPTURE, 0);
2090 }
2091 static inline ReplacementPart SubjectCapture(int capture_index) {
2092 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2093 }
2094 static inline ReplacementPart SubjectPrefix() {
2095 return ReplacementPart(SUBJECT_PREFIX, 0);
2096 }
2097 static inline ReplacementPart SubjectSuffix(int subject_length) {
2098 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2099 }
2100 static inline ReplacementPart ReplacementString() {
2101 return ReplacementPart(REPLACEMENT_STRING, 0);
2102 }
2103 static inline ReplacementPart ReplacementSubString(int from, int to) {
2104 ASSERT(from >= 0);
2105 ASSERT(to > from);
2106 return ReplacementPart(-from, to);
2107 }
2108
2109 // If tag <= 0 then it is the negation of a start index of a substring of
2110 // the replacement pattern, otherwise it's a value from PartType.
2111 ReplacementPart(int tag, int data)
2112 : tag(tag), data(data) {
2113 // Must be non-positive or a PartType value.
2114 ASSERT(tag < NUMBER_OF_PART_TYPES);
2115 }
2116 // Either a value of PartType or a non-positive number that is
2117 // the negation of an index into the replacement string.
2118 int tag;
2119 // The data value's interpretation depends on the value of tag:
2120 // tag == SUBJECT_PREFIX ||
2121 // tag == SUBJECT_SUFFIX: data is unused.
2122 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2123 // tag == REPLACEMENT_SUBSTRING ||
2124 // tag == REPLACEMENT_STRING: data is index into array of substrings
2125 // of the replacement string.
2126 // tag <= 0: Temporary representation of the substring of the replacement
2127 // string ranging over -tag .. data.
2128 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2129 // substring objects.
2130 int data;
2131 };
2132
2133 template<typename Char>
2134 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2135 Vector<Char> characters,
2136 int capture_count,
2137 int subject_length) {
2138 int length = characters.length();
2139 int last = 0;
2140 for (int i = 0; i < length; i++) {
2141 Char c = characters[i];
2142 if (c == '$') {
2143 int next_index = i + 1;
2144 if (next_index == length) { // No next character!
2145 break;
2146 }
2147 Char c2 = characters[next_index];
2148 switch (c2) {
2149 case '$':
2150 if (i > last) {
2151 // There is a substring before. Include the first "$".
2152 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2153 last = next_index + 1; // Continue after the second "$".
2154 } else {
2155 // Let the next substring start with the second "$".
2156 last = next_index;
2157 }
2158 i = next_index;
2159 break;
2160 case '`':
2161 if (i > last) {
2162 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2163 }
2164 parts->Add(ReplacementPart::SubjectPrefix());
2165 i = next_index;
2166 last = i + 1;
2167 break;
2168 case '\'':
2169 if (i > last) {
2170 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2171 }
2172 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2173 i = next_index;
2174 last = i + 1;
2175 break;
2176 case '&':
2177 if (i > last) {
2178 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2179 }
2180 parts->Add(ReplacementPart::SubjectMatch());
2181 i = next_index;
2182 last = i + 1;
2183 break;
2184 case '0':
2185 case '1':
2186 case '2':
2187 case '3':
2188 case '4':
2189 case '5':
2190 case '6':
2191 case '7':
2192 case '8':
2193 case '9': {
2194 int capture_ref = c2 - '0';
2195 if (capture_ref > capture_count) {
2196 i = next_index;
2197 continue;
2198 }
2199 int second_digit_index = next_index + 1;
2200 if (second_digit_index < length) {
2201 // Peek ahead to see if we have two digits.
2202 Char c3 = characters[second_digit_index];
2203 if ('0' <= c3 && c3 <= '9') { // Double digits.
2204 int double_digit_ref = capture_ref * 10 + c3 - '0';
2205 if (double_digit_ref <= capture_count) {
2206 next_index = second_digit_index;
2207 capture_ref = double_digit_ref;
2208 }
2209 }
2210 }
2211 if (capture_ref > 0) {
2212 if (i > last) {
2213 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2214 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002215 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002216 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2217 last = next_index + 1;
2218 }
2219 i = next_index;
2220 break;
2221 }
2222 default:
2223 i = next_index;
2224 break;
2225 }
2226 }
2227 }
2228 if (length > last) {
2229 if (last == 0) {
2230 parts->Add(ReplacementPart::ReplacementString());
2231 } else {
2232 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2233 }
2234 }
2235 }
2236
2237 ZoneList<ReplacementPart> parts_;
2238 ZoneList<Handle<String> > replacement_substrings_;
2239};
2240
2241
2242void CompiledReplacement::Compile(Handle<String> replacement,
2243 int capture_count,
2244 int subject_length) {
2245 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002246 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002247 AssertNoAllocation no_alloc;
2248 ParseReplacementPattern(&parts_,
2249 replacement->ToAsciiVector(),
2250 capture_count,
2251 subject_length);
2252 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002253 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002254 AssertNoAllocation no_alloc;
2255
2256 ParseReplacementPattern(&parts_,
2257 replacement->ToUC16Vector(),
2258 capture_count,
2259 subject_length);
2260 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002261 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002262 int substring_index = 0;
2263 for (int i = 0, n = parts_.length(); i < n; i++) {
2264 int tag = parts_[i].tag;
2265 if (tag <= 0) { // A replacement string slice.
2266 int from = -tag;
2267 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002268 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002269 parts_[i].tag = REPLACEMENT_SUBSTRING;
2270 parts_[i].data = substring_index;
2271 substring_index++;
2272 } else if (tag == REPLACEMENT_STRING) {
2273 replacement_substrings_.Add(replacement);
2274 parts_[i].data = substring_index;
2275 substring_index++;
2276 }
2277 }
2278}
2279
2280
2281void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2282 int match_from,
2283 int match_to,
2284 Handle<JSArray> last_match_info) {
2285 for (int i = 0, n = parts_.length(); i < n; i++) {
2286 ReplacementPart part = parts_[i];
2287 switch (part.tag) {
2288 case SUBJECT_PREFIX:
2289 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2290 break;
2291 case SUBJECT_SUFFIX: {
2292 int subject_length = part.data;
2293 if (match_to < subject_length) {
2294 builder->AddSubjectSlice(match_to, subject_length);
2295 }
2296 break;
2297 }
2298 case SUBJECT_CAPTURE: {
2299 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002300 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002301 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2302 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2303 if (from >= 0 && to > from) {
2304 builder->AddSubjectSlice(from, to);
2305 }
2306 break;
2307 }
2308 case REPLACEMENT_SUBSTRING:
2309 case REPLACEMENT_STRING:
2310 builder->AddString(replacement_substrings_[part.data]);
2311 break;
2312 default:
2313 UNREACHABLE();
2314 }
2315 }
2316}
2317
2318
2319
2320static Object* StringReplaceRegExpWithString(String* subject,
2321 JSRegExp* regexp,
2322 String* replacement,
2323 JSArray* last_match_info) {
2324 ASSERT(subject->IsFlat());
2325 ASSERT(replacement->IsFlat());
2326
2327 HandleScope handles;
2328
2329 int length = subject->length();
2330 Handle<String> subject_handle(subject);
2331 Handle<JSRegExp> regexp_handle(regexp);
2332 Handle<String> replacement_handle(replacement);
2333 Handle<JSArray> last_match_info_handle(last_match_info);
2334 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2335 subject_handle,
2336 0,
2337 last_match_info_handle);
2338 if (match.is_null()) {
2339 return Failure::Exception();
2340 }
2341 if (match->IsNull()) {
2342 return *subject_handle;
2343 }
2344
2345 int capture_count = regexp_handle->CaptureCount();
2346
2347 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002348 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002349 CompiledReplacement compiled_replacement;
2350 compiled_replacement.Compile(replacement_handle,
2351 capture_count,
2352 length);
2353
2354 bool is_global = regexp_handle->GetFlags().is_global();
2355
2356 // Guessing the number of parts that the final result string is built
2357 // from. Global regexps can match any number of times, so we guess
2358 // conservatively.
2359 int expected_parts =
2360 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2361 ReplacementStringBuilder builder(subject_handle, expected_parts);
2362
2363 // Index of end of last match.
2364 int prev = 0;
2365
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002366 // Number of parts added by compiled replacement plus preceeding
2367 // string and possibly suffix after last match. It is possible for
2368 // all components to use two elements when encoded as two smis.
2369 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002370 bool matched = true;
2371 do {
2372 ASSERT(last_match_info_handle->HasFastElements());
2373 // Increase the capacity of the builder before entering local handle-scope,
2374 // so its internal buffer can safely allocate a new handle if it grows.
2375 builder.EnsureCapacity(parts_added_per_loop);
2376
2377 HandleScope loop_scope;
2378 int start, end;
2379 {
2380 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002381 FixedArray* match_info_array =
2382 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002383
2384 ASSERT_EQ(capture_count * 2 + 2,
2385 RegExpImpl::GetLastCaptureCount(match_info_array));
2386 start = RegExpImpl::GetCapture(match_info_array, 0);
2387 end = RegExpImpl::GetCapture(match_info_array, 1);
2388 }
2389
2390 if (prev < start) {
2391 builder.AddSubjectSlice(prev, start);
2392 }
2393 compiled_replacement.Apply(&builder,
2394 start,
2395 end,
2396 last_match_info_handle);
2397 prev = end;
2398
2399 // Only continue checking for global regexps.
2400 if (!is_global) break;
2401
2402 // Continue from where the match ended, unless it was an empty match.
2403 int next = end;
2404 if (start == end) {
2405 next = end + 1;
2406 if (next > length) break;
2407 }
2408
2409 match = RegExpImpl::Exec(regexp_handle,
2410 subject_handle,
2411 next,
2412 last_match_info_handle);
2413 if (match.is_null()) {
2414 return Failure::Exception();
2415 }
2416 matched = !match->IsNull();
2417 } while (matched);
2418
2419 if (prev < length) {
2420 builder.AddSubjectSlice(prev, length);
2421 }
2422
2423 return *(builder.ToString());
2424}
2425
2426
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002427template <typename ResultSeqString>
2428static Object* StringReplaceRegExpWithEmptyString(String* subject,
2429 JSRegExp* regexp,
2430 JSArray* last_match_info) {
2431 ASSERT(subject->IsFlat());
2432
2433 HandleScope handles;
2434
2435 Handle<String> subject_handle(subject);
2436 Handle<JSRegExp> regexp_handle(regexp);
2437 Handle<JSArray> last_match_info_handle(last_match_info);
2438 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2439 subject_handle,
2440 0,
2441 last_match_info_handle);
2442 if (match.is_null()) return Failure::Exception();
2443 if (match->IsNull()) return *subject_handle;
2444
2445 ASSERT(last_match_info_handle->HasFastElements());
2446
2447 HandleScope loop_scope;
2448 int start, end;
2449 {
2450 AssertNoAllocation match_info_array_is_not_in_a_handle;
2451 FixedArray* match_info_array =
2452 FixedArray::cast(last_match_info_handle->elements());
2453
2454 start = RegExpImpl::GetCapture(match_info_array, 0);
2455 end = RegExpImpl::GetCapture(match_info_array, 1);
2456 }
2457
2458 int length = subject->length();
2459 int new_length = length - (end - start);
2460 if (new_length == 0) {
2461 return Heap::empty_string();
2462 }
2463 Handle<ResultSeqString> answer;
2464 if (ResultSeqString::kHasAsciiEncoding) {
2465 answer =
2466 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2467 } else {
2468 answer =
2469 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2470 }
2471
2472 // If the regexp isn't global, only match once.
2473 if (!regexp_handle->GetFlags().is_global()) {
2474 if (start > 0) {
2475 String::WriteToFlat(*subject_handle,
2476 answer->GetChars(),
2477 0,
2478 start);
2479 }
2480 if (end < length) {
2481 String::WriteToFlat(*subject_handle,
2482 answer->GetChars() + start,
2483 end,
2484 length);
2485 }
2486 return *answer;
2487 }
2488
2489 int prev = 0; // Index of end of last match.
2490 int next = 0; // Start of next search (prev unless last match was empty).
2491 int position = 0;
2492
2493 do {
2494 if (prev < start) {
2495 // Add substring subject[prev;start] to answer string.
2496 String::WriteToFlat(*subject_handle,
2497 answer->GetChars() + position,
2498 prev,
2499 start);
2500 position += start - prev;
2501 }
2502 prev = end;
2503 next = end;
2504 // Continue from where the match ended, unless it was an empty match.
2505 if (start == end) {
2506 next++;
2507 if (next > length) break;
2508 }
2509 match = RegExpImpl::Exec(regexp_handle,
2510 subject_handle,
2511 next,
2512 last_match_info_handle);
2513 if (match.is_null()) return Failure::Exception();
2514 if (match->IsNull()) break;
2515
2516 ASSERT(last_match_info_handle->HasFastElements());
2517 HandleScope loop_scope;
2518 {
2519 AssertNoAllocation match_info_array_is_not_in_a_handle;
2520 FixedArray* match_info_array =
2521 FixedArray::cast(last_match_info_handle->elements());
2522 start = RegExpImpl::GetCapture(match_info_array, 0);
2523 end = RegExpImpl::GetCapture(match_info_array, 1);
2524 }
2525 } while (true);
2526
2527 if (prev < length) {
2528 // Add substring subject[prev;length] to answer string.
2529 String::WriteToFlat(*subject_handle,
2530 answer->GetChars() + position,
2531 prev,
2532 length);
2533 position += length - prev;
2534 }
2535
2536 if (position == 0) {
2537 return Heap::empty_string();
2538 }
2539
2540 // Shorten string and fill
2541 int string_size = ResultSeqString::SizeFor(position);
2542 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2543 int delta = allocated_string_size - string_size;
2544
2545 answer->set_length(position);
2546 if (delta == 0) return *answer;
2547
2548 Address end_of_string = answer->address() + string_size;
2549 Heap::CreateFillerObjectAt(end_of_string, delta);
2550
2551 return *answer;
2552}
2553
2554
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002555static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
2556 ASSERT(args.length() == 4);
2557
2558 CONVERT_CHECKED(String, subject, args[0]);
2559 if (!subject->IsFlat()) {
2560 Object* flat_subject = subject->TryFlatten();
2561 if (flat_subject->IsFailure()) {
2562 return flat_subject;
2563 }
2564 subject = String::cast(flat_subject);
2565 }
2566
2567 CONVERT_CHECKED(String, replacement, args[2]);
2568 if (!replacement->IsFlat()) {
2569 Object* flat_replacement = replacement->TryFlatten();
2570 if (flat_replacement->IsFailure()) {
2571 return flat_replacement;
2572 }
2573 replacement = String::cast(flat_replacement);
2574 }
2575
2576 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2577 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2578
2579 ASSERT(last_match_info->HasFastElements());
2580
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002581 if (replacement->length() == 0) {
2582 if (subject->HasOnlyAsciiChars()) {
2583 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2584 subject, regexp, last_match_info);
2585 } else {
2586 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2587 subject, regexp, last_match_info);
2588 }
2589 }
2590
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002591 return StringReplaceRegExpWithString(subject,
2592 regexp,
2593 replacement,
2594 last_match_info);
2595}
2596
2597
ager@chromium.org7c537e22008-10-16 08:43:32 +00002598// Perform string match of pattern on subject, starting at start index.
2599// Caller must ensure that 0 <= start_index <= sub->length(),
2600// and should check that pat->length() + start_index <= sub->length()
2601int Runtime::StringMatch(Handle<String> sub,
2602 Handle<String> pat,
2603 int start_index) {
2604 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002605 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002606
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002607 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002608 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002609
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002610 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002611 if (start_index + pattern_length > subject_length) return -1;
2612
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002613 if (!sub->IsFlat()) FlattenString(sub);
2614 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002615
ager@chromium.org7c537e22008-10-16 08:43:32 +00002616 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002617 // Extract flattened substrings of cons strings before determining asciiness.
2618 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002619 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002620 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002621 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002622
ager@chromium.org7c537e22008-10-16 08:43:32 +00002623 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002624 if (seq_pat->IsAsciiRepresentation()) {
2625 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2626 if (seq_sub->IsAsciiRepresentation()) {
2627 return StringSearch(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002628 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002629 return StringSearch(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002630 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002631 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2632 if (seq_sub->IsAsciiRepresentation()) {
2633 return StringSearch(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002634 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002635 return StringSearch(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002636}
2637
2638
2639static Object* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002640 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002641 ASSERT(args.length() == 3);
2642
ager@chromium.org7c537e22008-10-16 08:43:32 +00002643 CONVERT_ARG_CHECKED(String, sub, 0);
2644 CONVERT_ARG_CHECKED(String, pat, 1);
2645
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002646 Object* index = args[2];
2647 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002648 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002649
ager@chromium.org870a0b62008-11-04 11:43:05 +00002650 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002651 int position = Runtime::StringMatch(sub, pat, start_index);
2652 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002653}
2654
2655
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002656template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002657static int StringMatchBackwards(Vector<const schar> subject,
2658 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002659 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002660 int pattern_length = pattern.length();
2661 ASSERT(pattern_length >= 1);
2662 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002663
2664 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002665 for (int i = 0; i < pattern_length; i++) {
2666 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002667 if (c > String::kMaxAsciiCharCode) {
2668 return -1;
2669 }
2670 }
2671 }
2672
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002673 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002674 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002675 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002676 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002677 while (j < pattern_length) {
2678 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002679 break;
2680 }
2681 j++;
2682 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002683 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002684 return i;
2685 }
2686 }
2687 return -1;
2688}
2689
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002690static Object* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002691 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002692 ASSERT(args.length() == 3);
2693
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002694 CONVERT_ARG_CHECKED(String, sub, 0);
2695 CONVERT_ARG_CHECKED(String, pat, 1);
2696
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002697 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002698 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002699 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002700
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002701 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002702 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002704 if (start_index + pat_length > sub_length) {
2705 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002706 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002707
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002708 if (pat_length == 0) {
2709 return Smi::FromInt(start_index);
2710 }
2711
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002712 if (!sub->IsFlat()) FlattenString(sub);
2713 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002714
2715 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2716
2717 int position = -1;
2718
2719 if (pat->IsAsciiRepresentation()) {
2720 Vector<const char> pat_vector = pat->ToAsciiVector();
2721 if (sub->IsAsciiRepresentation()) {
2722 position = StringMatchBackwards(sub->ToAsciiVector(),
2723 pat_vector,
2724 start_index);
2725 } else {
2726 position = StringMatchBackwards(sub->ToUC16Vector(),
2727 pat_vector,
2728 start_index);
2729 }
2730 } else {
2731 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2732 if (sub->IsAsciiRepresentation()) {
2733 position = StringMatchBackwards(sub->ToAsciiVector(),
2734 pat_vector,
2735 start_index);
2736 } else {
2737 position = StringMatchBackwards(sub->ToUC16Vector(),
2738 pat_vector,
2739 start_index);
2740 }
2741 }
2742
2743 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002744}
2745
2746
2747static Object* Runtime_StringLocaleCompare(Arguments args) {
2748 NoHandleAllocation ha;
2749 ASSERT(args.length() == 2);
2750
2751 CONVERT_CHECKED(String, str1, args[0]);
2752 CONVERT_CHECKED(String, str2, args[1]);
2753
2754 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002755 int str1_length = str1->length();
2756 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002757
2758 // Decide trivial cases without flattening.
2759 if (str1_length == 0) {
2760 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2761 return Smi::FromInt(-str2_length);
2762 } else {
2763 if (str2_length == 0) return Smi::FromInt(str1_length);
2764 }
2765
2766 int end = str1_length < str2_length ? str1_length : str2_length;
2767
2768 // No need to flatten if we are going to find the answer on the first
2769 // character. At this point we know there is at least one character
2770 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002771 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002772 if (d != 0) return Smi::FromInt(d);
2773
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002774 str1->TryFlatten();
2775 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002776
2777 static StringInputBuffer buf1;
2778 static StringInputBuffer buf2;
2779
2780 buf1.Reset(str1);
2781 buf2.Reset(str2);
2782
2783 for (int i = 0; i < end; i++) {
2784 uint16_t char1 = buf1.GetNext();
2785 uint16_t char2 = buf2.GetNext();
2786 if (char1 != char2) return Smi::FromInt(char1 - char2);
2787 }
2788
2789 return Smi::FromInt(str1_length - str2_length);
2790}
2791
2792
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002793static Object* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002794 NoHandleAllocation ha;
2795 ASSERT(args.length() == 3);
2796
2797 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002798 Object* from = args[1];
2799 Object* to = args[2];
2800 int start, end;
2801 // We have a fast integer-only case here to avoid a conversion to double in
2802 // the common case where from and to are Smis.
2803 if (from->IsSmi() && to->IsSmi()) {
2804 start = Smi::cast(from)->value();
2805 end = Smi::cast(to)->value();
2806 } else {
2807 CONVERT_DOUBLE_CHECKED(from_number, from);
2808 CONVERT_DOUBLE_CHECKED(to_number, to);
2809 start = FastD2I(from_number);
2810 end = FastD2I(to_number);
2811 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002812 RUNTIME_ASSERT(end >= start);
2813 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002814 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002815 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002816 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002817}
2818
2819
ager@chromium.org41826e72009-03-30 13:30:57 +00002820static Object* Runtime_StringMatch(Arguments args) {
2821 ASSERT_EQ(3, args.length());
2822
2823 CONVERT_ARG_CHECKED(String, subject, 0);
2824 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2825 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2826 HandleScope handles;
2827
2828 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2829
2830 if (match.is_null()) {
2831 return Failure::Exception();
2832 }
2833 if (match->IsNull()) {
2834 return Heap::null_value();
2835 }
2836 int length = subject->length();
2837
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002838 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002839 ZoneList<int> offsets(8);
2840 do {
2841 int start;
2842 int end;
2843 {
2844 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002845 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002846 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2847 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2848 }
2849 offsets.Add(start);
2850 offsets.Add(end);
2851 int index = start < end ? end : end + 1;
2852 if (index > length) break;
2853 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2854 if (match.is_null()) {
2855 return Failure::Exception();
2856 }
2857 } while (!match->IsNull());
2858 int matches = offsets.length() / 2;
2859 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2860 for (int i = 0; i < matches ; i++) {
2861 int from = offsets.at(i * 2);
2862 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002863 Handle<String> match = Factory::NewSubString(subject, from, to);
2864 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002865 }
2866 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2867 result->set_length(Smi::FromInt(matches));
2868 return *result;
2869}
2870
2871
lrn@chromium.org25156de2010-04-06 13:10:27 +00002872// Two smis before and after the match, for very long strings.
2873const int kMaxBuilderEntriesPerRegExpMatch = 5;
2874
2875
2876static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2877 Handle<JSArray> last_match_info,
2878 int match_start,
2879 int match_end) {
2880 // Fill last_match_info with a single capture.
2881 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2882 AssertNoAllocation no_gc;
2883 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2884 RegExpImpl::SetLastCaptureCount(elements, 2);
2885 RegExpImpl::SetLastInput(elements, *subject);
2886 RegExpImpl::SetLastSubject(elements, *subject);
2887 RegExpImpl::SetCapture(elements, 0, match_start);
2888 RegExpImpl::SetCapture(elements, 1, match_end);
2889}
2890
2891
lrn@chromium.org25156de2010-04-06 13:10:27 +00002892template <typename schar, typename pchar>
2893static bool SearchStringMultiple(Vector<schar> subject,
2894 String* pattern,
2895 Vector<pchar> pattern_string,
2896 FixedArrayBuilder* builder,
2897 int* match_pos) {
2898 int pos = *match_pos;
2899 int subject_length = subject.length();
2900 int pattern_length = pattern_string.length();
2901 int max_search_start = subject_length - pattern_length;
2902 bool is_ascii = (sizeof(schar) == 1);
2903 StringSearchStrategy strategy =
2904 InitializeStringSearch(pattern_string, is_ascii);
2905 switch (strategy) {
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002906 case SEARCH_FAIL: break;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002907 case SEARCH_SHORT:
2908 while (pos <= max_search_start) {
2909 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2910 *match_pos = pos;
2911 return false;
2912 }
2913 // Position of end of previous match.
2914 int match_end = pos + pattern_length;
2915 int new_pos = SimpleIndexOf(subject, pattern_string, match_end);
2916 if (new_pos >= 0) {
2917 // A match.
2918 if (new_pos > match_end) {
2919 ReplacementStringBuilder::AddSubjectSlice(builder,
2920 match_end,
2921 new_pos);
2922 }
2923 pos = new_pos;
2924 builder->Add(pattern);
2925 } else {
2926 break;
2927 }
2928 }
2929 break;
2930 case SEARCH_LONG:
2931 while (pos <= max_search_start) {
2932 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002933 *match_pos = pos;
2934 return false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002935 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002936 int match_end = pos + pattern_length;
2937 int new_pos = ComplexIndexOf(subject, pattern_string, match_end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002938 if (new_pos >= 0) {
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002939 // A match has been found.
2940 if (new_pos > match_end) {
2941 ReplacementStringBuilder::AddSubjectSlice(builder,
2942 match_end,
2943 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002944 }
2945 pos = new_pos;
2946 builder->Add(pattern);
2947 } else {
2948 break;
2949 }
2950 }
2951 break;
2952 }
2953 if (pos < max_search_start) {
2954 ReplacementStringBuilder::AddSubjectSlice(builder,
2955 pos + pattern_length,
2956 subject_length);
2957 }
2958 *match_pos = pos;
2959 return true;
2960}
2961
2962
2963static bool SearchStringMultiple(Handle<String> subject,
2964 Handle<String> pattern,
2965 Handle<JSArray> last_match_info,
2966 FixedArrayBuilder* builder) {
2967 ASSERT(subject->IsFlat());
2968 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002969
2970 // Treating as if a previous match was before first character.
2971 int match_pos = -pattern->length();
2972
2973 for (;;) { // Break when search complete.
2974 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
2975 AssertNoAllocation no_gc;
2976 if (subject->IsAsciiRepresentation()) {
2977 Vector<const char> subject_vector = subject->ToAsciiVector();
2978 if (pattern->IsAsciiRepresentation()) {
2979 if (SearchStringMultiple(subject_vector,
2980 *pattern,
2981 pattern->ToAsciiVector(),
2982 builder,
2983 &match_pos)) break;
2984 } else {
2985 if (SearchStringMultiple(subject_vector,
2986 *pattern,
2987 pattern->ToUC16Vector(),
2988 builder,
2989 &match_pos)) break;
2990 }
2991 } else {
2992 Vector<const uc16> subject_vector = subject->ToUC16Vector();
2993 if (pattern->IsAsciiRepresentation()) {
2994 if (SearchStringMultiple(subject_vector,
2995 *pattern,
2996 pattern->ToAsciiVector(),
2997 builder,
2998 &match_pos)) break;
2999 } else {
3000 if (SearchStringMultiple(subject_vector,
3001 *pattern,
3002 pattern->ToUC16Vector(),
3003 builder,
3004 &match_pos)) break;
3005 }
3006 }
3007 }
3008
3009 if (match_pos >= 0) {
3010 SetLastMatchInfoNoCaptures(subject,
3011 last_match_info,
3012 match_pos,
3013 match_pos + pattern->length());
3014 return true;
3015 }
3016 return false; // No matches at all.
3017}
3018
3019
3020static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3021 Handle<String> subject,
3022 Handle<JSRegExp> regexp,
3023 Handle<JSArray> last_match_array,
3024 FixedArrayBuilder* builder) {
3025 ASSERT(subject->IsFlat());
3026 int match_start = -1;
3027 int match_end = 0;
3028 int pos = 0;
3029 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3030 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3031
3032 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003033 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003034 int subject_length = subject->length();
3035
3036 for (;;) { // Break on failure, return on exception.
3037 RegExpImpl::IrregexpResult result =
3038 RegExpImpl::IrregexpExecOnce(regexp,
3039 subject,
3040 pos,
3041 register_vector);
3042 if (result == RegExpImpl::RE_SUCCESS) {
3043 match_start = register_vector[0];
3044 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3045 if (match_end < match_start) {
3046 ReplacementStringBuilder::AddSubjectSlice(builder,
3047 match_end,
3048 match_start);
3049 }
3050 match_end = register_vector[1];
3051 HandleScope loop_scope;
3052 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3053 if (match_start != match_end) {
3054 pos = match_end;
3055 } else {
3056 pos = match_end + 1;
3057 if (pos > subject_length) break;
3058 }
3059 } else if (result == RegExpImpl::RE_FAILURE) {
3060 break;
3061 } else {
3062 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3063 return result;
3064 }
3065 }
3066
3067 if (match_start >= 0) {
3068 if (match_end < subject_length) {
3069 ReplacementStringBuilder::AddSubjectSlice(builder,
3070 match_end,
3071 subject_length);
3072 }
3073 SetLastMatchInfoNoCaptures(subject,
3074 last_match_array,
3075 match_start,
3076 match_end);
3077 return RegExpImpl::RE_SUCCESS;
3078 } else {
3079 return RegExpImpl::RE_FAILURE; // No matches at all.
3080 }
3081}
3082
3083
3084static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3085 Handle<String> subject,
3086 Handle<JSRegExp> regexp,
3087 Handle<JSArray> last_match_array,
3088 FixedArrayBuilder* builder) {
3089
3090 ASSERT(subject->IsFlat());
3091 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3092 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3093
3094 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003095 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003096
3097 RegExpImpl::IrregexpResult result =
3098 RegExpImpl::IrregexpExecOnce(regexp,
3099 subject,
3100 0,
3101 register_vector);
3102
3103 int capture_count = regexp->CaptureCount();
3104 int subject_length = subject->length();
3105
3106 // Position to search from.
3107 int pos = 0;
3108 // End of previous match. Differs from pos if match was empty.
3109 int match_end = 0;
3110 if (result == RegExpImpl::RE_SUCCESS) {
3111 // Need to keep a copy of the previous match for creating last_match_info
3112 // at the end, so we have two vectors that we swap between.
3113 OffsetsVector registers2(required_registers);
3114 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3115
3116 do {
3117 int match_start = register_vector[0];
3118 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3119 if (match_end < match_start) {
3120 ReplacementStringBuilder::AddSubjectSlice(builder,
3121 match_end,
3122 match_start);
3123 }
3124 match_end = register_vector[1];
3125
3126 {
3127 // Avoid accumulating new handles inside loop.
3128 HandleScope temp_scope;
3129 // Arguments array to replace function is match, captures, index and
3130 // subject, i.e., 3 + capture count in total.
3131 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003132 Handle<String> match = Factory::NewSubString(subject,
3133 match_start,
3134 match_end);
3135 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003136 for (int i = 1; i <= capture_count; i++) {
3137 int start = register_vector[i * 2];
3138 if (start >= 0) {
3139 int end = register_vector[i * 2 + 1];
3140 ASSERT(start <= end);
3141 Handle<String> substring = Factory::NewSubString(subject,
3142 start,
3143 end);
3144 elements->set(i, *substring);
3145 } else {
3146 ASSERT(register_vector[i * 2 + 1] < 0);
3147 elements->set(i, Heap::undefined_value());
3148 }
3149 }
3150 elements->set(capture_count + 1, Smi::FromInt(match_start));
3151 elements->set(capture_count + 2, *subject);
3152 builder->Add(*Factory::NewJSArrayWithElements(elements));
3153 }
3154 // Swap register vectors, so the last successful match is in
3155 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003156 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003157 prev_register_vector = register_vector;
3158 register_vector = tmp;
3159
3160 if (match_end > match_start) {
3161 pos = match_end;
3162 } else {
3163 pos = match_end + 1;
3164 if (pos > subject_length) {
3165 break;
3166 }
3167 }
3168
3169 result = RegExpImpl::IrregexpExecOnce(regexp,
3170 subject,
3171 pos,
3172 register_vector);
3173 } while (result == RegExpImpl::RE_SUCCESS);
3174
3175 if (result != RegExpImpl::RE_EXCEPTION) {
3176 // Finished matching, with at least one match.
3177 if (match_end < subject_length) {
3178 ReplacementStringBuilder::AddSubjectSlice(builder,
3179 match_end,
3180 subject_length);
3181 }
3182
3183 int last_match_capture_count = (capture_count + 1) * 2;
3184 int last_match_array_size =
3185 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3186 last_match_array->EnsureSize(last_match_array_size);
3187 AssertNoAllocation no_gc;
3188 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3189 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3190 RegExpImpl::SetLastSubject(elements, *subject);
3191 RegExpImpl::SetLastInput(elements, *subject);
3192 for (int i = 0; i < last_match_capture_count; i++) {
3193 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3194 }
3195 return RegExpImpl::RE_SUCCESS;
3196 }
3197 }
3198 // No matches at all, return failure or exception result directly.
3199 return result;
3200}
3201
3202
3203static Object* Runtime_RegExpExecMultiple(Arguments args) {
3204 ASSERT(args.length() == 4);
3205 HandleScope handles;
3206
3207 CONVERT_ARG_CHECKED(String, subject, 1);
3208 if (!subject->IsFlat()) { FlattenString(subject); }
3209 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3210 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3211 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3212
3213 ASSERT(last_match_info->HasFastElements());
3214 ASSERT(regexp->GetFlags().is_global());
3215 Handle<FixedArray> result_elements;
3216 if (result_array->HasFastElements()) {
3217 result_elements =
3218 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3219 } else {
3220 result_elements = Factory::NewFixedArrayWithHoles(16);
3221 }
3222 FixedArrayBuilder builder(result_elements);
3223
3224 if (regexp->TypeTag() == JSRegExp::ATOM) {
3225 Handle<String> pattern(
3226 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003227 if (!pattern->IsFlat()) FlattenString(pattern);
3228 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3229 return *builder.ToJSArray(result_array);
3230 }
3231 return Heap::null_value();
3232 }
3233
3234 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3235
3236 RegExpImpl::IrregexpResult result;
3237 if (regexp->CaptureCount() == 0) {
3238 result = SearchRegExpNoCaptureMultiple(subject,
3239 regexp,
3240 last_match_info,
3241 &builder);
3242 } else {
3243 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3244 }
3245 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3246 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3247 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3248 return Failure::Exception();
3249}
3250
3251
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003252static Object* Runtime_NumberToRadixString(Arguments args) {
3253 NoHandleAllocation ha;
3254 ASSERT(args.length() == 2);
3255
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003256 // Fast case where the result is a one character string.
3257 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3258 int value = Smi::cast(args[0])->value();
3259 int radix = Smi::cast(args[1])->value();
3260 if (value >= 0 && value < radix) {
3261 RUNTIME_ASSERT(radix <= 36);
3262 // Character array used for conversion.
3263 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3264 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3265 }
3266 }
3267
3268 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003269 CONVERT_DOUBLE_CHECKED(value, args[0]);
3270 if (isnan(value)) {
3271 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3272 }
3273 if (isinf(value)) {
3274 if (value < 0) {
3275 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3276 }
3277 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3278 }
3279 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3280 int radix = FastD2I(radix_number);
3281 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3282 char* str = DoubleToRadixCString(value, radix);
3283 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
3284 DeleteArray(str);
3285 return result;
3286}
3287
3288
3289static Object* Runtime_NumberToFixed(Arguments args) {
3290 NoHandleAllocation ha;
3291 ASSERT(args.length() == 2);
3292
3293 CONVERT_DOUBLE_CHECKED(value, args[0]);
3294 if (isnan(value)) {
3295 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3296 }
3297 if (isinf(value)) {
3298 if (value < 0) {
3299 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3300 }
3301 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3302 }
3303 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3304 int f = FastD2I(f_number);
3305 RUNTIME_ASSERT(f >= 0);
3306 char* str = DoubleToFixedCString(value, f);
3307 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
3308 DeleteArray(str);
3309 return res;
3310}
3311
3312
3313static Object* Runtime_NumberToExponential(Arguments args) {
3314 NoHandleAllocation ha;
3315 ASSERT(args.length() == 2);
3316
3317 CONVERT_DOUBLE_CHECKED(value, args[0]);
3318 if (isnan(value)) {
3319 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3320 }
3321 if (isinf(value)) {
3322 if (value < 0) {
3323 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3324 }
3325 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3326 }
3327 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3328 int f = FastD2I(f_number);
3329 RUNTIME_ASSERT(f >= -1 && f <= 20);
3330 char* str = DoubleToExponentialCString(value, f);
3331 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
3332 DeleteArray(str);
3333 return res;
3334}
3335
3336
3337static Object* Runtime_NumberToPrecision(Arguments args) {
3338 NoHandleAllocation ha;
3339 ASSERT(args.length() == 2);
3340
3341 CONVERT_DOUBLE_CHECKED(value, args[0]);
3342 if (isnan(value)) {
3343 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3344 }
3345 if (isinf(value)) {
3346 if (value < 0) {
3347 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3348 }
3349 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3350 }
3351 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3352 int f = FastD2I(f_number);
3353 RUNTIME_ASSERT(f >= 1 && f <= 21);
3354 char* str = DoubleToPrecisionCString(value, f);
3355 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
3356 DeleteArray(str);
3357 return res;
3358}
3359
3360
3361// Returns a single character string where first character equals
3362// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003363static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003364 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003365 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003366 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003367 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003368 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003369 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370}
3371
3372
3373Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
3374 // Handle [] indexing on Strings
3375 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003376 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3377 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003378 }
3379
3380 // Handle [] indexing on String objects
3381 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003382 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3383 Handle<Object> result =
3384 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3385 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003386 }
3387
3388 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003389 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003390 return prototype->GetElement(index);
3391 }
3392
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003393 return GetElement(object, index);
3394}
3395
3396
3397Object* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003398 return object->GetElement(index);
3399}
3400
3401
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003402Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
3403 HandleScope scope;
3404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003405 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003406 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407 Handle<Object> error =
3408 Factory::NewTypeError("non_object_property_load",
3409 HandleVector(args, 2));
3410 return Top::Throw(*error);
3411 }
3412
3413 // Check if the given key is an array index.
3414 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003415 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003416 return GetElementOrCharAt(object, index);
3417 }
3418
3419 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003420 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003421 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003422 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003423 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003424 bool has_pending_exception = false;
3425 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003426 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003427 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003428 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003429 }
3430
ager@chromium.org32912102009-01-16 10:38:43 +00003431 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003432 // the element if so.
3433 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003434 return GetElementOrCharAt(object, index);
3435 } else {
3436 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003437 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003438 }
3439}
3440
3441
3442static Object* Runtime_GetProperty(Arguments args) {
3443 NoHandleAllocation ha;
3444 ASSERT(args.length() == 2);
3445
3446 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003447 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448
3449 return Runtime::GetObjectProperty(object, key);
3450}
3451
3452
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003453// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003454static Object* Runtime_KeyedGetProperty(Arguments args) {
3455 NoHandleAllocation ha;
3456 ASSERT(args.length() == 2);
3457
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003458 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003459 // itself.
3460 //
3461 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003462 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003463 // global proxy object never has properties. This is the case
3464 // because the global proxy object forwards everything to its hidden
3465 // prototype including local lookups.
3466 //
3467 // Additionally, we need to make sure that we do not cache results
3468 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003469 if (args[0]->IsJSObject() &&
3470 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003471 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003472 args[1]->IsString()) {
3473 JSObject* receiver = JSObject::cast(args[0]);
3474 String* key = String::cast(args[1]);
3475 if (receiver->HasFastProperties()) {
3476 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003477 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003478 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3479 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003480 Object* value = receiver->FastPropertyAt(offset);
3481 return value->IsTheHole() ? Heap::undefined_value() : value;
3482 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003483 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003484 LookupResult result;
3485 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003486 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003487 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003488 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003489 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003490 }
3491 } else {
3492 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003493 StringDictionary* dictionary = receiver->property_dictionary();
3494 int entry = dictionary->FindEntry(key);
3495 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003496 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003497 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003498 if (!receiver->IsGlobalObject()) return value;
3499 value = JSGlobalPropertyCell::cast(value)->value();
3500 if (!value->IsTheHole()) return value;
3501 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003502 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003503 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003504 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3505 // Fast case for string indexing using [] with a smi index.
3506 HandleScope scope;
3507 Handle<String> str = args.at<String>(0);
3508 int index = Smi::cast(args[1])->value();
3509 Handle<Object> result = GetCharAt(str, index);
3510 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003511 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003512
3513 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003514 return Runtime::GetObjectProperty(args.at<Object>(0),
3515 args.at<Object>(1));
3516}
3517
3518
ager@chromium.org5c838252010-02-19 08:53:10 +00003519static Object* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
3520 ASSERT(args.length() == 5);
3521 HandleScope scope;
3522 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3523 CONVERT_CHECKED(String, name, args[1]);
3524 CONVERT_CHECKED(Smi, flag_setter, args[2]);
3525 CONVERT_CHECKED(JSFunction, fun, args[3]);
3526 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3527 int unchecked = flag_attr->value();
3528 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3529 RUNTIME_ASSERT(!obj->IsNull());
3530 LookupResult result;
3531 obj->LocalLookupRealNamedProperty(name, &result);
3532
3533 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3534 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3535 // delete it to avoid running into trouble in DefineAccessor, which
3536 // handles this incorrectly if the property is readonly (does nothing)
3537 if (result.IsProperty() &&
3538 (result.type() == FIELD || result.type() == NORMAL
3539 || result.type() == CONSTANT_FUNCTION)) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003540 Object* ok = obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3541 if (ok->IsFailure()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00003542 }
3543 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3544}
3545
3546static Object* Runtime_DefineOrRedefineDataProperty(Arguments args) {
3547 ASSERT(args.length() == 4);
3548 HandleScope scope;
3549 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3550 CONVERT_ARG_CHECKED(String, name, 1);
3551 Handle<Object> obj_value = args.at<Object>(2);
3552
3553 CONVERT_CHECKED(Smi, flag, args[3]);
3554 int unchecked = flag->value();
3555 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3556
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003557 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3558
3559 // Check if this is an element.
3560 uint32_t index;
3561 bool is_element = name->AsArrayIndex(&index);
3562
3563 // Special case for elements if any of the flags are true.
3564 // If elements are in fast case we always implicitly assume that:
3565 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3566 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3567 is_element) {
3568 // Normalize the elements to enable attributes on the property.
3569 js_object->NormalizeElements();
3570 NumberDictionary* dictionary = js_object->element_dictionary();
3571 // Make sure that we never go back to fast case.
3572 dictionary->set_requires_slow_elements();
3573 PropertyDetails details = PropertyDetails(attr, NORMAL);
3574 dictionary->Set(index, *obj_value, details);
3575 }
3576
ager@chromium.org5c838252010-02-19 08:53:10 +00003577 LookupResult result;
3578 js_object->LocalLookupRealNamedProperty(*name, &result);
3579
ager@chromium.org5c838252010-02-19 08:53:10 +00003580 // Take special care when attributes are different and there is already
3581 // a property. For simplicity we normalize the property which enables us
3582 // to not worry about changing the instance_descriptor and creating a new
3583 // map. The current version of SetObjectProperty does not handle attributes
3584 // correctly in the case where a property is a field and is reset with
3585 // new attributes.
3586 if (result.IsProperty() && attr != result.GetAttributes()) {
3587 // New attributes - normalize to avoid writing to instance descriptor
3588 js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3589 // Use IgnoreAttributes version since a readonly property may be
3590 // overridden and SetProperty does not allow this.
3591 return js_object->IgnoreAttributesAndSetLocalProperty(*name,
3592 *obj_value,
3593 attr);
3594 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003595
ager@chromium.org5c838252010-02-19 08:53:10 +00003596 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3597}
3598
3599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003600Object* Runtime::SetObjectProperty(Handle<Object> object,
3601 Handle<Object> key,
3602 Handle<Object> value,
3603 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003604 HandleScope scope;
3605
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003607 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003608 Handle<Object> error =
3609 Factory::NewTypeError("non_object_property_store",
3610 HandleVector(args, 2));
3611 return Top::Throw(*error);
3612 }
3613
3614 // If the object isn't a JavaScript object, we ignore the store.
3615 if (!object->IsJSObject()) return *value;
3616
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003617 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003619 // Check if the given key is an array index.
3620 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003621 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3623 // of a string using [] notation. We need to support this too in
3624 // JavaScript.
3625 // In the case of a String object we just need to redirect the assignment to
3626 // the underlying string if the index is in range. Since the underlying
3627 // string does nothing with the assignment then we can ignore such
3628 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003629 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003630 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003631 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003632
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003633 Handle<Object> result = SetElement(js_object, index, value);
3634 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003635 return *value;
3636 }
3637
3638 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003639 Handle<Object> result;
3640 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003641 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003643 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003644 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003645 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003646 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003647 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003648 return *value;
3649 }
3650
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003651 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003652 bool has_pending_exception = false;
3653 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3654 if (has_pending_exception) return Failure::Exception();
3655 Handle<String> name = Handle<String>::cast(converted);
3656
3657 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003658 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003659 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003660 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 }
3662}
3663
3664
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003665Object* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3666 Handle<Object> key,
3667 Handle<Object> value,
3668 PropertyAttributes attr) {
3669 HandleScope scope;
3670
3671 // Check if the given key is an array index.
3672 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003673 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003674 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3675 // of a string using [] notation. We need to support this too in
3676 // JavaScript.
3677 // In the case of a String object we just need to redirect the assignment to
3678 // the underlying string if the index is in range. Since the underlying
3679 // string does nothing with the assignment then we can ignore such
3680 // assignments.
3681 if (js_object->IsStringObjectWithCharacterAt(index)) {
3682 return *value;
3683 }
3684
3685 return js_object->SetElement(index, *value);
3686 }
3687
3688 if (key->IsString()) {
3689 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003690 return js_object->SetElement(index, *value);
3691 } else {
3692 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003693 key_string->TryFlatten();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003694 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
3695 *value,
3696 attr);
3697 }
3698 }
3699
3700 // Call-back into JavaScript to convert the key to a string.
3701 bool has_pending_exception = false;
3702 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3703 if (has_pending_exception) return Failure::Exception();
3704 Handle<String> name = Handle<String>::cast(converted);
3705
3706 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003707 return js_object->SetElement(index, *value);
3708 } else {
3709 return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr);
3710 }
3711}
3712
3713
ager@chromium.orge2902be2009-06-08 12:21:35 +00003714Object* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3715 Handle<Object> key) {
3716 HandleScope scope;
3717
3718 // Check if the given key is an array index.
3719 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003720 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003721 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3722 // characters of a string using [] notation. In the case of a
3723 // String object we just need to redirect the deletion to the
3724 // underlying string if the index is in range. Since the
3725 // underlying string does nothing with the deletion, we can ignore
3726 // such deletions.
3727 if (js_object->IsStringObjectWithCharacterAt(index)) {
3728 return Heap::true_value();
3729 }
3730
3731 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3732 }
3733
3734 Handle<String> key_string;
3735 if (key->IsString()) {
3736 key_string = Handle<String>::cast(key);
3737 } else {
3738 // Call-back into JavaScript to convert the key to a string.
3739 bool has_pending_exception = false;
3740 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3741 if (has_pending_exception) return Failure::Exception();
3742 key_string = Handle<String>::cast(converted);
3743 }
3744
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003745 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003746 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3747}
3748
3749
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003750static Object* Runtime_SetProperty(Arguments args) {
3751 NoHandleAllocation ha;
3752 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3753
3754 Handle<Object> object = args.at<Object>(0);
3755 Handle<Object> key = args.at<Object>(1);
3756 Handle<Object> value = args.at<Object>(2);
3757
3758 // Compute attributes.
3759 PropertyAttributes attributes = NONE;
3760 if (args.length() == 4) {
3761 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003762 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003763 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003764 RUNTIME_ASSERT(
3765 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3766 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767 }
3768 return Runtime::SetObjectProperty(object, key, value, attributes);
3769}
3770
3771
3772// Set a local property, even if it is READ_ONLY. If the property does not
3773// exist, it will be added with attributes NONE.
3774static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
3775 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003776 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777 CONVERT_CHECKED(JSObject, object, args[0]);
3778 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003779 // Compute attributes.
3780 PropertyAttributes attributes = NONE;
3781 if (args.length() == 4) {
3782 CONVERT_CHECKED(Smi, value_obj, args[3]);
3783 int unchecked_value = value_obj->value();
3784 // Only attribute bits should be set.
3785 RUNTIME_ASSERT(
3786 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3787 attributes = static_cast<PropertyAttributes>(unchecked_value);
3788 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003789
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003790 return object->
3791 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003792}
3793
3794
3795static Object* Runtime_DeleteProperty(Arguments args) {
3796 NoHandleAllocation ha;
3797 ASSERT(args.length() == 2);
3798
3799 CONVERT_CHECKED(JSObject, object, args[0]);
3800 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003801 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003802}
3803
3804
ager@chromium.org9085a012009-05-11 19:22:57 +00003805static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3806 Handle<String> key) {
3807 if (object->HasLocalProperty(*key)) return Heap::true_value();
3808 // Handle hidden prototypes. If there's a hidden prototype above this thing
3809 // then we have to check it for properties, because they are supposed to
3810 // look like they are on this object.
3811 Handle<Object> proto(object->GetPrototype());
3812 if (proto->IsJSObject() &&
3813 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3814 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3815 }
3816 return Heap::false_value();
3817}
3818
3819
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003820static Object* Runtime_HasLocalProperty(Arguments args) {
3821 NoHandleAllocation ha;
3822 ASSERT(args.length() == 2);
3823 CONVERT_CHECKED(String, key, args[1]);
3824
ager@chromium.org9085a012009-05-11 19:22:57 +00003825 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003826 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003827 if (obj->IsJSObject()) {
3828 JSObject* object = JSObject::cast(obj);
3829 // Fast case - no interceptors.
3830 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3831 // Slow case. Either it's not there or we have an interceptor. We should
3832 // have handles for this kind of deal.
3833 HandleScope scope;
3834 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3835 Handle<String>(key));
3836 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003837 // Well, there is one exception: Handle [] on strings.
3838 uint32_t index;
3839 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003840 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003841 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003842 return Heap::true_value();
3843 }
3844 }
3845 return Heap::false_value();
3846}
3847
3848
3849static Object* Runtime_HasProperty(Arguments args) {
3850 NoHandleAllocation na;
3851 ASSERT(args.length() == 2);
3852
3853 // Only JS objects can have properties.
3854 if (args[0]->IsJSObject()) {
3855 JSObject* object = JSObject::cast(args[0]);
3856 CONVERT_CHECKED(String, key, args[1]);
3857 if (object->HasProperty(key)) return Heap::true_value();
3858 }
3859 return Heap::false_value();
3860}
3861
3862
3863static Object* Runtime_HasElement(Arguments args) {
3864 NoHandleAllocation na;
3865 ASSERT(args.length() == 2);
3866
3867 // Only JS objects can have elements.
3868 if (args[0]->IsJSObject()) {
3869 JSObject* object = JSObject::cast(args[0]);
3870 CONVERT_CHECKED(Smi, index_obj, args[1]);
3871 uint32_t index = index_obj->value();
3872 if (object->HasElement(index)) return Heap::true_value();
3873 }
3874 return Heap::false_value();
3875}
3876
3877
3878static Object* Runtime_IsPropertyEnumerable(Arguments args) {
3879 NoHandleAllocation ha;
3880 ASSERT(args.length() == 2);
3881
3882 CONVERT_CHECKED(JSObject, object, args[0]);
3883 CONVERT_CHECKED(String, key, args[1]);
3884
3885 uint32_t index;
3886 if (key->AsArrayIndex(&index)) {
3887 return Heap::ToBoolean(object->HasElement(index));
3888 }
3889
ager@chromium.org870a0b62008-11-04 11:43:05 +00003890 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3891 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003892}
3893
3894
3895static Object* Runtime_GetPropertyNames(Arguments args) {
3896 HandleScope scope;
3897 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003898 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003899 return *GetKeysFor(object);
3900}
3901
3902
3903// Returns either a FixedArray as Runtime_GetPropertyNames,
3904// or, if the given object has an enum cache that contains
3905// all enumerable properties of the object and its prototypes
3906// have none, the map of the object. This is used to speed up
3907// the check for deletions during a for-in.
3908static Object* Runtime_GetPropertyNamesFast(Arguments args) {
3909 ASSERT(args.length() == 1);
3910
3911 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3912
3913 if (raw_object->IsSimpleEnum()) return raw_object->map();
3914
3915 HandleScope scope;
3916 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003917 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3918 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003919
3920 // Test again, since cache may have been built by preceding call.
3921 if (object->IsSimpleEnum()) return object->map();
3922
3923 return *content;
3924}
3925
3926
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003927// Find the length of the prototype chain that is to to handled as one. If a
3928// prototype object is hidden it is to be viewed as part of the the object it
3929// is prototype for.
3930static int LocalPrototypeChainLength(JSObject* obj) {
3931 int count = 1;
3932 Object* proto = obj->GetPrototype();
3933 while (proto->IsJSObject() &&
3934 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3935 count++;
3936 proto = JSObject::cast(proto)->GetPrototype();
3937 }
3938 return count;
3939}
3940
3941
3942// Return the names of the local named properties.
3943// args[0]: object
3944static Object* Runtime_GetLocalPropertyNames(Arguments args) {
3945 HandleScope scope;
3946 ASSERT(args.length() == 1);
3947 if (!args[0]->IsJSObject()) {
3948 return Heap::undefined_value();
3949 }
3950 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3951
3952 // Skip the global proxy as it has no properties and always delegates to the
3953 // real global object.
3954 if (obj->IsJSGlobalProxy()) {
3955 // Only collect names if access is permitted.
3956 if (obj->IsAccessCheckNeeded() &&
3957 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3958 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3959 return *Factory::NewJSArray(0);
3960 }
3961 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3962 }
3963
3964 // Find the number of objects making up this.
3965 int length = LocalPrototypeChainLength(*obj);
3966
3967 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003968 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003969 int total_property_count = 0;
3970 Handle<JSObject> jsproto = obj;
3971 for (int i = 0; i < length; i++) {
3972 // Only collect names if access is permitted.
3973 if (jsproto->IsAccessCheckNeeded() &&
3974 !Top::MayNamedAccess(*jsproto,
3975 Heap::undefined_value(),
3976 v8::ACCESS_KEYS)) {
3977 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
3978 return *Factory::NewJSArray(0);
3979 }
3980 int n;
3981 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3982 local_property_count[i] = n;
3983 total_property_count += n;
3984 if (i < length - 1) {
3985 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3986 }
3987 }
3988
3989 // Allocate an array with storage for all the property names.
3990 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
3991
3992 // Get the property names.
3993 jsproto = obj;
3994 int proto_with_hidden_properties = 0;
3995 for (int i = 0; i < length; i++) {
3996 jsproto->GetLocalPropertyNames(*names,
3997 i == 0 ? 0 : local_property_count[i - 1]);
3998 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
3999 proto_with_hidden_properties++;
4000 }
4001 if (i < length - 1) {
4002 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4003 }
4004 }
4005
4006 // Filter out name of hidden propeties object.
4007 if (proto_with_hidden_properties > 0) {
4008 Handle<FixedArray> old_names = names;
4009 names = Factory::NewFixedArray(
4010 names->length() - proto_with_hidden_properties);
4011 int dest_pos = 0;
4012 for (int i = 0; i < total_property_count; i++) {
4013 Object* name = old_names->get(i);
4014 if (name == Heap::hidden_symbol()) {
4015 continue;
4016 }
4017 names->set(dest_pos++, name);
4018 }
4019 }
4020
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004021 return *Factory::NewJSArrayWithElements(names);
4022}
4023
4024
4025// Return the names of the local indexed properties.
4026// args[0]: object
4027static Object* Runtime_GetLocalElementNames(Arguments args) {
4028 HandleScope scope;
4029 ASSERT(args.length() == 1);
4030 if (!args[0]->IsJSObject()) {
4031 return Heap::undefined_value();
4032 }
4033 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4034
4035 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4036 Handle<FixedArray> names = Factory::NewFixedArray(n);
4037 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4038 return *Factory::NewJSArrayWithElements(names);
4039}
4040
4041
4042// Return information on whether an object has a named or indexed interceptor.
4043// args[0]: object
4044static Object* Runtime_GetInterceptorInfo(Arguments args) {
4045 HandleScope scope;
4046 ASSERT(args.length() == 1);
4047 if (!args[0]->IsJSObject()) {
4048 return Smi::FromInt(0);
4049 }
4050 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4051
4052 int result = 0;
4053 if (obj->HasNamedInterceptor()) result |= 2;
4054 if (obj->HasIndexedInterceptor()) result |= 1;
4055
4056 return Smi::FromInt(result);
4057}
4058
4059
4060// Return property names from named interceptor.
4061// args[0]: object
4062static Object* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
4063 HandleScope scope;
4064 ASSERT(args.length() == 1);
4065 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4066
4067 if (obj->HasNamedInterceptor()) {
4068 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4069 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4070 }
4071 return Heap::undefined_value();
4072}
4073
4074
4075// Return element names from indexed interceptor.
4076// args[0]: object
4077static Object* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
4078 HandleScope scope;
4079 ASSERT(args.length() == 1);
4080 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4081
4082 if (obj->HasIndexedInterceptor()) {
4083 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4084 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4085 }
4086 return Heap::undefined_value();
4087}
4088
4089
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004090static Object* Runtime_LocalKeys(Arguments args) {
4091 ASSERT_EQ(args.length(), 1);
4092 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4093 HandleScope scope;
4094 Handle<JSObject> object(raw_object);
4095 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4096 LOCAL_ONLY);
4097 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4098 // property array and since the result is mutable we have to create
4099 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004100 int length = contents->length();
4101 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4102 for (int i = 0; i < length; i++) {
4103 Object* entry = contents->get(i);
4104 if (entry->IsString()) {
4105 copy->set(i, entry);
4106 } else {
4107 ASSERT(entry->IsNumber());
4108 HandleScope scope;
4109 Handle<Object> entry_handle(entry);
4110 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4111 copy->set(i, *entry_str);
4112 }
4113 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004114 return *Factory::NewJSArrayWithElements(copy);
4115}
4116
4117
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118static Object* Runtime_GetArgumentsProperty(Arguments args) {
4119 NoHandleAllocation ha;
4120 ASSERT(args.length() == 1);
4121
4122 // Compute the frame holding the arguments.
4123 JavaScriptFrameIterator it;
4124 it.AdvanceToArgumentsFrame();
4125 JavaScriptFrame* frame = it.frame();
4126
4127 // Get the actual number of provided arguments.
4128 const uint32_t n = frame->GetProvidedParametersCount();
4129
4130 // Try to convert the key to an index. If successful and within
4131 // index return the the argument from the frame.
4132 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004133 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134 return frame->GetParameter(index);
4135 }
4136
4137 // Convert the key to a string.
4138 HandleScope scope;
4139 bool exception = false;
4140 Handle<Object> converted =
4141 Execution::ToString(args.at<Object>(0), &exception);
4142 if (exception) return Failure::Exception();
4143 Handle<String> key = Handle<String>::cast(converted);
4144
4145 // Try to convert the string key into an array index.
4146 if (key->AsArrayIndex(&index)) {
4147 if (index < n) {
4148 return frame->GetParameter(index);
4149 } else {
4150 return Top::initial_object_prototype()->GetElement(index);
4151 }
4152 }
4153
4154 // Handle special arguments properties.
4155 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4156 if (key->Equals(Heap::callee_symbol())) return frame->function();
4157
4158 // Lookup in the initial Object.prototype object.
4159 return Top::initial_object_prototype()->GetProperty(*key);
4160}
4161
4162
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004163static Object* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004164 HandleScope scope;
4165
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004166 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004167 Handle<Object> object = args.at<Object>(0);
4168 if (object->IsJSObject()) {
4169 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004170 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
4171 js_object->TransformToFastProperties(0);
4172 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004173 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004174 return *object;
4175}
4176
4177
4178static Object* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004179 HandleScope scope;
4180
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004181 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004182 Handle<Object> object = args.at<Object>(0);
4183 if (object->IsJSObject()) {
4184 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004185 js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004186 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004187 return *object;
4188}
4189
4190
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191static Object* Runtime_ToBool(Arguments args) {
4192 NoHandleAllocation ha;
4193 ASSERT(args.length() == 1);
4194
4195 return args[0]->ToBoolean();
4196}
4197
4198
4199// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4200// Possible optimizations: put the type string into the oddballs.
4201static Object* Runtime_Typeof(Arguments args) {
4202 NoHandleAllocation ha;
4203
4204 Object* obj = args[0];
4205 if (obj->IsNumber()) return Heap::number_symbol();
4206 HeapObject* heap_obj = HeapObject::cast(obj);
4207
4208 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004209 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004210
4211 InstanceType instance_type = heap_obj->map()->instance_type();
4212 if (instance_type < FIRST_NONSTRING_TYPE) {
4213 return Heap::string_symbol();
4214 }
4215
4216 switch (instance_type) {
4217 case ODDBALL_TYPE:
4218 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4219 return Heap::boolean_symbol();
4220 }
4221 if (heap_obj->IsNull()) {
4222 return Heap::object_symbol();
4223 }
4224 ASSERT(heap_obj->IsUndefined());
4225 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004226 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004227 return Heap::function_symbol();
4228 default:
4229 // For any kind of object not handled above, the spec rule for
4230 // host objects gives that it is okay to return "object"
4231 return Heap::object_symbol();
4232 }
4233}
4234
4235
lrn@chromium.org25156de2010-04-06 13:10:27 +00004236static bool AreDigits(const char*s, int from, int to) {
4237 for (int i = from; i < to; i++) {
4238 if (s[i] < '0' || s[i] > '9') return false;
4239 }
4240
4241 return true;
4242}
4243
4244
4245static int ParseDecimalInteger(const char*s, int from, int to) {
4246 ASSERT(to - from < 10); // Overflow is not possible.
4247 ASSERT(from < to);
4248 int d = s[from] - '0';
4249
4250 for (int i = from + 1; i < to; i++) {
4251 d = 10 * d + (s[i] - '0');
4252 }
4253
4254 return d;
4255}
4256
4257
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004258static Object* Runtime_StringToNumber(Arguments args) {
4259 NoHandleAllocation ha;
4260 ASSERT(args.length() == 1);
4261 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004262 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004263
4264 // Fast case: short integer or some sorts of junk values.
4265 int len = subject->length();
4266 if (subject->IsSeqAsciiString()) {
4267 if (len == 0) return Smi::FromInt(0);
4268
4269 char const* data = SeqAsciiString::cast(subject)->GetChars();
4270 bool minus = (data[0] == '-');
4271 int start_pos = (minus ? 1 : 0);
4272
4273 if (start_pos == len) {
4274 return Heap::nan_value();
4275 } else if (data[start_pos] > '9') {
4276 // Fast check for a junk value. A valid string may start from a
4277 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4278 // the 'I' character ('Infinity'). All of that have codes not greater than
4279 // '9' except 'I'.
4280 if (data[start_pos] != 'I') {
4281 return Heap::nan_value();
4282 }
4283 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4284 // The maximal/minimal smi has 10 digits. If the string has less digits we
4285 // know it will fit into the smi-data type.
4286 int d = ParseDecimalInteger(data, start_pos, len);
4287 if (minus) {
4288 if (d == 0) return Heap::minus_zero_value();
4289 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004290 } else if (!subject->HasHashCode() &&
4291 len <= String::kMaxArrayIndexSize &&
4292 (len == 1 || data[0] != '0')) {
4293 // String hash is not calculated yet but all the data are present.
4294 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004295 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004296#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004297 subject->Hash(); // Force hash calculation.
4298 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4299 static_cast<int>(hash));
4300#endif
4301 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004302 }
4303 return Smi::FromInt(d);
4304 }
4305 }
4306
4307 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004308 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4309}
4310
4311
4312static Object* Runtime_StringFromCharCodeArray(Arguments args) {
4313 NoHandleAllocation ha;
4314 ASSERT(args.length() == 1);
4315
4316 CONVERT_CHECKED(JSArray, codes, args[0]);
4317 int length = Smi::cast(codes->length())->value();
4318
4319 // Check if the string can be ASCII.
4320 int i;
4321 for (i = 0; i < length; i++) {
4322 Object* element = codes->GetElement(i);
4323 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4324 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4325 break;
4326 }
4327
4328 Object* object = NULL;
4329 if (i == length) { // The string is ASCII.
4330 object = Heap::AllocateRawAsciiString(length);
4331 } else { // The string is not ASCII.
4332 object = Heap::AllocateRawTwoByteString(length);
4333 }
4334
4335 if (object->IsFailure()) return object;
4336 String* result = String::cast(object);
4337 for (int i = 0; i < length; i++) {
4338 Object* element = codes->GetElement(i);
4339 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004340 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004341 }
4342 return result;
4343}
4344
4345
4346// kNotEscaped is generated by the following:
4347//
4348// #!/bin/perl
4349// for (my $i = 0; $i < 256; $i++) {
4350// print "\n" if $i % 16 == 0;
4351// my $c = chr($i);
4352// my $escaped = 1;
4353// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4354// print $escaped ? "0, " : "1, ";
4355// }
4356
4357
4358static bool IsNotEscaped(uint16_t character) {
4359 // Only for 8 bit characters, the rest are always escaped (in a different way)
4360 ASSERT(character < 256);
4361 static const char kNotEscaped[256] = {
4362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4365 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4366 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4367 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4368 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4369 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4378 };
4379 return kNotEscaped[character] != 0;
4380}
4381
4382
4383static Object* Runtime_URIEscape(Arguments args) {
4384 const char hex_chars[] = "0123456789ABCDEF";
4385 NoHandleAllocation ha;
4386 ASSERT(args.length() == 1);
4387 CONVERT_CHECKED(String, source, args[0]);
4388
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004389 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004390
4391 int escaped_length = 0;
4392 int length = source->length();
4393 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004394 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004395 buffer->Reset(source);
4396 while (buffer->has_more()) {
4397 uint16_t character = buffer->GetNext();
4398 if (character >= 256) {
4399 escaped_length += 6;
4400 } else if (IsNotEscaped(character)) {
4401 escaped_length++;
4402 } else {
4403 escaped_length += 3;
4404 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004405 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004406 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004407 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004408 Top::context()->mark_out_of_memory();
4409 return Failure::OutOfMemoryException();
4410 }
4411 }
4412 }
4413 // No length change implies no change. Return original string if no change.
4414 if (escaped_length == length) {
4415 return source;
4416 }
4417 Object* o = Heap::AllocateRawAsciiString(escaped_length);
4418 if (o->IsFailure()) return o;
4419 String* destination = String::cast(o);
4420 int dest_position = 0;
4421
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004422 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004423 buffer->Rewind();
4424 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004425 uint16_t chr = buffer->GetNext();
4426 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004427 destination->Set(dest_position, '%');
4428 destination->Set(dest_position+1, 'u');
4429 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4430 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4431 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4432 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004433 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004434 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004435 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004436 dest_position++;
4437 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004438 destination->Set(dest_position, '%');
4439 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4440 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004441 dest_position += 3;
4442 }
4443 }
4444 return destination;
4445}
4446
4447
4448static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4449 static const signed char kHexValue['g'] = {
4450 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4451 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4452 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4453 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4454 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4455 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4456 -1, 10, 11, 12, 13, 14, 15 };
4457
4458 if (character1 > 'f') return -1;
4459 int hi = kHexValue[character1];
4460 if (hi == -1) return -1;
4461 if (character2 > 'f') return -1;
4462 int lo = kHexValue[character2];
4463 if (lo == -1) return -1;
4464 return (hi << 4) + lo;
4465}
4466
4467
ager@chromium.org870a0b62008-11-04 11:43:05 +00004468static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004469 int i,
4470 int length,
4471 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004472 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004473 int32_t hi = 0;
4474 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004475 if (character == '%' &&
4476 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004477 source->Get(i + 1) == 'u' &&
4478 (hi = TwoDigitHex(source->Get(i + 2),
4479 source->Get(i + 3))) != -1 &&
4480 (lo = TwoDigitHex(source->Get(i + 4),
4481 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004482 *step = 6;
4483 return (hi << 8) + lo;
4484 } else if (character == '%' &&
4485 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004486 (lo = TwoDigitHex(source->Get(i + 1),
4487 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 *step = 3;
4489 return lo;
4490 } else {
4491 *step = 1;
4492 return character;
4493 }
4494}
4495
4496
4497static Object* Runtime_URIUnescape(Arguments args) {
4498 NoHandleAllocation ha;
4499 ASSERT(args.length() == 1);
4500 CONVERT_CHECKED(String, source, args[0]);
4501
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004502 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503
4504 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004505 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004506
4507 int unescaped_length = 0;
4508 for (int i = 0; i < length; unescaped_length++) {
4509 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004510 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004511 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004512 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513 i += step;
4514 }
4515
4516 // No length change implies no change. Return original string if no change.
4517 if (unescaped_length == length)
4518 return source;
4519
4520 Object* o = ascii ?
4521 Heap::AllocateRawAsciiString(unescaped_length) :
4522 Heap::AllocateRawTwoByteString(unescaped_length);
4523 if (o->IsFailure()) return o;
4524 String* destination = String::cast(o);
4525
4526 int dest_position = 0;
4527 for (int i = 0; i < length; dest_position++) {
4528 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004529 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004530 i += step;
4531 }
4532 return destination;
4533}
4534
4535
4536static Object* Runtime_StringParseInt(Arguments args) {
4537 NoHandleAllocation ha;
4538
4539 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004540 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004541
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004542 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004543
lrn@chromium.org25156de2010-04-06 13:10:27 +00004544 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4545 double value = StringToInt(s, radix);
4546 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004547}
4548
4549
4550static Object* Runtime_StringParseFloat(Arguments args) {
4551 NoHandleAllocation ha;
4552 CONVERT_CHECKED(String, str, args[0]);
4553
4554 // ECMA-262 section 15.1.2.3, empty string is NaN
4555 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4556
4557 // Create a number object from the value.
4558 return Heap::NumberFromDouble(value);
4559}
4560
4561
4562static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4563static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4564
4565
4566template <class Converter>
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004567static Object* ConvertCaseHelper(String* s,
4568 int length,
4569 int input_string_length,
4570 unibrow::Mapping<Converter, 128>* mapping) {
4571 // We try this twice, once with the assumption that the result is no longer
4572 // than the input and, if that assumption breaks, again with the exact
4573 // length. This may not be pretty, but it is nicer than what was here before
4574 // and I hereby claim my vaffel-is.
4575 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004576 // Allocate the resulting string.
4577 //
4578 // NOTE: This assumes that the upper/lower case of an ascii
4579 // character is also ascii. This is currently the case, but it
4580 // might break in the future if we implement more context and locale
4581 // dependent upper/lower conversions.
ager@chromium.org5ec48922009-05-05 07:25:34 +00004582 Object* o = s->IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004583 ? Heap::AllocateRawAsciiString(length)
4584 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004585 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586 String* result = String::cast(o);
4587 bool has_changed_character = false;
4588
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 // Convert all characters to upper case, assuming that they will fit
4590 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004591 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004592 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004593 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594 // We can assume that the string is not empty
4595 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004596 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004597 bool has_next = buffer->has_more();
4598 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004599 int char_length = mapping->get(current, next, chars);
4600 if (char_length == 0) {
4601 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004602 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 i++;
4604 } else if (char_length == 1) {
4605 // Common case: converting the letter resulted in one character.
4606 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004607 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004608 has_changed_character = true;
4609 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004610 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004611 // We've assumed that the result would be as long as the
4612 // input but here is a character that converts to several
4613 // characters. No matter, we calculate the exact length
4614 // of the result and try the whole thing again.
4615 //
4616 // Note that this leaves room for optimization. We could just
4617 // memcpy what we already have to the result string. Also,
4618 // the result string is the last object allocated we could
4619 // "realloc" it and probably, in the vast majority of cases,
4620 // extend the existing string to be able to hold the full
4621 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004622 int next_length = 0;
4623 if (has_next) {
4624 next_length = mapping->get(next, 0, chars);
4625 if (next_length == 0) next_length = 1;
4626 }
4627 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004628 while (buffer->has_more()) {
4629 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004630 // NOTE: we use 0 as the next character here because, while
4631 // the next character may affect what a character converts to,
4632 // it does not in any case affect the length of what it convert
4633 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634 int char_length = mapping->get(current, 0, chars);
4635 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004636 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004637 if (current_length > Smi::kMaxValue) {
4638 Top::context()->mark_out_of_memory();
4639 return Failure::OutOfMemoryException();
4640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004641 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004642 // Try again with the real length.
4643 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004644 } else {
4645 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004646 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004647 i++;
4648 }
4649 has_changed_character = true;
4650 }
4651 current = next;
4652 }
4653 if (has_changed_character) {
4654 return result;
4655 } else {
4656 // If we didn't actually change anything in doing the conversion
4657 // we simple return the result and let the converted string
4658 // become garbage; there is no reason to keep two identical strings
4659 // alive.
4660 return s;
4661 }
4662}
4663
4664
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004665namespace {
4666
4667struct ToLowerTraits {
4668 typedef unibrow::ToLowercase UnibrowConverter;
4669
4670 static bool ConvertAscii(char* dst, char* src, int length) {
4671 bool changed = false;
4672 for (int i = 0; i < length; ++i) {
4673 char c = src[i];
4674 if ('A' <= c && c <= 'Z') {
4675 c += ('a' - 'A');
4676 changed = true;
4677 }
4678 dst[i] = c;
4679 }
4680 return changed;
4681 }
4682};
4683
4684
4685struct ToUpperTraits {
4686 typedef unibrow::ToUppercase UnibrowConverter;
4687
4688 static bool ConvertAscii(char* dst, char* src, int length) {
4689 bool changed = false;
4690 for (int i = 0; i < length; ++i) {
4691 char c = src[i];
4692 if ('a' <= c && c <= 'z') {
4693 c -= ('a' - 'A');
4694 changed = true;
4695 }
4696 dst[i] = c;
4697 }
4698 return changed;
4699 }
4700};
4701
4702} // namespace
4703
4704
4705template <typename ConvertTraits>
4706static Object* ConvertCase(
4707 Arguments args,
4708 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004709 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004710 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004711 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004712
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004713 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004714 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004715 if (length == 0) return s;
4716
4717 // Simpler handling of ascii strings.
4718 //
4719 // NOTE: This assumes that the upper/lower case of an ascii
4720 // character is also ascii. This is currently the case, but it
4721 // might break in the future if we implement more context and locale
4722 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004723 if (s->IsSeqAsciiString()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004724 Object* o = Heap::AllocateRawAsciiString(length);
4725 if (o->IsFailure()) return o;
4726 SeqAsciiString* result = SeqAsciiString::cast(o);
4727 bool has_changed_character = ConvertTraits::ConvertAscii(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004728 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004729 return has_changed_character ? result : s;
4730 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004731
4732 Object* answer = ConvertCaseHelper(s, length, length, mapping);
4733 if (answer->IsSmi()) {
4734 // Retry with correct length.
4735 answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
4736 }
4737 return answer; // This may be a failure.
4738}
4739
4740
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004741static Object* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004742 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004743}
4744
4745
4746static Object* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004747 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004748}
4749
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004750
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004751static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
4752 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
4753}
4754
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004755
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004756static Object* Runtime_StringTrim(Arguments args) {
4757 NoHandleAllocation ha;
4758 ASSERT(args.length() == 3);
4759
4760 CONVERT_CHECKED(String, s, args[0]);
4761 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
4762 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
4763
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004764 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004765 int length = s->length();
4766
4767 int left = 0;
4768 if (trimLeft) {
4769 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
4770 left++;
4771 }
4772 }
4773
4774 int right = length;
4775 if (trimRight) {
4776 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
4777 right--;
4778 }
4779 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004780 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004781}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004782
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004783
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004784// Define storage for buffers declared in header file.
4785// TODO(lrn): Remove these when rewriting search code.
4786int BMBuffers::bad_char_occurrence[kBMAlphabetSize];
4787BMGoodSuffixBuffers BMBuffers::bmgs_buffers;
4788
4789
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004790template <typename schar, typename pchar>
4791void FindStringIndices(Vector<const schar> subject,
4792 Vector<const pchar> pattern,
4793 ZoneList<int>* indices,
4794 unsigned int limit) {
4795 ASSERT(limit > 0);
4796 // Collect indices of pattern in subject, and the end-of-string index.
4797 // Stop after finding at most limit values.
4798 StringSearchStrategy strategy =
4799 InitializeStringSearch(pattern, sizeof(schar) == 1);
4800 switch (strategy) {
4801 case SEARCH_FAIL: return;
4802 case SEARCH_SHORT: {
4803 int pattern_length = pattern.length();
4804 int index = 0;
4805 while (limit > 0) {
4806 index = SimpleIndexOf(subject, pattern, index);
4807 if (index < 0) return;
4808 indices->Add(index);
4809 index += pattern_length;
4810 limit--;
4811 }
4812 return;
4813 }
4814 case SEARCH_LONG: {
4815 int pattern_length = pattern.length();
4816 int index = 0;
4817 while (limit > 0) {
4818 index = ComplexIndexOf(subject, pattern, index);
4819 if (index < 0) return;
4820 indices->Add(index);
4821 index += pattern_length;
4822 limit--;
4823 }
4824 return;
4825 }
4826 default:
4827 UNREACHABLE();
4828 return;
4829 }
4830}
4831
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004832
4833static Object* Runtime_StringSplit(Arguments args) {
4834 ASSERT(args.length() == 3);
4835 HandleScope handle_scope;
4836 CONVERT_ARG_CHECKED(String, subject, 0);
4837 CONVERT_ARG_CHECKED(String, pattern, 1);
4838 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
4839
4840 int subject_length = subject->length();
4841 int pattern_length = pattern->length();
4842 RUNTIME_ASSERT(pattern_length > 0);
4843
4844 // The limit can be very large (0xffffffffu), but since the pattern
4845 // isn't empty, we can never create more parts than ~half the length
4846 // of the subject.
4847
4848 if (!subject->IsFlat()) FlattenString(subject);
4849
4850 static const int kMaxInitialListCapacity = 16;
4851
4852 ZoneScope scope(DELETE_ON_EXIT);
4853
4854 // Find (up to limit) indices of separator and end-of-string in subject
4855 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
4856 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004857 if (!pattern->IsFlat()) FlattenString(pattern);
4858
4859 // No allocation block.
4860 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004861 AssertNoAllocation nogc;
4862 if (subject->IsAsciiRepresentation()) {
4863 Vector<const char> subject_vector = subject->ToAsciiVector();
4864 if (pattern->IsAsciiRepresentation()) {
4865 FindStringIndices(subject_vector,
4866 pattern->ToAsciiVector(),
4867 &indices,
4868 limit);
4869 } else {
4870 FindStringIndices(subject_vector,
4871 pattern->ToUC16Vector(),
4872 &indices,
4873 limit);
4874 }
4875 } else {
4876 Vector<const uc16> subject_vector = subject->ToUC16Vector();
4877 if (pattern->IsAsciiRepresentation()) {
4878 FindStringIndices(subject_vector,
4879 pattern->ToAsciiVector(),
4880 &indices,
4881 limit);
4882 } else {
4883 FindStringIndices(subject_vector,
4884 pattern->ToUC16Vector(),
4885 &indices,
4886 limit);
4887 }
4888 }
4889 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004890
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004891 if (static_cast<uint32_t>(indices.length()) < limit) {
4892 indices.Add(subject_length);
4893 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004894
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004895 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004896
4897 // Create JSArray of substrings separated by separator.
4898 int part_count = indices.length();
4899
4900 Handle<JSArray> result = Factory::NewJSArray(part_count);
4901 result->set_length(Smi::FromInt(part_count));
4902
4903 ASSERT(result->HasFastElements());
4904
4905 if (part_count == 1 && indices.at(0) == subject_length) {
4906 FixedArray::cast(result->elements())->set(0, *subject);
4907 return *result;
4908 }
4909
4910 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
4911 int part_start = 0;
4912 for (int i = 0; i < part_count; i++) {
4913 HandleScope local_loop_handle;
4914 int part_end = indices.at(i);
4915 Handle<String> substring =
4916 Factory::NewSubString(subject, part_start, part_end);
4917 elements->set(i, *substring);
4918 part_start = part_end + pattern_length;
4919 }
4920
4921 return *result;
4922}
4923
4924
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004925// Copies ascii characters to the given fixed array looking up
4926// one-char strings in the cache. Gives up on the first char that is
4927// not in the cache and fills the remainder with smi zeros. Returns
4928// the length of the successfully copied prefix.
4929static int CopyCachedAsciiCharsToArray(const char* chars,
4930 FixedArray* elements,
4931 int length) {
4932 AssertNoAllocation nogc;
4933 FixedArray* ascii_cache = Heap::single_character_string_cache();
4934 Object* undefined = Heap::undefined_value();
4935 int i;
4936 for (i = 0; i < length; ++i) {
4937 Object* value = ascii_cache->get(chars[i]);
4938 if (value == undefined) break;
4939 ASSERT(!Heap::InNewSpace(value));
4940 elements->set(i, value, SKIP_WRITE_BARRIER);
4941 }
4942 if (i < length) {
4943 ASSERT(Smi::FromInt(0) == 0);
4944 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
4945 }
4946#ifdef DEBUG
4947 for (int j = 0; j < length; ++j) {
4948 Object* element = elements->get(j);
4949 ASSERT(element == Smi::FromInt(0) ||
4950 (element->IsString() && String::cast(element)->LooksValid()));
4951 }
4952#endif
4953 return i;
4954}
4955
4956
4957// Converts a String to JSArray.
4958// For example, "foo" => ["f", "o", "o"].
4959static Object* Runtime_StringToArray(Arguments args) {
4960 HandleScope scope;
4961 ASSERT(args.length() == 1);
4962 CONVERT_ARG_CHECKED(String, s, 0);
4963
4964 s->TryFlatten();
4965 const int length = s->length();
4966
4967 Handle<FixedArray> elements;
4968 if (s->IsFlat() && s->IsAsciiRepresentation()) {
4969 Object* obj = Heap::AllocateUninitializedFixedArray(length);
4970 if (obj->IsFailure()) return obj;
4971 elements = Handle<FixedArray>(FixedArray::cast(obj));
4972
4973 Vector<const char> chars = s->ToAsciiVector();
4974 // Note, this will initialize all elements (not only the prefix)
4975 // to prevent GC from seeing partially initialized array.
4976 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
4977 *elements,
4978 length);
4979
4980 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004981 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
4982 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004983 }
4984 } else {
4985 elements = Factory::NewFixedArray(length);
4986 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004987 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
4988 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004989 }
4990 }
4991
4992#ifdef DEBUG
4993 for (int i = 0; i < length; ++i) {
4994 ASSERT(String::cast(elements->get(i))->length() == 1);
4995 }
4996#endif
4997
4998 return *Factory::NewJSArrayWithElements(elements);
4999}
5000
5001
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005002static Object* Runtime_NewStringWrapper(Arguments args) {
5003 NoHandleAllocation ha;
5004 ASSERT(args.length() == 1);
5005 CONVERT_CHECKED(String, value, args[0]);
5006 return value->ToObject();
5007}
5008
5009
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005010bool Runtime::IsUpperCaseChar(uint16_t ch) {
5011 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5012 int char_length = to_upper_mapping.get(ch, 0, chars);
5013 return char_length == 0;
5014}
5015
5016
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005017static Object* Runtime_NumberToString(Arguments args) {
5018 NoHandleAllocation ha;
5019 ASSERT(args.length() == 1);
5020
5021 Object* number = args[0];
5022 RUNTIME_ASSERT(number->IsNumber());
5023
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005024 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005025}
5026
5027
ager@chromium.org357bf652010-04-12 11:30:10 +00005028static Object* Runtime_NumberToStringSkipCache(Arguments args) {
5029 NoHandleAllocation ha;
5030 ASSERT(args.length() == 1);
5031
5032 Object* number = args[0];
5033 RUNTIME_ASSERT(number->IsNumber());
5034
5035 return Heap::NumberToString(number, false);
5036}
5037
5038
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005039static Object* Runtime_NumberToInteger(Arguments args) {
5040 NoHandleAllocation ha;
5041 ASSERT(args.length() == 1);
5042
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005043 CONVERT_DOUBLE_CHECKED(number, args[0]);
5044
5045 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5046 if (number > 0 && number <= Smi::kMaxValue) {
5047 return Smi::FromInt(static_cast<int>(number));
5048 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005049 return Heap::NumberFromDouble(DoubleToInteger(number));
5050}
5051
5052
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005053static Object* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
5054 NoHandleAllocation ha;
5055 ASSERT(args.length() == 1);
5056
5057 CONVERT_DOUBLE_CHECKED(number, args[0]);
5058
5059 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5060 if (number > 0 && number <= Smi::kMaxValue) {
5061 return Smi::FromInt(static_cast<int>(number));
5062 }
5063
5064 double double_value = DoubleToInteger(number);
5065 // Map both -0 and +0 to +0.
5066 if (double_value == 0) double_value = 0;
5067
5068 return Heap::NumberFromDouble(double_value);
5069}
5070
5071
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005072static Object* Runtime_NumberToJSUint32(Arguments args) {
5073 NoHandleAllocation ha;
5074 ASSERT(args.length() == 1);
5075
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005076 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005077 return Heap::NumberFromUint32(number);
5078}
5079
5080
5081static Object* Runtime_NumberToJSInt32(Arguments args) {
5082 NoHandleAllocation ha;
5083 ASSERT(args.length() == 1);
5084
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005085 CONVERT_DOUBLE_CHECKED(number, args[0]);
5086
5087 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5088 if (number > 0 && number <= Smi::kMaxValue) {
5089 return Smi::FromInt(static_cast<int>(number));
5090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005091 return Heap::NumberFromInt32(DoubleToInt32(number));
5092}
5093
5094
ager@chromium.org870a0b62008-11-04 11:43:05 +00005095// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5096// a small integer.
5097static Object* Runtime_NumberToSmi(Arguments args) {
5098 NoHandleAllocation ha;
5099 ASSERT(args.length() == 1);
5100
5101 Object* obj = args[0];
5102 if (obj->IsSmi()) {
5103 return obj;
5104 }
5105 if (obj->IsHeapNumber()) {
5106 double value = HeapNumber::cast(obj)->value();
5107 int int_value = FastD2I(value);
5108 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5109 return Smi::FromInt(int_value);
5110 }
5111 }
5112 return Heap::nan_value();
5113}
5114
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005115
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005116static Object* Runtime_NumberAdd(Arguments args) {
5117 NoHandleAllocation ha;
5118 ASSERT(args.length() == 2);
5119
5120 CONVERT_DOUBLE_CHECKED(x, args[0]);
5121 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005122 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005123}
5124
5125
5126static Object* Runtime_NumberSub(Arguments args) {
5127 NoHandleAllocation ha;
5128 ASSERT(args.length() == 2);
5129
5130 CONVERT_DOUBLE_CHECKED(x, args[0]);
5131 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005132 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005133}
5134
5135
5136static Object* Runtime_NumberMul(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]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005142 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005143}
5144
5145
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005146static Object* Runtime_NumberUnaryMinus(Arguments args) {
5147 NoHandleAllocation ha;
5148 ASSERT(args.length() == 1);
5149
5150 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005151 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005152}
5153
5154
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005155static Object* Runtime_NumberAlloc(Arguments args) {
5156 NoHandleAllocation ha;
5157 ASSERT(args.length() == 0);
5158
5159 return Heap::NumberFromDouble(9876543210.0);
5160}
5161
5162
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005163static Object* Runtime_NumberDiv(Arguments args) {
5164 NoHandleAllocation ha;
5165 ASSERT(args.length() == 2);
5166
5167 CONVERT_DOUBLE_CHECKED(x, args[0]);
5168 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005169 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005170}
5171
5172
5173static Object* Runtime_NumberMod(Arguments args) {
5174 NoHandleAllocation ha;
5175 ASSERT(args.length() == 2);
5176
5177 CONVERT_DOUBLE_CHECKED(x, args[0]);
5178 CONVERT_DOUBLE_CHECKED(y, args[1]);
5179
ager@chromium.org3811b432009-10-28 14:53:37 +00005180 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005181 // NumberFromDouble may return a Smi instead of a Number object
5182 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005183}
5184
5185
5186static Object* Runtime_StringAdd(Arguments args) {
5187 NoHandleAllocation ha;
5188 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005189 CONVERT_CHECKED(String, str1, args[0]);
5190 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005191 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005192 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005193}
5194
5195
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005196template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005197static inline void StringBuilderConcatHelper(String* special,
5198 sinkchar* sink,
5199 FixedArray* fixed_array,
5200 int array_length) {
5201 int position = 0;
5202 for (int i = 0; i < array_length; i++) {
5203 Object* element = fixed_array->get(i);
5204 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005205 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005206 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005207 int pos;
5208 int len;
5209 if (encoded_slice > 0) {
5210 // Position and length encoded in one smi.
5211 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5212 len = StringBuilderSubstringLength::decode(encoded_slice);
5213 } else {
5214 // Position and length encoded in two smis.
5215 Object* obj = fixed_array->get(++i);
5216 ASSERT(obj->IsSmi());
5217 pos = Smi::cast(obj)->value();
5218 len = -encoded_slice;
5219 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005220 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005221 sink + position,
5222 pos,
5223 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005224 position += len;
5225 } else {
5226 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005227 int element_length = string->length();
5228 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005229 position += element_length;
5230 }
5231 }
5232}
5233
5234
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005235static Object* Runtime_StringBuilderConcat(Arguments args) {
5236 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005237 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005238 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005239 if (!args[1]->IsSmi()) {
5240 Top::context()->mark_out_of_memory();
5241 return Failure::OutOfMemoryException();
5242 }
5243 int array_length = Smi::cast(args[1])->value();
5244 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005245
5246 // This assumption is used by the slice encoding in one or two smis.
5247 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5248
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005249 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005250 if (!array->HasFastElements()) {
5251 return Top::Throw(Heap::illegal_argument_symbol());
5252 }
5253 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005254 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005255 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005256 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005257
5258 if (array_length == 0) {
5259 return Heap::empty_string();
5260 } else if (array_length == 1) {
5261 Object* first = fixed_array->get(0);
5262 if (first->IsString()) return first;
5263 }
5264
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005265 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005266 int position = 0;
5267 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005268 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005269 Object* elt = fixed_array->get(i);
5270 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005271 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005272 int smi_value = Smi::cast(elt)->value();
5273 int pos;
5274 int len;
5275 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005276 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005277 pos = StringBuilderSubstringPosition::decode(smi_value);
5278 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005279 } else {
5280 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005281 len = -smi_value;
5282 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005283 i++;
5284 if (i >= array_length) {
5285 return Top::Throw(Heap::illegal_argument_symbol());
5286 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005287 Object* next_smi = fixed_array->get(i);
5288 if (!next_smi->IsSmi()) {
5289 return Top::Throw(Heap::illegal_argument_symbol());
5290 }
5291 pos = Smi::cast(next_smi)->value();
5292 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005293 return Top::Throw(Heap::illegal_argument_symbol());
5294 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005295 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005296 ASSERT(pos >= 0);
5297 ASSERT(len >= 0);
5298 if (pos > special_length || len > special_length - pos) {
5299 return Top::Throw(Heap::illegal_argument_symbol());
5300 }
5301 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005302 } else if (elt->IsString()) {
5303 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005304 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005305 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005306 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005307 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005308 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005309 } else {
5310 return Top::Throw(Heap::illegal_argument_symbol());
5311 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005312 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005313 Top::context()->mark_out_of_memory();
5314 return Failure::OutOfMemoryException();
5315 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005316 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005317 }
5318
5319 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005320 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005321
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005322 if (ascii) {
5323 object = Heap::AllocateRawAsciiString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005324 if (object->IsFailure()) return object;
5325 SeqAsciiString* answer = SeqAsciiString::cast(object);
5326 StringBuilderConcatHelper(special,
5327 answer->GetChars(),
5328 fixed_array,
5329 array_length);
5330 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005331 } else {
5332 object = Heap::AllocateRawTwoByteString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005333 if (object->IsFailure()) return object;
5334 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5335 StringBuilderConcatHelper(special,
5336 answer->GetChars(),
5337 fixed_array,
5338 array_length);
5339 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005341}
5342
5343
5344static Object* Runtime_NumberOr(Arguments args) {
5345 NoHandleAllocation ha;
5346 ASSERT(args.length() == 2);
5347
5348 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5349 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5350 return Heap::NumberFromInt32(x | y);
5351}
5352
5353
5354static Object* Runtime_NumberAnd(Arguments args) {
5355 NoHandleAllocation ha;
5356 ASSERT(args.length() == 2);
5357
5358 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5359 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5360 return Heap::NumberFromInt32(x & y);
5361}
5362
5363
5364static Object* Runtime_NumberXor(Arguments args) {
5365 NoHandleAllocation ha;
5366 ASSERT(args.length() == 2);
5367
5368 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5369 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5370 return Heap::NumberFromInt32(x ^ y);
5371}
5372
5373
5374static Object* Runtime_NumberNot(Arguments args) {
5375 NoHandleAllocation ha;
5376 ASSERT(args.length() == 1);
5377
5378 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5379 return Heap::NumberFromInt32(~x);
5380}
5381
5382
5383static Object* Runtime_NumberShl(Arguments args) {
5384 NoHandleAllocation ha;
5385 ASSERT(args.length() == 2);
5386
5387 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5388 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5389 return Heap::NumberFromInt32(x << (y & 0x1f));
5390}
5391
5392
5393static Object* Runtime_NumberShr(Arguments args) {
5394 NoHandleAllocation ha;
5395 ASSERT(args.length() == 2);
5396
5397 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5398 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5399 return Heap::NumberFromUint32(x >> (y & 0x1f));
5400}
5401
5402
5403static Object* Runtime_NumberSar(Arguments args) {
5404 NoHandleAllocation ha;
5405 ASSERT(args.length() == 2);
5406
5407 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5408 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5409 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5410}
5411
5412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005413static Object* Runtime_NumberEquals(Arguments args) {
5414 NoHandleAllocation ha;
5415 ASSERT(args.length() == 2);
5416
5417 CONVERT_DOUBLE_CHECKED(x, args[0]);
5418 CONVERT_DOUBLE_CHECKED(y, args[1]);
5419 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5420 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5421 if (x == y) return Smi::FromInt(EQUAL);
5422 Object* result;
5423 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5424 result = Smi::FromInt(EQUAL);
5425 } else {
5426 result = Smi::FromInt(NOT_EQUAL);
5427 }
5428 return result;
5429}
5430
5431
5432static Object* Runtime_StringEquals(Arguments args) {
5433 NoHandleAllocation ha;
5434 ASSERT(args.length() == 2);
5435
5436 CONVERT_CHECKED(String, x, args[0]);
5437 CONVERT_CHECKED(String, y, args[1]);
5438
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005439 bool not_equal = !x->Equals(y);
5440 // This is slightly convoluted because the value that signifies
5441 // equality is 0 and inequality is 1 so we have to negate the result
5442 // from String::Equals.
5443 ASSERT(not_equal == 0 || not_equal == 1);
5444 STATIC_CHECK(EQUAL == 0);
5445 STATIC_CHECK(NOT_EQUAL == 1);
5446 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005447}
5448
5449
5450static Object* Runtime_NumberCompare(Arguments args) {
5451 NoHandleAllocation ha;
5452 ASSERT(args.length() == 3);
5453
5454 CONVERT_DOUBLE_CHECKED(x, args[0]);
5455 CONVERT_DOUBLE_CHECKED(y, args[1]);
5456 if (isnan(x) || isnan(y)) return args[2];
5457 if (x == y) return Smi::FromInt(EQUAL);
5458 if (isless(x, y)) return Smi::FromInt(LESS);
5459 return Smi::FromInt(GREATER);
5460}
5461
5462
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005463// Compare two Smis as if they were converted to strings and then
5464// compared lexicographically.
5465static Object* Runtime_SmiLexicographicCompare(Arguments args) {
5466 NoHandleAllocation ha;
5467 ASSERT(args.length() == 2);
5468
5469 // Arrays for the individual characters of the two Smis. Smis are
5470 // 31 bit integers and 10 decimal digits are therefore enough.
5471 static int x_elms[10];
5472 static int y_elms[10];
5473
5474 // Extract the integer values from the Smis.
5475 CONVERT_CHECKED(Smi, x, args[0]);
5476 CONVERT_CHECKED(Smi, y, args[1]);
5477 int x_value = x->value();
5478 int y_value = y->value();
5479
5480 // If the integers are equal so are the string representations.
5481 if (x_value == y_value) return Smi::FromInt(EQUAL);
5482
5483 // If one of the integers are zero the normal integer order is the
5484 // same as the lexicographic order of the string representations.
5485 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5486
ager@chromium.org32912102009-01-16 10:38:43 +00005487 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005488 // smallest because the char code of '-' is less than the char code
5489 // of any digit. Otherwise, we make both values positive.
5490 if (x_value < 0 || y_value < 0) {
5491 if (y_value >= 0) return Smi::FromInt(LESS);
5492 if (x_value >= 0) return Smi::FromInt(GREATER);
5493 x_value = -x_value;
5494 y_value = -y_value;
5495 }
5496
5497 // Convert the integers to arrays of their decimal digits.
5498 int x_index = 0;
5499 int y_index = 0;
5500 while (x_value > 0) {
5501 x_elms[x_index++] = x_value % 10;
5502 x_value /= 10;
5503 }
5504 while (y_value > 0) {
5505 y_elms[y_index++] = y_value % 10;
5506 y_value /= 10;
5507 }
5508
5509 // Loop through the arrays of decimal digits finding the first place
5510 // where they differ.
5511 while (--x_index >= 0 && --y_index >= 0) {
5512 int diff = x_elms[x_index] - y_elms[y_index];
5513 if (diff != 0) return Smi::FromInt(diff);
5514 }
5515
5516 // If one array is a suffix of the other array, the longest array is
5517 // the representation of the largest of the Smis in the
5518 // lexicographic ordering.
5519 return Smi::FromInt(x_index - y_index);
5520}
5521
5522
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005523static Object* StringInputBufferCompare(String* x, String* y) {
5524 static StringInputBuffer bufx;
5525 static StringInputBuffer bufy;
5526 bufx.Reset(x);
5527 bufy.Reset(y);
5528 while (bufx.has_more() && bufy.has_more()) {
5529 int d = bufx.GetNext() - bufy.GetNext();
5530 if (d < 0) return Smi::FromInt(LESS);
5531 else if (d > 0) return Smi::FromInt(GREATER);
5532 }
5533
5534 // x is (non-trivial) prefix of y:
5535 if (bufy.has_more()) return Smi::FromInt(LESS);
5536 // y is prefix of x:
5537 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5538}
5539
5540
5541static Object* FlatStringCompare(String* x, String* y) {
5542 ASSERT(x->IsFlat());
5543 ASSERT(y->IsFlat());
5544 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5545 int prefix_length = x->length();
5546 if (y->length() < prefix_length) {
5547 prefix_length = y->length();
5548 equal_prefix_result = Smi::FromInt(GREATER);
5549 } else if (y->length() > prefix_length) {
5550 equal_prefix_result = Smi::FromInt(LESS);
5551 }
5552 int r;
5553 if (x->IsAsciiRepresentation()) {
5554 Vector<const char> x_chars = x->ToAsciiVector();
5555 if (y->IsAsciiRepresentation()) {
5556 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005557 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005558 } else {
5559 Vector<const uc16> y_chars = y->ToUC16Vector();
5560 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5561 }
5562 } else {
5563 Vector<const uc16> x_chars = x->ToUC16Vector();
5564 if (y->IsAsciiRepresentation()) {
5565 Vector<const char> y_chars = y->ToAsciiVector();
5566 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5567 } else {
5568 Vector<const uc16> y_chars = y->ToUC16Vector();
5569 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5570 }
5571 }
5572 Object* result;
5573 if (r == 0) {
5574 result = equal_prefix_result;
5575 } else {
5576 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5577 }
5578 ASSERT(result == StringInputBufferCompare(x, y));
5579 return result;
5580}
5581
5582
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005583static Object* Runtime_StringCompare(Arguments args) {
5584 NoHandleAllocation ha;
5585 ASSERT(args.length() == 2);
5586
5587 CONVERT_CHECKED(String, x, args[0]);
5588 CONVERT_CHECKED(String, y, args[1]);
5589
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005590 Counters::string_compare_runtime.Increment();
5591
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005592 // A few fast case tests before we flatten.
5593 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005594 if (y->length() == 0) {
5595 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005596 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005597 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005598 return Smi::FromInt(LESS);
5599 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005600
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005601 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005602 if (d < 0) return Smi::FromInt(LESS);
5603 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005604
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005605 Object* obj = Heap::PrepareForCompare(x);
5606 if (obj->IsFailure()) return obj;
5607 obj = Heap::PrepareForCompare(y);
5608 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005609
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005610 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5611 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005612}
5613
5614
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005615static Object* Runtime_Math_acos(Arguments args) {
5616 NoHandleAllocation ha;
5617 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005618 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005619
5620 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005621 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005622}
5623
5624
5625static Object* Runtime_Math_asin(Arguments args) {
5626 NoHandleAllocation ha;
5627 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005628 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005629
5630 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005631 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005632}
5633
5634
5635static Object* Runtime_Math_atan(Arguments args) {
5636 NoHandleAllocation ha;
5637 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005638 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005639
5640 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005641 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005642}
5643
5644
5645static Object* Runtime_Math_atan2(Arguments args) {
5646 NoHandleAllocation ha;
5647 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005648 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005649
5650 CONVERT_DOUBLE_CHECKED(x, args[0]);
5651 CONVERT_DOUBLE_CHECKED(y, args[1]);
5652 double result;
5653 if (isinf(x) && isinf(y)) {
5654 // Make sure that the result in case of two infinite arguments
5655 // is a multiple of Pi / 4. The sign of the result is determined
5656 // by the first argument (x) and the sign of the second argument
5657 // determines the multiplier: one or three.
5658 static double kPiDividedBy4 = 0.78539816339744830962;
5659 int multiplier = (x < 0) ? -1 : 1;
5660 if (y < 0) multiplier *= 3;
5661 result = multiplier * kPiDividedBy4;
5662 } else {
5663 result = atan2(x, y);
5664 }
5665 return Heap::AllocateHeapNumber(result);
5666}
5667
5668
5669static Object* Runtime_Math_ceil(Arguments args) {
5670 NoHandleAllocation ha;
5671 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005672 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005673
5674 CONVERT_DOUBLE_CHECKED(x, args[0]);
5675 return Heap::NumberFromDouble(ceiling(x));
5676}
5677
5678
5679static Object* Runtime_Math_cos(Arguments args) {
5680 NoHandleAllocation ha;
5681 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005682 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005683
5684 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005685 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005686}
5687
5688
5689static Object* Runtime_Math_exp(Arguments args) {
5690 NoHandleAllocation ha;
5691 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005692 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005693
5694 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005695 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005696}
5697
5698
5699static Object* Runtime_Math_floor(Arguments args) {
5700 NoHandleAllocation ha;
5701 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005702 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005703
5704 CONVERT_DOUBLE_CHECKED(x, args[0]);
5705 return Heap::NumberFromDouble(floor(x));
5706}
5707
5708
5709static Object* Runtime_Math_log(Arguments args) {
5710 NoHandleAllocation ha;
5711 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005712 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005713
5714 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005715 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005716}
5717
5718
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005719// Helper function to compute x^y, where y is known to be an
5720// integer. Uses binary decomposition to limit the number of
5721// multiplications; see the discussion in "Hacker's Delight" by Henry
5722// S. Warren, Jr., figure 11-6, page 213.
5723static double powi(double x, int y) {
5724 ASSERT(y != kMinInt);
5725 unsigned n = (y < 0) ? -y : y;
5726 double m = x;
5727 double p = 1;
5728 while (true) {
5729 if ((n & 1) != 0) p *= m;
5730 n >>= 1;
5731 if (n == 0) {
5732 if (y < 0) {
5733 // Unfortunately, we have to be careful when p has reached
5734 // infinity in the computation, because sometimes the higher
5735 // internal precision in the pow() implementation would have
5736 // given us a finite p. This happens very rarely.
5737 double result = 1.0 / p;
5738 return (result == 0 && isinf(p))
5739 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
5740 : result;
5741 } else {
5742 return p;
5743 }
5744 }
5745 m *= m;
5746 }
5747}
5748
5749
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005750static Object* Runtime_Math_pow(Arguments args) {
5751 NoHandleAllocation ha;
5752 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005753 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005754
5755 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005756
5757 // If the second argument is a smi, it is much faster to call the
5758 // custom powi() function than the generic pow().
5759 if (args[1]->IsSmi()) {
5760 int y = Smi::cast(args[1])->value();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005761 return Heap::NumberFromDouble(powi(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005762 }
5763
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005764 CONVERT_DOUBLE_CHECKED(y, args[1]);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005765
5766 if (!isinf(x)) {
5767 if (y == 0.5) {
5768 // It's not uncommon to use Math.pow(x, 0.5) to compute the
5769 // square root of a number. To speed up such computations, we
5770 // explictly check for this case and use the sqrt() function
5771 // which is faster than pow().
5772 return Heap::AllocateHeapNumber(sqrt(x));
5773 } else if (y == -0.5) {
5774 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
5775 return Heap::AllocateHeapNumber(1.0 / sqrt(x));
5776 }
5777 }
5778
5779 if (y == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005780 return Smi::FromInt(1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005781 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5782 return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005783 } else {
5784 return Heap::AllocateHeapNumber(pow(x, y));
5785 }
5786}
5787
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005788// Fast version of Math.pow if we know that y is not an integer and
5789// y is not -0.5 or 0.5. Used as slowcase from codegen.
5790static Object* Runtime_Math_pow_cfunction(Arguments args) {
5791 NoHandleAllocation ha;
5792 ASSERT(args.length() == 2);
5793 CONVERT_DOUBLE_CHECKED(x, args[0]);
5794 CONVERT_DOUBLE_CHECKED(y, args[1]);
5795 if (y == 0) {
5796 return Smi::FromInt(1);
5797 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5798 return Heap::nan_value();
5799 } else {
5800 return Heap::AllocateHeapNumber(pow(x, y));
5801 }
5802}
5803
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005804
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005805static Object* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005806 NoHandleAllocation ha;
5807 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005808 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005809
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005810 if (!args[0]->IsHeapNumber()) {
5811 // Must be smi. Return the argument unchanged for all the other types
5812 // to make fuzz-natives test happy.
5813 return args[0];
5814 }
5815
5816 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
5817
5818 double value = number->value();
5819 int exponent = number->get_exponent();
5820 int sign = number->get_sign();
5821
5822 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
5823 // should be rounded to 2^30, which is not smi.
5824 if (!sign && exponent <= kSmiValueSize - 3) {
5825 return Smi::FromInt(static_cast<int>(value + 0.5));
5826 }
5827
5828 // If the magnitude is big enough, there's no place for fraction part. If we
5829 // try to add 0.5 to this number, 1.0 will be added instead.
5830 if (exponent >= 52) {
5831 return number;
5832 }
5833
5834 if (sign && value >= -0.5) return Heap::minus_zero_value();
5835
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005836 // Do not call NumberFromDouble() to avoid extra checks.
5837 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005838}
5839
5840
5841static Object* Runtime_Math_sin(Arguments args) {
5842 NoHandleAllocation ha;
5843 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005844 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005845
5846 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005847 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005848}
5849
5850
5851static Object* Runtime_Math_sqrt(Arguments args) {
5852 NoHandleAllocation ha;
5853 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005854 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005855
5856 CONVERT_DOUBLE_CHECKED(x, args[0]);
5857 return Heap::AllocateHeapNumber(sqrt(x));
5858}
5859
5860
5861static Object* Runtime_Math_tan(Arguments args) {
5862 NoHandleAllocation ha;
5863 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005864 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005865
5866 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005867 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005868}
5869
5870
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005871static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005872 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
5873 181, 212, 243, 273, 304, 334};
5874 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
5875 182, 213, 244, 274, 305, 335};
5876
5877 year += month / 12;
5878 month %= 12;
5879 if (month < 0) {
5880 year--;
5881 month += 12;
5882 }
5883
5884 ASSERT(month >= 0);
5885 ASSERT(month < 12);
5886
5887 // year_delta is an arbitrary number such that:
5888 // a) year_delta = -1 (mod 400)
5889 // b) year + year_delta > 0 for years in the range defined by
5890 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
5891 // Jan 1 1970. This is required so that we don't run into integer
5892 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005893 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005894 // operations.
5895 static const int year_delta = 399999;
5896 static const int base_day = 365 * (1970 + year_delta) +
5897 (1970 + year_delta) / 4 -
5898 (1970 + year_delta) / 100 +
5899 (1970 + year_delta) / 400;
5900
5901 int year1 = year + year_delta;
5902 int day_from_year = 365 * year1 +
5903 year1 / 4 -
5904 year1 / 100 +
5905 year1 / 400 -
5906 base_day;
5907
5908 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005909 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005910 }
5911
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005912 return day_from_year + day_from_month_leap[month] + day - 1;
5913}
5914
5915
5916static Object* Runtime_DateMakeDay(Arguments args) {
5917 NoHandleAllocation ha;
5918 ASSERT(args.length() == 3);
5919
5920 CONVERT_SMI_CHECKED(year, args[0]);
5921 CONVERT_SMI_CHECKED(month, args[1]);
5922 CONVERT_SMI_CHECKED(date, args[2]);
5923
5924 return Smi::FromInt(MakeDay(year, month, date));
5925}
5926
5927
5928static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
5929static const int kDaysIn4Years = 4 * 365 + 1;
5930static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
5931static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
5932static const int kDays1970to2000 = 30 * 365 + 7;
5933static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
5934 kDays1970to2000;
5935static const int kYearsOffset = 400000;
5936
5937static const char kDayInYear[] = {
5938 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5939 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 31,
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,
5946 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5947 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5948 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5949 22, 23, 24, 25, 26, 27, 28, 29, 30,
5950 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5951 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5952 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5953 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 31,
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,
5960 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5961 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5962
5963 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5964 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 31,
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,
5971 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5972 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5973 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5974 22, 23, 24, 25, 26, 27, 28, 29, 30,
5975 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5976 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5977 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5978 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 31,
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,
5985 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5986 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5987
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, 29, 30, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
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,
6010 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6011 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6012
6013 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6014 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6015 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6016 22, 23, 24, 25, 26, 27, 28,
6017 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6018 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6019 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6020 22, 23, 24, 25, 26, 27, 28, 29, 30,
6021 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6022 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6023 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6024 22, 23, 24, 25, 26, 27, 28, 29, 30,
6025 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6026 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6027 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6028 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6029 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6030 22, 23, 24, 25, 26, 27, 28, 29, 30,
6031 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6032 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6033 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6034 22, 23, 24, 25, 26, 27, 28, 29, 30,
6035 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6036 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6037
6038static const char kMonthInYear[] = {
6039 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,
6040 0, 0, 0, 0, 0, 0,
6041 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,
6042 1, 1, 1,
6043 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,
6044 2, 2, 2, 2, 2, 2,
6045 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,
6046 3, 3, 3, 3, 3,
6047 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,
6048 4, 4, 4, 4, 4, 4,
6049 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,
6050 5, 5, 5, 5, 5,
6051 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,
6052 6, 6, 6, 6, 6, 6,
6053 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,
6054 7, 7, 7, 7, 7, 7,
6055 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,
6056 8, 8, 8, 8, 8,
6057 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,
6058 9, 9, 9, 9, 9, 9,
6059 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6060 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6061 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6062 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6063
6064 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,
6065 0, 0, 0, 0, 0, 0,
6066 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,
6067 1, 1, 1,
6068 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,
6069 2, 2, 2, 2, 2, 2,
6070 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,
6071 3, 3, 3, 3, 3,
6072 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,
6073 4, 4, 4, 4, 4, 4,
6074 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,
6075 5, 5, 5, 5, 5,
6076 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,
6077 6, 6, 6, 6, 6, 6,
6078 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,
6079 7, 7, 7, 7, 7, 7,
6080 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,
6081 8, 8, 8, 8, 8,
6082 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,
6083 9, 9, 9, 9, 9, 9,
6084 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6085 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6086 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6087 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6088
6089 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,
6090 0, 0, 0, 0, 0, 0,
6091 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,
6092 1, 1, 1, 1,
6093 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,
6094 2, 2, 2, 2, 2, 2,
6095 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,
6096 3, 3, 3, 3, 3,
6097 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,
6098 4, 4, 4, 4, 4, 4,
6099 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,
6100 5, 5, 5, 5, 5,
6101 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,
6102 6, 6, 6, 6, 6, 6,
6103 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,
6104 7, 7, 7, 7, 7, 7,
6105 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,
6106 8, 8, 8, 8, 8,
6107 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,
6108 9, 9, 9, 9, 9, 9,
6109 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6110 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6111 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6112 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6113
6114 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,
6115 0, 0, 0, 0, 0, 0,
6116 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,
6117 1, 1, 1,
6118 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,
6119 2, 2, 2, 2, 2, 2,
6120 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,
6121 3, 3, 3, 3, 3,
6122 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,
6123 4, 4, 4, 4, 4, 4,
6124 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,
6125 5, 5, 5, 5, 5,
6126 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,
6127 6, 6, 6, 6, 6, 6,
6128 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,
6129 7, 7, 7, 7, 7, 7,
6130 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,
6131 8, 8, 8, 8, 8,
6132 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,
6133 9, 9, 9, 9, 9, 9,
6134 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6135 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6136 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6137 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6138
6139
6140// This function works for dates from 1970 to 2099.
6141static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006142 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006143#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006144 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006145#endif
6146
6147 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6148 date %= kDaysIn4Years;
6149
6150 month = kMonthInYear[date];
6151 day = kDayInYear[date];
6152
6153 ASSERT(MakeDay(year, month, day) == save_date);
6154}
6155
6156
6157static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006158 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006159#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006160 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006161#endif
6162
6163 date += kDaysOffset;
6164 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6165 date %= kDaysIn400Years;
6166
6167 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6168
6169 date--;
6170 int yd1 = date / kDaysIn100Years;
6171 date %= kDaysIn100Years;
6172 year += 100 * yd1;
6173
6174 date++;
6175 int yd2 = date / kDaysIn4Years;
6176 date %= kDaysIn4Years;
6177 year += 4 * yd2;
6178
6179 date--;
6180 int yd3 = date / 365;
6181 date %= 365;
6182 year += yd3;
6183
6184 bool is_leap = (!yd1 || yd2) && !yd3;
6185
6186 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006187 ASSERT(is_leap || (date >= 0));
6188 ASSERT((date < 365) || (is_leap && (date < 366)));
6189 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6190 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6191 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006192
6193 if (is_leap) {
6194 day = kDayInYear[2*365 + 1 + date];
6195 month = kMonthInYear[2*365 + 1 + date];
6196 } else {
6197 day = kDayInYear[date];
6198 month = kMonthInYear[date];
6199 }
6200
6201 ASSERT(MakeDay(year, month, day) == save_date);
6202}
6203
6204
6205static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006206 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006207 if (date >= 0 && date < 32 * kDaysIn4Years) {
6208 DateYMDFromTimeAfter1970(date, year, month, day);
6209 } else {
6210 DateYMDFromTimeSlow(date, year, month, day);
6211 }
6212}
6213
6214
6215static Object* Runtime_DateYMDFromTime(Arguments args) {
6216 NoHandleAllocation ha;
6217 ASSERT(args.length() == 2);
6218
6219 CONVERT_DOUBLE_CHECKED(t, args[0]);
6220 CONVERT_CHECKED(JSArray, res_array, args[1]);
6221
6222 int year, month, day;
6223 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6224
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006225 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6226 FixedArray* elms = FixedArray::cast(res_array->elements());
6227 RUNTIME_ASSERT(elms->length() == 3);
6228
6229 elms->set(0, Smi::FromInt(year));
6230 elms->set(1, Smi::FromInt(month));
6231 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006232
6233 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006234}
6235
6236
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006237static Object* Runtime_NewArgumentsFast(Arguments args) {
6238 NoHandleAllocation ha;
6239 ASSERT(args.length() == 3);
6240
6241 JSFunction* callee = JSFunction::cast(args[0]);
6242 Object** parameters = reinterpret_cast<Object**>(args[1]);
6243 const int length = Smi::cast(args[2])->value();
6244
6245 Object* result = Heap::AllocateArgumentsObject(callee, length);
6246 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006247 // Allocate the elements if needed.
6248 if (length > 0) {
6249 // Allocate the fixed array.
6250 Object* obj = Heap::AllocateRawFixedArray(length);
6251 if (obj->IsFailure()) return obj;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006252
6253 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006254 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6255 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006256 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006257
6258 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006259 for (int i = 0; i < length; i++) {
6260 array->set(i, *--parameters, mode);
6261 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006262 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006263 }
6264 return result;
6265}
6266
6267
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006268static Object* Runtime_NewClosure(Arguments args) {
6269 HandleScope scope;
6270 ASSERT(args.length() == 2);
ager@chromium.org3811b432009-10-28 14:53:37 +00006271 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006272 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006273
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00006274 PretenureFlag pretenure = (context->global_context() == *context)
6275 ? TENURED // Allocate global closures in old space.
6276 : NOT_TENURED; // Allocate local closures in new space.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006277 Handle<JSFunction> result =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006278 Factory::NewFunctionFromSharedFunctionInfo(shared, context, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006279 return *result;
6280}
6281
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006282static Object* Runtime_NewObjectFromBound(Arguments args) {
6283 HandleScope scope;
6284 ASSERT(args.length() == 2);
6285 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6286 CONVERT_ARG_CHECKED(JSArray, params, 1);
6287
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006288 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006289 FixedArray* fixed = FixedArray::cast(params->elements());
6290
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006291 int fixed_length = Smi::cast(params->length())->value();
6292 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6293 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006294 Handle<Object> val = Handle<Object>(fixed->get(i));
6295 param_data[i] = val.location();
6296 }
6297
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006298 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006299 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006300 function, fixed_length, *param_data, &exception);
6301 if (exception) {
6302 return Failure::Exception();
6303 }
6304 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006305 return *result;
6306}
6307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006308
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006309static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006310 Handle<Object> prototype = Factory::null_value();
6311 if (function->has_instance_prototype()) {
6312 prototype = Handle<Object>(function->instance_prototype());
6313 }
6314 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006315 ConstructStubCompiler compiler;
ager@chromium.org5c838252010-02-19 08:53:10 +00006316 Object* code = compiler.CompileConstructStub(function->shared());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006317 if (!code->IsFailure()) {
6318 function->shared()->set_construct_stub(Code::cast(code));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006319 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006320 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006321}
6322
6323
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006324static Object* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006325 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006326 ASSERT(args.length() == 1);
6327
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006328 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006329
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006330 // If the constructor isn't a proper function we throw a type error.
6331 if (!constructor->IsJSFunction()) {
6332 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6333 Handle<Object> type_error =
6334 Factory::NewTypeError("not_constructor", arguments);
6335 return Top::Throw(*type_error);
6336 }
6337
6338 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006339
6340 // If function should not have prototype, construction is not allowed. In this
6341 // case generated code bailouts here, since function has no initial_map.
6342 if (!function->should_have_prototype()) {
6343 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6344 Handle<Object> type_error =
6345 Factory::NewTypeError("not_constructor", arguments);
6346 return Top::Throw(*type_error);
6347 }
6348
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006349#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006350 // Handle stepping into constructors if step into is active.
6351 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006352 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006353 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006354#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006355
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006356 if (function->has_initial_map()) {
6357 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006358 // The 'Function' function ignores the receiver object when
6359 // called using 'new' and creates a new JSFunction object that
6360 // is returned. The receiver object is only used for error
6361 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006362 // JSFunction. Factory::NewJSObject() should not be used to
6363 // allocate JSFunctions since it does not properly initialize
6364 // the shared part of the function. Since the receiver is
6365 // ignored anyway, we use the global object as the receiver
6366 // instead of a new JSFunction object. This way, errors are
6367 // reported the same way whether or not 'Function' is called
6368 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006369 return Top::context()->global();
6370 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006371 }
6372
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006373 // The function should be compiled for the optimization hints to be available.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006374 Handle<SharedFunctionInfo> shared(function->shared());
6375 EnsureCompiled(shared, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006376
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006377 if (!function->has_initial_map() &&
6378 shared->IsInobjectSlackTrackingInProgress()) {
6379 // The tracking is already in progress for another function. We can only
6380 // track one initial_map at a time, so we force the completion before the
6381 // function is called as a constructor for the first time.
6382 shared->CompleteInobjectSlackTracking();
6383 TrySettingInlineConstructStub(function);
6384 }
6385
6386 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006387 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006388 // Delay setting the stub if inobject slack tracking is in progress.
6389 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6390 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006391 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006392
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006393 Counters::constructed_objects.Increment();
6394 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006395
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006396 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006397}
6398
6399
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006400static Object* Runtime_FinalizeInstanceSize(Arguments args) {
6401 HandleScope scope;
6402 ASSERT(args.length() == 1);
6403
6404 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6405 function->shared()->CompleteInobjectSlackTracking();
6406 TrySettingInlineConstructStub(function);
6407
6408 return Heap::undefined_value();
6409}
6410
6411
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006412static Object* Runtime_LazyCompile(Arguments args) {
6413 HandleScope scope;
6414 ASSERT(args.length() == 1);
6415
6416 Handle<JSFunction> function = args.at<JSFunction>(0);
6417#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006418 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006419 PrintF("[lazy: ");
6420 function->shared()->name()->Print();
6421 PrintF("]\n");
6422 }
6423#endif
6424
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006425 // Compile the target function. Here we compile using CompileLazyInLoop in
6426 // order to get the optimized version. This helps code like delta-blue
6427 // that calls performance-critical routines through constructors. A
6428 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6429 // direct call. Since the in-loop tracking takes place through CallICs
6430 // this means that things called through constructors are never known to
6431 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006432 ASSERT(!function->is_compiled());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006433 if (!CompileLazyInLoop(function, Handle<Object>::null(), KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006434 return Failure::Exception();
6435 }
6436
6437 return function->code();
6438}
6439
6440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441static Object* Runtime_GetFunctionDelegate(Arguments args) {
6442 HandleScope scope;
6443 ASSERT(args.length() == 1);
6444 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6445 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6446}
6447
6448
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006449static Object* Runtime_GetConstructorDelegate(Arguments args) {
6450 HandleScope scope;
6451 ASSERT(args.length() == 1);
6452 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6453 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6454}
6455
6456
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457static Object* Runtime_NewContext(Arguments args) {
6458 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006459 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006460
kasper.lund7276f142008-07-30 08:49:36 +00006461 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006462 int length = function->shared()->scope_info()->NumberOfContextSlots();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006463 Object* result = Heap::AllocateFunctionContext(length, function);
6464 if (result->IsFailure()) return result;
6465
6466 Top::set_context(Context::cast(result));
6467
kasper.lund7276f142008-07-30 08:49:36 +00006468 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006469}
6470
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006471static Object* PushContextHelper(Object* object, bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006472 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006473 Object* js_object = object;
6474 if (!js_object->IsJSObject()) {
6475 js_object = js_object->ToObject();
6476 if (js_object->IsFailure()) {
6477 if (!Failure::cast(js_object)->IsInternalError()) return js_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006478 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006479 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006480 Handle<Object> result =
6481 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
6482 return Top::Throw(*result);
6483 }
6484 }
6485
6486 Object* result =
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006487 Heap::AllocateWithContext(Top::context(),
6488 JSObject::cast(js_object),
6489 is_catch_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006490 if (result->IsFailure()) return result;
6491
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006492 Context* context = Context::cast(result);
6493 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006494
kasper.lund7276f142008-07-30 08:49:36 +00006495 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006496}
6497
6498
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006499static Object* Runtime_PushContext(Arguments args) {
6500 NoHandleAllocation ha;
6501 ASSERT(args.length() == 1);
6502 return PushContextHelper(args[0], false);
6503}
6504
6505
6506static Object* Runtime_PushCatchContext(Arguments args) {
6507 NoHandleAllocation ha;
6508 ASSERT(args.length() == 1);
6509 return PushContextHelper(args[0], true);
6510}
6511
6512
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006513static Object* Runtime_LookupContext(Arguments args) {
6514 HandleScope scope;
6515 ASSERT(args.length() == 2);
6516
6517 CONVERT_ARG_CHECKED(Context, context, 0);
6518 CONVERT_ARG_CHECKED(String, name, 1);
6519
6520 int index;
6521 PropertyAttributes attributes;
6522 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006523 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006524 context->Lookup(name, flags, &index, &attributes);
6525
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006526 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006527 ASSERT(holder->IsJSObject());
6528 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006529 }
6530
6531 // No intermediate context found. Use global object by default.
6532 return Top::context()->global();
6533}
6534
6535
ager@chromium.orga1645e22009-09-09 19:27:10 +00006536// A mechanism to return a pair of Object pointers in registers (if possible).
6537// How this is achieved is calling convention-dependent.
6538// All currently supported x86 compiles uses calling conventions that are cdecl
6539// variants where a 64-bit value is returned in two 32-bit registers
6540// (edx:eax on ia32, r1:r0 on ARM).
6541// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
6542// In Win64 calling convention, a struct of two pointers is returned in memory,
6543// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006544#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006545struct ObjectPair {
6546 Object* x;
6547 Object* y;
6548};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006549
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006550static inline ObjectPair MakePair(Object* x, Object* y) {
6551 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006552 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
6553 // In Win64 they are assigned to a hidden first argument.
6554 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006555}
6556#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006557typedef uint64_t ObjectPair;
6558static inline ObjectPair MakePair(Object* x, Object* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006559 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006560 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006561}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006562#endif
6563
6564
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006565static inline Object* Unhole(Object* x, PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
6567 USE(attributes);
6568 return x->IsTheHole() ? Heap::undefined_value() : x;
6569}
6570
6571
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006572static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
6573 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006574 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006575 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006576 JSFunction* context_extension_function =
6577 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006578 // If the holder isn't a context extension object, we just return it
6579 // as the receiver. This allows arguments objects to be used as
6580 // receivers, but only if they are put in the context scope chain
6581 // explicitly via a with-statement.
6582 Object* constructor = holder->map()->constructor();
6583 if (constructor != context_extension_function) return holder;
6584 // Fall back to using the global object as the receiver if the
6585 // property turns out to be a local variable allocated in a context
6586 // extension object - introduced via eval.
6587 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006588}
6589
6590
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006591static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006592 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006593 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006595 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00006596 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006597 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006598 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006599 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006600
6601 int index;
6602 PropertyAttributes attributes;
6603 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006604 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605 context->Lookup(name, flags, &index, &attributes);
6606
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006607 // If the index is non-negative, the slot has been found in a local
6608 // variable or a parameter. Read it from the context object or the
6609 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006611 // If the "property" we were looking for is a local variable or an
6612 // argument in a context, the receiver is the global object; see
6613 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
6614 JSObject* receiver = Top::context()->global()->global_receiver();
6615 Object* value = (holder->IsContext())
6616 ? Context::cast(*holder)->get(index)
6617 : JSObject::cast(*holder)->GetElement(index);
6618 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619 }
6620
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006621 // If the holder is found, we read the property from it.
6622 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006623 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006624 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006625 JSObject* receiver;
6626 if (object->IsGlobalObject()) {
6627 receiver = GlobalObject::cast(object)->global_receiver();
6628 } else if (context->is_exception_holder(*holder)) {
6629 receiver = Top::context()->global()->global_receiver();
6630 } else {
6631 receiver = ComputeReceiverForNonGlobal(object);
6632 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006633 // No need to unhole the value here. This is taken care of by the
6634 // GetProperty function.
6635 Object* value = object->GetProperty(*name);
6636 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637 }
6638
6639 if (throw_error) {
6640 // The property doesn't exist - throw exception.
6641 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006642 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006643 return MakePair(Top::Throw(*reference_error), NULL);
6644 } else {
6645 // The property doesn't exist - return undefined
6646 return MakePair(Heap::undefined_value(), Heap::undefined_value());
6647 }
6648}
6649
6650
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006651static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 return LoadContextSlotHelper(args, true);
6653}
6654
6655
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006656static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006657 return LoadContextSlotHelper(args, false);
6658}
6659
6660
6661static Object* Runtime_StoreContextSlot(Arguments args) {
6662 HandleScope scope;
6663 ASSERT(args.length() == 3);
6664
6665 Handle<Object> value(args[0]);
6666 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006667 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006668
6669 int index;
6670 PropertyAttributes attributes;
6671 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006672 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006673 context->Lookup(name, flags, &index, &attributes);
6674
6675 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006676 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677 // Ignore if read_only variable.
6678 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006679 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006680 }
6681 } else {
6682 ASSERT((attributes & READ_ONLY) == 0);
6683 Object* result =
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006684 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006685 USE(result);
6686 ASSERT(!result->IsFailure());
6687 }
6688 return *value;
6689 }
6690
6691 // Slow case: The property is not in a FixedArray context.
6692 // It is either in an JSObject extension context or it was not found.
6693 Handle<JSObject> context_ext;
6694
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006695 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006696 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006697 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006698 } else {
6699 // The property was not found. It needs to be stored in the global context.
6700 ASSERT(attributes == ABSENT);
6701 attributes = NONE;
6702 context_ext = Handle<JSObject>(Top::context()->global());
6703 }
6704
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006705 // Set the property, but ignore if read_only variable on the context
6706 // extension object itself.
6707 if ((attributes & READ_ONLY) == 0 ||
6708 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
6710 if (set.is_null()) {
6711 // Failure::Exception is converted to a null handle in the
6712 // handle-based methods such as SetProperty. We therefore need
6713 // to convert null handles back to exceptions.
6714 ASSERT(Top::has_pending_exception());
6715 return Failure::Exception();
6716 }
6717 }
6718 return *value;
6719}
6720
6721
6722static Object* Runtime_Throw(Arguments args) {
6723 HandleScope scope;
6724 ASSERT(args.length() == 1);
6725
6726 return Top::Throw(args[0]);
6727}
6728
6729
6730static Object* Runtime_ReThrow(Arguments args) {
6731 HandleScope scope;
6732 ASSERT(args.length() == 1);
6733
6734 return Top::ReThrow(args[0]);
6735}
6736
6737
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006738static Object* Runtime_PromoteScheduledException(Arguments args) {
6739 ASSERT_EQ(0, args.length());
6740 return Top::PromoteScheduledException();
6741}
6742
6743
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006744static Object* Runtime_ThrowReferenceError(Arguments args) {
6745 HandleScope scope;
6746 ASSERT(args.length() == 1);
6747
6748 Handle<Object> name(args[0]);
6749 Handle<Object> reference_error =
6750 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
6751 return Top::Throw(*reference_error);
6752}
6753
6754
6755static Object* Runtime_StackOverflow(Arguments args) {
6756 NoHandleAllocation na;
6757 return Top::StackOverflow();
6758}
6759
6760
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761static Object* Runtime_StackGuard(Arguments args) {
6762 ASSERT(args.length() == 1);
6763
6764 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00006765 if (StackGuard::IsStackOverflow()) {
6766 return Runtime_StackOverflow(args);
6767 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006768
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006769 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770}
6771
6772
6773// NOTE: These PrintXXX functions are defined for all builds (not just
6774// DEBUG builds) because we may want to be able to trace function
6775// calls in all modes.
6776static void PrintString(String* str) {
6777 // not uncommon to have empty strings
6778 if (str->length() > 0) {
6779 SmartPointer<char> s =
6780 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
6781 PrintF("%s", *s);
6782 }
6783}
6784
6785
6786static void PrintObject(Object* obj) {
6787 if (obj->IsSmi()) {
6788 PrintF("%d", Smi::cast(obj)->value());
6789 } else if (obj->IsString() || obj->IsSymbol()) {
6790 PrintString(String::cast(obj));
6791 } else if (obj->IsNumber()) {
6792 PrintF("%g", obj->Number());
6793 } else if (obj->IsFailure()) {
6794 PrintF("<failure>");
6795 } else if (obj->IsUndefined()) {
6796 PrintF("<undefined>");
6797 } else if (obj->IsNull()) {
6798 PrintF("<null>");
6799 } else if (obj->IsTrue()) {
6800 PrintF("<true>");
6801 } else if (obj->IsFalse()) {
6802 PrintF("<false>");
6803 } else {
6804 PrintF("%p", obj);
6805 }
6806}
6807
6808
6809static int StackSize() {
6810 int n = 0;
6811 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
6812 return n;
6813}
6814
6815
6816static void PrintTransition(Object* result) {
6817 // indentation
6818 { const int nmax = 80;
6819 int n = StackSize();
6820 if (n <= nmax)
6821 PrintF("%4d:%*s", n, n, "");
6822 else
6823 PrintF("%4d:%*s", n, nmax, "...");
6824 }
6825
6826 if (result == NULL) {
6827 // constructor calls
6828 JavaScriptFrameIterator it;
6829 JavaScriptFrame* frame = it.frame();
6830 if (frame->IsConstructor()) PrintF("new ");
6831 // function name
6832 Object* fun = frame->function();
6833 if (fun->IsJSFunction()) {
6834 PrintObject(JSFunction::cast(fun)->shared()->name());
6835 } else {
6836 PrintObject(fun);
6837 }
6838 // function arguments
6839 // (we are intentionally only printing the actually
6840 // supplied parameters, not all parameters required)
6841 PrintF("(this=");
6842 PrintObject(frame->receiver());
6843 const int length = frame->GetProvidedParametersCount();
6844 for (int i = 0; i < length; i++) {
6845 PrintF(", ");
6846 PrintObject(frame->GetParameter(i));
6847 }
6848 PrintF(") {\n");
6849
6850 } else {
6851 // function result
6852 PrintF("} -> ");
6853 PrintObject(result);
6854 PrintF("\n");
6855 }
6856}
6857
6858
6859static Object* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006860 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006861 NoHandleAllocation ha;
6862 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006863 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006864}
6865
6866
6867static Object* Runtime_TraceExit(Arguments args) {
6868 NoHandleAllocation ha;
6869 PrintTransition(args[0]);
6870 return args[0]; // return TOS
6871}
6872
6873
6874static Object* Runtime_DebugPrint(Arguments args) {
6875 NoHandleAllocation ha;
6876 ASSERT(args.length() == 1);
6877
6878#ifdef DEBUG
6879 if (args[0]->IsString()) {
6880 // If we have a string, assume it's a code "marker"
6881 // and print some interesting cpu debugging info.
6882 JavaScriptFrameIterator it;
6883 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00006884 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
6885 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006886 } else {
6887 PrintF("DebugPrint: ");
6888 }
6889 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006890 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006891 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006892 HeapObject::cast(args[0])->map()->Print();
6893 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006894#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006895 // ShortPrint is available in release mode. Print is not.
6896 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006897#endif
6898 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00006899 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006900
6901 return args[0]; // return TOS
6902}
6903
6904
6905static Object* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006906 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006907 NoHandleAllocation ha;
6908 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006909 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006910}
6911
6912
mads.s.ager31e71382008-08-13 09:32:07 +00006913static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006914 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00006915 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006916
6917 // According to ECMA-262, section 15.9.1, page 117, the precision of
6918 // the number in a Date object representing a particular instant in
6919 // time is milliseconds. Therefore, we floor the result of getting
6920 // the OS time.
6921 double millis = floor(OS::TimeCurrentMillis());
6922 return Heap::NumberFromDouble(millis);
6923}
6924
6925
6926static Object* Runtime_DateParseString(Arguments args) {
6927 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006928 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006929
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006930 CONVERT_ARG_CHECKED(String, str, 0);
6931 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006932
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006933 CONVERT_ARG_CHECKED(JSArray, output, 1);
6934 RUNTIME_ASSERT(output->HasFastElements());
6935
6936 AssertNoAllocation no_allocation;
6937
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006938 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006939 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
6940 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00006941 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006942 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006943 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00006944 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006945 result = DateParser::Parse(str->ToUC16Vector(), output_array);
6946 }
6947
6948 if (result) {
6949 return *output;
6950 } else {
6951 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006952 }
6953}
6954
6955
6956static Object* Runtime_DateLocalTimezone(Arguments args) {
6957 NoHandleAllocation ha;
6958 ASSERT(args.length() == 1);
6959
6960 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00006961 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006962 return Heap::AllocateStringFromUtf8(CStrVector(zone));
6963}
6964
6965
6966static Object* Runtime_DateLocalTimeOffset(Arguments args) {
6967 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00006968 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006969
6970 return Heap::NumberFromDouble(OS::LocalTimeOffset());
6971}
6972
6973
6974static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
6975 NoHandleAllocation ha;
6976 ASSERT(args.length() == 1);
6977
6978 CONVERT_DOUBLE_CHECKED(x, args[0]);
6979 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
6980}
6981
6982
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006983static Object* Runtime_GlobalReceiver(Arguments args) {
6984 ASSERT(args.length() == 1);
6985 Object* global = args[0];
6986 if (!global->IsJSGlobalObject()) return Heap::null_value();
6987 return JSGlobalObject::cast(global)->global_receiver();
6988}
6989
6990
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006991static Object* Runtime_CompileString(Arguments args) {
6992 HandleScope scope;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006993 ASSERT_EQ(2, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006994 CONVERT_ARG_CHECKED(String, source, 0);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006995 CONVERT_ARG_CHECKED(Oddball, is_json, 1)
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006996
ager@chromium.org381abbb2009-02-25 13:23:22 +00006997 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006998 Handle<Context> context(Top::context()->global_context());
ager@chromium.orgadd848f2009-08-13 12:44:13 +00006999 Compiler::ValidationState validate = (is_json->IsTrue())
7000 ? Compiler::VALIDATE_JSON : Compiler::DONT_VALIDATE_JSON;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007001 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7002 context,
7003 true,
7004 validate);
7005 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007006 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007007 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007008 return *fun;
7009}
7010
7011
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007012static ObjectPair CompileGlobalEval(Handle<String> source,
7013 Handle<Object> receiver) {
7014 // Deal with a normal eval call with a string argument. Compile it
7015 // and return the compiled function bound in the local context.
7016 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7017 source,
7018 Handle<Context>(Top::context()),
7019 Top::context()->IsGlobalContext(),
7020 Compiler::DONT_VALIDATE_JSON);
7021 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7022 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7023 shared,
7024 Handle<Context>(Top::context()),
7025 NOT_TENURED);
7026 return MakePair(*compiled, *receiver);
7027}
7028
7029
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007030static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
7031 ASSERT(args.length() == 3);
7032 if (!args[0]->IsJSFunction()) {
7033 return MakePair(Top::ThrowIllegalOperation(), NULL);
7034 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007035
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007036 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007037 Handle<JSFunction> callee = args.at<JSFunction>(0);
7038 Handle<Object> receiver; // Will be overwritten.
7039
7040 // Compute the calling context.
7041 Handle<Context> context = Handle<Context>(Top::context());
7042#ifdef DEBUG
7043 // Make sure Top::context() agrees with the old code that traversed
7044 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007045 StackFrameLocator locator;
7046 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007047 ASSERT(Context::cast(frame->context()) == *context);
7048#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007049
7050 // Find where the 'eval' symbol is bound. It is unaliased only if
7051 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007052 int index = -1;
7053 PropertyAttributes attributes = ABSENT;
7054 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007055 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7056 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007057 // Stop search when eval is found or when the global context is
7058 // reached.
7059 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007060 if (context->is_function_context()) {
7061 context = Handle<Context>(Context::cast(context->closure()->context()));
7062 } else {
7063 context = Handle<Context>(context->previous());
7064 }
7065 }
7066
iposva@chromium.org245aa852009-02-10 00:49:54 +00007067 // If eval could not be resolved, it has been deleted and we need to
7068 // throw a reference error.
7069 if (attributes == ABSENT) {
7070 Handle<Object> name = Factory::eval_symbol();
7071 Handle<Object> reference_error =
7072 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007073 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007074 }
7075
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007076 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007077 // 'eval' is not bound in the global context. Just call the function
7078 // with the given arguments. This is not necessarily the global eval.
7079 if (receiver->IsContext()) {
7080 context = Handle<Context>::cast(receiver);
7081 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007082 } else if (receiver->IsJSContextExtensionObject()) {
7083 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007084 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007085 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007086 }
7087
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007088 // 'eval' is bound in the global context, but it may have been overwritten.
7089 // Compare it to the builtin 'GlobalEval' function to make sure.
7090 if (*callee != Top::global_context()->global_eval_fun() ||
7091 !args[1]->IsString()) {
7092 return MakePair(*callee, Top::context()->global()->global_receiver());
7093 }
7094
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007095 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7096}
7097
7098
7099static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7100 ASSERT(args.length() == 3);
7101 if (!args[0]->IsJSFunction()) {
7102 return MakePair(Top::ThrowIllegalOperation(), NULL);
7103 }
7104
7105 HandleScope scope;
7106 Handle<JSFunction> callee = args.at<JSFunction>(0);
7107
7108 // 'eval' is bound in the global context, but it may have been overwritten.
7109 // Compare it to the builtin 'GlobalEval' function to make sure.
7110 if (*callee != Top::global_context()->global_eval_fun() ||
7111 !args[1]->IsString()) {
7112 return MakePair(*callee, Top::context()->global()->global_receiver());
7113 }
7114
7115 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007116}
7117
7118
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007119static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
7120 // This utility adjusts the property attributes for newly created Function
7121 // object ("new Function(...)") by changing the map.
7122 // All it does is changing the prototype property to enumerable
7123 // as specified in ECMA262, 15.3.5.2.
7124 HandleScope scope;
7125 ASSERT(args.length() == 1);
7126 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7127 ASSERT(func->map()->instance_type() ==
7128 Top::function_instance_map()->instance_type());
7129 ASSERT(func->map()->instance_size() ==
7130 Top::function_instance_map()->instance_size());
7131 func->set_map(*Top::function_instance_map());
7132 return *func;
7133}
7134
7135
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007136static Object* Runtime_AllocateInNewSpace(Arguments args) {
7137 // Allocate a block of memory in NewSpace (filled with a filler).
7138 // Use as fallback for allocation in generated code when NewSpace
7139 // is full.
7140 ASSERT(args.length() == 1);
7141 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7142 int size = size_smi->value();
7143 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7144 RUNTIME_ASSERT(size > 0);
7145 static const int kMinFreeNewSpaceAfterGC =
7146 Heap::InitialSemiSpaceSize() * 3/4;
7147 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
7148 Object* allocation = Heap::new_space()->AllocateRaw(size);
7149 if (!allocation->IsFailure()) {
7150 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7151 }
7152 return allocation;
7153}
7154
7155
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007156// Push an array unto an array of arrays if it is not already in the
7157// array. Returns true if the element was pushed on the stack and
7158// false otherwise.
7159static Object* Runtime_PushIfAbsent(Arguments args) {
7160 ASSERT(args.length() == 2);
7161 CONVERT_CHECKED(JSArray, array, args[0]);
7162 CONVERT_CHECKED(JSArray, element, args[1]);
7163 RUNTIME_ASSERT(array->HasFastElements());
7164 int length = Smi::cast(array->length())->value();
7165 FixedArray* elements = FixedArray::cast(array->elements());
7166 for (int i = 0; i < length; i++) {
7167 if (elements->get(i) == element) return Heap::false_value();
7168 }
7169 Object* obj = array->SetFastElement(length, element);
7170 if (obj->IsFailure()) return obj;
7171 return Heap::true_value();
7172}
7173
7174
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007175/**
7176 * A simple visitor visits every element of Array's.
7177 * The backend storage can be a fixed array for fast elements case,
7178 * or a dictionary for sparse array. Since Dictionary is a subtype
7179 * of FixedArray, the class can be used by both fast and slow cases.
7180 * The second parameter of the constructor, fast_elements, specifies
7181 * whether the storage is a FixedArray or Dictionary.
7182 *
7183 * An index limit is used to deal with the situation that a result array
7184 * length overflows 32-bit non-negative integer.
7185 */
7186class ArrayConcatVisitor {
7187 public:
7188 ArrayConcatVisitor(Handle<FixedArray> storage,
7189 uint32_t index_limit,
7190 bool fast_elements) :
7191 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007192 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007193
7194 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007195 if (i >= index_limit_ - index_offset_) return;
7196 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007197
7198 if (fast_elements_) {
7199 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7200 storage_->set(index, *elm);
7201
7202 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007203 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7204 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007205 Factory::DictionaryAtNumberPut(dict, index, elm);
7206 if (!result.is_identical_to(dict))
7207 storage_ = result;
7208 }
7209 }
7210
7211 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007212 if (index_limit_ - index_offset_ < delta) {
7213 index_offset_ = index_limit_;
7214 } else {
7215 index_offset_ += delta;
7216 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007217 }
7218
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007219 Handle<FixedArray> storage() { return storage_; }
7220
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007221 private:
7222 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007223 // Limit on the accepted indices. Elements with indices larger than the
7224 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007225 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007226 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007227 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007228 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007229};
7230
7231
ager@chromium.org3811b432009-10-28 14:53:37 +00007232template<class ExternalArrayClass, class ElementType>
7233static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7234 bool elements_are_ints,
7235 bool elements_are_guaranteed_smis,
7236 uint32_t range,
7237 ArrayConcatVisitor* visitor) {
7238 Handle<ExternalArrayClass> array(
7239 ExternalArrayClass::cast(receiver->elements()));
7240 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7241
7242 if (visitor != NULL) {
7243 if (elements_are_ints) {
7244 if (elements_are_guaranteed_smis) {
7245 for (uint32_t j = 0; j < len; j++) {
7246 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7247 visitor->visit(j, e);
7248 }
7249 } else {
7250 for (uint32_t j = 0; j < len; j++) {
7251 int64_t val = static_cast<int64_t>(array->get(j));
7252 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7253 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7254 visitor->visit(j, e);
7255 } else {
7256 Handle<Object> e(
7257 Heap::AllocateHeapNumber(static_cast<ElementType>(val)));
7258 visitor->visit(j, e);
7259 }
7260 }
7261 }
7262 } else {
7263 for (uint32_t j = 0; j < len; j++) {
7264 Handle<Object> e(Heap::AllocateHeapNumber(array->get(j)));
7265 visitor->visit(j, e);
7266 }
7267 }
7268 }
7269
7270 return len;
7271}
7272
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007273/**
7274 * A helper function that visits elements of a JSObject. Only elements
7275 * whose index between 0 and range (exclusive) are visited.
7276 *
7277 * If the third parameter, visitor, is not NULL, the visitor is called
7278 * with parameters, 'visitor_index_offset + element index' and the element.
7279 *
7280 * It returns the number of visisted elements.
7281 */
7282static uint32_t IterateElements(Handle<JSObject> receiver,
7283 uint32_t range,
7284 ArrayConcatVisitor* visitor) {
7285 uint32_t num_of_elements = 0;
7286
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007287 switch (receiver->GetElementsKind()) {
7288 case JSObject::FAST_ELEMENTS: {
7289 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7290 uint32_t len = elements->length();
7291 if (range < len) {
7292 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007293 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007294
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007295 for (uint32_t j = 0; j < len; j++) {
7296 Handle<Object> e(elements->get(j));
7297 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007298 num_of_elements++;
7299 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007300 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007301 }
7302 }
7303 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007304 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007305 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007306 case JSObject::PIXEL_ELEMENTS: {
7307 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7308 uint32_t len = pixels->length();
7309 if (range < len) {
7310 len = range;
7311 }
7312
7313 for (uint32_t j = 0; j < len; j++) {
7314 num_of_elements++;
7315 if (visitor != NULL) {
7316 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7317 visitor->visit(j, e);
7318 }
7319 }
7320 break;
7321 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007322 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7323 num_of_elements =
7324 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7325 receiver, true, true, range, visitor);
7326 break;
7327 }
7328 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7329 num_of_elements =
7330 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7331 receiver, true, true, range, visitor);
7332 break;
7333 }
7334 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7335 num_of_elements =
7336 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7337 receiver, true, true, range, visitor);
7338 break;
7339 }
7340 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7341 num_of_elements =
7342 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7343 receiver, true, true, range, visitor);
7344 break;
7345 }
7346 case JSObject::EXTERNAL_INT_ELEMENTS: {
7347 num_of_elements =
7348 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7349 receiver, true, false, range, visitor);
7350 break;
7351 }
7352 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7353 num_of_elements =
7354 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7355 receiver, true, false, range, visitor);
7356 break;
7357 }
7358 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7359 num_of_elements =
7360 IterateExternalArrayElements<ExternalFloatArray, float>(
7361 receiver, false, false, range, visitor);
7362 break;
7363 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007364 case JSObject::DICTIONARY_ELEMENTS: {
7365 Handle<NumberDictionary> dict(receiver->element_dictionary());
7366 uint32_t capacity = dict->Capacity();
7367 for (uint32_t j = 0; j < capacity; j++) {
7368 Handle<Object> k(dict->KeyAt(j));
7369 if (dict->IsKey(*k)) {
7370 ASSERT(k->IsNumber());
7371 uint32_t index = static_cast<uint32_t>(k->Number());
7372 if (index < range) {
7373 num_of_elements++;
7374 if (visitor) {
7375 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7376 }
7377 }
7378 }
7379 }
7380 break;
7381 }
7382 default:
7383 UNREACHABLE();
7384 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007385 }
7386
7387 return num_of_elements;
7388}
7389
7390
7391/**
7392 * A helper function that visits elements of an Array object, and elements
7393 * on its prototypes.
7394 *
7395 * Elements on prototypes are visited first, and only elements whose indices
7396 * less than Array length are visited.
7397 *
7398 * If a ArrayConcatVisitor object is given, the visitor is called with
7399 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007400 *
7401 * The returned number of elements is an upper bound on the actual number
7402 * of elements added. If the same element occurs in more than one object
7403 * in the array's prototype chain, it will be counted more than once, but
7404 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007405 */
7406static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7407 ArrayConcatVisitor* visitor) {
7408 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7409 Handle<Object> obj = array;
7410
7411 static const int kEstimatedPrototypes = 3;
7412 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7413
7414 // Visit prototype first. If an element on the prototype is shadowed by
7415 // the inheritor using the same index, the ArrayConcatVisitor visits
7416 // the prototype element before the shadowing element.
7417 // The visitor can simply overwrite the old value by new value using
7418 // the same index. This follows Array::concat semantics.
7419 while (!obj->IsNull()) {
7420 objects.Add(Handle<JSObject>::cast(obj));
7421 obj = Handle<Object>(obj->GetPrototype());
7422 }
7423
7424 uint32_t nof_elements = 0;
7425 for (int i = objects.length() - 1; i >= 0; i--) {
7426 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007427 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007428 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007429
7430 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7431 nof_elements = JSObject::kMaxElementCount;
7432 } else {
7433 nof_elements += encountered_elements;
7434 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007435 }
7436
7437 return nof_elements;
7438}
7439
7440
7441/**
7442 * A helper function of Runtime_ArrayConcat.
7443 *
7444 * The first argument is an Array of arrays and objects. It is the
7445 * same as the arguments array of Array::concat JS function.
7446 *
7447 * If an argument is an Array object, the function visits array
7448 * elements. If an argument is not an Array object, the function
7449 * visits the object as if it is an one-element array.
7450 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007451 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007452 * non-negative number is used as new length. For example, if one
7453 * array length is 2^32 - 1, second array length is 1, the
7454 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007455 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
7456 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007457 */
7458static uint32_t IterateArguments(Handle<JSArray> arguments,
7459 ArrayConcatVisitor* visitor) {
7460 uint32_t visited_elements = 0;
7461 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7462
7463 for (uint32_t i = 0; i < num_of_args; i++) {
7464 Handle<Object> obj(arguments->GetElement(i));
7465 if (obj->IsJSArray()) {
7466 Handle<JSArray> array = Handle<JSArray>::cast(obj);
7467 uint32_t len = static_cast<uint32_t>(array->length()->Number());
7468 uint32_t nof_elements =
7469 IterateArrayAndPrototypeElements(array, visitor);
7470 // Total elements of array and its prototype chain can be more than
7471 // the array length, but ArrayConcat can only concatenate at most
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007472 // the array length number of elements. We use the length as an estimate
7473 // for the actual number of elements added.
7474 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
7475 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
7476 visited_elements = JSArray::kMaxElementCount;
7477 } else {
7478 visited_elements += added_elements;
7479 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007480 if (visitor) visitor->increase_index_offset(len);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007481 } else {
7482 if (visitor) {
7483 visitor->visit(0, obj);
7484 visitor->increase_index_offset(1);
7485 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007486 if (visited_elements < JSArray::kMaxElementCount) {
7487 visited_elements++;
7488 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007489 }
7490 }
7491 return visited_elements;
7492}
7493
7494
7495/**
7496 * Array::concat implementation.
7497 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007498 * TODO(lrn): Fix non-compliance for very large concatenations and update to
7499 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007500 */
7501static Object* Runtime_ArrayConcat(Arguments args) {
7502 ASSERT(args.length() == 1);
7503 HandleScope handle_scope;
7504
7505 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
7506 Handle<JSArray> arguments(arg_arrays);
7507
7508 // Pass 1: estimate the number of elements of the result
7509 // (it could be more than real numbers if prototype has elements).
7510 uint32_t result_length = 0;
7511 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7512
7513 { AssertNoAllocation nogc;
7514 for (uint32_t i = 0; i < num_of_args; i++) {
7515 Object* obj = arguments->GetElement(i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007516 uint32_t length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007517 if (obj->IsJSArray()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007518 length_estimate =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007519 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
7520 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007521 length_estimate = 1;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007522 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007523 if (JSObject::kMaxElementCount - result_length < length_estimate) {
7524 result_length = JSObject::kMaxElementCount;
7525 break;
7526 }
7527 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007528 }
7529 }
7530
7531 // Allocate an empty array, will set length and content later.
7532 Handle<JSArray> result = Factory::NewJSArray(0);
7533
7534 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
7535 // If estimated number of elements is more than half of length, a
7536 // fixed array (fast case) is more time and space-efficient than a
7537 // dictionary.
7538 bool fast_case = (estimate_nof_elements * 2) >= result_length;
7539
7540 Handle<FixedArray> storage;
7541 if (fast_case) {
7542 // The backing storage array must have non-existing elements to
7543 // preserve holes across concat operations.
7544 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007545 Handle<Map> fast_map =
7546 Factory::GetFastElementsMap(Handle<Map>(result->map()));
7547 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007548 } else {
7549 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
7550 uint32_t at_least_space_for = estimate_nof_elements +
7551 (estimate_nof_elements >> 2);
7552 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007553 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007554 Handle<Map> slow_map =
7555 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
7556 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007557 }
7558
7559 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
7560
7561 ArrayConcatVisitor visitor(storage, result_length, fast_case);
7562
7563 IterateArguments(arguments, &visitor);
7564
7565 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007566 // Please note the storage might have changed in the visitor.
7567 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007568
7569 return *result;
7570}
7571
7572
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007573// This will not allocate (flatten the string), but it may run
7574// very slowly for very deeply nested ConsStrings. For debugging use only.
7575static Object* Runtime_GlobalPrint(Arguments args) {
7576 NoHandleAllocation ha;
7577 ASSERT(args.length() == 1);
7578
7579 CONVERT_CHECKED(String, string, args[0]);
7580 StringInputBuffer buffer(string);
7581 while (buffer.has_more()) {
7582 uint16_t character = buffer.GetNext();
7583 PrintF("%c", character);
7584 }
7585 return string;
7586}
7587
ager@chromium.org5ec48922009-05-05 07:25:34 +00007588// Moves all own elements of an object, that are below a limit, to positions
7589// starting at zero. All undefined values are placed after non-undefined values,
7590// and are followed by non-existing element. Does not change the length
7591// property.
7592// Returns the number of non-undefined elements collected.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007593static Object* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007594 ASSERT(args.length() == 2);
7595 CONVERT_CHECKED(JSObject, object, args[0]);
7596 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
7597 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007598}
7599
7600
7601// Move contents of argument 0 (an array) to argument 1 (an array)
7602static Object* Runtime_MoveArrayContents(Arguments args) {
7603 ASSERT(args.length() == 2);
7604 CONVERT_CHECKED(JSArray, from, args[0]);
7605 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007606 HeapObject* new_elements = from->elements();
7607 Object* new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007608 if (new_elements->map() == Heap::fixed_array_map() ||
7609 new_elements->map() == Heap::fixed_cow_array_map()) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007610 new_map = to->map()->GetFastElementsMap();
7611 } else {
7612 new_map = to->map()->GetSlowElementsMap();
7613 }
7614 if (new_map->IsFailure()) return new_map;
7615 to->set_map(Map::cast(new_map));
7616 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007617 to->set_length(from->length());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007618 Object* obj = from->ResetElements();
7619 if (obj->IsFailure()) return obj;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007620 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007621 return to;
7622}
7623
7624
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007625// How many elements does this object/array have?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007626static Object* Runtime_EstimateNumberOfElements(Arguments args) {
7627 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007628 CONVERT_CHECKED(JSObject, object, args[0]);
7629 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007630 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007631 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007632 } else if (object->IsJSArray()) {
7633 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007634 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007635 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007636 }
7637}
7638
7639
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007640static Object* Runtime_SwapElements(Arguments args) {
7641 HandleScope handle_scope;
7642
7643 ASSERT_EQ(3, args.length());
7644
ager@chromium.orgac091b72010-05-05 07:34:42 +00007645 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007646 Handle<Object> key1 = args.at<Object>(1);
7647 Handle<Object> key2 = args.at<Object>(2);
7648
7649 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007650 if (!key1->ToArrayIndex(&index1)
7651 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00007652 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007653 }
7654
ager@chromium.orgac091b72010-05-05 07:34:42 +00007655 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
7656 Handle<Object> tmp1 = GetElement(jsobject, index1);
7657 Handle<Object> tmp2 = GetElement(jsobject, index2);
7658
7659 SetElement(jsobject, index1, tmp2);
7660 SetElement(jsobject, index2, tmp1);
7661
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007662 return Heap::undefined_value();
7663}
7664
7665
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007666// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007667// might have elements. Can either return keys (positive integers) or
7668// intervals (pair of a negative integer (-start-1) followed by a
7669// positive (length)) or undefined values.
7670// Intervals can span over some keys that are not in the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007671static Object* Runtime_GetArrayKeys(Arguments args) {
7672 ASSERT(args.length() == 2);
7673 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007674 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007675 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007676 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007677 // Create an array and get all the keys into it, then remove all the
7678 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007679 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007680 int keys_length = keys->length();
7681 for (int i = 0; i < keys_length; i++) {
7682 Object* key = keys->get(i);
7683 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007684 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007685 // Zap invalid keys.
7686 keys->set_undefined(i);
7687 }
7688 }
7689 return *Factory::NewJSArrayWithElements(keys);
7690 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007691 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007692 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
7693 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007694 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007695 uint32_t actual_length =
7696 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00007697 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007698 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00007699 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007700 single_interval->set(1, *length_object);
7701 return *Factory::NewJSArrayWithElements(single_interval);
7702 }
7703}
7704
7705
7706// DefineAccessor takes an optional final argument which is the
7707// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
7708// to the way accessors are implemented, it is set for both the getter
7709// and setter on the first call to DefineAccessor and ignored on
7710// subsequent calls.
7711static Object* Runtime_DefineAccessor(Arguments args) {
7712 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
7713 // Compute attributes.
7714 PropertyAttributes attributes = NONE;
7715 if (args.length() == 5) {
7716 CONVERT_CHECKED(Smi, attrs, args[4]);
7717 int value = attrs->value();
7718 // Only attribute bits should be set.
7719 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
7720 attributes = static_cast<PropertyAttributes>(value);
7721 }
7722
7723 CONVERT_CHECKED(JSObject, obj, args[0]);
7724 CONVERT_CHECKED(String, name, args[1]);
7725 CONVERT_CHECKED(Smi, flag, args[2]);
7726 CONVERT_CHECKED(JSFunction, fun, args[3]);
7727 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
7728}
7729
7730
7731static Object* Runtime_LookupAccessor(Arguments args) {
7732 ASSERT(args.length() == 3);
7733 CONVERT_CHECKED(JSObject, obj, args[0]);
7734 CONVERT_CHECKED(String, name, args[1]);
7735 CONVERT_CHECKED(Smi, flag, args[2]);
7736 return obj->LookupAccessor(name, flag->value() == 0);
7737}
7738
7739
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007740#ifdef ENABLE_DEBUGGER_SUPPORT
7741static Object* Runtime_DebugBreak(Arguments args) {
7742 ASSERT(args.length() == 0);
7743 return Execution::DebugBreakHelper();
7744}
7745
7746
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007747// Helper functions for wrapping and unwrapping stack frame ids.
7748static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007749 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007750 return Smi::FromInt(id >> 2);
7751}
7752
7753
7754static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
7755 return static_cast<StackFrame::Id>(wrapped->value() << 2);
7756}
7757
7758
7759// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00007760// args[0]: debug event listener function to set or null or undefined for
7761// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007762// args[1]: object supplied during callback
iposva@chromium.org245aa852009-02-10 00:49:54 +00007763static Object* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007764 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007765 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
7766 args[0]->IsUndefined() ||
7767 args[0]->IsNull());
7768 Handle<Object> callback = args.at<Object>(0);
7769 Handle<Object> data = args.at<Object>(1);
7770 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007771
7772 return Heap::undefined_value();
7773}
7774
7775
7776static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00007777 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007778 StackGuard::DebugBreak();
7779 return Heap::undefined_value();
7780}
7781
7782
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007783static Object* DebugLookupResultValue(Object* receiver, String* name,
7784 LookupResult* result,
ager@chromium.org32912102009-01-16 10:38:43 +00007785 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007786 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007787 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007788 case NORMAL:
7789 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007790 if (value->IsTheHole()) {
7791 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007792 }
7793 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007794 case FIELD:
7795 value =
7796 JSObject::cast(
7797 result->holder())->FastPropertyAt(result->GetFieldIndex());
7798 if (value->IsTheHole()) {
7799 return Heap::undefined_value();
7800 }
7801 return value;
7802 case CONSTANT_FUNCTION:
7803 return result->GetConstantFunction();
7804 case CALLBACKS: {
7805 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007806 if (structure->IsProxy() || structure->IsAccessorInfo()) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007807 value = receiver->GetPropertyWithCallback(
7808 receiver, structure, name, result->holder());
ager@chromium.org381abbb2009-02-25 13:23:22 +00007809 if (value->IsException()) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007810 value = Top::pending_exception();
7811 Top::clear_pending_exception();
7812 if (caught_exception != NULL) {
7813 *caught_exception = true;
7814 }
7815 }
7816 return value;
7817 } else {
7818 return Heap::undefined_value();
7819 }
7820 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007821 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007822 case MAP_TRANSITION:
7823 case CONSTANT_TRANSITION:
7824 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007825 return Heap::undefined_value();
7826 default:
7827 UNREACHABLE();
7828 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007829 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007830 return Heap::undefined_value();
7831}
7832
7833
ager@chromium.org32912102009-01-16 10:38:43 +00007834// Get debugger related details for an object property.
7835// args[0]: object holding property
7836// args[1]: name of the property
7837//
7838// The array returned contains the following information:
7839// 0: Property value
7840// 1: Property details
7841// 2: Property value is exception
7842// 3: Getter function if defined
7843// 4: Setter function if defined
7844// Items 2-4 are only filled if the property has either a getter or a setter
7845// defined through __defineGetter__ and/or __defineSetter__.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007846static Object* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007847 HandleScope scope;
7848
7849 ASSERT(args.length() == 2);
7850
7851 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7852 CONVERT_ARG_CHECKED(String, name, 1);
7853
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007854 // Make sure to set the current context to the context before the debugger was
7855 // entered (if the debugger is entered). The reason for switching context here
7856 // is that for some property lookups (accessors and interceptors) callbacks
7857 // into the embedding application can occour, and the embedding application
7858 // could have the assumption that its own global context is the current
7859 // context and not some internal debugger context.
7860 SaveContext save;
7861 if (Debug::InDebugger()) {
7862 Top::set_context(*Debug::debugger_entry()->GetContext());
7863 }
7864
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007865 // Skip the global proxy as it has no properties and always delegates to the
7866 // real global object.
7867 if (obj->IsJSGlobalProxy()) {
7868 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
7869 }
7870
7871
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007872 // Check if the name is trivially convertible to an index and get the element
7873 // if so.
7874 uint32_t index;
7875 if (name->AsArrayIndex(&index)) {
7876 Handle<FixedArray> details = Factory::NewFixedArray(2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007877 Object* element_or_char = Runtime::GetElementOrCharAt(obj, index);
7878 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007879 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
7880 return *Factory::NewJSArrayWithElements(details);
7881 }
7882
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007883 // Find the number of objects making up this.
7884 int length = LocalPrototypeChainLength(*obj);
7885
7886 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007887 Handle<JSObject> jsproto = obj;
7888 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007889 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007890 jsproto->LocalLookup(*name, &result);
7891 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007892 // LookupResult is not GC safe as it holds raw object pointers.
7893 // GC can happen later in this code so put the required fields into
7894 // local variables using handles when required for later use.
7895 PropertyType result_type = result.type();
7896 Handle<Object> result_callback_obj;
7897 if (result_type == CALLBACKS) {
7898 result_callback_obj = Handle<Object>(result.GetCallbackObject());
7899 }
7900 Smi* property_details = result.GetPropertyDetails().AsSmi();
7901 // DebugLookupResultValue can cause GC so details from LookupResult needs
7902 // to be copied to handles before this.
7903 bool caught_exception = false;
7904 Object* raw_value = DebugLookupResultValue(*obj, *name, &result,
7905 &caught_exception);
7906 if (raw_value->IsFailure()) return raw_value;
7907 Handle<Object> value(raw_value);
7908
7909 // If the callback object is a fixed array then it contains JavaScript
7910 // getter and/or setter.
7911 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
7912 result_callback_obj->IsFixedArray();
7913 Handle<FixedArray> details =
7914 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
7915 details->set(0, *value);
7916 details->set(1, property_details);
7917 if (hasJavaScriptAccessors) {
7918 details->set(2,
7919 caught_exception ? Heap::true_value()
7920 : Heap::false_value());
7921 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
7922 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
7923 }
7924
7925 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007926 }
7927 if (i < length - 1) {
7928 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
7929 }
7930 }
7931
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007932 return Heap::undefined_value();
7933}
7934
7935
7936static Object* Runtime_DebugGetProperty(Arguments args) {
7937 HandleScope scope;
7938
7939 ASSERT(args.length() == 2);
7940
7941 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7942 CONVERT_ARG_CHECKED(String, name, 1);
7943
7944 LookupResult result;
7945 obj->Lookup(*name, &result);
7946 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007947 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007948 }
7949 return Heap::undefined_value();
7950}
7951
7952
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007953// Return the property type calculated from the property details.
7954// args[0]: smi with property details.
7955static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
7956 ASSERT(args.length() == 1);
7957 CONVERT_CHECKED(Smi, details, args[0]);
7958 PropertyType type = PropertyDetails(details).type();
7959 return Smi::FromInt(static_cast<int>(type));
7960}
7961
7962
7963// Return the property attribute calculated from the property details.
7964// args[0]: smi with property details.
7965static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
7966 ASSERT(args.length() == 1);
7967 CONVERT_CHECKED(Smi, details, args[0]);
7968 PropertyAttributes attributes = PropertyDetails(details).attributes();
7969 return Smi::FromInt(static_cast<int>(attributes));
7970}
7971
7972
7973// Return the property insertion index calculated from the property details.
7974// args[0]: smi with property details.
7975static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
7976 ASSERT(args.length() == 1);
7977 CONVERT_CHECKED(Smi, details, args[0]);
7978 int index = PropertyDetails(details).index();
7979 return Smi::FromInt(index);
7980}
7981
7982
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007983// Return property value from named interceptor.
7984// args[0]: object
7985// args[1]: property name
7986static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
7987 HandleScope scope;
7988 ASSERT(args.length() == 2);
7989 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7990 RUNTIME_ASSERT(obj->HasNamedInterceptor());
7991 CONVERT_ARG_CHECKED(String, name, 1);
7992
7993 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007994 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007995}
7996
7997
7998// Return element value from indexed interceptor.
7999// args[0]: object
8000// args[1]: index
8001static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
8002 HandleScope scope;
8003 ASSERT(args.length() == 2);
8004 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8005 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8006 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8007
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008008 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008009}
8010
8011
8012static Object* Runtime_CheckExecutionState(Arguments args) {
8013 ASSERT(args.length() >= 1);
8014 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008015 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008016 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008017 return Top::Throw(Heap::illegal_execution_state_symbol());
8018 }
8019
8020 return Heap::true_value();
8021}
8022
8023
8024static Object* Runtime_GetFrameCount(Arguments args) {
8025 HandleScope scope;
8026 ASSERT(args.length() == 1);
8027
8028 // Check arguments.
8029 Object* result = Runtime_CheckExecutionState(args);
8030 if (result->IsFailure()) return result;
8031
8032 // Count all frames which are relevant to debugging stack trace.
8033 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008034 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008035 if (id == StackFrame::NO_ID) {
8036 // If there is no JavaScript stack frame count is 0.
8037 return Smi::FromInt(0);
8038 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008039 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8040 return Smi::FromInt(n);
8041}
8042
8043
8044static const int kFrameDetailsFrameIdIndex = 0;
8045static const int kFrameDetailsReceiverIndex = 1;
8046static const int kFrameDetailsFunctionIndex = 2;
8047static const int kFrameDetailsArgumentCountIndex = 3;
8048static const int kFrameDetailsLocalCountIndex = 4;
8049static const int kFrameDetailsSourcePositionIndex = 5;
8050static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008051static const int kFrameDetailsAtReturnIndex = 7;
8052static const int kFrameDetailsDebuggerFrameIndex = 8;
8053static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008054
8055// Return an array with frame details
8056// args[0]: number: break id
8057// args[1]: number: frame index
8058//
8059// The array returned contains the following information:
8060// 0: Frame id
8061// 1: Receiver
8062// 2: Function
8063// 3: Argument count
8064// 4: Local count
8065// 5: Source position
8066// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008067// 7: Is at return
8068// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008069// Arguments name, value
8070// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008071// Return value if any
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072static Object* Runtime_GetFrameDetails(Arguments args) {
8073 HandleScope scope;
8074 ASSERT(args.length() == 2);
8075
8076 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008077 Object* check = Runtime_CheckExecutionState(args);
8078 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008079 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8080
8081 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008082 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008083 if (id == StackFrame::NO_ID) {
8084 // If there are no JavaScript stack frames return undefined.
8085 return Heap::undefined_value();
8086 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008087 int count = 0;
8088 JavaScriptFrameIterator it(id);
8089 for (; !it.done(); it.Advance()) {
8090 if (count == index) break;
8091 count++;
8092 }
8093 if (it.done()) return Heap::undefined_value();
8094
8095 // Traverse the saved contexts chain to find the active context for the
8096 // selected frame.
8097 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008098 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008099 save = save->prev();
8100 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008101 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008102
8103 // Get the frame id.
8104 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8105
8106 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008107 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008108
8109 // Check for constructor frame.
8110 bool constructor = it.frame()->IsConstructor();
8111
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008112 // Get scope info and read from it for local variable information.
8113 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008114 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008115 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008116
8117 // Get the context.
8118 Handle<Context> context(Context::cast(it.frame()->context()));
8119
8120 // Get the locals names and values into a temporary array.
8121 //
8122 // TODO(1240907): Hide compiler-introduced stack variables
8123 // (e.g. .result)? For users of the debugger, they will probably be
8124 // confusing.
8125 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
8126 for (int i = 0; i < info.NumberOfLocals(); i++) {
8127 // Name of the local.
8128 locals->set(i * 2, *info.LocalName(i));
8129
8130 // Fetch the value of the local - either from the stack or from a
8131 // heap-allocated context.
8132 if (i < info.number_of_stack_slots()) {
8133 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8134 } else {
8135 Handle<String> name = info.LocalName(i);
8136 // Traverse the context chain to the function context as all local
8137 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008138 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008139 context = Handle<Context>(context->previous());
8140 }
8141 ASSERT(context->is_function_context());
8142 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008143 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008144 }
8145 }
8146
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008147 // Check whether this frame is positioned at return.
8148 int at_return = (index == 0) ? Debug::IsBreakAtReturn(it.frame()) : false;
8149
8150 // If positioned just before return find the value to be returned and add it
8151 // to the frame information.
8152 Handle<Object> return_value = Factory::undefined_value();
8153 if (at_return) {
8154 StackFrameIterator it2;
8155 Address internal_frame_sp = NULL;
8156 while (!it2.done()) {
8157 if (it2.frame()->is_internal()) {
8158 internal_frame_sp = it2.frame()->sp();
8159 } else {
8160 if (it2.frame()->is_java_script()) {
8161 if (it2.frame()->id() == it.frame()->id()) {
8162 // The internal frame just before the JavaScript frame contains the
8163 // value to return on top. A debug break at return will create an
8164 // internal frame to store the return value (eax/rax/r0) before
8165 // entering the debug break exit frame.
8166 if (internal_frame_sp != NULL) {
8167 return_value =
8168 Handle<Object>(Memory::Object_at(internal_frame_sp));
8169 break;
8170 }
8171 }
8172 }
8173
8174 // Indicate that the previous frame was not an internal frame.
8175 internal_frame_sp = NULL;
8176 }
8177 it2.Advance();
8178 }
8179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008180
8181 // Now advance to the arguments adapter frame (if any). It contains all
8182 // the provided parameters whereas the function frame always have the number
8183 // of arguments matching the functions parameters. The rest of the
8184 // information (except for what is collected above) is the same.
8185 it.AdvanceToArgumentsFrame();
8186
8187 // Find the number of arguments to fill. At least fill the number of
8188 // parameters for the function and fill more if more parameters are provided.
8189 int argument_count = info.number_of_parameters();
8190 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8191 argument_count = it.frame()->GetProvidedParametersCount();
8192 }
8193
8194 // Calculate the size of the result.
8195 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008196 2 * (argument_count + info.NumberOfLocals()) +
8197 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008198 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8199
8200 // Add the frame id.
8201 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8202
8203 // Add the function (same as in function frame).
8204 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8205
8206 // Add the arguments count.
8207 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8208
8209 // Add the locals count
8210 details->set(kFrameDetailsLocalCountIndex,
8211 Smi::FromInt(info.NumberOfLocals()));
8212
8213 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008214 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008215 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8216 } else {
8217 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8218 }
8219
8220 // Add the constructor information.
8221 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8222
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008223 // Add the at return information.
8224 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8225
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008226 // Add information on whether this frame is invoked in the debugger context.
8227 details->set(kFrameDetailsDebuggerFrameIndex,
8228 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8229
8230 // Fill the dynamic part.
8231 int details_index = kFrameDetailsFirstDynamicIndex;
8232
8233 // Add arguments name and value.
8234 for (int i = 0; i < argument_count; i++) {
8235 // Name of the argument.
8236 if (i < info.number_of_parameters()) {
8237 details->set(details_index++, *info.parameter_name(i));
8238 } else {
8239 details->set(details_index++, Heap::undefined_value());
8240 }
8241
8242 // Parameter value.
8243 if (i < it.frame()->GetProvidedParametersCount()) {
8244 details->set(details_index++, it.frame()->GetParameter(i));
8245 } else {
8246 details->set(details_index++, Heap::undefined_value());
8247 }
8248 }
8249
8250 // Add locals name and value from the temporary copy from the function frame.
8251 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8252 details->set(details_index++, locals->get(i));
8253 }
8254
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008255 // Add the value being returned.
8256 if (at_return) {
8257 details->set(details_index++, *return_value);
8258 }
8259
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008260 // Add the receiver (same as in function frame).
8261 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8262 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8263 Handle<Object> receiver(it.frame()->receiver());
8264 if (!receiver->IsJSObject()) {
8265 // If the receiver is NOT a JSObject we have hit an optimization
8266 // where a value object is not converted into a wrapped JS objects.
8267 // To hide this optimization from the debugger, we wrap the receiver
8268 // by creating correct wrapper object based on the calling frame's
8269 // global context.
8270 it.Advance();
8271 Handle<Context> calling_frames_global_context(
8272 Context::cast(Context::cast(it.frame()->context())->global_context()));
8273 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8274 }
8275 details->set(kFrameDetailsReceiverIndex, *receiver);
8276
8277 ASSERT_EQ(details_size, details_index);
8278 return *Factory::NewJSArrayWithElements(details);
8279}
8280
8281
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008282// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008283static void CopyContextLocalsToScopeObject(
8284 Handle<SerializedScopeInfo> serialized_scope_info,
8285 ScopeInfo<>& scope_info,
8286 Handle<Context> context,
8287 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008288 // Fill all context locals to the context extension.
8289 for (int i = Context::MIN_CONTEXT_SLOTS;
8290 i < scope_info.number_of_context_slots();
8291 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008292 int context_index = serialized_scope_info->ContextSlotIndex(
8293 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008294
8295 // Don't include the arguments shadow (.arguments) context variable.
8296 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8297 SetProperty(scope_object,
8298 scope_info.context_slot_name(i),
8299 Handle<Object>(context->get(context_index)), NONE);
8300 }
8301 }
8302}
8303
8304
8305// Create a plain JSObject which materializes the local scope for the specified
8306// frame.
8307static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8308 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008309 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008310 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8311 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008312
8313 // Allocate and initialize a JSObject with all the arguments, stack locals
8314 // heap locals and extension properties of the debugged function.
8315 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8316
8317 // First fill all parameters.
8318 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8319 SetProperty(local_scope,
8320 scope_info.parameter_name(i),
8321 Handle<Object>(frame->GetParameter(i)), NONE);
8322 }
8323
8324 // Second fill all stack locals.
8325 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8326 SetProperty(local_scope,
8327 scope_info.stack_slot_name(i),
8328 Handle<Object>(frame->GetExpression(i)), NONE);
8329 }
8330
8331 // Third fill all context locals.
8332 Handle<Context> frame_context(Context::cast(frame->context()));
8333 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008334 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008335 function_context, local_scope);
8336
8337 // Finally copy any properties from the function context extension. This will
8338 // be variables introduced by eval.
8339 if (function_context->closure() == *function) {
8340 if (function_context->has_extension() &&
8341 !function_context->IsGlobalContext()) {
8342 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008343 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008344 for (int i = 0; i < keys->length(); i++) {
8345 // Names of variables introduced by eval are strings.
8346 ASSERT(keys->get(i)->IsString());
8347 Handle<String> key(String::cast(keys->get(i)));
8348 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8349 }
8350 }
8351 }
8352 return local_scope;
8353}
8354
8355
8356// Create a plain JSObject which materializes the closure content for the
8357// context.
8358static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8359 ASSERT(context->is_function_context());
8360
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008361 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008362 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8363 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008364
8365 // Allocate and initialize a JSObject with all the content of theis function
8366 // closure.
8367 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8368
8369 // Check whether the arguments shadow object exists.
8370 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008371 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8372 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008373 if (arguments_shadow_index >= 0) {
8374 // In this case all the arguments are available in the arguments shadow
8375 // object.
8376 Handle<JSObject> arguments_shadow(
8377 JSObject::cast(context->get(arguments_shadow_index)));
8378 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8379 SetProperty(closure_scope,
8380 scope_info.parameter_name(i),
8381 Handle<Object>(arguments_shadow->GetElement(i)), NONE);
8382 }
8383 }
8384
8385 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008386 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8387 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008388
8389 // Finally copy any properties from the function context extension. This will
8390 // be variables introduced by eval.
8391 if (context->has_extension()) {
8392 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008393 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008394 for (int i = 0; i < keys->length(); i++) {
8395 // Names of variables introduced by eval are strings.
8396 ASSERT(keys->get(i)->IsString());
8397 Handle<String> key(String::cast(keys->get(i)));
8398 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
8399 }
8400 }
8401
8402 return closure_scope;
8403}
8404
8405
8406// Iterate over the actual scopes visible from a stack frame. All scopes are
8407// backed by an actual context except the local scope, which is inserted
8408// "artifically" in the context chain.
8409class ScopeIterator {
8410 public:
8411 enum ScopeType {
8412 ScopeTypeGlobal = 0,
8413 ScopeTypeLocal,
8414 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00008415 ScopeTypeClosure,
8416 // Every catch block contains an implicit with block (its parameter is
8417 // a JSContextExtensionObject) that extends current scope with a variable
8418 // holding exception object. Such with blocks are treated as scopes of their
8419 // own type.
8420 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008421 };
8422
8423 explicit ScopeIterator(JavaScriptFrame* frame)
8424 : frame_(frame),
8425 function_(JSFunction::cast(frame->function())),
8426 context_(Context::cast(frame->context())),
8427 local_done_(false),
8428 at_local_(false) {
8429
8430 // Check whether the first scope is actually a local scope.
8431 if (context_->IsGlobalContext()) {
8432 // If there is a stack slot for .result then this local scope has been
8433 // created for evaluating top level code and it is not a real local scope.
8434 // Checking for the existence of .result seems fragile, but the scope info
8435 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008436 int index = function_->shared()->scope_info()->
8437 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008438 at_local_ = index < 0;
8439 } else if (context_->is_function_context()) {
8440 at_local_ = true;
8441 }
8442 }
8443
8444 // More scopes?
8445 bool Done() { return context_.is_null(); }
8446
8447 // Move to the next scope.
8448 void Next() {
8449 // If at a local scope mark the local scope as passed.
8450 if (at_local_) {
8451 at_local_ = false;
8452 local_done_ = true;
8453
8454 // If the current context is not associated with the local scope the
8455 // current context is the next real scope, so don't move to the next
8456 // context in this case.
8457 if (context_->closure() != *function_) {
8458 return;
8459 }
8460 }
8461
8462 // The global scope is always the last in the chain.
8463 if (context_->IsGlobalContext()) {
8464 context_ = Handle<Context>();
8465 return;
8466 }
8467
8468 // Move to the next context.
8469 if (context_->is_function_context()) {
8470 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
8471 } else {
8472 context_ = Handle<Context>(context_->previous());
8473 }
8474
8475 // If passing the local scope indicate that the current scope is now the
8476 // local scope.
8477 if (!local_done_ &&
8478 (context_->IsGlobalContext() || (context_->is_function_context()))) {
8479 at_local_ = true;
8480 }
8481 }
8482
8483 // Return the type of the current scope.
8484 int Type() {
8485 if (at_local_) {
8486 return ScopeTypeLocal;
8487 }
8488 if (context_->IsGlobalContext()) {
8489 ASSERT(context_->global()->IsGlobalObject());
8490 return ScopeTypeGlobal;
8491 }
8492 if (context_->is_function_context()) {
8493 return ScopeTypeClosure;
8494 }
8495 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00008496 // Current scope is either an explicit with statement or a with statement
8497 // implicitely generated for a catch block.
8498 // If the extension object here is a JSContextExtensionObject then
8499 // current with statement is one frome a catch block otherwise it's a
8500 // regular with statement.
8501 if (context_->extension()->IsJSContextExtensionObject()) {
8502 return ScopeTypeCatch;
8503 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008504 return ScopeTypeWith;
8505 }
8506
8507 // Return the JavaScript object with the content of the current scope.
8508 Handle<JSObject> ScopeObject() {
8509 switch (Type()) {
8510 case ScopeIterator::ScopeTypeGlobal:
8511 return Handle<JSObject>(CurrentContext()->global());
8512 break;
8513 case ScopeIterator::ScopeTypeLocal:
8514 // Materialize the content of the local scope into a JSObject.
8515 return MaterializeLocalScope(frame_);
8516 break;
8517 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00008518 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008519 // Return the with object.
8520 return Handle<JSObject>(CurrentContext()->extension());
8521 break;
8522 case ScopeIterator::ScopeTypeClosure:
8523 // Materialize the content of the closure scope into a JSObject.
8524 return MaterializeClosure(CurrentContext());
8525 break;
8526 }
8527 UNREACHABLE();
8528 return Handle<JSObject>();
8529 }
8530
8531 // Return the context for this scope. For the local context there might not
8532 // be an actual context.
8533 Handle<Context> CurrentContext() {
8534 if (at_local_ && context_->closure() != *function_) {
8535 return Handle<Context>();
8536 }
8537 return context_;
8538 }
8539
8540#ifdef DEBUG
8541 // Debug print of the content of the current scope.
8542 void DebugPrint() {
8543 switch (Type()) {
8544 case ScopeIterator::ScopeTypeGlobal:
8545 PrintF("Global:\n");
8546 CurrentContext()->Print();
8547 break;
8548
8549 case ScopeIterator::ScopeTypeLocal: {
8550 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008551 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008552 scope_info.Print();
8553 if (!CurrentContext().is_null()) {
8554 CurrentContext()->Print();
8555 if (CurrentContext()->has_extension()) {
8556 Handle<JSObject> extension =
8557 Handle<JSObject>(CurrentContext()->extension());
8558 if (extension->IsJSContextExtensionObject()) {
8559 extension->Print();
8560 }
8561 }
8562 }
8563 break;
8564 }
8565
8566 case ScopeIterator::ScopeTypeWith: {
8567 PrintF("With:\n");
8568 Handle<JSObject> extension =
8569 Handle<JSObject>(CurrentContext()->extension());
8570 extension->Print();
8571 break;
8572 }
8573
ager@chromium.orga1645e22009-09-09 19:27:10 +00008574 case ScopeIterator::ScopeTypeCatch: {
8575 PrintF("Catch:\n");
8576 Handle<JSObject> extension =
8577 Handle<JSObject>(CurrentContext()->extension());
8578 extension->Print();
8579 break;
8580 }
8581
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008582 case ScopeIterator::ScopeTypeClosure: {
8583 PrintF("Closure:\n");
8584 CurrentContext()->Print();
8585 if (CurrentContext()->has_extension()) {
8586 Handle<JSObject> extension =
8587 Handle<JSObject>(CurrentContext()->extension());
8588 if (extension->IsJSContextExtensionObject()) {
8589 extension->Print();
8590 }
8591 }
8592 break;
8593 }
8594
8595 default:
8596 UNREACHABLE();
8597 }
8598 PrintF("\n");
8599 }
8600#endif
8601
8602 private:
8603 JavaScriptFrame* frame_;
8604 Handle<JSFunction> function_;
8605 Handle<Context> context_;
8606 bool local_done_;
8607 bool at_local_;
8608
8609 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
8610};
8611
8612
8613static Object* Runtime_GetScopeCount(Arguments args) {
8614 HandleScope scope;
8615 ASSERT(args.length() == 2);
8616
8617 // Check arguments.
8618 Object* check = Runtime_CheckExecutionState(args);
8619 if (check->IsFailure()) return check;
8620 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8621
8622 // Get the frame where the debugging is performed.
8623 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8624 JavaScriptFrameIterator it(id);
8625 JavaScriptFrame* frame = it.frame();
8626
8627 // Count the visible scopes.
8628 int n = 0;
8629 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8630 n++;
8631 }
8632
8633 return Smi::FromInt(n);
8634}
8635
8636
8637static const int kScopeDetailsTypeIndex = 0;
8638static const int kScopeDetailsObjectIndex = 1;
8639static const int kScopeDetailsSize = 2;
8640
8641// Return an array with scope details
8642// args[0]: number: break id
8643// args[1]: number: frame index
8644// args[2]: number: scope index
8645//
8646// The array returned contains the following information:
8647// 0: Scope type
8648// 1: Scope object
8649static Object* Runtime_GetScopeDetails(Arguments args) {
8650 HandleScope scope;
8651 ASSERT(args.length() == 3);
8652
8653 // Check arguments.
8654 Object* check = Runtime_CheckExecutionState(args);
8655 if (check->IsFailure()) return check;
8656 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8657 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
8658
8659 // Get the frame where the debugging is performed.
8660 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8661 JavaScriptFrameIterator frame_it(id);
8662 JavaScriptFrame* frame = frame_it.frame();
8663
8664 // Find the requested scope.
8665 int n = 0;
8666 ScopeIterator it(frame);
8667 for (; !it.Done() && n < index; it.Next()) {
8668 n++;
8669 }
8670 if (it.Done()) {
8671 return Heap::undefined_value();
8672 }
8673
8674 // Calculate the size of the result.
8675 int details_size = kScopeDetailsSize;
8676 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8677
8678 // Fill in scope details.
8679 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008680 Handle<JSObject> scope_object = it.ScopeObject();
8681 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008682
8683 return *Factory::NewJSArrayWithElements(details);
8684}
8685
8686
8687static Object* Runtime_DebugPrintScopes(Arguments args) {
8688 HandleScope scope;
8689 ASSERT(args.length() == 0);
8690
8691#ifdef DEBUG
8692 // Print the scopes for the top frame.
8693 StackFrameLocator locator;
8694 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
8695 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8696 it.DebugPrint();
8697 }
8698#endif
8699 return Heap::undefined_value();
8700}
8701
8702
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008703static Object* Runtime_GetCFrames(Arguments args) {
8704 HandleScope scope;
8705 ASSERT(args.length() == 1);
8706 Object* result = Runtime_CheckExecutionState(args);
8707 if (result->IsFailure()) return result;
8708
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00008709#if V8_HOST_ARCH_64_BIT
8710 UNIMPLEMENTED();
8711 return Heap::undefined_value();
8712#else
8713
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008714 static const int kMaxCFramesSize = 200;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008715 ScopedVector<OS::StackFrame> frames(kMaxCFramesSize);
8716 int frames_count = OS::StackWalk(frames);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008717 if (frames_count == OS::kStackWalkError) {
8718 return Heap::undefined_value();
8719 }
8720
8721 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
8722 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
8723 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
8724 for (int i = 0; i < frames_count; i++) {
8725 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008726 Handle<Object> frame_address =
8727 Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address));
8728
8729 frame_value->SetProperty(*address_str, *frame_address, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008730
8731 // Get the stack walk text for this frame.
8732 Handle<String> frame_text;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008733 int frame_text_length = StrLength(frames[i].text);
8734 if (frame_text_length > 0) {
8735 Vector<const char> str(frames[i].text, frame_text_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008736 frame_text = Factory::NewStringFromAscii(str);
8737 }
8738
8739 if (!frame_text.is_null()) {
8740 frame_value->SetProperty(*text_str, *frame_text, NONE);
8741 }
8742
8743 frames_array->set(i, *frame_value);
8744 }
8745 return *Factory::NewJSArrayWithElements(frames_array);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00008746#endif // V8_HOST_ARCH_64_BIT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008747}
8748
8749
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008750static Object* Runtime_GetThreadCount(Arguments args) {
8751 HandleScope scope;
8752 ASSERT(args.length() == 1);
8753
8754 // Check arguments.
8755 Object* result = Runtime_CheckExecutionState(args);
8756 if (result->IsFailure()) return result;
8757
8758 // Count all archived V8 threads.
8759 int n = 0;
8760 for (ThreadState* thread = ThreadState::FirstInUse();
8761 thread != NULL;
8762 thread = thread->Next()) {
8763 n++;
8764 }
8765
8766 // Total number of threads is current thread and archived threads.
8767 return Smi::FromInt(n + 1);
8768}
8769
8770
8771static const int kThreadDetailsCurrentThreadIndex = 0;
8772static const int kThreadDetailsThreadIdIndex = 1;
8773static const int kThreadDetailsSize = 2;
8774
8775// Return an array with thread details
8776// args[0]: number: break id
8777// args[1]: number: thread index
8778//
8779// The array returned contains the following information:
8780// 0: Is current thread?
8781// 1: Thread id
8782static Object* Runtime_GetThreadDetails(Arguments args) {
8783 HandleScope scope;
8784 ASSERT(args.length() == 2);
8785
8786 // Check arguments.
8787 Object* check = Runtime_CheckExecutionState(args);
8788 if (check->IsFailure()) return check;
8789 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8790
8791 // Allocate array for result.
8792 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
8793
8794 // Thread index 0 is current thread.
8795 if (index == 0) {
8796 // Fill the details.
8797 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
8798 details->set(kThreadDetailsThreadIdIndex,
8799 Smi::FromInt(ThreadManager::CurrentId()));
8800 } else {
8801 // Find the thread with the requested index.
8802 int n = 1;
8803 ThreadState* thread = ThreadState::FirstInUse();
8804 while (index != n && thread != NULL) {
8805 thread = thread->Next();
8806 n++;
8807 }
8808 if (thread == NULL) {
8809 return Heap::undefined_value();
8810 }
8811
8812 // Fill the details.
8813 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
8814 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
8815 }
8816
8817 // Convert to JS array and return.
8818 return *Factory::NewJSArrayWithElements(details);
8819}
8820
8821
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008822// Sets the disable break state
8823// args[0]: disable break state
8824static Object* Runtime_SetDisableBreak(Arguments args) {
8825 HandleScope scope;
8826 ASSERT(args.length() == 1);
8827 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
8828 Debug::set_disable_break(disable_break);
8829 return Heap::undefined_value();
8830}
8831
8832
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008833static Object* Runtime_GetBreakLocations(Arguments args) {
8834 HandleScope scope;
8835 ASSERT(args.length() == 1);
8836
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008837 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8838 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008839 // Find the number of break points
8840 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
8841 if (break_locations->IsUndefined()) return Heap::undefined_value();
8842 // Return array as JS array
8843 return *Factory::NewJSArrayWithElements(
8844 Handle<FixedArray>::cast(break_locations));
8845}
8846
8847
8848// Set a break point in a function
8849// args[0]: function
8850// args[1]: number: break source position (within the function source)
8851// args[2]: number: break point object
8852static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
8853 HandleScope scope;
8854 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008855 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8856 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008857 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
8858 RUNTIME_ASSERT(source_position >= 0);
8859 Handle<Object> break_point_object_arg = args.at<Object>(2);
8860
8861 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008862 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008863
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008864 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008865}
8866
8867
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00008868Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
8869 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008870 // Iterate the heap looking for SharedFunctionInfo generated from the
8871 // script. The inner most SharedFunctionInfo containing the source position
8872 // for the requested break point is found.
8873 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
8874 // which is found is not compiled it is compiled and the heap is iterated
8875 // again as the compilation might create inner functions from the newly
8876 // compiled function and the actual requested break point might be in one of
8877 // these functions.
8878 bool done = false;
8879 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00008880 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008881 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008882 while (!done) {
8883 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008884 for (HeapObject* obj = iterator.next();
8885 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008886 if (obj->IsSharedFunctionInfo()) {
8887 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
8888 if (shared->script() == *script) {
8889 // If the SharedFunctionInfo found has the requested script data and
8890 // contains the source position it is a candidate.
8891 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00008892 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008893 start_position = shared->start_position();
8894 }
8895 if (start_position <= position &&
8896 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00008897 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008898 // candidate this is the new candidate.
8899 if (target.is_null()) {
8900 target_start_position = start_position;
8901 target = shared;
8902 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00008903 if (target_start_position == start_position &&
8904 shared->end_position() == target->end_position()) {
8905 // If a top-level function contain only one function
8906 // declartion the source for the top-level and the function is
8907 // the same. In that case prefer the non top-level function.
8908 if (!shared->is_toplevel()) {
8909 target_start_position = start_position;
8910 target = shared;
8911 }
8912 } else if (target_start_position <= start_position &&
8913 shared->end_position() <= target->end_position()) {
8914 // This containment check includes equality as a function inside
8915 // a top-level function can share either start or end position
8916 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008917 target_start_position = start_position;
8918 target = shared;
8919 }
8920 }
8921 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008922 }
8923 }
8924 }
8925
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008926 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008927 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008928 }
8929
8930 // If the candidate found is compiled we are done. NOTE: when lazy
8931 // compilation of inner functions is introduced some additional checking
8932 // needs to be done here to compile inner functions.
8933 done = target->is_compiled();
8934 if (!done) {
8935 // If the candidate is not compiled compile it to reveal any inner
8936 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008937 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008938 }
8939 }
8940
8941 return *target;
8942}
8943
8944
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008945// Changes the state of a break point in a script and returns source position
8946// where break point was set. NOTE: Regarding performance see the NOTE for
8947// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008948// args[0]: script to set break point in
8949// args[1]: number: break source position (within the script source)
8950// args[2]: number: break point object
8951static Object* Runtime_SetScriptBreakPoint(Arguments args) {
8952 HandleScope scope;
8953 ASSERT(args.length() == 3);
8954 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
8955 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
8956 RUNTIME_ASSERT(source_position >= 0);
8957 Handle<Object> break_point_object_arg = args.at<Object>(2);
8958
8959 // Get the script from the script wrapper.
8960 RUNTIME_ASSERT(wrapper->value()->IsScript());
8961 Handle<Script> script(Script::cast(wrapper->value()));
8962
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00008963 Object* result = Runtime::FindSharedFunctionInfoInScript(
8964 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008965 if (!result->IsUndefined()) {
8966 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
8967 // Find position within function. The script position might be before the
8968 // source position of the first function.
8969 int position;
8970 if (shared->start_position() > source_position) {
8971 position = 0;
8972 } else {
8973 position = source_position - shared->start_position();
8974 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00008975 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
8976 position += shared->start_position();
8977 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008978 }
8979 return Heap::undefined_value();
8980}
8981
8982
8983// Clear a break point
8984// args[0]: number: break point object
8985static Object* Runtime_ClearBreakPoint(Arguments args) {
8986 HandleScope scope;
8987 ASSERT(args.length() == 1);
8988 Handle<Object> break_point_object_arg = args.at<Object>(0);
8989
8990 // Clear break point.
8991 Debug::ClearBreakPoint(break_point_object_arg);
8992
8993 return Heap::undefined_value();
8994}
8995
8996
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00008997// Change the state of break on exceptions.
8998// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
8999// args[1]: Boolean indicating on/off.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009000static Object* Runtime_ChangeBreakOnException(Arguments args) {
9001 HandleScope scope;
9002 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009003 RUNTIME_ASSERT(args[0]->IsNumber());
9004 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009005
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009006 // If the number doesn't match an enum value, the ChangeBreakOnException
9007 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009008 ExceptionBreakType type =
9009 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009010 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011 Debug::ChangeBreakOnException(type, enable);
9012 return Heap::undefined_value();
9013}
9014
9015
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009016// Returns the state of break on exceptions
9017// args[0]: boolean indicating uncaught exceptions
9018static Object* Runtime_IsBreakOnException(Arguments args) {
9019 HandleScope scope;
9020 ASSERT(args.length() == 1);
9021 RUNTIME_ASSERT(args[0]->IsNumber());
9022
9023 ExceptionBreakType type =
9024 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9025 bool result = Debug::IsBreakOnException(type);
9026 return Smi::FromInt(result);
9027}
9028
9029
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009030// Prepare for stepping
9031// args[0]: break id for checking execution state
9032// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009033// args[2]: number of times to perform the step, for step out it is the number
9034// of frames to step down.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009035static Object* Runtime_PrepareStep(Arguments args) {
9036 HandleScope scope;
9037 ASSERT(args.length() == 3);
9038 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009039 Object* check = Runtime_CheckExecutionState(args);
9040 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009041 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9042 return Top::Throw(Heap::illegal_argument_symbol());
9043 }
9044
9045 // Get the step action and check validity.
9046 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9047 if (step_action != StepIn &&
9048 step_action != StepNext &&
9049 step_action != StepOut &&
9050 step_action != StepInMin &&
9051 step_action != StepMin) {
9052 return Top::Throw(Heap::illegal_argument_symbol());
9053 }
9054
9055 // Get the number of steps.
9056 int step_count = NumberToInt32(args[2]);
9057 if (step_count < 1) {
9058 return Top::Throw(Heap::illegal_argument_symbol());
9059 }
9060
ager@chromium.orga1645e22009-09-09 19:27:10 +00009061 // Clear all current stepping setup.
9062 Debug::ClearStepping();
9063
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009064 // Prepare step.
9065 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9066 return Heap::undefined_value();
9067}
9068
9069
9070// Clear all stepping set by PrepareStep.
9071static Object* Runtime_ClearStepping(Arguments args) {
9072 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009073 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074 Debug::ClearStepping();
9075 return Heap::undefined_value();
9076}
9077
9078
9079// Creates a copy of the with context chain. The copy of the context chain is
9080// is linked to the function context supplied.
9081static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9082 Handle<Context> function_context) {
9083 // At the bottom of the chain. Return the function context to link to.
9084 if (context_chain->is_function_context()) {
9085 return function_context;
9086 }
9087
9088 // Recursively copy the with contexts.
9089 Handle<Context> previous(context_chain->previous());
9090 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009091 Handle<Context> context = CopyWithContextChain(function_context, previous);
9092 return Factory::NewWithContext(context,
9093 extension,
9094 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009095}
9096
9097
9098// Helper function to find or create the arguments object for
9099// Runtime_DebugEvaluate.
9100static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9101 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009102 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009103 const ScopeInfo<>* sinfo,
9104 Handle<Context> function_context) {
9105 // Try to find the value of 'arguments' to pass as parameter. If it is not
9106 // found (that is the debugged function does not reference 'arguments' and
9107 // does not support eval) then create an 'arguments' object.
9108 int index;
9109 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009110 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009111 if (index != -1) {
9112 return Handle<Object>(frame->GetExpression(index));
9113 }
9114 }
9115
9116 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009117 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009118 if (index != -1) {
9119 return Handle<Object>(function_context->get(index));
9120 }
9121 }
9122
9123 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009124 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9125 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009126
9127 AssertNoAllocation no_gc;
9128 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009129 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009130 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009131 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009132 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009133 return arguments;
9134}
9135
9136
9137// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009138// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009139// extension part has all the parameters and locals of the function on the
9140// stack frame. A function which calls eval with the code to evaluate is then
9141// compiled in this context and called in this context. As this context
9142// replaces the context of the function on the stack frame a new (empty)
9143// function is created as well to be used as the closure for the context.
9144// This function and the context acts as replacements for the function on the
9145// stack frame presenting the same view of the values of parameters and
9146// local variables as if the piece of JavaScript was evaluated at the point
9147// where the function on the stack frame is currently stopped.
9148static Object* Runtime_DebugEvaluate(Arguments args) {
9149 HandleScope scope;
9150
9151 // Check the execution state and decode arguments frame and source to be
9152 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009153 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009154 Object* check_result = Runtime_CheckExecutionState(args);
9155 if (check_result->IsFailure()) return check_result;
9156 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9157 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009158 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
9159
9160 // Handle the processing of break.
9161 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162
9163 // Get the frame where the debugging is performed.
9164 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9165 JavaScriptFrameIterator it(id);
9166 JavaScriptFrame* frame = it.frame();
9167 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009168 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009169 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009170
9171 // Traverse the saved contexts chain to find the active context for the
9172 // selected frame.
9173 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009174 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009175 save = save->prev();
9176 }
9177 ASSERT(save != NULL);
9178 SaveContext savex;
9179 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180
9181 // Create the (empty) function replacing the function on the stack frame for
9182 // the purpose of evaluating in the context created below. It is important
9183 // that this function does not describe any parameters and local variables
9184 // in the context. If it does then this will cause problems with the lookup
9185 // in Context::Lookup, where context slots for parameters and local variables
9186 // are looked at before the extension object.
9187 Handle<JSFunction> go_between =
9188 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9189 go_between->set_context(function->context());
9190#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009191 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009192 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9193 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9194#endif
9195
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009196 // Materialize the content of the local scope into a JSObject.
9197 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009198
9199 // Allocate a new context for the debug evaluation and set the extension
9200 // object build.
9201 Handle<Context> context =
9202 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009203 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009204 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009205 Handle<Context> frame_context(Context::cast(frame->context()));
9206 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009207 context = CopyWithContextChain(frame_context, context);
9208
9209 // Wrap the evaluation statement in a new function compiled in the newly
9210 // created context. The function has one parameter which has to be called
9211 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009212 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009213 // function(arguments,__source__) {return eval(__source__);}
9214 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009215 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009216 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009217 Handle<String> function_source =
9218 Factory::NewStringFromAscii(Vector<const char>(source_str,
9219 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009220 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009221 Compiler::CompileEval(function_source,
9222 context,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00009223 context->IsGlobalContext(),
ager@chromium.orgadd848f2009-08-13 12:44:13 +00009224 Compiler::DONT_VALIDATE_JSON);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009225 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009226 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009227 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228
9229 // Invoke the result of the compilation to get the evaluation function.
9230 bool has_pending_exception;
9231 Handle<Object> receiver(frame->receiver());
9232 Handle<Object> evaluation_function =
9233 Execution::Call(compiled_function, receiver, 0, NULL,
9234 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009235 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009236
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009237 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9238 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009239
9240 // Invoke the evaluation function and return the result.
9241 const int argc = 2;
9242 Object** argv[argc] = { arguments.location(),
9243 Handle<Object>::cast(source).location() };
9244 Handle<Object> result =
9245 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9246 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009247 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009248
9249 // Skip the global proxy as it has no properties and always delegates to the
9250 // real global object.
9251 if (result->IsJSGlobalProxy()) {
9252 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9253 }
9254
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009255 return *result;
9256}
9257
9258
9259static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
9260 HandleScope scope;
9261
9262 // Check the execution state and decode arguments frame and source to be
9263 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009264 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009265 Object* check_result = Runtime_CheckExecutionState(args);
9266 if (check_result->IsFailure()) return check_result;
9267 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009268 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
9269
9270 // Handle the processing of break.
9271 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009272
9273 // Enter the top context from before the debugger was invoked.
9274 SaveContext save;
9275 SaveContext* top = &save;
9276 while (top != NULL && *top->context() == *Debug::debug_context()) {
9277 top = top->prev();
9278 }
9279 if (top != NULL) {
9280 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009281 }
9282
9283 // Get the global context now set to the top context from before the
9284 // debugger was invoked.
9285 Handle<Context> context = Top::global_context();
9286
9287 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009288 Handle<SharedFunctionInfo> shared =
9289 Compiler::CompileEval(source,
9290 context,
9291 true,
9292 Compiler::DONT_VALIDATE_JSON);
9293 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009294 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009295 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9296 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009297
9298 // Invoke the result of the compilation to get the evaluation function.
9299 bool has_pending_exception;
9300 Handle<Object> receiver = Top::global();
9301 Handle<Object> result =
9302 Execution::Call(compiled_function, receiver, 0, NULL,
9303 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009304 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009305 return *result;
9306}
9307
9308
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009309static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
9310 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009311 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009312
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009313 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009314 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009315
9316 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009317 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009318 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9319 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9320 // because using
9321 // instances->set(i, *GetScriptWrapper(script))
9322 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9323 // already have deferenced the instances handle.
9324 Handle<JSValue> wrapper = GetScriptWrapper(script);
9325 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009326 }
9327
9328 // Return result as a JS array.
9329 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9330 Handle<JSArray>::cast(result)->SetContent(*instances);
9331 return *result;
9332}
9333
9334
9335// Helper function used by Runtime_DebugReferencedBy below.
9336static int DebugReferencedBy(JSObject* target,
9337 Object* instance_filter, int max_references,
9338 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009339 JSFunction* arguments_function) {
9340 NoHandleAllocation ha;
9341 AssertNoAllocation no_alloc;
9342
9343 // Iterate the heap.
9344 int count = 0;
9345 JSObject* last = NULL;
9346 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009347 HeapObject* heap_obj = NULL;
9348 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009349 (max_references == 0 || count < max_references)) {
9350 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009351 if (heap_obj->IsJSObject()) {
9352 // Skip context extension objects and argument arrays as these are
9353 // checked in the context of functions using them.
9354 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009355 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009356 obj->map()->constructor() == arguments_function) {
9357 continue;
9358 }
9359
9360 // Check if the JS object has a reference to the object looked for.
9361 if (obj->ReferencesObject(target)) {
9362 // Check instance filter if supplied. This is normally used to avoid
9363 // references from mirror objects (see Runtime_IsInPrototypeChain).
9364 if (!instance_filter->IsUndefined()) {
9365 Object* V = obj;
9366 while (true) {
9367 Object* prototype = V->GetPrototype();
9368 if (prototype->IsNull()) {
9369 break;
9370 }
9371 if (instance_filter == prototype) {
9372 obj = NULL; // Don't add this object.
9373 break;
9374 }
9375 V = prototype;
9376 }
9377 }
9378
9379 if (obj != NULL) {
9380 // Valid reference found add to instance array if supplied an update
9381 // count.
9382 if (instances != NULL && count < instances_size) {
9383 instances->set(count, obj);
9384 }
9385 last = obj;
9386 count++;
9387 }
9388 }
9389 }
9390 }
9391
9392 // Check for circular reference only. This can happen when the object is only
9393 // referenced from mirrors and has a circular reference in which case the
9394 // object is not really alive and would have been garbage collected if not
9395 // referenced from the mirror.
9396 if (count == 1 && last == target) {
9397 count = 0;
9398 }
9399
9400 // Return the number of referencing objects found.
9401 return count;
9402}
9403
9404
9405// Scan the heap for objects with direct references to an object
9406// args[0]: the object to find references to
9407// args[1]: constructor function for instances to exclude (Mirror)
9408// args[2]: the the maximum number of objects to return
9409static Object* Runtime_DebugReferencedBy(Arguments args) {
9410 ASSERT(args.length() == 3);
9411
9412 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009413 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009414
9415 // Check parameters.
9416 CONVERT_CHECKED(JSObject, target, args[0]);
9417 Object* instance_filter = args[1];
9418 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
9419 instance_filter->IsJSObject());
9420 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
9421 RUNTIME_ASSERT(max_references >= 0);
9422
9423 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009424 JSObject* arguments_boilerplate =
9425 Top::context()->global_context()->arguments_boilerplate();
9426 JSFunction* arguments_function =
9427 JSFunction::cast(arguments_boilerplate->map()->constructor());
9428
9429 // Get the number of referencing objects.
9430 int count;
9431 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009432 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009433
9434 // Allocate an array to hold the result.
9435 Object* object = Heap::AllocateFixedArray(count);
9436 if (object->IsFailure()) return object;
9437 FixedArray* instances = FixedArray::cast(object);
9438
9439 // Fill the referencing objects.
9440 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009441 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009442
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
9452// Helper function used by Runtime_DebugConstructedBy below.
9453static int DebugConstructedBy(JSFunction* constructor, int max_references,
9454 FixedArray* instances, int instances_size) {
9455 AssertNoAllocation no_alloc;
9456
9457 // Iterate the heap.
9458 int count = 0;
9459 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009460 HeapObject* heap_obj = NULL;
9461 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009462 (max_references == 0 || count < max_references)) {
9463 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009464 if (heap_obj->IsJSObject()) {
9465 JSObject* obj = JSObject::cast(heap_obj);
9466 if (obj->map()->constructor() == constructor) {
9467 // Valid reference found add to instance array if supplied an update
9468 // count.
9469 if (instances != NULL && count < instances_size) {
9470 instances->set(count, obj);
9471 }
9472 count++;
9473 }
9474 }
9475 }
9476
9477 // Return the number of referencing objects found.
9478 return count;
9479}
9480
9481
9482// Scan the heap for objects constructed by a specific function.
9483// args[0]: the constructor to find instances of
9484// args[1]: the the maximum number of objects to return
9485static Object* Runtime_DebugConstructedBy(Arguments args) {
9486 ASSERT(args.length() == 2);
9487
9488 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009489 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009490
9491 // Check parameters.
9492 CONVERT_CHECKED(JSFunction, constructor, args[0]);
9493 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
9494 RUNTIME_ASSERT(max_references >= 0);
9495
9496 // Get the number of referencing objects.
9497 int count;
9498 count = DebugConstructedBy(constructor, max_references, NULL, 0);
9499
9500 // Allocate an array to hold the result.
9501 Object* object = Heap::AllocateFixedArray(count);
9502 if (object->IsFailure()) return object;
9503 FixedArray* instances = FixedArray::cast(object);
9504
9505 // Fill the referencing objects.
9506 count = DebugConstructedBy(constructor, max_references, instances, count);
9507
9508 // Return result as JS array.
9509 Object* result =
9510 Heap::AllocateJSObject(
9511 Top::context()->global_context()->array_function());
9512 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
9513 return result;
9514}
9515
9516
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009517// Find the effective prototype object as returned by __proto__.
9518// args[0]: the object to find the prototype for.
9519static Object* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009520 ASSERT(args.length() == 1);
9521
9522 CONVERT_CHECKED(JSObject, obj, args[0]);
9523
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009524 // Use the __proto__ accessor.
9525 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009526}
9527
9528
9529static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00009530 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009531 CPU::DebugBreak();
9532 return Heap::undefined_value();
9533}
9534
9535
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009536static Object* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009537#ifdef DEBUG
9538 HandleScope scope;
9539 ASSERT(args.length() == 1);
9540 // Get the function and make sure it is compiled.
9541 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009542 Handle<SharedFunctionInfo> shared(func->shared());
9543 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009544 return Failure::Exception();
9545 }
9546 func->code()->PrintLn();
9547#endif // DEBUG
9548 return Heap::undefined_value();
9549}
ager@chromium.org9085a012009-05-11 19:22:57 +00009550
9551
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009552static Object* Runtime_DebugDisassembleConstructor(Arguments args) {
9553#ifdef DEBUG
9554 HandleScope scope;
9555 ASSERT(args.length() == 1);
9556 // Get the function and make sure it is compiled.
9557 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009558 Handle<SharedFunctionInfo> shared(func->shared());
9559 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009560 return Failure::Exception();
9561 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009562 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009563#endif // DEBUG
9564 return Heap::undefined_value();
9565}
9566
9567
ager@chromium.org9085a012009-05-11 19:22:57 +00009568static Object* Runtime_FunctionGetInferredName(Arguments args) {
9569 NoHandleAllocation ha;
9570 ASSERT(args.length() == 1);
9571
9572 CONVERT_CHECKED(JSFunction, f, args[0]);
9573 return f->shared()->inferred_name();
9574}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009575
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009576
9577static int FindSharedFunctionInfosForScript(Script* script,
9578 FixedArray* buffer) {
9579 AssertNoAllocation no_allocations;
9580
9581 int counter = 0;
9582 int buffer_size = buffer->length();
9583 HeapIterator iterator;
9584 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
9585 ASSERT(obj != NULL);
9586 if (!obj->IsSharedFunctionInfo()) {
9587 continue;
9588 }
9589 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
9590 if (shared->script() != script) {
9591 continue;
9592 }
9593 if (counter < buffer_size) {
9594 buffer->set(counter, shared);
9595 }
9596 counter++;
9597 }
9598 return counter;
9599}
9600
9601// For a script finds all SharedFunctionInfo's in the heap that points
9602// to this script. Returns JSArray of SharedFunctionInfo wrapped
9603// in OpaqueReferences.
9604static Object* Runtime_LiveEditFindSharedFunctionInfosForScript(
9605 Arguments args) {
9606 ASSERT(args.length() == 1);
9607 HandleScope scope;
9608 CONVERT_CHECKED(JSValue, script_value, args[0]);
9609
9610 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
9611
9612 const int kBufferSize = 32;
9613
9614 Handle<FixedArray> array;
9615 array = Factory::NewFixedArray(kBufferSize);
9616 int number = FindSharedFunctionInfosForScript(*script, *array);
9617 if (number > kBufferSize) {
9618 array = Factory::NewFixedArray(number);
9619 FindSharedFunctionInfosForScript(*script, *array);
9620 }
9621
9622 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
9623 result->set_length(Smi::FromInt(number));
9624
9625 LiveEdit::WrapSharedFunctionInfos(result);
9626
9627 return *result;
9628}
9629
9630// For a script calculates compilation information about all its functions.
9631// The script source is explicitly specified by the second argument.
9632// The source of the actual script is not used, however it is important that
9633// all generated code keeps references to this particular instance of script.
9634// Returns a JSArray of compilation infos. The array is ordered so that
9635// each function with all its descendant is always stored in a continues range
9636// with the function itself going first. The root function is a script function.
9637static Object* Runtime_LiveEditGatherCompileInfo(Arguments args) {
9638 ASSERT(args.length() == 2);
9639 HandleScope scope;
9640 CONVERT_CHECKED(JSValue, script, args[0]);
9641 CONVERT_ARG_CHECKED(String, source, 1);
9642 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
9643
9644 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
9645
9646 if (Top::has_pending_exception()) {
9647 return Failure::Exception();
9648 }
9649
9650 return result;
9651}
9652
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009653// Changes the source of the script to a new_source.
9654// If old_script_name is provided (i.e. is a String), also creates a copy of
9655// the script with its original source and sends notification to debugger.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009656static Object* Runtime_LiveEditReplaceScript(Arguments args) {
9657 ASSERT(args.length() == 3);
9658 HandleScope scope;
9659 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
9660 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009661 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009662
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009663 CONVERT_CHECKED(Script, original_script_pointer,
9664 original_script_value->value());
9665 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009666
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009667 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
9668 new_source,
9669 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009670
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009671 if (old_script->IsScript()) {
9672 Handle<Script> script_handle(Script::cast(old_script));
9673 return *(GetScriptWrapper(script_handle));
9674 } else {
9675 return Heap::null_value();
9676 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009677}
9678
9679// Replaces code of SharedFunctionInfo with a new one.
9680static Object* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
9681 ASSERT(args.length() == 2);
9682 HandleScope scope;
9683 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
9684 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
9685
ager@chromium.orgac091b72010-05-05 07:34:42 +00009686 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009687}
9688
9689// Connects SharedFunctionInfo to another script.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009690static Object* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009691 ASSERT(args.length() == 2);
9692 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009693 Handle<Object> function_object(args[0]);
9694 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009695
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009696 if (function_object->IsJSValue()) {
9697 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
9698 if (script_object->IsJSValue()) {
9699 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
9700 script_object = Handle<Object>(script);
9701 }
9702
9703 LiveEdit::SetFunctionScript(function_wrapper, script_object);
9704 } else {
9705 // Just ignore this. We may not have a SharedFunctionInfo for some functions
9706 // and we check it in this function.
9707 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009708
9709 return Heap::undefined_value();
9710}
9711
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009712
9713// In a code of a parent function replaces original function as embedded object
9714// with a substitution one.
9715static Object* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
9716 ASSERT(args.length() == 3);
9717 HandleScope scope;
9718
9719 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
9720 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
9721 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
9722
9723 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
9724 subst_wrapper);
9725
9726 return Heap::undefined_value();
9727}
9728
9729
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009730// Updates positions of a shared function info (first parameter) according
9731// to script source change. Text change is described in second parameter as
9732// array of groups of 3 numbers:
9733// (change_begin, change_end, change_end_new_position).
9734// Each group describes a change in text; groups are sorted by change_begin.
9735static Object* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
9736 ASSERT(args.length() == 2);
9737 HandleScope scope;
9738 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
9739 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
9740
ager@chromium.orgac091b72010-05-05 07:34:42 +00009741 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009742}
9743
9744
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009745// For array of SharedFunctionInfo's (each wrapped in JSValue)
9746// checks that none of them have activations on stacks (of any thread).
9747// Returns array of the same length with corresponding results of
9748// LiveEdit::FunctionPatchabilityStatus type.
ager@chromium.org357bf652010-04-12 11:30:10 +00009749static Object* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
9750 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009751 HandleScope scope;
9752 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +00009753 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009754
ager@chromium.org357bf652010-04-12 11:30:10 +00009755 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009756}
9757
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009758// Compares 2 strings line-by-line and returns diff in form of JSArray of
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00009759// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009760static Object* Runtime_LiveEditCompareStringsLinewise(Arguments args) {
9761 ASSERT(args.length() == 2);
9762 HandleScope scope;
9763 CONVERT_ARG_CHECKED(String, s1, 0);
9764 CONVERT_ARG_CHECKED(String, s2, 1);
9765
9766 return *LiveEdit::CompareStringsLinewise(s1, s2);
9767}
9768
9769
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009770
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009771// A testing entry. Returns statement position which is the closest to
9772// source_position.
9773static Object* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
9774 ASSERT(args.length() == 2);
9775 HandleScope scope;
9776 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9777 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9778
9779 Handle<Code> code(function->code());
9780
9781 RelocIterator it(*code, 1 << RelocInfo::STATEMENT_POSITION);
9782 int closest_pc = 0;
9783 int distance = kMaxInt;
9784 while (!it.done()) {
9785 int statement_position = static_cast<int>(it.rinfo()->data());
9786 // Check if this break point is closer that what was previously found.
9787 if (source_position <= statement_position &&
9788 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00009789 closest_pc =
9790 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009791 distance = statement_position - source_position;
9792 // Check whether we can't get any closer.
9793 if (distance == 0) break;
9794 }
9795 it.next();
9796 }
9797
9798 return Smi::FromInt(closest_pc);
9799}
9800
9801
ager@chromium.org357bf652010-04-12 11:30:10 +00009802// Calls specified function with or without entering the debugger.
9803// This is used in unit tests to run code as if debugger is entered or simply
9804// to have a stack with C++ frame in the middle.
9805static Object* Runtime_ExecuteInDebugContext(Arguments args) {
9806 ASSERT(args.length() == 2);
9807 HandleScope scope;
9808 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9809 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
9810
9811 Handle<Object> result;
9812 bool pending_exception;
9813 {
9814 if (without_debugger) {
9815 result = Execution::Call(function, Top::global(), 0, NULL,
9816 &pending_exception);
9817 } else {
9818 EnterDebugger enter_debugger;
9819 result = Execution::Call(function, Top::global(), 0, NULL,
9820 &pending_exception);
9821 }
9822 }
9823 if (!pending_exception) {
9824 return *result;
9825 } else {
9826 return Failure::Exception();
9827 }
9828}
9829
9830
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009831#endif // ENABLE_DEBUGGER_SUPPORT
9832
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009833#ifdef ENABLE_LOGGING_AND_PROFILING
9834
9835static Object* Runtime_ProfilerResume(Arguments args) {
9836 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009837 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009838
9839 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00009840 CONVERT_CHECKED(Smi, smi_tag, args[1]);
9841 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009842 return Heap::undefined_value();
9843}
9844
9845
9846static Object* Runtime_ProfilerPause(Arguments args) {
9847 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009848 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009849
9850 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00009851 CONVERT_CHECKED(Smi, smi_tag, args[1]);
9852 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009853 return Heap::undefined_value();
9854}
9855
9856#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009857
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009858// Finds the script object from the script data. NOTE: This operation uses
9859// heap traversal to find the function generated for the source position
9860// for the requested break point. For lazily compiled functions several heap
9861// traversals might be required rendering this operation as a rather slow
9862// operation. However for setting break points which is normally done through
9863// some kind of user interaction the performance is not crucial.
9864static Handle<Object> Runtime_GetScriptFromScriptName(
9865 Handle<String> script_name) {
9866 // Scan the heap for Script objects to find the script with the requested
9867 // script data.
9868 Handle<Script> script;
9869 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009870 HeapObject* obj = NULL;
9871 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009872 // If a script is found check if it has the script data requested.
9873 if (obj->IsScript()) {
9874 if (Script::cast(obj)->name()->IsString()) {
9875 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
9876 script = Handle<Script>(Script::cast(obj));
9877 }
9878 }
9879 }
9880 }
9881
9882 // If no script with the requested script data is found return undefined.
9883 if (script.is_null()) return Factory::undefined_value();
9884
9885 // Return the script found.
9886 return GetScriptWrapper(script);
9887}
9888
9889
9890// Get the script object from script data. NOTE: Regarding performance
9891// see the NOTE for GetScriptFromScriptData.
9892// args[0]: script data for the script to find the source for
9893static Object* Runtime_GetScript(Arguments args) {
9894 HandleScope scope;
9895
9896 ASSERT(args.length() == 1);
9897
9898 CONVERT_CHECKED(String, script_name, args[0]);
9899
9900 // Find the requested script.
9901 Handle<Object> result =
9902 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
9903 return *result;
9904}
9905
9906
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009907// Determines whether the given stack frame should be displayed in
9908// a stack trace. The caller is the error constructor that asked
9909// for the stack trace to be collected. The first time a construct
9910// call to this function is encountered it is skipped. The seen_caller
9911// in/out parameter is used to remember if the caller has been seen
9912// yet.
9913static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
9914 bool* seen_caller) {
9915 // Only display JS frames.
9916 if (!raw_frame->is_java_script())
9917 return false;
9918 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
9919 Object* raw_fun = frame->function();
9920 // Not sure when this can happen but skip it just in case.
9921 if (!raw_fun->IsJSFunction())
9922 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009923 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009924 *seen_caller = true;
9925 return false;
9926 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009927 // Skip all frames until we've seen the caller. Also, skip the most
9928 // obvious builtin calls. Some builtin calls (such as Number.ADD
9929 // which is invoked using 'call') are very difficult to recognize
9930 // so we're leaving them in for now.
9931 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009932}
9933
9934
9935// Collect the raw data for a stack trace. Returns an array of three
9936// element segments each containing a receiver, function and native
9937// code offset.
9938static Object* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009939 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009940 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009941 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
9942
9943 HandleScope scope;
9944
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00009945 limit = Max(limit, 0); // Ensure that limit is not negative.
9946 int initial_size = Min(limit, 10);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009947 Handle<JSArray> result = Factory::NewJSArray(initial_size * 3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009948
9949 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009950 // If the caller parameter is a function we skip frames until we're
9951 // under it before starting to collect.
9952 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009953 int cursor = 0;
9954 int frames_seen = 0;
9955 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009956 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009957 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009958 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009959 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009960 Object* recv = frame->receiver();
9961 Object* fun = frame->function();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009962 Address pc = frame->pc();
9963 Address start = frame->code()->address();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009964 Smi* offset = Smi::FromInt(static_cast<int>(pc - start));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009965 FixedArray* elements = FixedArray::cast(result->elements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009966 if (cursor + 2 < elements->length()) {
9967 elements->set(cursor++, recv);
9968 elements->set(cursor++, fun);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009969 elements->set(cursor++, offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009970 } else {
9971 HandleScope scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009972 Handle<Object> recv_handle(recv);
9973 Handle<Object> fun_handle(fun);
9974 SetElement(result, cursor++, recv_handle);
9975 SetElement(result, cursor++, fun_handle);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009976 SetElement(result, cursor++, Handle<Smi>(offset));
9977 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009978 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009979 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009980 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009981
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009982 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009983 return *result;
9984}
9985
9986
ager@chromium.org3811b432009-10-28 14:53:37 +00009987// Returns V8 version as a string.
9988static Object* Runtime_GetV8Version(Arguments args) {
9989 ASSERT_EQ(args.length(), 0);
9990
9991 NoHandleAllocation ha;
9992
9993 const char* version_string = v8::V8::GetVersion();
9994
9995 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
9996}
9997
9998
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009999static Object* Runtime_Abort(Arguments args) {
10000 ASSERT(args.length() == 2);
10001 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10002 Smi::cast(args[1])->value());
10003 Top::PrintStack();
10004 OS::Abort();
10005 UNREACHABLE();
10006 return NULL;
10007}
10008
10009
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010010static Object* Runtime_DeleteHandleScopeExtensions(Arguments args) {
10011 ASSERT(args.length() == 0);
10012 HandleScope::DeleteExtensions();
10013 return Heap::undefined_value();
10014}
10015
10016
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010017static Object* CacheMiss(FixedArray* cache_obj, int index, Object* key_obj) {
10018 ASSERT(index % 2 == 0); // index of the key
10019 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10020 ASSERT(index < cache_obj->length());
10021
10022 HandleScope scope;
10023
10024 Handle<FixedArray> cache(cache_obj);
10025 Handle<Object> key(key_obj);
10026 Handle<JSFunction> factory(JSFunction::cast(
10027 cache->get(JSFunctionResultCache::kFactoryIndex)));
10028 // TODO(antonm): consider passing a receiver when constructing a cache.
10029 Handle<Object> receiver(Top::global_context()->global());
10030
10031 Handle<Object> value;
10032 {
10033 // This handle is nor shared, nor used later, so it's safe.
10034 Object** argv[] = { key.location() };
10035 bool pending_exception = false;
10036 value = Execution::Call(factory,
10037 receiver,
10038 1,
10039 argv,
10040 &pending_exception);
10041 if (pending_exception) return Failure::Exception();
10042 }
10043
10044 cache->set(index, *key);
10045 cache->set(index + 1, *value);
10046 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index));
10047
10048 return *value;
10049}
10050
10051
10052static Object* Runtime_GetFromCache(Arguments args) {
10053 // This is only called from codegen, so checks might be more lax.
10054 CONVERT_CHECKED(FixedArray, cache, args[0]);
10055 Object* key = args[1];
10056
10057 const int finger_index =
10058 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value();
10059
10060 Object* o = cache->get(finger_index);
10061 if (o == key) {
10062 // The fastest case: hit the same place again.
10063 return cache->get(finger_index + 1);
10064 }
10065
10066 for (int i = finger_index - 2;
10067 i >= JSFunctionResultCache::kEntriesIndex;
10068 i -= 2) {
10069 o = cache->get(i);
10070 if (o == key) {
10071 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10072 return cache->get(i + 1);
10073 }
10074 }
10075
10076 const int size =
10077 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value();
10078 ASSERT(size <= cache->length());
10079
10080 for (int i = size - 2; i > finger_index; i -= 2) {
10081 o = cache->get(i);
10082 if (o == key) {
10083 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10084 return cache->get(i + 1);
10085 }
10086 }
10087
10088 // Cache miss. If we have spare room, put new data into it, otherwise
10089 // evict post finger entry which must be least recently used.
10090 if (size < cache->length()) {
10091 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2));
10092 return CacheMiss(cache, size, key);
10093 } else {
antonm@chromium.org397e23c2010-04-21 12:00:05 +000010094 int target_index = finger_index + JSFunctionResultCache::kEntrySize;
10095 if (target_index == cache->length()) {
10096 target_index = JSFunctionResultCache::kEntriesIndex;
10097 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010098 return CacheMiss(cache, target_index, key);
10099 }
10100}
10101
kasper.lund44510672008-07-25 07:37:58 +000010102#ifdef DEBUG
10103// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10104// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010105static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010106 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010107 HandleScope scope;
10108 Handle<JSArray> result = Factory::NewJSArray(0);
10109 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010110 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010111#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010112 { \
10113 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010114 Handle<String> name; \
10115 /* Inline runtime functions have an underscore in front of the name. */ \
10116 if (inline_runtime_functions) { \
10117 name = Factory::NewStringFromAscii( \
10118 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10119 } else { \
10120 name = Factory::NewStringFromAscii( \
10121 Vector<const char>(#Name, StrLength(#Name))); \
10122 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010123 Handle<JSArray> pair = Factory::NewJSArray(0); \
10124 SetElement(pair, 0, name); \
10125 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10126 SetElement(result, index++, pair); \
10127 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010128 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010129 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010130 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010131 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010132 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010133#undef ADD_ENTRY
10134 return *result;
10135}
kasper.lund44510672008-07-25 07:37:58 +000010136#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010137
10138
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010139static Object* Runtime_Log(Arguments args) {
10140 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010141 CONVERT_CHECKED(String, format, args[0]);
10142 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010143 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010144 Logger::LogRuntime(chars, elms);
10145 return Heap::undefined_value();
10146}
10147
10148
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010149static Object* Runtime_IS_VAR(Arguments args) {
10150 UNREACHABLE(); // implemented as macro in the parser
10151 return NULL;
10152}
10153
10154
10155// ----------------------------------------------------------------------------
10156// Implementation of Runtime
10157
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010158#define F(name, number_of_args, result_size) \
10159 { Runtime::k##name, Runtime::RUNTIME, #name, \
10160 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010161
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010162
10163#define I(name, number_of_args, result_size) \
10164 { Runtime::kInline##name, Runtime::INLINE, \
10165 "_" #name, NULL, number_of_args, result_size },
10166
10167Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010168 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010169 INLINE_FUNCTION_LIST(I)
10170 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010171};
10172
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010173
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010174Object* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
10175 ASSERT(dictionary != NULL);
10176 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10177 for (int i = 0; i < kNumFunctions; ++i) {
10178 Object* name_symbol = Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10179 if (name_symbol->IsFailure()) return name_symbol;
10180 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
10181 dictionary = string_dictionary->Add(String::cast(name_symbol),
10182 Smi::FromInt(i),
10183 PropertyDetails(NONE, NORMAL));
10184 // Non-recoverable failure. Calling code must restart heap initialization.
10185 if (dictionary->IsFailure()) return dictionary;
10186 }
10187 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010188}
10189
10190
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010191Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10192 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10193 if (entry != kNotFound) {
10194 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10195 int function_index = Smi::cast(smi_index)->value();
10196 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010197 }
10198 return NULL;
10199}
10200
10201
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010202Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10203 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10204}
10205
10206
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010207void Runtime::PerformGC(Object* result) {
10208 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010209 if (failure->IsRetryAfterGC()) {
10210 // Try to do a garbage collection; ignore it if it fails. The C
10211 // entry stub will throw an out-of-memory exception in that case.
10212 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
10213 } else {
10214 // Handle last resort GC and make sure to allow future allocations
10215 // to grow the heap without causing GCs (if possible).
10216 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010217 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010218 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010219}
10220
10221
10222} } // namespace v8::internal