blob: b34981521935bc717b5cfedb09bd14c402df6136 [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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050
kasperl@chromium.org71affb52009-05-26 05:44:31 +000051namespace v8 {
52namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053
54
ager@chromium.org3e875802009-06-29 08:26:34 +000055#define RUNTIME_ASSERT(value) \
56 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
58// Cast the given object to a value of the specified type and store
59// it in a variable with the given name. If the object is not of the
60// expected type call IllegalOperation and return.
61#define CONVERT_CHECKED(Type, name, obj) \
62 RUNTIME_ASSERT(obj->Is##Type()); \
63 Type* name = Type::cast(obj);
64
65#define CONVERT_ARG_CHECKED(Type, name, index) \
66 RUNTIME_ASSERT(args[index]->Is##Type()); \
67 Handle<Type> name = args.at<Type>(index);
68
kasper.lundbd3ec4e2008-07-09 11:06:54 +000069// Cast the given object to a boolean and store it in a variable with
70// the given name. If the object is not a boolean call IllegalOperation
71// and return.
72#define CONVERT_BOOLEAN_CHECKED(name, obj) \
73 RUNTIME_ASSERT(obj->IsBoolean()); \
74 bool name = (obj)->IsTrue();
75
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000076// Cast the given object to a Smi and store its value in an int variable
77// with the given name. If the object is not a Smi call IllegalOperation
78// and return.
79#define CONVERT_SMI_CHECKED(name, obj) \
80 RUNTIME_ASSERT(obj->IsSmi()); \
81 int name = Smi::cast(obj)->value();
82
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000083// Cast the given object to a double and store it in a variable with
84// the given name. If the object is not a number (as opposed to
85// the number not-a-number) call IllegalOperation and return.
86#define CONVERT_DOUBLE_CHECKED(name, obj) \
87 RUNTIME_ASSERT(obj->IsNumber()); \
88 double name = (obj)->Number();
89
90// Call the specified converter on the object *comand store the result in
91// a variable of the specified type with the given name. If the
92// object is not a Number call IllegalOperation and return.
93#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
94 RUNTIME_ASSERT(obj->IsNumber()); \
95 type name = NumberTo##Type(obj);
96
97// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000098static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099
100
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000101static Object* DeepCopyBoilerplate(JSObject* boilerplate) {
102 StackLimitCheck check;
103 if (check.HasOverflowed()) return Top::StackOverflow();
104
105 Object* result = Heap::CopyJSObject(boilerplate);
106 if (result->IsFailure()) return result;
107 JSObject* copy = JSObject::cast(result);
108
109 // Deep copy local properties.
110 if (copy->HasFastProperties()) {
111 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000112 for (int i = 0; i < properties->length(); i++) {
113 Object* value = properties->get(i);
114 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000115 JSObject* js_object = JSObject::cast(value);
116 result = DeepCopyBoilerplate(js_object);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000117 if (result->IsFailure()) return result;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000118 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119 }
120 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000121 int nof = copy->map()->inobject_properties();
122 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000123 Object* value = copy->InObjectPropertyAt(i);
124 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 JSObject* js_object = JSObject::cast(value);
126 result = DeepCopyBoilerplate(js_object);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000127 if (result->IsFailure()) return result;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000128 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 }
130 }
131 } else {
132 result = Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
133 if (result->IsFailure()) return result;
134 FixedArray* names = FixedArray::cast(result);
135 copy->GetLocalPropertyNames(names, 0);
136 for (int i = 0; i < names->length(); i++) {
137 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000138 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000139 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000140 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000141 // Only deep copy fields from the object literal expression.
142 // In particular, don't try to copy the length attribute of
143 // an array.
144 if (attributes != NONE) continue;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000145 Object* value = copy->GetProperty(key_string, &attributes);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 ASSERT(!value->IsFailure());
147 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 JSObject* js_object = JSObject::cast(value);
149 result = DeepCopyBoilerplate(js_object);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 if (result->IsFailure()) return result;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 result = copy->SetProperty(key_string, result, NONE);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 if (result->IsFailure()) return result;
153 }
154 }
155 }
156
157 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000158 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000159 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000160 switch (copy->GetElementsKind()) {
161 case JSObject::FAST_ELEMENTS: {
162 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000163 for (int i = 0; i < elements->length(); i++) {
164 Object* value = elements->get(i);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000165 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000166 JSObject* js_object = JSObject::cast(value);
167 result = DeepCopyBoilerplate(js_object);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000168 if (result->IsFailure()) return result;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000169 elements->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000170 }
171 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000172 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000174 case JSObject::DICTIONARY_ELEMENTS: {
175 NumberDictionary* element_dictionary = copy->element_dictionary();
176 int capacity = element_dictionary->Capacity();
177 for (int i = 0; i < capacity; i++) {
178 Object* k = element_dictionary->KeyAt(i);
179 if (element_dictionary->IsKey(k)) {
180 Object* value = element_dictionary->ValueAt(i);
181 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000182 JSObject* js_object = JSObject::cast(value);
183 result = DeepCopyBoilerplate(js_object);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000184 if (result->IsFailure()) return result;
185 element_dictionary->ValueAtPut(i, result);
186 }
187 }
188 }
189 break;
190 }
191 default:
192 UNREACHABLE();
193 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000194 }
195 return copy;
196}
197
198
199static Object* Runtime_CloneLiteralBoilerplate(Arguments args) {
200 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
201 return DeepCopyBoilerplate(boilerplate);
202}
203
204
205static Object* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000206 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000207 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000208}
209
210
ager@chromium.org236ad962008-09-25 09:45:57 +0000211static Handle<Map> ComputeObjectLiteralMap(
212 Handle<Context> context,
213 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000214 bool* is_result_from_cache) {
ager@chromium.org32912102009-01-16 10:38:43 +0000215 int number_of_properties = constant_properties->length() / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000216 if (FLAG_canonicalize_object_literal_maps) {
217 // First find prefix of consecutive symbol keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000218 int number_of_symbol_keys = 0;
219 while ((number_of_symbol_keys < number_of_properties) &&
220 (constant_properties->get(number_of_symbol_keys*2)->IsSymbol())) {
221 number_of_symbol_keys++;
222 }
223 // Based on the number of prefix symbols key we decide whether
224 // to use the map cache in the global context.
225 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000226 if ((number_of_symbol_keys == number_of_properties) &&
227 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000228 // Create the fixed array with the key.
229 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
230 for (int i = 0; i < number_of_symbol_keys; i++) {
231 keys->set(i, constant_properties->get(i*2));
232 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000233 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000234 return Factory::ObjectLiteralMapFromCache(context, keys);
235 }
236 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000237 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000238 return Factory::CopyMap(
239 Handle<Map>(context->object_function()->initial_map()),
240 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000241}
242
243
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000244static Handle<Object> CreateLiteralBoilerplate(
245 Handle<FixedArray> literals,
246 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000247
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000248
249static Handle<Object> CreateObjectLiteralBoilerplate(
250 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000251 Handle<FixedArray> constant_properties,
252 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000253 // Get the global context from the literals array. This is the
254 // context in which the function was created and we use the object
255 // function from this context to create the object literal. We do
256 // not use the object function from the current global context
257 // because this might be the object function from another context
258 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000259 Handle<Context> context =
260 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
261
262 bool is_result_from_cache;
263 Handle<Map> map = ComputeObjectLiteralMap(context,
264 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000265 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000266
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000268
269 // Normalize the elements of the boilerplate to save space if needed.
270 if (!should_have_fast_elements) NormalizeElements(boilerplate);
271
ager@chromium.org32912102009-01-16 10:38:43 +0000272 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000273 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000274 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000275 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000276 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000277 for (int index = 0; index < length; index +=2) {
278 Handle<Object> key(constant_properties->get(index+0));
279 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000280 if (value->IsFixedArray()) {
281 // The value contains the constant_properties of a
282 // simple object literal.
283 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
284 value = CreateLiteralBoilerplate(literals, array);
285 if (value.is_null()) return value;
286 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000287 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000288 uint32_t element_index = 0;
289 if (key->IsSymbol()) {
290 // If key is a symbol it is not an array element.
291 Handle<String> name(String::cast(*key));
292 ASSERT(!name->AsArrayIndex(&element_index));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000293 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000294 } else if (Array::IndexFromObject(*key, &element_index)) {
295 // Array index (uint32).
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000296 result = SetElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297 } else {
298 // Non-uint32 number.
299 ASSERT(key->IsNumber());
300 double num = key->Number();
301 char arr[100];
302 Vector<char> buffer(arr, ARRAY_SIZE(arr));
303 const char* str = DoubleToCString(num, buffer);
304 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000305 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000306 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000307 // If setting the property on the boilerplate throws an
308 // exception, the exception is converted to an empty handle in
309 // the handle based operations. In that case, we need to
310 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000311 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000312 }
313 }
314
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000315 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000316}
317
318
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000319static Handle<Object> CreateArrayLiteralBoilerplate(
320 Handle<FixedArray> literals,
321 Handle<FixedArray> elements) {
322 // Create the JSArray.
323 Handle<JSFunction> constructor(
324 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
325 Handle<Object> object = Factory::NewJSObject(constructor);
326
327 Handle<Object> copied_elements = Factory::CopyFixedArray(elements);
328
329 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
330 for (int i = 0; i < content->length(); i++) {
331 if (content->get(i)->IsFixedArray()) {
332 // The value contains the constant_properties of a
333 // simple object literal.
334 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
335 Handle<Object> result =
336 CreateLiteralBoilerplate(literals, fa);
337 if (result.is_null()) return result;
338 content->set(i, *result);
339 }
340 }
341
342 // Set the elements.
343 Handle<JSArray>::cast(object)->SetContent(*content);
344 return object;
345}
346
347
348static Handle<Object> CreateLiteralBoilerplate(
349 Handle<FixedArray> literals,
350 Handle<FixedArray> array) {
351 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
352 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000353 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
354 return CreateObjectLiteralBoilerplate(literals, elements, true);
355 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
356 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000357 case CompileTimeValue::ARRAY_LITERAL:
358 return CreateArrayLiteralBoilerplate(literals, elements);
359 default:
360 UNREACHABLE();
361 return Handle<Object>::null();
362 }
363}
364
365
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000366static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000367 // Takes a FixedArray of elements containing the literal elements of
368 // the array literal and produces JSArray with those elements.
369 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000370 // which contains the context from which to get the Array function
371 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000372 HandleScope scope;
373 ASSERT(args.length() == 3);
374 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
375 CONVERT_SMI_CHECKED(literals_index, args[1]);
376 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000378 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
379 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000380
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000381 // Update the functions literal and return the boilerplate.
382 literals->set(literals_index, *object);
383 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384}
385
386
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000387static Object* Runtime_CreateObjectLiteral(Arguments args) {
388 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000389 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000390 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
391 CONVERT_SMI_CHECKED(literals_index, args[1]);
392 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000393 CONVERT_SMI_CHECKED(fast_elements, args[3]);
394 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000395
396 // Check if boilerplate exists. If not, create it first.
397 Handle<Object> boilerplate(literals->get(literals_index));
398 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000399 boilerplate = CreateObjectLiteralBoilerplate(literals,
400 constant_properties,
401 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000402 if (boilerplate.is_null()) return Failure::Exception();
403 // Update the functions literal and return the boilerplate.
404 literals->set(literals_index, *boilerplate);
405 }
406 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
407}
408
409
410static Object* Runtime_CreateObjectLiteralShallow(Arguments args) {
411 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000412 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000413 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
414 CONVERT_SMI_CHECKED(literals_index, args[1]);
415 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000416 CONVERT_SMI_CHECKED(fast_elements, args[3]);
417 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000418
419 // Check if boilerplate exists. If not, create it first.
420 Handle<Object> boilerplate(literals->get(literals_index));
421 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000422 boilerplate = CreateObjectLiteralBoilerplate(literals,
423 constant_properties,
424 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000425 if (boilerplate.is_null()) return Failure::Exception();
426 // Update the functions literal and return the boilerplate.
427 literals->set(literals_index, *boilerplate);
428 }
429 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
430}
431
432
433static Object* Runtime_CreateArrayLiteral(Arguments args) {
434 HandleScope scope;
435 ASSERT(args.length() == 3);
436 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
437 CONVERT_SMI_CHECKED(literals_index, args[1]);
438 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
439
440 // Check if boilerplate exists. If not, create it first.
441 Handle<Object> boilerplate(literals->get(literals_index));
442 if (*boilerplate == Heap::undefined_value()) {
443 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
444 if (boilerplate.is_null()) return Failure::Exception();
445 // Update the functions literal and return the boilerplate.
446 literals->set(literals_index, *boilerplate);
447 }
448 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
449}
450
451
452static Object* Runtime_CreateArrayLiteralShallow(Arguments args) {
453 HandleScope scope;
454 ASSERT(args.length() == 3);
455 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
456 CONVERT_SMI_CHECKED(literals_index, args[1]);
457 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
458
459 // Check if boilerplate exists. If not, create it first.
460 Handle<Object> boilerplate(literals->get(literals_index));
461 if (*boilerplate == Heap::undefined_value()) {
462 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
463 if (boilerplate.is_null()) return Failure::Exception();
464 // Update the functions literal and return the boilerplate.
465 literals->set(literals_index, *boilerplate);
466 }
467 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
468}
469
470
ager@chromium.org32912102009-01-16 10:38:43 +0000471static Object* Runtime_CreateCatchExtensionObject(Arguments args) {
472 ASSERT(args.length() == 2);
473 CONVERT_CHECKED(String, key, args[0]);
474 Object* value = args[1];
475 // Create a catch context extension object.
476 JSFunction* constructor =
477 Top::context()->global_context()->context_extension_function();
478 Object* object = Heap::AllocateJSObject(constructor);
479 if (object->IsFailure()) return object;
480 // Assign the exception value to the catch variable and make sure
481 // that the catch variable is DontDelete.
482 value = JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
483 if (value->IsFailure()) return value;
484 return object;
485}
486
487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000488static Object* Runtime_ClassOf(Arguments args) {
489 NoHandleAllocation ha;
490 ASSERT(args.length() == 1);
491 Object* obj = args[0];
492 if (!obj->IsJSObject()) return Heap::null_value();
493 return JSObject::cast(obj)->class_name();
494}
495
ager@chromium.org7c537e22008-10-16 08:43:32 +0000496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497static Object* Runtime_IsInPrototypeChain(Arguments args) {
498 NoHandleAllocation ha;
499 ASSERT(args.length() == 2);
500 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
501 Object* O = args[0];
502 Object* V = args[1];
503 while (true) {
504 Object* prototype = V->GetPrototype();
505 if (prototype->IsNull()) return Heap::false_value();
506 if (O == prototype) return Heap::true_value();
507 V = prototype;
508 }
509}
510
511
ager@chromium.org9085a012009-05-11 19:22:57 +0000512// Inserts an object as the hidden prototype of another object.
513static Object* Runtime_SetHiddenPrototype(Arguments args) {
514 NoHandleAllocation ha;
515 ASSERT(args.length() == 2);
516 CONVERT_CHECKED(JSObject, jsobject, args[0]);
517 CONVERT_CHECKED(JSObject, proto, args[1]);
518
519 // Sanity checks. The old prototype (that we are replacing) could
520 // theoretically be null, but if it is not null then check that we
521 // didn't already install a hidden prototype here.
522 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
523 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
524 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
525
526 // Allocate up front before we start altering state in case we get a GC.
527 Object* map_or_failure = proto->map()->CopyDropTransitions();
528 if (map_or_failure->IsFailure()) return map_or_failure;
529 Map* new_proto_map = Map::cast(map_or_failure);
530
531 map_or_failure = jsobject->map()->CopyDropTransitions();
532 if (map_or_failure->IsFailure()) return map_or_failure;
533 Map* new_map = Map::cast(map_or_failure);
534
535 // Set proto's prototype to be the old prototype of the object.
536 new_proto_map->set_prototype(jsobject->GetPrototype());
537 proto->set_map(new_proto_map);
538 new_proto_map->set_is_hidden_prototype();
539
540 // Set the object's prototype to proto.
541 new_map->set_prototype(proto);
542 jsobject->set_map(new_map);
543
544 return Heap::undefined_value();
545}
546
547
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548static Object* Runtime_IsConstructCall(Arguments args) {
549 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000550 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551 JavaScriptFrameIterator it;
552 return Heap::ToBoolean(it.frame()->IsConstructor());
553}
554
555
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000556// Recursively traverses hidden prototypes if property is not found
557static void GetOwnPropertyImplementation(JSObject* obj,
558 String* name,
559 LookupResult* result) {
560 obj->LocalLookupRealNamedProperty(name, result);
561
562 if (!result->IsProperty()) {
563 Object* proto = obj->GetPrototype();
564 if (proto->IsJSObject() &&
565 JSObject::cast(proto)->map()->is_hidden_prototype())
566 GetOwnPropertyImplementation(JSObject::cast(proto),
567 name, result);
568 }
569}
570
571
572// Returns an array with the property description:
573// if args[1] is not a property on args[0]
574// returns undefined
575// if args[1] is a data property on args[0]
576// [false, value, Writeable, Enumerable, Configurable]
577// if args[1] is an accessor on args[0]
578// [true, GetFunction, SetFunction, Enumerable, Configurable]
579static Object* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000580 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000581 HandleScope scope;
582 Handle<FixedArray> elms = Factory::NewFixedArray(5);
583 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
584 LookupResult result;
585 CONVERT_CHECKED(JSObject, obj, args[0]);
586 CONVERT_CHECKED(String, name, args[1]);
587
588 // Use recursive implementation to also traverse hidden prototypes
589 GetOwnPropertyImplementation(obj, name, &result);
590
591 if (!result.IsProperty())
592 return Heap::undefined_value();
593
594 if (result.type() == CALLBACKS) {
595 Object* structure = result.GetCallbackObject();
ager@chromium.org5c838252010-02-19 08:53:10 +0000596 if (structure->IsProxy() || structure->IsAccessorInfo()) {
597 // Property that is internally implemented as a callback or
598 // an API defined callback.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000599 Object* value = obj->GetPropertyWithCallback(
600 obj, structure, name, result.holder());
601 elms->set(0, Heap::false_value());
602 elms->set(1, value);
603 elms->set(2, Heap::ToBoolean(!result.IsReadOnly()));
604 } else if (structure->IsFixedArray()) {
605 // __defineGetter__/__defineSetter__ callback.
606 elms->set(0, Heap::true_value());
607 elms->set(1, FixedArray::cast(structure)->get(0));
608 elms->set(2, FixedArray::cast(structure)->get(1));
609 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000610 return Heap::undefined_value();
611 }
612 } else {
613 elms->set(0, Heap::false_value());
614 elms->set(1, result.GetLazyValue());
615 elms->set(2, Heap::ToBoolean(!result.IsReadOnly()));
616 }
617
618 elms->set(3, Heap::ToBoolean(!result.IsDontEnum()));
ager@chromium.org5c838252010-02-19 08:53:10 +0000619 elms->set(4, Heap::ToBoolean(!result.IsDontDelete()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000620 return *desc;
621}
622
623
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000624static Object* Runtime_IsExtensible(Arguments args) {
625 ASSERT(args.length() == 1);
626 CONVERT_CHECKED(JSObject, obj, args[0]);
627 return obj->map()->is_extensible() ? Heap::true_value()
628 : Heap::false_value();
629}
630
631
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000632static Object* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000633 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000635 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
636 CONVERT_ARG_CHECKED(String, pattern, 1);
637 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000638 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
639 if (result.is_null()) return Failure::Exception();
640 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641}
642
643
644static Object* Runtime_CreateApiFunction(Arguments args) {
645 HandleScope scope;
646 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000647 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648 return *Factory::CreateApiFunction(data);
649}
650
651
652static Object* Runtime_IsTemplate(Arguments args) {
653 ASSERT(args.length() == 1);
654 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000655 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000656 return Heap::ToBoolean(result);
657}
658
659
660static Object* Runtime_GetTemplateField(Arguments args) {
661 ASSERT(args.length() == 2);
662 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000663 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000664 int index = field->value();
665 int offset = index * kPointerSize + HeapObject::kHeaderSize;
666 InstanceType type = templ->map()->instance_type();
667 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
668 type == OBJECT_TEMPLATE_INFO_TYPE);
669 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000670 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000671 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
672 } else {
673 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
674 }
675 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000676}
677
678
ager@chromium.org870a0b62008-11-04 11:43:05 +0000679static Object* Runtime_DisableAccessChecks(Arguments args) {
680 ASSERT(args.length() == 1);
681 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000682 Map* old_map = object->map();
683 bool needs_access_checks = old_map->is_access_check_needed();
684 if (needs_access_checks) {
685 // Copy map so it won't interfere constructor's initial map.
686 Object* new_map = old_map->CopyDropTransitions();
687 if (new_map->IsFailure()) return new_map;
688
689 Map::cast(new_map)->set_is_access_check_needed(false);
690 object->set_map(Map::cast(new_map));
691 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000692 return needs_access_checks ? Heap::true_value() : Heap::false_value();
693}
694
695
696static Object* Runtime_EnableAccessChecks(Arguments args) {
697 ASSERT(args.length() == 1);
698 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000699 Map* old_map = object->map();
700 if (!old_map->is_access_check_needed()) {
701 // Copy map so it won't interfere constructor's initial map.
702 Object* new_map = old_map->CopyDropTransitions();
703 if (new_map->IsFailure()) return new_map;
704
705 Map::cast(new_map)->set_is_access_check_needed(true);
706 object->set_map(Map::cast(new_map));
707 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000708 return Heap::undefined_value();
709}
710
711
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
713 HandleScope scope;
714 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
715 Handle<Object> args[2] = { type_handle, name };
716 Handle<Object> error =
717 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
718 return Top::Throw(*error);
719}
720
721
722static Object* Runtime_DeclareGlobals(Arguments args) {
723 HandleScope scope;
724 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
725
ager@chromium.org3811b432009-10-28 14:53:37 +0000726 Handle<Context> context = args.at<Context>(0);
727 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000728 bool is_eval = Smi::cast(args[2])->value() == 1;
729
730 // Compute the property attributes. According to ECMA-262, section
731 // 13, page 71, the property must be read-only and
732 // non-deletable. However, neither SpiderMonkey nor KJS creates the
733 // property as read-only, so we don't either.
734 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
735
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000736 // Traverse the name/value pairs and set the properties.
737 int length = pairs->length();
738 for (int i = 0; i < length; i += 2) {
739 HandleScope scope;
740 Handle<String> name(String::cast(pairs->get(i)));
741 Handle<Object> value(pairs->get(i + 1));
742
743 // We have to declare a global const property. To capture we only
744 // assign to it when evaluating the assignment for "const x =
745 // <expr>" the initial value is the hole.
746 bool is_const_property = value->IsTheHole();
747
748 if (value->IsUndefined() || is_const_property) {
749 // Lookup the property in the global object, and don't set the
750 // value of the variable if the property is already there.
751 LookupResult lookup;
752 global->Lookup(*name, &lookup);
753 if (lookup.IsProperty()) {
754 // Determine if the property is local by comparing the holder
755 // against the global object. The information will be used to
756 // avoid throwing re-declaration errors when declaring
757 // variables or constants that exist in the prototype chain.
758 bool is_local = (*global == lookup.holder());
759 // Get the property attributes and determine if the property is
760 // read-only.
761 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
762 bool is_read_only = (attributes & READ_ONLY) != 0;
763 if (lookup.type() == INTERCEPTOR) {
764 // If the interceptor says the property is there, we
765 // just return undefined without overwriting the property.
766 // Otherwise, we continue to setting the property.
767 if (attributes != ABSENT) {
768 // Check if the existing property conflicts with regards to const.
769 if (is_local && (is_read_only || is_const_property)) {
770 const char* type = (is_read_only) ? "const" : "var";
771 return ThrowRedeclarationError(type, name);
772 };
773 // The property already exists without conflicting: Go to
774 // the next declaration.
775 continue;
776 }
777 // Fall-through and introduce the absent property by using
778 // SetProperty.
779 } else {
780 if (is_local && (is_read_only || is_const_property)) {
781 const char* type = (is_read_only) ? "const" : "var";
782 return ThrowRedeclarationError(type, name);
783 }
784 // The property already exists without conflicting: Go to
785 // the next declaration.
786 continue;
787 }
788 }
789 } else {
790 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000791 Handle<SharedFunctionInfo> shared =
792 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000794 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000795 value = function;
796 }
797
798 LookupResult lookup;
799 global->LocalLookup(*name, &lookup);
800
801 PropertyAttributes attributes = is_const_property
802 ? static_cast<PropertyAttributes>(base | READ_ONLY)
803 : base;
804
805 if (lookup.IsProperty()) {
806 // There's a local property that we need to overwrite because
807 // we're either declaring a function or there's an interceptor
808 // that claims the property is absent.
809
810 // Check for conflicting re-declarations. We cannot have
811 // conflicting types in case of intercepted properties because
812 // they are absent.
813 if (lookup.type() != INTERCEPTOR &&
814 (lookup.IsReadOnly() || is_const_property)) {
815 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
816 return ThrowRedeclarationError(type, name);
817 }
818 SetProperty(global, name, value, attributes);
819 } else {
820 // If a property with this name does not already exist on the
821 // global object add the property locally. We take special
822 // precautions to always add it as a local property even in case
823 // of callbacks in the prototype chain (this rules out using
824 // SetProperty). Also, we must use the handle-based version to
825 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000826 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827 }
828 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000829
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830 return Heap::undefined_value();
831}
832
833
834static Object* Runtime_DeclareContextSlot(Arguments args) {
835 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000836 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000837
ager@chromium.org7c537e22008-10-16 08:43:32 +0000838 CONVERT_ARG_CHECKED(Context, context, 0);
839 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000841 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842 ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000843 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000844
845 // Declarations are always done in the function context.
846 context = Handle<Context>(context->fcontext());
847
848 int index;
849 PropertyAttributes attributes;
850 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000851 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000852 context->Lookup(name, flags, &index, &attributes);
853
854 if (attributes != ABSENT) {
855 // The name was declared before; check for conflicting
856 // re-declarations: This is similar to the code in parser.cc in
857 // the AstBuildingParser::Declare function.
858 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
859 // Functions are not read-only.
860 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
861 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
862 return ThrowRedeclarationError(type, name);
863 }
864
865 // Initialize it if necessary.
866 if (*initial_value != NULL) {
867 if (index >= 0) {
868 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000869 // the function context or the arguments object.
870 if (holder->IsContext()) {
871 ASSERT(holder.is_identical_to(context));
872 if (((attributes & READ_ONLY) == 0) ||
873 context->get(index)->IsTheHole()) {
874 context->set(index, *initial_value);
875 }
876 } else {
877 Handle<JSObject>::cast(holder)->SetElement(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000878 }
879 } else {
880 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000881 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000882 SetProperty(context_ext, name, initial_value, mode);
883 }
884 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000887 // The property is not in the function context. It needs to be
888 // "declared" in the function context's extension context, or in the
889 // global context.
890 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000891 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000892 // The function context's extension context exists - use it.
893 context_ext = Handle<JSObject>(context->extension());
894 } else {
895 // The function context's extension context does not exists - allocate
896 // it.
897 context_ext = Factory::NewJSObject(Top::context_extension_function());
898 // And store it in the extension slot.
899 context->set_extension(*context_ext);
900 }
901 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902
ager@chromium.org7c537e22008-10-16 08:43:32 +0000903 // Declare the property by setting it to the initial value if provided,
904 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
905 // constant declarations).
906 ASSERT(!context_ext->HasLocalProperty(*name));
907 Handle<Object> value(Heap::undefined_value());
908 if (*initial_value != NULL) value = initial_value;
909 SetProperty(context_ext, name, value, mode);
910 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
911 }
912
913 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914}
915
916
917static Object* Runtime_InitializeVarGlobal(Arguments args) {
918 NoHandleAllocation nha;
919
920 // Determine if we need to assign to the variable if it already
921 // exists (based on the number of arguments).
922 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
923 bool assign = args.length() == 2;
924
925 CONVERT_ARG_CHECKED(String, name, 0);
926 GlobalObject* global = Top::context()->global();
927
928 // According to ECMA-262, section 12.2, page 62, the property must
929 // not be deletable.
930 PropertyAttributes attributes = DONT_DELETE;
931
932 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000933 // there, there is a property with this name in the prototype chain.
934 // We follow Safari and Firefox behavior and only set the property
935 // locally if there is an explicit initialization value that we have
936 // to assign to the property. When adding the property we take
937 // special precautions to always add it as a local property even in
938 // case of callbacks in the prototype chain (this rules out using
939 // SetProperty). We have IgnoreAttributesAndSetLocalProperty for
940 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000941 // Note that objects can have hidden prototypes, so we need to traverse
942 // the whole chain of hidden prototypes to do a 'local' lookup.
943 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000944 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000945 while (true) {
946 real_holder->LocalLookup(*name, &lookup);
947 if (lookup.IsProperty()) {
948 // Determine if this is a redeclaration of something read-only.
949 if (lookup.IsReadOnly()) {
950 // If we found readonly property on one of hidden prototypes,
951 // just shadow it.
952 if (real_holder != Top::context()->global()) break;
953 return ThrowRedeclarationError("const", name);
954 }
955
956 // Determine if this is a redeclaration of an intercepted read-only
957 // property and figure out if the property exists at all.
958 bool found = true;
959 PropertyType type = lookup.type();
960 if (type == INTERCEPTOR) {
961 HandleScope handle_scope;
962 Handle<JSObject> holder(real_holder);
963 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
964 real_holder = *holder;
965 if (intercepted == ABSENT) {
966 // The interceptor claims the property isn't there. We need to
967 // make sure to introduce it.
968 found = false;
969 } else if ((intercepted & READ_ONLY) != 0) {
970 // The property is present, but read-only. Since we're trying to
971 // overwrite it with a variable declaration we must throw a
972 // re-declaration error. However if we found readonly property
973 // on one of hidden prototypes, just shadow it.
974 if (real_holder != Top::context()->global()) break;
975 return ThrowRedeclarationError("const", name);
976 }
977 }
978
979 if (found && !assign) {
980 // The global property is there and we're not assigning any value
981 // to it. Just return.
982 return Heap::undefined_value();
983 }
984
985 // Assign the value (or undefined) to the property.
986 Object* value = (assign) ? args[1] : Heap::undefined_value();
987 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000988 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000989
990 Object* proto = real_holder->GetPrototype();
991 if (!proto->IsJSObject())
992 break;
993
994 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
995 break;
996
997 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 }
999
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001000 global = Top::context()->global();
1001 if (assign) {
1002 return global->IgnoreAttributesAndSetLocalProperty(*name,
1003 args[1],
1004 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001005 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001006 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007}
1008
1009
1010static Object* Runtime_InitializeConstGlobal(Arguments args) {
1011 // All constants are declared with an initial value. The name
1012 // of the constant is the first argument and the initial value
1013 // is the second.
1014 RUNTIME_ASSERT(args.length() == 2);
1015 CONVERT_ARG_CHECKED(String, name, 0);
1016 Handle<Object> value = args.at<Object>(1);
1017
1018 // Get the current global object from top.
1019 GlobalObject* global = Top::context()->global();
1020
1021 // According to ECMA-262, section 12.2, page 62, the property must
1022 // not be deletable. Since it's a const, it must be READ_ONLY too.
1023 PropertyAttributes attributes =
1024 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1025
1026 // Lookup the property locally in the global object. If it isn't
1027 // there, we add the property and take special precautions to always
1028 // add it as a local property even in case of callbacks in the
1029 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001030 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001031 LookupResult lookup;
1032 global->LocalLookup(*name, &lookup);
1033 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001034 return global->IgnoreAttributesAndSetLocalProperty(*name,
1035 *value,
1036 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001037 }
1038
1039 // Determine if this is a redeclaration of something not
1040 // read-only. In case the result is hidden behind an interceptor we
1041 // need to ask it for the property attributes.
1042 if (!lookup.IsReadOnly()) {
1043 if (lookup.type() != INTERCEPTOR) {
1044 return ThrowRedeclarationError("var", name);
1045 }
1046
1047 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1048
1049 // Throw re-declaration error if the intercepted property is present
1050 // but not read-only.
1051 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1052 return ThrowRedeclarationError("var", name);
1053 }
1054
1055 // Restore global object from context (in case of GC) and continue
1056 // with setting the value because the property is either absent or
1057 // read-only. We also have to do redo the lookup.
1058 global = Top::context()->global();
1059
1060 // BUG 1213579: Handle the case where we have to set a read-only
1061 // property through an interceptor and only do it if it's
1062 // uninitialized, e.g. the hole. Nirk...
1063 global->SetProperty(*name, *value, attributes);
1064 return *value;
1065 }
1066
1067 // Set the value, but only we're assigning the initial value to a
1068 // constant. For now, we determine this by checking if the
1069 // current value is the hole.
1070 PropertyType type = lookup.type();
1071 if (type == FIELD) {
1072 FixedArray* properties = global->properties();
1073 int index = lookup.GetFieldIndex();
1074 if (properties->get(index)->IsTheHole()) {
1075 properties->set(index, *value);
1076 }
1077 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001078 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1079 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080 }
1081 } else {
1082 // Ignore re-initialization of constants that have already been
1083 // assigned a function value.
1084 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1085 }
1086
1087 // Use the set value as the result of the operation.
1088 return *value;
1089}
1090
1091
1092static Object* Runtime_InitializeConstContextSlot(Arguments args) {
1093 HandleScope scope;
1094 ASSERT(args.length() == 3);
1095
1096 Handle<Object> value(args[0]);
1097 ASSERT(!value->IsTheHole());
1098 CONVERT_ARG_CHECKED(Context, context, 1);
1099 Handle<String> name(String::cast(args[2]));
1100
1101 // Initializations are always done in the function context.
1102 context = Handle<Context>(context->fcontext());
1103
1104 int index;
1105 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001106 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001107 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001108 context->Lookup(name, flags, &index, &attributes);
1109
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001110 // In most situations, the property introduced by the const
1111 // declaration should be present in the context extension object.
1112 // However, because declaration and initialization are separate, the
1113 // property might have been deleted (if it was introduced by eval)
1114 // before we reach the initialization point.
1115 //
1116 // Example:
1117 //
1118 // function f() { eval("delete x; const x;"); }
1119 //
1120 // In that case, the initialization behaves like a normal assignment
1121 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001122 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001123 // Property was found in a context.
1124 if (holder->IsContext()) {
1125 // The holder cannot be the function context. If it is, there
1126 // should have been a const redeclaration error when declaring
1127 // the const property.
1128 ASSERT(!holder.is_identical_to(context));
1129 if ((attributes & READ_ONLY) == 0) {
1130 Handle<Context>::cast(holder)->set(index, *value);
1131 }
1132 } else {
1133 // The holder is an arguments object.
1134 ASSERT((attributes & READ_ONLY) == 0);
1135 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001136 }
1137 return *value;
1138 }
1139
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001140 // The property could not be found, we introduce it in the global
1141 // context.
1142 if (attributes == ABSENT) {
1143 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1144 SetProperty(global, name, value, NONE);
1145 return *value;
1146 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001148 // The property was present in a context extension object.
1149 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001150
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001151 if (*context_ext == context->extension()) {
1152 // This is the property that was introduced by the const
1153 // declaration. Set it if it hasn't been set before. NOTE: We
1154 // cannot use GetProperty() to get the current value as it
1155 // 'unholes' the value.
1156 LookupResult lookup;
1157 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1158 ASSERT(lookup.IsProperty()); // the property was declared
1159 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1160
1161 PropertyType type = lookup.type();
1162 if (type == FIELD) {
1163 FixedArray* properties = context_ext->properties();
1164 int index = lookup.GetFieldIndex();
1165 if (properties->get(index)->IsTheHole()) {
1166 properties->set(index, *value);
1167 }
1168 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001169 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1170 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001171 }
1172 } else {
1173 // We should not reach here. Any real, named property should be
1174 // either a field or a dictionary slot.
1175 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176 }
1177 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001178 // The property was found in a different context extension object.
1179 // Set it if it is not a read-only property.
1180 if ((attributes & READ_ONLY) == 0) {
1181 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1182 // Setting a property might throw an exception. Exceptions
1183 // are converted to empty handles in handle operations. We
1184 // need to convert back to exceptions here.
1185 if (set.is_null()) {
1186 ASSERT(Top::has_pending_exception());
1187 return Failure::Exception();
1188 }
1189 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001191
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192 return *value;
1193}
1194
1195
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001196static Object* Runtime_OptimizeObjectForAddingMultipleProperties(
1197 Arguments args) {
1198 HandleScope scope;
1199 ASSERT(args.length() == 2);
1200 CONVERT_ARG_CHECKED(JSObject, object, 0);
1201 CONVERT_SMI_CHECKED(properties, args[1]);
1202 if (object->HasFastProperties()) {
1203 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1204 }
1205 return *object;
1206}
1207
1208
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209static Object* Runtime_RegExpExec(Arguments args) {
1210 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001211 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001212 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1213 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001214 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001215 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001216 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001217 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001218 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001219 RUNTIME_ASSERT(index >= 0);
1220 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001221 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001222 Handle<Object> result = RegExpImpl::Exec(regexp,
1223 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001224 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001225 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001226 if (result.is_null()) return Failure::Exception();
1227 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228}
1229
1230
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001231static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) {
1232 HandleScope scope;
1233 ASSERT(args.length() == 1);
1234 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1235 // This is necessary to enable fast checks for absence of elements
1236 // on Array.prototype and below.
1237 prototype->set_elements(Heap::empty_fixed_array());
1238 return Smi::FromInt(0);
1239}
1240
1241
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001242static void SetCustomCallGenerator(Handle<JSFunction> function,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001243 ExternalReference* generator) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001244 if (function->shared()->function_data()->IsUndefined()) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001245 function->shared()->set_function_data(*FromCData(generator->address()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001246 }
1247}
1248
1249
1250static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1251 const char* name,
1252 Builtins::Name builtin_name,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001253 ExternalReference* generator = NULL) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001254 Handle<String> key = Factory::LookupAsciiSymbol(name);
1255 Handle<Code> code(Builtins::builtin(builtin_name));
1256 Handle<JSFunction> optimized = Factory::NewFunction(key,
1257 JS_OBJECT_TYPE,
1258 JSObject::kHeaderSize,
1259 code,
1260 false);
1261 optimized->shared()->DontAdaptArguments();
1262 if (generator != NULL) {
1263 SetCustomCallGenerator(optimized, generator);
1264 }
1265 SetProperty(holder, key, optimized, NONE);
1266 return optimized;
1267}
1268
1269
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001270Object* CompileArrayPushCall(CallStubCompiler* compiler,
1271 Object* object,
1272 JSObject* holder,
1273 JSFunction* function,
1274 String* name,
1275 StubCompiler::CheckType check) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001276 return compiler->CompileArrayPushCall(object, holder, function, name, check);
1277}
1278
1279
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001280Object* CompileArrayPopCall(CallStubCompiler* compiler,
1281 Object* object,
1282 JSObject* holder,
1283 JSFunction* function,
1284 String* name,
1285 StubCompiler::CheckType check) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001286 return compiler->CompileArrayPopCall(object, holder, function, name, check);
1287}
1288
1289
1290static Object* Runtime_SpecialArrayFunctions(Arguments args) {
1291 HandleScope scope;
1292 ASSERT(args.length() == 1);
1293 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1294
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001295 ExternalReference pop = ExternalReference::compile_array_pop_call();
1296 ExternalReference push = ExternalReference::compile_array_push_call();
1297
1298 InstallBuiltin(holder, "pop", Builtins::ArrayPop, &pop);
1299 InstallBuiltin(holder, "push", Builtins::ArrayPush, &push);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001300 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1301 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1302 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1303 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001304 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001305
1306 return *holder;
1307}
1308
1309
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
1311 HandleScope scope;
1312 ASSERT(args.length() == 4);
1313 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1314 int index = Smi::cast(args[1])->value();
1315 Handle<String> pattern = args.at<String>(2);
1316 Handle<String> flags = args.at<String>(3);
1317
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001318 // Get the RegExp function from the context in the literals array.
1319 // This is the RegExp function from the context in which the
1320 // function was created. We do not use the RegExp function from the
1321 // current global context because this might be the RegExp function
1322 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001323 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001324 Handle<JSFunction>(
1325 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326 // Compute the regular expression literal.
1327 bool has_pending_exception;
1328 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001329 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1330 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331 if (has_pending_exception) {
1332 ASSERT(Top::has_pending_exception());
1333 return Failure::Exception();
1334 }
1335 literals->set(index, *regexp);
1336 return *regexp;
1337}
1338
1339
1340static Object* Runtime_FunctionGetName(Arguments args) {
1341 NoHandleAllocation ha;
1342 ASSERT(args.length() == 1);
1343
1344 CONVERT_CHECKED(JSFunction, f, args[0]);
1345 return f->shared()->name();
1346}
1347
1348
ager@chromium.org236ad962008-09-25 09:45:57 +00001349static Object* Runtime_FunctionSetName(Arguments args) {
1350 NoHandleAllocation ha;
1351 ASSERT(args.length() == 2);
1352
1353 CONVERT_CHECKED(JSFunction, f, args[0]);
1354 CONVERT_CHECKED(String, name, args[1]);
1355 f->shared()->set_name(name);
1356 return Heap::undefined_value();
1357}
1358
1359
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360static Object* Runtime_FunctionGetScript(Arguments args) {
1361 HandleScope scope;
1362 ASSERT(args.length() == 1);
1363
1364 CONVERT_CHECKED(JSFunction, fun, args[0]);
1365 Handle<Object> script = Handle<Object>(fun->shared()->script());
1366 if (!script->IsScript()) return Heap::undefined_value();
1367
1368 return *GetScriptWrapper(Handle<Script>::cast(script));
1369}
1370
1371
1372static Object* Runtime_FunctionGetSourceCode(Arguments args) {
1373 NoHandleAllocation ha;
1374 ASSERT(args.length() == 1);
1375
1376 CONVERT_CHECKED(JSFunction, f, args[0]);
1377 return f->shared()->GetSourceCode();
1378}
1379
1380
1381static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
1382 NoHandleAllocation ha;
1383 ASSERT(args.length() == 1);
1384
1385 CONVERT_CHECKED(JSFunction, fun, args[0]);
1386 int pos = fun->shared()->start_position();
1387 return Smi::FromInt(pos);
1388}
1389
1390
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001391static Object* Runtime_FunctionGetPositionForOffset(Arguments args) {
1392 ASSERT(args.length() == 2);
1393
1394 CONVERT_CHECKED(JSFunction, fun, args[0]);
1395 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1396
1397 Code* code = fun->code();
1398 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1399
1400 Address pc = code->address() + offset;
1401 return Smi::FromInt(fun->code()->SourcePosition(pc));
1402}
1403
1404
1405
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
1407 NoHandleAllocation ha;
1408 ASSERT(args.length() == 2);
1409
1410 CONVERT_CHECKED(JSFunction, fun, args[0]);
1411 CONVERT_CHECKED(String, name, args[1]);
1412 fun->SetInstanceClassName(name);
1413 return Heap::undefined_value();
1414}
1415
1416
1417static Object* Runtime_FunctionSetLength(Arguments args) {
1418 NoHandleAllocation ha;
1419 ASSERT(args.length() == 2);
1420
1421 CONVERT_CHECKED(JSFunction, fun, args[0]);
1422 CONVERT_CHECKED(Smi, length, args[1]);
1423 fun->shared()->set_length(length->value());
1424 return length;
1425}
1426
1427
1428static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001429 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 ASSERT(args.length() == 2);
1431
1432 CONVERT_CHECKED(JSFunction, fun, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001433 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
1434 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435 return args[0]; // return TOS
1436}
1437
1438
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001439static Object* Runtime_FunctionIsAPIFunction(Arguments args) {
1440 NoHandleAllocation ha;
1441 ASSERT(args.length() == 1);
1442
1443 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001444 return f->shared()->IsApiFunction() ? Heap::true_value()
1445 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001446}
1447
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001448static Object* Runtime_FunctionIsBuiltin(Arguments args) {
1449 NoHandleAllocation ha;
1450 ASSERT(args.length() == 1);
1451
1452 CONVERT_CHECKED(JSFunction, f, args[0]);
1453 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1454}
1455
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001456
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001457static Object* Runtime_SetCode(Arguments args) {
1458 HandleScope scope;
1459 ASSERT(args.length() == 2);
1460
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001461 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001462 Handle<Object> code = args.at<Object>(1);
1463
1464 Handle<Context> context(target->context());
1465
1466 if (!code->IsNull()) {
1467 RUNTIME_ASSERT(code->IsJSFunction());
1468 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001469 Handle<SharedFunctionInfo> shared(fun->shared());
1470 SetExpectedNofProperties(target, shared->expected_nof_properties());
1471
1472 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473 return Failure::Exception();
1474 }
1475 // Set the code, formal parameter count, and the length of the target
1476 // function.
1477 target->set_code(fun->code());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001478 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001480 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001481 // Set the source code of the target function to undefined.
1482 // SetCode is only used for built-in constructors like String,
1483 // Array, and Object, and some web code
1484 // doesn't like seeing source code for constructors.
1485 target->shared()->set_script(Heap::undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001486 // Clear the optimization hints related to the compiled code as these are no
1487 // longer valid when the code is overwritten.
1488 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489 context = Handle<Context>(fun->context());
1490
1491 // Make sure we get a fresh copy of the literal vector to avoid
1492 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001493 int number_of_literals = fun->NumberOfLiterals();
1494 Handle<FixedArray> literals =
1495 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001496 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001497 // Insert the object, regexp and array functions in the literals
1498 // array prefix. These are the functions that will be used when
1499 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001500 literals->set(JSFunction::kLiteralGlobalContextIndex,
1501 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001503 // It's okay to skip the write barrier here because the literals
1504 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001505 target->set_literals(*literals, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001506 }
1507
1508 target->set_context(*context);
1509 return *target;
1510}
1511
1512
1513static Object* CharCodeAt(String* subject, Object* index) {
1514 uint32_t i = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001515 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001516 // Flatten the string. If someone wants to get a char at an index
1517 // in a cons string, it is likely that more indices will be
1518 // accessed.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001519 Object* flat = subject->TryFlatten();
1520 if (flat->IsFailure()) return flat;
1521 subject = String::cast(flat);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001522 if (i >= static_cast<uint32_t>(subject->length())) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001523 return Heap::nan_value();
1524 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001525 return Smi::FromInt(subject->Get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526}
1527
1528
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001529static Object* CharFromCode(Object* char_code) {
1530 uint32_t code;
1531 if (Array::IndexFromObject(char_code, &code)) {
1532 if (code <= 0xffff) {
1533 return Heap::LookupSingleCharacterStringFromCode(code);
1534 }
1535 }
1536 return Heap::empty_string();
1537}
1538
1539
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540static Object* Runtime_StringCharCodeAt(Arguments args) {
1541 NoHandleAllocation ha;
1542 ASSERT(args.length() == 2);
1543
1544 CONVERT_CHECKED(String, subject, args[0]);
1545 Object* index = args[1];
1546 return CharCodeAt(subject, index);
1547}
1548
1549
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001550static Object* Runtime_StringCharAt(Arguments args) {
1551 NoHandleAllocation ha;
1552 ASSERT(args.length() == 2);
1553
1554 CONVERT_CHECKED(String, subject, args[0]);
1555 Object* index = args[1];
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001556 Object* code = CharCodeAt(subject, index);
1557 if (code == Heap::nan_value()) {
1558 return Heap::undefined_value();
1559 }
1560 return CharFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001561}
1562
1563
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564static Object* Runtime_CharFromCode(Arguments args) {
1565 NoHandleAllocation ha;
1566 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001567 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568}
1569
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001570// Forward declarations.
1571static const int kStringBuilderConcatHelperLengthBits = 11;
1572static const int kStringBuilderConcatHelperPositionBits = 19;
1573
1574template <typename schar>
1575static inline void StringBuilderConcatHelper(String*,
1576 schar*,
1577 FixedArray*,
1578 int);
1579
1580typedef BitField<int, 0, 11> StringBuilderSubstringLength;
1581typedef BitField<int, 11, 19> StringBuilderSubstringPosition;
1582
1583class ReplacementStringBuilder {
1584 public:
1585 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
1586 : subject_(subject),
1587 parts_(Factory::NewFixedArray(estimated_part_count)),
1588 part_count_(0),
1589 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001590 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001591 // Require a non-zero initial size. Ensures that doubling the size to
1592 // extend the array will work.
1593 ASSERT(estimated_part_count > 0);
1594 }
1595
1596 void EnsureCapacity(int elements) {
1597 int length = parts_->length();
1598 int required_length = part_count_ + elements;
1599 if (length < required_length) {
1600 int new_length = length;
1601 do {
1602 new_length *= 2;
1603 } while (new_length < required_length);
1604 Handle<FixedArray> extended_array =
1605 Factory::NewFixedArray(new_length);
1606 parts_->CopyTo(0, *extended_array, 0, part_count_);
1607 parts_ = extended_array;
1608 }
1609 }
1610
1611 void AddSubjectSlice(int from, int to) {
1612 ASSERT(from >= 0);
1613 int length = to - from;
1614 ASSERT(length > 0);
1615 // Can we encode the slice in 11 bits for length and 19 bits for
1616 // start position - as used by StringBuilderConcatHelper?
1617 if (StringBuilderSubstringLength::is_valid(length) &&
1618 StringBuilderSubstringPosition::is_valid(from)) {
1619 int encoded_slice = StringBuilderSubstringLength::encode(length) |
1620 StringBuilderSubstringPosition::encode(from);
1621 AddElement(Smi::FromInt(encoded_slice));
1622 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001623 // Otherwise encode as two smis.
1624 AddElement(Smi::FromInt(-length));
1625 AddElement(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001626 }
1627 IncrementCharacterCount(length);
1628 }
1629
1630
1631 void AddString(Handle<String> string) {
1632 int length = string->length();
1633 ASSERT(length > 0);
1634 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00001635 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001636 is_ascii_ = false;
1637 }
1638 IncrementCharacterCount(length);
1639 }
1640
1641
1642 Handle<String> ToString() {
1643 if (part_count_ == 0) {
1644 return Factory::empty_string();
1645 }
1646
1647 Handle<String> joined_string;
1648 if (is_ascii_) {
1649 joined_string = NewRawAsciiString(character_count_);
1650 AssertNoAllocation no_alloc;
1651 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
1652 char* char_buffer = seq->GetChars();
1653 StringBuilderConcatHelper(*subject_,
1654 char_buffer,
1655 *parts_,
1656 part_count_);
1657 } else {
1658 // Non-ASCII.
1659 joined_string = NewRawTwoByteString(character_count_);
1660 AssertNoAllocation no_alloc;
1661 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
1662 uc16* char_buffer = seq->GetChars();
1663 StringBuilderConcatHelper(*subject_,
1664 char_buffer,
1665 *parts_,
1666 part_count_);
1667 }
1668 return joined_string;
1669 }
1670
1671
1672 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001673 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001674 V8::FatalProcessOutOfMemory("String.replace result too large.");
1675 }
1676 character_count_ += by;
1677 }
1678
1679 private:
1680
1681 Handle<String> NewRawAsciiString(int size) {
1682 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
1683 }
1684
1685
1686 Handle<String> NewRawTwoByteString(int size) {
1687 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
1688 }
1689
1690
1691 void AddElement(Object* element) {
1692 ASSERT(element->IsSmi() || element->IsString());
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001693 ASSERT(parts_->length() > part_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001694 parts_->set(part_count_, element);
1695 part_count_++;
1696 }
1697
1698 Handle<String> subject_;
1699 Handle<FixedArray> parts_;
1700 int part_count_;
1701 int character_count_;
1702 bool is_ascii_;
1703};
1704
1705
1706class CompiledReplacement {
1707 public:
1708 CompiledReplacement()
1709 : parts_(1), replacement_substrings_(0) {}
1710
1711 void Compile(Handle<String> replacement,
1712 int capture_count,
1713 int subject_length);
1714
1715 void Apply(ReplacementStringBuilder* builder,
1716 int match_from,
1717 int match_to,
1718 Handle<JSArray> last_match_info);
1719
1720 // Number of distinct parts of the replacement pattern.
1721 int parts() {
1722 return parts_.length();
1723 }
1724 private:
1725 enum PartType {
1726 SUBJECT_PREFIX = 1,
1727 SUBJECT_SUFFIX,
1728 SUBJECT_CAPTURE,
1729 REPLACEMENT_SUBSTRING,
1730 REPLACEMENT_STRING,
1731
1732 NUMBER_OF_PART_TYPES
1733 };
1734
1735 struct ReplacementPart {
1736 static inline ReplacementPart SubjectMatch() {
1737 return ReplacementPart(SUBJECT_CAPTURE, 0);
1738 }
1739 static inline ReplacementPart SubjectCapture(int capture_index) {
1740 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
1741 }
1742 static inline ReplacementPart SubjectPrefix() {
1743 return ReplacementPart(SUBJECT_PREFIX, 0);
1744 }
1745 static inline ReplacementPart SubjectSuffix(int subject_length) {
1746 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
1747 }
1748 static inline ReplacementPart ReplacementString() {
1749 return ReplacementPart(REPLACEMENT_STRING, 0);
1750 }
1751 static inline ReplacementPart ReplacementSubString(int from, int to) {
1752 ASSERT(from >= 0);
1753 ASSERT(to > from);
1754 return ReplacementPart(-from, to);
1755 }
1756
1757 // If tag <= 0 then it is the negation of a start index of a substring of
1758 // the replacement pattern, otherwise it's a value from PartType.
1759 ReplacementPart(int tag, int data)
1760 : tag(tag), data(data) {
1761 // Must be non-positive or a PartType value.
1762 ASSERT(tag < NUMBER_OF_PART_TYPES);
1763 }
1764 // Either a value of PartType or a non-positive number that is
1765 // the negation of an index into the replacement string.
1766 int tag;
1767 // The data value's interpretation depends on the value of tag:
1768 // tag == SUBJECT_PREFIX ||
1769 // tag == SUBJECT_SUFFIX: data is unused.
1770 // tag == SUBJECT_CAPTURE: data is the number of the capture.
1771 // tag == REPLACEMENT_SUBSTRING ||
1772 // tag == REPLACEMENT_STRING: data is index into array of substrings
1773 // of the replacement string.
1774 // tag <= 0: Temporary representation of the substring of the replacement
1775 // string ranging over -tag .. data.
1776 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
1777 // substring objects.
1778 int data;
1779 };
1780
1781 template<typename Char>
1782 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
1783 Vector<Char> characters,
1784 int capture_count,
1785 int subject_length) {
1786 int length = characters.length();
1787 int last = 0;
1788 for (int i = 0; i < length; i++) {
1789 Char c = characters[i];
1790 if (c == '$') {
1791 int next_index = i + 1;
1792 if (next_index == length) { // No next character!
1793 break;
1794 }
1795 Char c2 = characters[next_index];
1796 switch (c2) {
1797 case '$':
1798 if (i > last) {
1799 // There is a substring before. Include the first "$".
1800 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
1801 last = next_index + 1; // Continue after the second "$".
1802 } else {
1803 // Let the next substring start with the second "$".
1804 last = next_index;
1805 }
1806 i = next_index;
1807 break;
1808 case '`':
1809 if (i > last) {
1810 parts->Add(ReplacementPart::ReplacementSubString(last, i));
1811 }
1812 parts->Add(ReplacementPart::SubjectPrefix());
1813 i = next_index;
1814 last = i + 1;
1815 break;
1816 case '\'':
1817 if (i > last) {
1818 parts->Add(ReplacementPart::ReplacementSubString(last, i));
1819 }
1820 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
1821 i = next_index;
1822 last = i + 1;
1823 break;
1824 case '&':
1825 if (i > last) {
1826 parts->Add(ReplacementPart::ReplacementSubString(last, i));
1827 }
1828 parts->Add(ReplacementPart::SubjectMatch());
1829 i = next_index;
1830 last = i + 1;
1831 break;
1832 case '0':
1833 case '1':
1834 case '2':
1835 case '3':
1836 case '4':
1837 case '5':
1838 case '6':
1839 case '7':
1840 case '8':
1841 case '9': {
1842 int capture_ref = c2 - '0';
1843 if (capture_ref > capture_count) {
1844 i = next_index;
1845 continue;
1846 }
1847 int second_digit_index = next_index + 1;
1848 if (second_digit_index < length) {
1849 // Peek ahead to see if we have two digits.
1850 Char c3 = characters[second_digit_index];
1851 if ('0' <= c3 && c3 <= '9') { // Double digits.
1852 int double_digit_ref = capture_ref * 10 + c3 - '0';
1853 if (double_digit_ref <= capture_count) {
1854 next_index = second_digit_index;
1855 capture_ref = double_digit_ref;
1856 }
1857 }
1858 }
1859 if (capture_ref > 0) {
1860 if (i > last) {
1861 parts->Add(ReplacementPart::ReplacementSubString(last, i));
1862 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001863 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001864 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
1865 last = next_index + 1;
1866 }
1867 i = next_index;
1868 break;
1869 }
1870 default:
1871 i = next_index;
1872 break;
1873 }
1874 }
1875 }
1876 if (length > last) {
1877 if (last == 0) {
1878 parts->Add(ReplacementPart::ReplacementString());
1879 } else {
1880 parts->Add(ReplacementPart::ReplacementSubString(last, length));
1881 }
1882 }
1883 }
1884
1885 ZoneList<ReplacementPart> parts_;
1886 ZoneList<Handle<String> > replacement_substrings_;
1887};
1888
1889
1890void CompiledReplacement::Compile(Handle<String> replacement,
1891 int capture_count,
1892 int subject_length) {
1893 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00001894 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001895 AssertNoAllocation no_alloc;
1896 ParseReplacementPattern(&parts_,
1897 replacement->ToAsciiVector(),
1898 capture_count,
1899 subject_length);
1900 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00001901 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001902 AssertNoAllocation no_alloc;
1903
1904 ParseReplacementPattern(&parts_,
1905 replacement->ToUC16Vector(),
1906 capture_count,
1907 subject_length);
1908 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001909 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001910 int substring_index = 0;
1911 for (int i = 0, n = parts_.length(); i < n; i++) {
1912 int tag = parts_[i].tag;
1913 if (tag <= 0) { // A replacement string slice.
1914 int from = -tag;
1915 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001916 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001917 parts_[i].tag = REPLACEMENT_SUBSTRING;
1918 parts_[i].data = substring_index;
1919 substring_index++;
1920 } else if (tag == REPLACEMENT_STRING) {
1921 replacement_substrings_.Add(replacement);
1922 parts_[i].data = substring_index;
1923 substring_index++;
1924 }
1925 }
1926}
1927
1928
1929void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
1930 int match_from,
1931 int match_to,
1932 Handle<JSArray> last_match_info) {
1933 for (int i = 0, n = parts_.length(); i < n; i++) {
1934 ReplacementPart part = parts_[i];
1935 switch (part.tag) {
1936 case SUBJECT_PREFIX:
1937 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
1938 break;
1939 case SUBJECT_SUFFIX: {
1940 int subject_length = part.data;
1941 if (match_to < subject_length) {
1942 builder->AddSubjectSlice(match_to, subject_length);
1943 }
1944 break;
1945 }
1946 case SUBJECT_CAPTURE: {
1947 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001948 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001949 int from = RegExpImpl::GetCapture(match_info, capture * 2);
1950 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
1951 if (from >= 0 && to > from) {
1952 builder->AddSubjectSlice(from, to);
1953 }
1954 break;
1955 }
1956 case REPLACEMENT_SUBSTRING:
1957 case REPLACEMENT_STRING:
1958 builder->AddString(replacement_substrings_[part.data]);
1959 break;
1960 default:
1961 UNREACHABLE();
1962 }
1963 }
1964}
1965
1966
1967
1968static Object* StringReplaceRegExpWithString(String* subject,
1969 JSRegExp* regexp,
1970 String* replacement,
1971 JSArray* last_match_info) {
1972 ASSERT(subject->IsFlat());
1973 ASSERT(replacement->IsFlat());
1974
1975 HandleScope handles;
1976
1977 int length = subject->length();
1978 Handle<String> subject_handle(subject);
1979 Handle<JSRegExp> regexp_handle(regexp);
1980 Handle<String> replacement_handle(replacement);
1981 Handle<JSArray> last_match_info_handle(last_match_info);
1982 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
1983 subject_handle,
1984 0,
1985 last_match_info_handle);
1986 if (match.is_null()) {
1987 return Failure::Exception();
1988 }
1989 if (match->IsNull()) {
1990 return *subject_handle;
1991 }
1992
1993 int capture_count = regexp_handle->CaptureCount();
1994
1995 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001996 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001997 CompiledReplacement compiled_replacement;
1998 compiled_replacement.Compile(replacement_handle,
1999 capture_count,
2000 length);
2001
2002 bool is_global = regexp_handle->GetFlags().is_global();
2003
2004 // Guessing the number of parts that the final result string is built
2005 // from. Global regexps can match any number of times, so we guess
2006 // conservatively.
2007 int expected_parts =
2008 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2009 ReplacementStringBuilder builder(subject_handle, expected_parts);
2010
2011 // Index of end of last match.
2012 int prev = 0;
2013
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002014 // Number of parts added by compiled replacement plus preceeding
2015 // string and possibly suffix after last match. It is possible for
2016 // all components to use two elements when encoded as two smis.
2017 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002018 bool matched = true;
2019 do {
2020 ASSERT(last_match_info_handle->HasFastElements());
2021 // Increase the capacity of the builder before entering local handle-scope,
2022 // so its internal buffer can safely allocate a new handle if it grows.
2023 builder.EnsureCapacity(parts_added_per_loop);
2024
2025 HandleScope loop_scope;
2026 int start, end;
2027 {
2028 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002029 FixedArray* match_info_array =
2030 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002031
2032 ASSERT_EQ(capture_count * 2 + 2,
2033 RegExpImpl::GetLastCaptureCount(match_info_array));
2034 start = RegExpImpl::GetCapture(match_info_array, 0);
2035 end = RegExpImpl::GetCapture(match_info_array, 1);
2036 }
2037
2038 if (prev < start) {
2039 builder.AddSubjectSlice(prev, start);
2040 }
2041 compiled_replacement.Apply(&builder,
2042 start,
2043 end,
2044 last_match_info_handle);
2045 prev = end;
2046
2047 // Only continue checking for global regexps.
2048 if (!is_global) break;
2049
2050 // Continue from where the match ended, unless it was an empty match.
2051 int next = end;
2052 if (start == end) {
2053 next = end + 1;
2054 if (next > length) break;
2055 }
2056
2057 match = RegExpImpl::Exec(regexp_handle,
2058 subject_handle,
2059 next,
2060 last_match_info_handle);
2061 if (match.is_null()) {
2062 return Failure::Exception();
2063 }
2064 matched = !match->IsNull();
2065 } while (matched);
2066
2067 if (prev < length) {
2068 builder.AddSubjectSlice(prev, length);
2069 }
2070
2071 return *(builder.ToString());
2072}
2073
2074
2075static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
2076 ASSERT(args.length() == 4);
2077
2078 CONVERT_CHECKED(String, subject, args[0]);
2079 if (!subject->IsFlat()) {
2080 Object* flat_subject = subject->TryFlatten();
2081 if (flat_subject->IsFailure()) {
2082 return flat_subject;
2083 }
2084 subject = String::cast(flat_subject);
2085 }
2086
2087 CONVERT_CHECKED(String, replacement, args[2]);
2088 if (!replacement->IsFlat()) {
2089 Object* flat_replacement = replacement->TryFlatten();
2090 if (flat_replacement->IsFailure()) {
2091 return flat_replacement;
2092 }
2093 replacement = String::cast(flat_replacement);
2094 }
2095
2096 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2097 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2098
2099 ASSERT(last_match_info->HasFastElements());
2100
2101 return StringReplaceRegExpWithString(subject,
2102 regexp,
2103 replacement,
2104 last_match_info);
2105}
2106
2107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002108
ager@chromium.org7c537e22008-10-16 08:43:32 +00002109// Cap on the maximal shift in the Boyer-Moore implementation. By setting a
2110// limit, we can fix the size of tables.
2111static const int kBMMaxShift = 0xff;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002112// Reduce alphabet to this size.
2113static const int kBMAlphabetSize = 0x100;
2114// For patterns below this length, the skip length of Boyer-Moore is too short
2115// to compensate for the algorithmic overhead compared to simple brute force.
2116static const int kBMMinPatternLength = 5;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002117
ager@chromium.org7c537e22008-10-16 08:43:32 +00002118// Holds the two buffers used by Boyer-Moore string search's Good Suffix
2119// shift. Only allows the last kBMMaxShift characters of the needle
2120// to be indexed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002121class BMGoodSuffixBuffers {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002122 public:
2123 BMGoodSuffixBuffers() {}
2124 inline void init(int needle_length) {
2125 ASSERT(needle_length > 1);
2126 int start = needle_length < kBMMaxShift ? 0 : needle_length - kBMMaxShift;
2127 int len = needle_length - start;
2128 biased_suffixes_ = suffixes_ - start;
2129 biased_good_suffix_shift_ = good_suffix_shift_ - start;
2130 for (int i = 0; i <= len; i++) {
2131 good_suffix_shift_[i] = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002132 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002133 }
2134 inline int& suffix(int index) {
2135 ASSERT(biased_suffixes_ + index >= suffixes_);
2136 return biased_suffixes_[index];
2137 }
2138 inline int& shift(int index) {
2139 ASSERT(biased_good_suffix_shift_ + index >= good_suffix_shift_);
2140 return biased_good_suffix_shift_[index];
2141 }
2142 private:
2143 int suffixes_[kBMMaxShift + 1];
2144 int good_suffix_shift_[kBMMaxShift + 1];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002145 int* biased_suffixes_;
2146 int* biased_good_suffix_shift_;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002147 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers);
2148};
2149
2150// buffers reused by BoyerMoore
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002151static int bad_char_occurrence[kBMAlphabetSize];
ager@chromium.org7c537e22008-10-16 08:43:32 +00002152static BMGoodSuffixBuffers bmgs_buffers;
2153
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002154// State of the string match tables.
2155// SIMPLE: No usable content in the buffers.
2156// BOYER_MOORE_HORSPOOL: The bad_char_occurences table has been populated.
2157// BOYER_MOORE: The bmgs_buffers tables have also been populated.
2158// Whenever starting with a new needle, one should call InitializeStringSearch
2159// to determine which search strategy to use, and in the case of a long-needle
2160// strategy, the call also initializes the algorithm to SIMPLE.
2161enum StringSearchAlgorithm { SIMPLE_SEARCH, BOYER_MOORE_HORSPOOL, BOYER_MOORE };
2162static StringSearchAlgorithm algorithm;
2163
2164
ager@chromium.org7c537e22008-10-16 08:43:32 +00002165// Compute the bad-char table for Boyer-Moore in the static buffer.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002166template <typename pchar>
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002167static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern) {
2168 // Only preprocess at most kBMMaxShift last characters of pattern.
2169 int start = pattern.length() < kBMMaxShift ? 0
2170 : pattern.length() - kBMMaxShift;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002171 // Run forwards to populate bad_char_table, so that *last* instance
2172 // of character equivalence class is the one registered.
2173 // Notice: Doesn't include the last character.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002174 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1
2175 : kBMAlphabetSize;
2176 if (start == 0) { // All patterns less than kBMMaxShift in length.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002177 memset(bad_char_occurrence, -1, table_size * sizeof(*bad_char_occurrence));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002178 } else {
2179 for (int i = 0; i < table_size; i++) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002180 bad_char_occurrence[i] = start - 1;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002181 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002182 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002183 for (int i = start; i < pattern.length() - 1; i++) {
2184 pchar c = pattern[i];
2185 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002186 bad_char_occurrence[bucket] = i;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002187 }
2188}
2189
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002190
ager@chromium.org7c537e22008-10-16 08:43:32 +00002191template <typename pchar>
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002192static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002193 int m = pattern.length();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002194 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002195 int len = m - start;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002196 // Compute Good Suffix tables.
2197 bmgs_buffers.init(m);
2198
2199 bmgs_buffers.shift(m-1) = 1;
2200 bmgs_buffers.suffix(m) = m + 1;
2201 pchar last_char = pattern[m - 1];
2202 int suffix = m + 1;
2203 for (int i = m; i > start;) {
2204 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) {
2205 if (bmgs_buffers.shift(suffix) == len) {
2206 bmgs_buffers.shift(suffix) = suffix - i;
2207 }
2208 suffix = bmgs_buffers.suffix(suffix);
2209 }
2210 i--;
2211 suffix--;
2212 bmgs_buffers.suffix(i) = suffix;
2213 if (suffix == m) {
2214 // No suffix to extend, so we check against last_char only.
2215 while (i > start && pattern[i - 1] != last_char) {
2216 if (bmgs_buffers.shift(m) == len) {
2217 bmgs_buffers.shift(m) = m - i;
2218 }
2219 i--;
2220 bmgs_buffers.suffix(i) = m;
2221 }
2222 if (i > start) {
2223 i--;
2224 suffix--;
2225 bmgs_buffers.suffix(i) = suffix;
2226 }
2227 }
2228 }
2229 if (suffix < m) {
2230 for (int i = start; i <= m; i++) {
2231 if (bmgs_buffers.shift(i) == len) {
2232 bmgs_buffers.shift(i) = suffix - start;
2233 }
2234 if (i == suffix) {
2235 suffix = bmgs_buffers.suffix(suffix);
2236 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002237 }
2238 }
2239}
2240
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002241
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002242template <typename schar, typename pchar>
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002243static inline int CharOccurrence(int char_code) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002244 if (sizeof(schar) == 1) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002245 return bad_char_occurrence[char_code];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002246 }
2247 if (sizeof(pchar) == 1) {
2248 if (char_code > String::kMaxAsciiCharCode) {
2249 return -1;
2250 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002251 return bad_char_occurrence[char_code];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002252 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002253 return bad_char_occurrence[char_code % kBMAlphabetSize];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002254}
2255
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002256
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002257// Restricted simplified Boyer-Moore string matching.
2258// Uses only the bad-shift table of Boyer-Moore and only uses it
2259// for the character compared to the last character of the needle.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002260template <typename schar, typename pchar>
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002261static int BoyerMooreHorspool(Vector<const schar> subject,
2262 Vector<const pchar> pattern,
2263 int start_index,
2264 bool* complete) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002265 ASSERT(algorithm <= BOYER_MOORE_HORSPOOL);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002266 int n = subject.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002267 int m = pattern.length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002268
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002269 int badness = -m;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002270
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002271 // How bad we are doing without a good-suffix table.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002272 int idx; // No matches found prior to this index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002273 pchar last_char = pattern[m - 1];
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002274 int last_char_shift = m - 1 - CharOccurrence<schar, pchar>(last_char);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002275 // Perform search
2276 for (idx = start_index; idx <= n - m;) {
2277 int j = m - 1;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002278 int c;
2279 while (last_char != (c = subject[idx + j])) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002280 int bc_occ = CharOccurrence<schar, pchar>(c);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002281 int shift = j - bc_occ;
2282 idx += shift;
2283 badness += 1 - shift; // at most zero, so badness cannot increase.
2284 if (idx > n - m) {
2285 *complete = true;
2286 return -1;
2287 }
2288 }
2289 j--;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002290 while (j >= 0 && pattern[j] == (subject[idx + j])) j--;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002291 if (j < 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002292 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002293 return idx;
2294 } else {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002295 idx += last_char_shift;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002296 // Badness increases by the number of characters we have
2297 // checked, and decreases by the number of characters we
2298 // can skip by shifting. It's a measure of how we are doing
2299 // compared to reading each character exactly once.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002300 badness += (m - j) - last_char_shift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002301 if (badness > 0) {
2302 *complete = false;
2303 return idx;
2304 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002305 }
2306 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002307 *complete = true;
2308 return -1;
2309}
ager@chromium.org7c537e22008-10-16 08:43:32 +00002310
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002311
2312template <typename schar, typename pchar>
2313static int BoyerMooreIndexOf(Vector<const schar> subject,
2314 Vector<const pchar> pattern,
2315 int idx) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002316 ASSERT(algorithm <= BOYER_MOORE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002317 int n = subject.length();
2318 int m = pattern.length();
2319 // Only preprocess at most kBMMaxShift last characters of pattern.
2320 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
2321
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002322 pchar last_char = pattern[m - 1];
2323 // Continue search from i.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002324 while (idx <= n - m) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002325 int j = m - 1;
2326 schar c;
2327 while (last_char != (c = subject[idx + j])) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002328 int shift = j - CharOccurrence<schar, pchar>(c);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002329 idx += shift;
2330 if (idx > n - m) {
2331 return -1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002332 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002333 }
2334 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
2335 if (j < 0) {
2336 return idx;
2337 } else if (j < start) {
2338 // we have matched more than our tables allow us to be smart about.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002339 // Fall back on BMH shift.
2340 idx += m - 1 - CharOccurrence<schar, pchar>(last_char);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002341 } else {
2342 int gs_shift = bmgs_buffers.shift(j + 1); // Good suffix shift.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002343 int bc_occ = CharOccurrence<schar, pchar>(c);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002344 int shift = j - bc_occ; // Bad-char shift.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002345 if (gs_shift > shift) {
2346 shift = gs_shift;
2347 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002348 idx += shift;
2349 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002350 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002351
2352 return -1;
2353}
2354
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002355
2356template <typename schar>
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002357static inline int SingleCharIndexOf(Vector<const schar> string,
2358 schar pattern_char,
2359 int start_index) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00002360 if (sizeof(schar) == 1) {
2361 const schar* pos = reinterpret_cast<const schar*>(
2362 memchr(string.start() + start_index,
2363 pattern_char,
2364 string.length() - start_index));
2365 if (pos == NULL) return -1;
2366 return pos - string.start();
2367 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002368 for (int i = start_index, n = string.length(); i < n; i++) {
2369 if (pattern_char == string[i]) {
2370 return i;
2371 }
2372 }
2373 return -1;
2374}
2375
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002376
2377template <typename schar>
2378static int SingleCharLastIndexOf(Vector<const schar> string,
2379 schar pattern_char,
2380 int start_index) {
2381 for (int i = start_index; i >= 0; i--) {
2382 if (pattern_char == string[i]) {
2383 return i;
2384 }
2385 }
2386 return -1;
2387}
2388
2389
ager@chromium.org7c537e22008-10-16 08:43:32 +00002390// Trivial string search for shorter strings.
2391// On return, if "complete" is set to true, the return value is the
2392// final result of searching for the patter in the subject.
2393// If "complete" is set to false, the return value is the index where
2394// further checking should start, i.e., it's guaranteed that the pattern
2395// does not occur at a position prior to the returned index.
2396template <typename pchar, typename schar>
2397static int SimpleIndexOf(Vector<const schar> subject,
2398 Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002399 int idx,
2400 bool* complete) {
2401 // Badness is a count of how much work we have done. When we have
2402 // done enough work we decide it's probably worth switching to a better
2403 // algorithm.
2404 int badness = -10 - (pattern.length() << 2);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002405
ager@chromium.org7c537e22008-10-16 08:43:32 +00002406 // We know our pattern is at least 2 characters, we cache the first so
2407 // the common case of the first character not matching is faster.
2408 pchar pattern_first_char = pattern[0];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002409 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
2410 badness++;
2411 if (badness > 0) {
2412 *complete = false;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002413 return i;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002414 }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00002415 if (sizeof(schar) == 1 && sizeof(pchar) == 1) {
2416 const schar* pos = reinterpret_cast<const schar*>(
2417 memchr(subject.start() + i,
2418 pattern_first_char,
2419 n - i + 1));
2420 if (pos == NULL) {
2421 *complete = true;
2422 return -1;
2423 }
2424 i = pos - subject.start();
2425 } else {
2426 if (subject[i] != pattern_first_char) continue;
2427 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002428 int j = 1;
2429 do {
2430 if (pattern[j] != subject[i+j]) {
2431 break;
2432 }
2433 j++;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002434 } while (j < pattern.length());
2435 if (j == pattern.length()) {
2436 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002437 return i;
2438 }
2439 badness += j;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002440 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002441 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002442 return -1;
2443}
2444
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002445// Simple indexOf that never bails out. For short patterns only.
2446template <typename pchar, typename schar>
2447static int SimpleIndexOf(Vector<const schar> subject,
2448 Vector<const pchar> pattern,
2449 int idx) {
2450 pchar pattern_first_char = pattern[0];
2451 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00002452 if (sizeof(schar) == 1 && sizeof(pchar) == 1) {
2453 const schar* pos = reinterpret_cast<const schar*>(
2454 memchr(subject.start() + i,
2455 pattern_first_char,
2456 n - i + 1));
2457 if (pos == NULL) return -1;
2458 i = pos - subject.start();
2459 } else {
2460 if (subject[i] != pattern_first_char) continue;
2461 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002462 int j = 1;
2463 do {
2464 if (pattern[j] != subject[i+j]) {
2465 break;
2466 }
2467 j++;
2468 } while (j < pattern.length());
2469 if (j == pattern.length()) {
2470 return i;
2471 }
2472 }
2473 return -1;
2474}
2475
2476
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002477// Strategy for searching for a string in another string.
2478enum StringSearchStrategy { SEARCH_FAIL, SEARCH_SHORT, SEARCH_LONG };
ager@chromium.org7c537e22008-10-16 08:43:32 +00002479
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002480
2481template <typename pchar>
2482static inline StringSearchStrategy InitializeStringSearch(
2483 Vector<const pchar> pat, bool ascii_subject) {
2484 ASSERT(pat.length() > 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002485 // We have an ASCII haystack and a non-ASCII needle. Check if there
2486 // really is a non-ASCII character in the needle and bail out if there
2487 // is.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002488 if (ascii_subject && sizeof(pchar) > 1) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002489 for (int i = 0; i < pat.length(); i++) {
2490 uc16 c = pat[i];
2491 if (c > String::kMaxAsciiCharCode) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002492 return SEARCH_FAIL;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002493 }
2494 }
2495 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002496 if (pat.length() < kBMMinPatternLength) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002497 return SEARCH_SHORT;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002498 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002499 algorithm = SIMPLE_SEARCH;
2500 return SEARCH_LONG;
2501}
2502
2503
2504// Dispatch long needle searches to different algorithms.
2505template <typename schar, typename pchar>
2506static int ComplexIndexOf(Vector<const schar> sub,
2507 Vector<const pchar> pat,
2508 int start_index) {
2509 ASSERT(pat.length() >= kBMMinPatternLength);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002510 // Try algorithms in order of increasing setup cost and expected performance.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002511 bool complete;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002512 int idx = start_index;
2513 switch (algorithm) {
2514 case SIMPLE_SEARCH:
2515 idx = SimpleIndexOf(sub, pat, idx, &complete);
2516 if (complete) return idx;
2517 BoyerMoorePopulateBadCharTable(pat);
2518 algorithm = BOYER_MOORE_HORSPOOL;
2519 // FALLTHROUGH.
2520 case BOYER_MOORE_HORSPOOL:
2521 idx = BoyerMooreHorspool(sub, pat, idx, &complete);
2522 if (complete) return idx;
2523 // Build the Good Suffix table and continue searching.
2524 BoyerMoorePopulateGoodSuffixTable(pat);
2525 algorithm = BOYER_MOORE;
2526 // FALLTHROUGH.
2527 case BOYER_MOORE:
2528 return BoyerMooreIndexOf(sub, pat, idx);
2529 }
2530 UNREACHABLE();
2531 return -1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002532}
2533
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002534
2535// Dispatch to different search strategies for a single search.
2536// If searching multiple times on the same needle, the search
2537// strategy should only be computed once and then dispatch to different
2538// loops.
2539template <typename schar, typename pchar>
2540static int StringSearch(Vector<const schar> sub,
2541 Vector<const pchar> pat,
2542 int start_index) {
2543 bool ascii_subject = (sizeof(schar) == 1);
2544 StringSearchStrategy strategy = InitializeStringSearch(pat, ascii_subject);
2545 switch (strategy) {
2546 case SEARCH_FAIL: return -1;
2547 case SEARCH_SHORT: return SimpleIndexOf(sub, pat, start_index);
2548 case SEARCH_LONG: return ComplexIndexOf(sub, pat, start_index);
2549 }
2550 UNREACHABLE();
2551 return -1;
2552}
2553
2554
ager@chromium.org7c537e22008-10-16 08:43:32 +00002555// Perform string match of pattern on subject, starting at start index.
2556// Caller must ensure that 0 <= start_index <= sub->length(),
2557// and should check that pat->length() + start_index <= sub->length()
2558int Runtime::StringMatch(Handle<String> sub,
2559 Handle<String> pat,
2560 int start_index) {
2561 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002562 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002563
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002564 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002565 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002566
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002567 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002568 if (start_index + pattern_length > subject_length) return -1;
2569
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002570 if (!sub->IsFlat()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002571 FlattenString(sub);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002572 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002573
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002574 // Searching for one specific character is common. For one
ager@chromium.org7c537e22008-10-16 08:43:32 +00002575 // character patterns linear search is necessary, so any smart
2576 // algorithm is unnecessary overhead.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002577 if (pattern_length == 1) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002578 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
ager@chromium.org5ec48922009-05-05 07:25:34 +00002579 if (sub->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002580 uc16 pchar = pat->Get(0);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002581 if (pchar > String::kMaxAsciiCharCode) {
2582 return -1;
2583 }
2584 Vector<const char> ascii_vector =
2585 sub->ToAsciiVector().SubVector(start_index, subject_length);
2586 const void* pos = memchr(ascii_vector.start(),
2587 static_cast<const char>(pchar),
2588 static_cast<size_t>(ascii_vector.length()));
2589 if (pos == NULL) {
2590 return -1;
2591 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002592 return static_cast<int>(reinterpret_cast<const char*>(pos)
2593 - ascii_vector.start() + start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002594 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002595 return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002596 }
2597
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002598 if (!pat->IsFlat()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002599 FlattenString(pat);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002600 }
ager@chromium.org236ad962008-09-25 09:45:57 +00002601
ager@chromium.org7c537e22008-10-16 08:43:32 +00002602 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2603 // dispatch on type of strings
ager@chromium.org5ec48922009-05-05 07:25:34 +00002604 if (pat->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002605 Vector<const char> pat_vector = pat->ToAsciiVector();
ager@chromium.org5ec48922009-05-05 07:25:34 +00002606 if (sub->IsAsciiRepresentation()) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002607 return StringSearch(sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002608 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002609 return StringSearch(sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002610 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002611 Vector<const uc16> pat_vector = pat->ToUC16Vector();
ager@chromium.org5ec48922009-05-05 07:25:34 +00002612 if (sub->IsAsciiRepresentation()) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002613 return StringSearch(sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002614 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002615 return StringSearch(sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002616}
2617
2618
2619static Object* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002620 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002621 ASSERT(args.length() == 3);
2622
ager@chromium.org7c537e22008-10-16 08:43:32 +00002623 CONVERT_ARG_CHECKED(String, sub, 0);
2624 CONVERT_ARG_CHECKED(String, pat, 1);
2625
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002626 Object* index = args[2];
2627 uint32_t start_index;
2628 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
2629
ager@chromium.org870a0b62008-11-04 11:43:05 +00002630 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002631 int position = Runtime::StringMatch(sub, pat, start_index);
2632 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002633}
2634
2635
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002636template <typename schar, typename pchar>
2637static int StringMatchBackwards(Vector<const schar> sub,
2638 Vector<const pchar> pat,
2639 int idx) {
2640 ASSERT(pat.length() >= 1);
2641 ASSERT(idx + pat.length() <= sub.length());
2642
2643 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
2644 for (int i = 0; i < pat.length(); i++) {
2645 uc16 c = pat[i];
2646 if (c > String::kMaxAsciiCharCode) {
2647 return -1;
2648 }
2649 }
2650 }
2651
2652 pchar pattern_first_char = pat[0];
2653 for (int i = idx; i >= 0; i--) {
2654 if (sub[i] != pattern_first_char) continue;
2655 int j = 1;
2656 while (j < pat.length()) {
2657 if (pat[j] != sub[i+j]) {
2658 break;
2659 }
2660 j++;
2661 }
2662 if (j == pat.length()) {
2663 return i;
2664 }
2665 }
2666 return -1;
2667}
2668
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002669static Object* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002670 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002671 ASSERT(args.length() == 3);
2672
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002673 CONVERT_ARG_CHECKED(String, sub, 0);
2674 CONVERT_ARG_CHECKED(String, pat, 1);
2675
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002676 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002677 uint32_t start_index;
2678 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
2679
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002680 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002681 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002682
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002683 if (start_index + pat_length > sub_length) {
2684 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002685 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002686
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002687 if (pat_length == 0) {
2688 return Smi::FromInt(start_index);
2689 }
2690
2691 if (!sub->IsFlat()) {
2692 FlattenString(sub);
2693 }
2694
2695 if (pat_length == 1) {
2696 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2697 if (sub->IsAsciiRepresentation()) {
2698 uc16 pchar = pat->Get(0);
2699 if (pchar > String::kMaxAsciiCharCode) {
2700 return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002701 }
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002702 return Smi::FromInt(SingleCharLastIndexOf(sub->ToAsciiVector(),
2703 static_cast<char>(pat->Get(0)),
2704 start_index));
2705 } else {
2706 return Smi::FromInt(SingleCharLastIndexOf(sub->ToUC16Vector(),
2707 pat->Get(0),
2708 start_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002709 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002710 }
2711
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002712 if (!pat->IsFlat()) {
2713 FlattenString(pat);
2714 }
2715
2716 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2717
2718 int position = -1;
2719
2720 if (pat->IsAsciiRepresentation()) {
2721 Vector<const char> pat_vector = pat->ToAsciiVector();
2722 if (sub->IsAsciiRepresentation()) {
2723 position = StringMatchBackwards(sub->ToAsciiVector(),
2724 pat_vector,
2725 start_index);
2726 } else {
2727 position = StringMatchBackwards(sub->ToUC16Vector(),
2728 pat_vector,
2729 start_index);
2730 }
2731 } else {
2732 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2733 if (sub->IsAsciiRepresentation()) {
2734 position = StringMatchBackwards(sub->ToAsciiVector(),
2735 pat_vector,
2736 start_index);
2737 } else {
2738 position = StringMatchBackwards(sub->ToUC16Vector(),
2739 pat_vector,
2740 start_index);
2741 }
2742 }
2743
2744 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002745}
2746
2747
2748static Object* Runtime_StringLocaleCompare(Arguments args) {
2749 NoHandleAllocation ha;
2750 ASSERT(args.length() == 2);
2751
2752 CONVERT_CHECKED(String, str1, args[0]);
2753 CONVERT_CHECKED(String, str2, args[1]);
2754
2755 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002756 int str1_length = str1->length();
2757 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002758
2759 // Decide trivial cases without flattening.
2760 if (str1_length == 0) {
2761 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2762 return Smi::FromInt(-str2_length);
2763 } else {
2764 if (str2_length == 0) return Smi::FromInt(str1_length);
2765 }
2766
2767 int end = str1_length < str2_length ? str1_length : str2_length;
2768
2769 // No need to flatten if we are going to find the answer on the first
2770 // character. At this point we know there is at least one character
2771 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002772 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002773 if (d != 0) return Smi::FromInt(d);
2774
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002775 str1->TryFlatten();
2776 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002777
2778 static StringInputBuffer buf1;
2779 static StringInputBuffer buf2;
2780
2781 buf1.Reset(str1);
2782 buf2.Reset(str2);
2783
2784 for (int i = 0; i < end; i++) {
2785 uint16_t char1 = buf1.GetNext();
2786 uint16_t char2 = buf2.GetNext();
2787 if (char1 != char2) return Smi::FromInt(char1 - char2);
2788 }
2789
2790 return Smi::FromInt(str1_length - str2_length);
2791}
2792
2793
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002794static Object* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002795 NoHandleAllocation ha;
2796 ASSERT(args.length() == 3);
2797
2798 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002799 Object* from = args[1];
2800 Object* to = args[2];
2801 int start, end;
2802 // We have a fast integer-only case here to avoid a conversion to double in
2803 // the common case where from and to are Smis.
2804 if (from->IsSmi() && to->IsSmi()) {
2805 start = Smi::cast(from)->value();
2806 end = Smi::cast(to)->value();
2807 } else {
2808 CONVERT_DOUBLE_CHECKED(from_number, from);
2809 CONVERT_DOUBLE_CHECKED(to_number, to);
2810 start = FastD2I(from_number);
2811 end = FastD2I(to_number);
2812 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002813 RUNTIME_ASSERT(end >= start);
2814 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002815 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002816 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002817 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002818}
2819
2820
ager@chromium.org41826e72009-03-30 13:30:57 +00002821static Object* Runtime_StringMatch(Arguments args) {
2822 ASSERT_EQ(3, args.length());
2823
2824 CONVERT_ARG_CHECKED(String, subject, 0);
2825 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2826 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2827 HandleScope handles;
2828
2829 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2830
2831 if (match.is_null()) {
2832 return Failure::Exception();
2833 }
2834 if (match->IsNull()) {
2835 return Heap::null_value();
2836 }
2837 int length = subject->length();
2838
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002839 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002840 ZoneList<int> offsets(8);
2841 do {
2842 int start;
2843 int end;
2844 {
2845 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002846 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002847 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2848 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2849 }
2850 offsets.Add(start);
2851 offsets.Add(end);
2852 int index = start < end ? end : end + 1;
2853 if (index > length) break;
2854 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2855 if (match.is_null()) {
2856 return Failure::Exception();
2857 }
2858 } while (!match->IsNull());
2859 int matches = offsets.length() / 2;
2860 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2861 for (int i = 0; i < matches ; i++) {
2862 int from = offsets.at(i * 2);
2863 int to = offsets.at(i * 2 + 1);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002864 elements->set(i, *Factory::NewSubString(subject, from, to));
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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002872static Object* Runtime_NumberToRadixString(Arguments args) {
2873 NoHandleAllocation ha;
2874 ASSERT(args.length() == 2);
2875
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002876 // Fast case where the result is a one character string.
2877 if (args[0]->IsSmi() && args[1]->IsSmi()) {
2878 int value = Smi::cast(args[0])->value();
2879 int radix = Smi::cast(args[1])->value();
2880 if (value >= 0 && value < radix) {
2881 RUNTIME_ASSERT(radix <= 36);
2882 // Character array used for conversion.
2883 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
2884 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
2885 }
2886 }
2887
2888 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002889 CONVERT_DOUBLE_CHECKED(value, args[0]);
2890 if (isnan(value)) {
2891 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
2892 }
2893 if (isinf(value)) {
2894 if (value < 0) {
2895 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
2896 }
2897 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
2898 }
2899 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
2900 int radix = FastD2I(radix_number);
2901 RUNTIME_ASSERT(2 <= radix && radix <= 36);
2902 char* str = DoubleToRadixCString(value, radix);
2903 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
2904 DeleteArray(str);
2905 return result;
2906}
2907
2908
2909static Object* Runtime_NumberToFixed(Arguments args) {
2910 NoHandleAllocation ha;
2911 ASSERT(args.length() == 2);
2912
2913 CONVERT_DOUBLE_CHECKED(value, args[0]);
2914 if (isnan(value)) {
2915 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
2916 }
2917 if (isinf(value)) {
2918 if (value < 0) {
2919 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
2920 }
2921 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
2922 }
2923 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
2924 int f = FastD2I(f_number);
2925 RUNTIME_ASSERT(f >= 0);
2926 char* str = DoubleToFixedCString(value, f);
2927 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
2928 DeleteArray(str);
2929 return res;
2930}
2931
2932
2933static Object* Runtime_NumberToExponential(Arguments args) {
2934 NoHandleAllocation ha;
2935 ASSERT(args.length() == 2);
2936
2937 CONVERT_DOUBLE_CHECKED(value, args[0]);
2938 if (isnan(value)) {
2939 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
2940 }
2941 if (isinf(value)) {
2942 if (value < 0) {
2943 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
2944 }
2945 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
2946 }
2947 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
2948 int f = FastD2I(f_number);
2949 RUNTIME_ASSERT(f >= -1 && f <= 20);
2950 char* str = DoubleToExponentialCString(value, f);
2951 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
2952 DeleteArray(str);
2953 return res;
2954}
2955
2956
2957static Object* Runtime_NumberToPrecision(Arguments args) {
2958 NoHandleAllocation ha;
2959 ASSERT(args.length() == 2);
2960
2961 CONVERT_DOUBLE_CHECKED(value, args[0]);
2962 if (isnan(value)) {
2963 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
2964 }
2965 if (isinf(value)) {
2966 if (value < 0) {
2967 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
2968 }
2969 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
2970 }
2971 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
2972 int f = FastD2I(f_number);
2973 RUNTIME_ASSERT(f >= 1 && f <= 21);
2974 char* str = DoubleToPrecisionCString(value, f);
2975 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
2976 DeleteArray(str);
2977 return res;
2978}
2979
2980
2981// Returns a single character string where first character equals
2982// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002983static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002984 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002985 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00002986 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002987 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002988 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002989 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002990}
2991
2992
2993Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
2994 // Handle [] indexing on Strings
2995 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002996 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
2997 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002998 }
2999
3000 // Handle [] indexing on String objects
3001 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003002 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3003 Handle<Object> result =
3004 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3005 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003006 }
3007
3008 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003009 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003010 return prototype->GetElement(index);
3011 }
3012
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003013 return GetElement(object, index);
3014}
3015
3016
3017Object* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003018 return object->GetElement(index);
3019}
3020
3021
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003022Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
3023 HandleScope scope;
3024
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003026 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003027 Handle<Object> error =
3028 Factory::NewTypeError("non_object_property_load",
3029 HandleVector(args, 2));
3030 return Top::Throw(*error);
3031 }
3032
3033 // Check if the given key is an array index.
3034 uint32_t index;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003035 if (Array::IndexFromObject(*key, &index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003036 return GetElementOrCharAt(object, index);
3037 }
3038
3039 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003040 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003041 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003042 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003043 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003044 bool has_pending_exception = false;
3045 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003046 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003047 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003048 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003049 }
3050
ager@chromium.org32912102009-01-16 10:38:43 +00003051 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003052 // the element if so.
3053 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003054 return GetElementOrCharAt(object, index);
3055 } else {
3056 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003057 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003058 }
3059}
3060
3061
3062static Object* Runtime_GetProperty(Arguments args) {
3063 NoHandleAllocation ha;
3064 ASSERT(args.length() == 2);
3065
3066 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003067 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003068
3069 return Runtime::GetObjectProperty(object, key);
3070}
3071
3072
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003073// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003074static Object* Runtime_KeyedGetProperty(Arguments args) {
3075 NoHandleAllocation ha;
3076 ASSERT(args.length() == 2);
3077
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003078 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003079 // itself.
3080 //
3081 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003082 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003083 // global proxy object never has properties. This is the case
3084 // because the global proxy object forwards everything to its hidden
3085 // prototype including local lookups.
3086 //
3087 // Additionally, we need to make sure that we do not cache results
3088 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003089 if (args[0]->IsJSObject() &&
3090 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003091 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003092 args[1]->IsString()) {
3093 JSObject* receiver = JSObject::cast(args[0]);
3094 String* key = String::cast(args[1]);
3095 if (receiver->HasFastProperties()) {
3096 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003097 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003098 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3099 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003100 Object* value = receiver->FastPropertyAt(offset);
3101 return value->IsTheHole() ? Heap::undefined_value() : value;
3102 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003103 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003104 LookupResult result;
3105 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003106 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003107 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003108 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003109 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003110 }
3111 } else {
3112 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003113 StringDictionary* dictionary = receiver->property_dictionary();
3114 int entry = dictionary->FindEntry(key);
3115 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003116 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003117 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003118 if (!receiver->IsGlobalObject()) return value;
3119 value = JSGlobalPropertyCell::cast(value)->value();
3120 if (!value->IsTheHole()) return value;
3121 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003122 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003123 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003124 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3125 // Fast case for string indexing using [] with a smi index.
3126 HandleScope scope;
3127 Handle<String> str = args.at<String>(0);
3128 int index = Smi::cast(args[1])->value();
3129 Handle<Object> result = GetCharAt(str, index);
3130 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003131 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003132
3133 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003134 return Runtime::GetObjectProperty(args.at<Object>(0),
3135 args.at<Object>(1));
3136}
3137
3138
ager@chromium.org5c838252010-02-19 08:53:10 +00003139static Object* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
3140 ASSERT(args.length() == 5);
3141 HandleScope scope;
3142 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3143 CONVERT_CHECKED(String, name, args[1]);
3144 CONVERT_CHECKED(Smi, flag_setter, args[2]);
3145 CONVERT_CHECKED(JSFunction, fun, args[3]);
3146 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3147 int unchecked = flag_attr->value();
3148 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3149 RUNTIME_ASSERT(!obj->IsNull());
3150 LookupResult result;
3151 obj->LocalLookupRealNamedProperty(name, &result);
3152
3153 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3154 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3155 // delete it to avoid running into trouble in DefineAccessor, which
3156 // handles this incorrectly if the property is readonly (does nothing)
3157 if (result.IsProperty() &&
3158 (result.type() == FIELD || result.type() == NORMAL
3159 || result.type() == CONSTANT_FUNCTION)) {
3160 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3161 }
3162 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3163}
3164
3165static Object* Runtime_DefineOrRedefineDataProperty(Arguments args) {
3166 ASSERT(args.length() == 4);
3167 HandleScope scope;
3168 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3169 CONVERT_ARG_CHECKED(String, name, 1);
3170 Handle<Object> obj_value = args.at<Object>(2);
3171
3172 CONVERT_CHECKED(Smi, flag, args[3]);
3173 int unchecked = flag->value();
3174 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3175
3176 LookupResult result;
3177 js_object->LocalLookupRealNamedProperty(*name, &result);
3178
3179 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3180
3181 // Take special care when attributes are different and there is already
3182 // a property. For simplicity we normalize the property which enables us
3183 // to not worry about changing the instance_descriptor and creating a new
3184 // map. The current version of SetObjectProperty does not handle attributes
3185 // correctly in the case where a property is a field and is reset with
3186 // new attributes.
3187 if (result.IsProperty() && attr != result.GetAttributes()) {
3188 // New attributes - normalize to avoid writing to instance descriptor
3189 js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3190 // Use IgnoreAttributes version since a readonly property may be
3191 // overridden and SetProperty does not allow this.
3192 return js_object->IgnoreAttributesAndSetLocalProperty(*name,
3193 *obj_value,
3194 attr);
3195 }
3196 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3197}
3198
3199
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003200Object* Runtime::SetObjectProperty(Handle<Object> object,
3201 Handle<Object> key,
3202 Handle<Object> value,
3203 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003204 HandleScope scope;
3205
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003206 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003207 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003208 Handle<Object> error =
3209 Factory::NewTypeError("non_object_property_store",
3210 HandleVector(args, 2));
3211 return Top::Throw(*error);
3212 }
3213
3214 // If the object isn't a JavaScript object, we ignore the store.
3215 if (!object->IsJSObject()) return *value;
3216
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003217 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3218
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003219 // Check if the given key is an array index.
3220 uint32_t index;
3221 if (Array::IndexFromObject(*key, &index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003222 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3223 // of a string using [] notation. We need to support this too in
3224 // JavaScript.
3225 // In the case of a String object we just need to redirect the assignment to
3226 // the underlying string if the index is in range. Since the underlying
3227 // string does nothing with the assignment then we can ignore such
3228 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003229 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003230 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003231 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003232
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003233 Handle<Object> result = SetElement(js_object, index, value);
3234 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003235 return *value;
3236 }
3237
3238 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003239 Handle<Object> result;
3240 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003241 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003242 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003243 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003244 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003245 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003246 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003247 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003248 return *value;
3249 }
3250
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003251 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003252 bool has_pending_exception = false;
3253 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3254 if (has_pending_exception) return Failure::Exception();
3255 Handle<String> name = Handle<String>::cast(converted);
3256
3257 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003258 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003259 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003260 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003261 }
3262}
3263
3264
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003265Object* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3266 Handle<Object> key,
3267 Handle<Object> value,
3268 PropertyAttributes attr) {
3269 HandleScope scope;
3270
3271 // Check if the given key is an array index.
3272 uint32_t index;
3273 if (Array::IndexFromObject(*key, &index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003274 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3275 // of a string using [] notation. We need to support this too in
3276 // JavaScript.
3277 // In the case of a String object we just need to redirect the assignment to
3278 // the underlying string if the index is in range. Since the underlying
3279 // string does nothing with the assignment then we can ignore such
3280 // assignments.
3281 if (js_object->IsStringObjectWithCharacterAt(index)) {
3282 return *value;
3283 }
3284
3285 return js_object->SetElement(index, *value);
3286 }
3287
3288 if (key->IsString()) {
3289 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003290 return js_object->SetElement(index, *value);
3291 } else {
3292 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003293 key_string->TryFlatten();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003294 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
3295 *value,
3296 attr);
3297 }
3298 }
3299
3300 // Call-back into JavaScript to convert the key to a string.
3301 bool has_pending_exception = false;
3302 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3303 if (has_pending_exception) return Failure::Exception();
3304 Handle<String> name = Handle<String>::cast(converted);
3305
3306 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003307 return js_object->SetElement(index, *value);
3308 } else {
3309 return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr);
3310 }
3311}
3312
3313
ager@chromium.orge2902be2009-06-08 12:21:35 +00003314Object* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3315 Handle<Object> key) {
3316 HandleScope scope;
3317
3318 // Check if the given key is an array index.
3319 uint32_t index;
3320 if (Array::IndexFromObject(*key, &index)) {
3321 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3322 // characters of a string using [] notation. In the case of a
3323 // String object we just need to redirect the deletion to the
3324 // underlying string if the index is in range. Since the
3325 // underlying string does nothing with the deletion, we can ignore
3326 // such deletions.
3327 if (js_object->IsStringObjectWithCharacterAt(index)) {
3328 return Heap::true_value();
3329 }
3330
3331 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3332 }
3333
3334 Handle<String> key_string;
3335 if (key->IsString()) {
3336 key_string = Handle<String>::cast(key);
3337 } else {
3338 // Call-back into JavaScript to convert the key to a string.
3339 bool has_pending_exception = false;
3340 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3341 if (has_pending_exception) return Failure::Exception();
3342 key_string = Handle<String>::cast(converted);
3343 }
3344
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003345 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003346 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3347}
3348
3349
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003350static Object* Runtime_SetProperty(Arguments args) {
3351 NoHandleAllocation ha;
3352 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3353
3354 Handle<Object> object = args.at<Object>(0);
3355 Handle<Object> key = args.at<Object>(1);
3356 Handle<Object> value = args.at<Object>(2);
3357
3358 // Compute attributes.
3359 PropertyAttributes attributes = NONE;
3360 if (args.length() == 4) {
3361 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003362 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003364 RUNTIME_ASSERT(
3365 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3366 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003367 }
3368 return Runtime::SetObjectProperty(object, key, value, attributes);
3369}
3370
3371
3372// Set a local property, even if it is READ_ONLY. If the property does not
3373// exist, it will be added with attributes NONE.
3374static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
3375 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003376 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003377 CONVERT_CHECKED(JSObject, object, args[0]);
3378 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003379 // Compute attributes.
3380 PropertyAttributes attributes = NONE;
3381 if (args.length() == 4) {
3382 CONVERT_CHECKED(Smi, value_obj, args[3]);
3383 int unchecked_value = value_obj->value();
3384 // Only attribute bits should be set.
3385 RUNTIME_ASSERT(
3386 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3387 attributes = static_cast<PropertyAttributes>(unchecked_value);
3388 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003389
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003390 return object->
3391 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003392}
3393
3394
3395static Object* Runtime_DeleteProperty(Arguments args) {
3396 NoHandleAllocation ha;
3397 ASSERT(args.length() == 2);
3398
3399 CONVERT_CHECKED(JSObject, object, args[0]);
3400 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003401 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402}
3403
3404
ager@chromium.org9085a012009-05-11 19:22:57 +00003405static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3406 Handle<String> key) {
3407 if (object->HasLocalProperty(*key)) return Heap::true_value();
3408 // Handle hidden prototypes. If there's a hidden prototype above this thing
3409 // then we have to check it for properties, because they are supposed to
3410 // look like they are on this object.
3411 Handle<Object> proto(object->GetPrototype());
3412 if (proto->IsJSObject() &&
3413 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3414 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3415 }
3416 return Heap::false_value();
3417}
3418
3419
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003420static Object* Runtime_HasLocalProperty(Arguments args) {
3421 NoHandleAllocation ha;
3422 ASSERT(args.length() == 2);
3423 CONVERT_CHECKED(String, key, args[1]);
3424
ager@chromium.org9085a012009-05-11 19:22:57 +00003425 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003426 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003427 if (obj->IsJSObject()) {
3428 JSObject* object = JSObject::cast(obj);
3429 // Fast case - no interceptors.
3430 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3431 // Slow case. Either it's not there or we have an interceptor. We should
3432 // have handles for this kind of deal.
3433 HandleScope scope;
3434 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3435 Handle<String>(key));
3436 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003437 // Well, there is one exception: Handle [] on strings.
3438 uint32_t index;
3439 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003440 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003441 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003442 return Heap::true_value();
3443 }
3444 }
3445 return Heap::false_value();
3446}
3447
3448
3449static Object* Runtime_HasProperty(Arguments args) {
3450 NoHandleAllocation na;
3451 ASSERT(args.length() == 2);
3452
3453 // Only JS objects can have properties.
3454 if (args[0]->IsJSObject()) {
3455 JSObject* object = JSObject::cast(args[0]);
3456 CONVERT_CHECKED(String, key, args[1]);
3457 if (object->HasProperty(key)) return Heap::true_value();
3458 }
3459 return Heap::false_value();
3460}
3461
3462
3463static Object* Runtime_HasElement(Arguments args) {
3464 NoHandleAllocation na;
3465 ASSERT(args.length() == 2);
3466
3467 // Only JS objects can have elements.
3468 if (args[0]->IsJSObject()) {
3469 JSObject* object = JSObject::cast(args[0]);
3470 CONVERT_CHECKED(Smi, index_obj, args[1]);
3471 uint32_t index = index_obj->value();
3472 if (object->HasElement(index)) return Heap::true_value();
3473 }
3474 return Heap::false_value();
3475}
3476
3477
3478static Object* Runtime_IsPropertyEnumerable(Arguments args) {
3479 NoHandleAllocation ha;
3480 ASSERT(args.length() == 2);
3481
3482 CONVERT_CHECKED(JSObject, object, args[0]);
3483 CONVERT_CHECKED(String, key, args[1]);
3484
3485 uint32_t index;
3486 if (key->AsArrayIndex(&index)) {
3487 return Heap::ToBoolean(object->HasElement(index));
3488 }
3489
ager@chromium.org870a0b62008-11-04 11:43:05 +00003490 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3491 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003492}
3493
3494
3495static Object* Runtime_GetPropertyNames(Arguments args) {
3496 HandleScope scope;
3497 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003498 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003499 return *GetKeysFor(object);
3500}
3501
3502
3503// Returns either a FixedArray as Runtime_GetPropertyNames,
3504// or, if the given object has an enum cache that contains
3505// all enumerable properties of the object and its prototypes
3506// have none, the map of the object. This is used to speed up
3507// the check for deletions during a for-in.
3508static Object* Runtime_GetPropertyNamesFast(Arguments args) {
3509 ASSERT(args.length() == 1);
3510
3511 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3512
3513 if (raw_object->IsSimpleEnum()) return raw_object->map();
3514
3515 HandleScope scope;
3516 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003517 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3518 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003519
3520 // Test again, since cache may have been built by preceding call.
3521 if (object->IsSimpleEnum()) return object->map();
3522
3523 return *content;
3524}
3525
3526
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003527// Find the length of the prototype chain that is to to handled as one. If a
3528// prototype object is hidden it is to be viewed as part of the the object it
3529// is prototype for.
3530static int LocalPrototypeChainLength(JSObject* obj) {
3531 int count = 1;
3532 Object* proto = obj->GetPrototype();
3533 while (proto->IsJSObject() &&
3534 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3535 count++;
3536 proto = JSObject::cast(proto)->GetPrototype();
3537 }
3538 return count;
3539}
3540
3541
3542// Return the names of the local named properties.
3543// args[0]: object
3544static Object* Runtime_GetLocalPropertyNames(Arguments args) {
3545 HandleScope scope;
3546 ASSERT(args.length() == 1);
3547 if (!args[0]->IsJSObject()) {
3548 return Heap::undefined_value();
3549 }
3550 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3551
3552 // Skip the global proxy as it has no properties and always delegates to the
3553 // real global object.
3554 if (obj->IsJSGlobalProxy()) {
3555 // Only collect names if access is permitted.
3556 if (obj->IsAccessCheckNeeded() &&
3557 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3558 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3559 return *Factory::NewJSArray(0);
3560 }
3561 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3562 }
3563
3564 // Find the number of objects making up this.
3565 int length = LocalPrototypeChainLength(*obj);
3566
3567 // Find the number of local properties for each of the objects.
3568 int* local_property_count = NewArray<int>(length);
3569 int total_property_count = 0;
3570 Handle<JSObject> jsproto = obj;
3571 for (int i = 0; i < length; i++) {
3572 // Only collect names if access is permitted.
3573 if (jsproto->IsAccessCheckNeeded() &&
3574 !Top::MayNamedAccess(*jsproto,
3575 Heap::undefined_value(),
3576 v8::ACCESS_KEYS)) {
3577 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
3578 return *Factory::NewJSArray(0);
3579 }
3580 int n;
3581 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3582 local_property_count[i] = n;
3583 total_property_count += n;
3584 if (i < length - 1) {
3585 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3586 }
3587 }
3588
3589 // Allocate an array with storage for all the property names.
3590 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
3591
3592 // Get the property names.
3593 jsproto = obj;
3594 int proto_with_hidden_properties = 0;
3595 for (int i = 0; i < length; i++) {
3596 jsproto->GetLocalPropertyNames(*names,
3597 i == 0 ? 0 : local_property_count[i - 1]);
3598 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
3599 proto_with_hidden_properties++;
3600 }
3601 if (i < length - 1) {
3602 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3603 }
3604 }
3605
3606 // Filter out name of hidden propeties object.
3607 if (proto_with_hidden_properties > 0) {
3608 Handle<FixedArray> old_names = names;
3609 names = Factory::NewFixedArray(
3610 names->length() - proto_with_hidden_properties);
3611 int dest_pos = 0;
3612 for (int i = 0; i < total_property_count; i++) {
3613 Object* name = old_names->get(i);
3614 if (name == Heap::hidden_symbol()) {
3615 continue;
3616 }
3617 names->set(dest_pos++, name);
3618 }
3619 }
3620
3621 DeleteArray(local_property_count);
3622 return *Factory::NewJSArrayWithElements(names);
3623}
3624
3625
3626// Return the names of the local indexed properties.
3627// args[0]: object
3628static Object* Runtime_GetLocalElementNames(Arguments args) {
3629 HandleScope scope;
3630 ASSERT(args.length() == 1);
3631 if (!args[0]->IsJSObject()) {
3632 return Heap::undefined_value();
3633 }
3634 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3635
3636 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
3637 Handle<FixedArray> names = Factory::NewFixedArray(n);
3638 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
3639 return *Factory::NewJSArrayWithElements(names);
3640}
3641
3642
3643// Return information on whether an object has a named or indexed interceptor.
3644// args[0]: object
3645static Object* Runtime_GetInterceptorInfo(Arguments args) {
3646 HandleScope scope;
3647 ASSERT(args.length() == 1);
3648 if (!args[0]->IsJSObject()) {
3649 return Smi::FromInt(0);
3650 }
3651 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3652
3653 int result = 0;
3654 if (obj->HasNamedInterceptor()) result |= 2;
3655 if (obj->HasIndexedInterceptor()) result |= 1;
3656
3657 return Smi::FromInt(result);
3658}
3659
3660
3661// Return property names from named interceptor.
3662// args[0]: object
3663static Object* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
3664 HandleScope scope;
3665 ASSERT(args.length() == 1);
3666 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3667
3668 if (obj->HasNamedInterceptor()) {
3669 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
3670 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
3671 }
3672 return Heap::undefined_value();
3673}
3674
3675
3676// Return element names from indexed interceptor.
3677// args[0]: object
3678static Object* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
3679 HandleScope scope;
3680 ASSERT(args.length() == 1);
3681 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3682
3683 if (obj->HasIndexedInterceptor()) {
3684 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
3685 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
3686 }
3687 return Heap::undefined_value();
3688}
3689
3690
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003691static Object* Runtime_LocalKeys(Arguments args) {
3692 ASSERT_EQ(args.length(), 1);
3693 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3694 HandleScope scope;
3695 Handle<JSObject> object(raw_object);
3696 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
3697 LOCAL_ONLY);
3698 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
3699 // property array and since the result is mutable we have to create
3700 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003701 int length = contents->length();
3702 Handle<FixedArray> copy = Factory::NewFixedArray(length);
3703 for (int i = 0; i < length; i++) {
3704 Object* entry = contents->get(i);
3705 if (entry->IsString()) {
3706 copy->set(i, entry);
3707 } else {
3708 ASSERT(entry->IsNumber());
3709 HandleScope scope;
3710 Handle<Object> entry_handle(entry);
3711 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
3712 copy->set(i, *entry_str);
3713 }
3714 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003715 return *Factory::NewJSArrayWithElements(copy);
3716}
3717
3718
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003719static Object* Runtime_GetArgumentsProperty(Arguments args) {
3720 NoHandleAllocation ha;
3721 ASSERT(args.length() == 1);
3722
3723 // Compute the frame holding the arguments.
3724 JavaScriptFrameIterator it;
3725 it.AdvanceToArgumentsFrame();
3726 JavaScriptFrame* frame = it.frame();
3727
3728 // Get the actual number of provided arguments.
3729 const uint32_t n = frame->GetProvidedParametersCount();
3730
3731 // Try to convert the key to an index. If successful and within
3732 // index return the the argument from the frame.
3733 uint32_t index;
3734 if (Array::IndexFromObject(args[0], &index) && index < n) {
3735 return frame->GetParameter(index);
3736 }
3737
3738 // Convert the key to a string.
3739 HandleScope scope;
3740 bool exception = false;
3741 Handle<Object> converted =
3742 Execution::ToString(args.at<Object>(0), &exception);
3743 if (exception) return Failure::Exception();
3744 Handle<String> key = Handle<String>::cast(converted);
3745
3746 // Try to convert the string key into an array index.
3747 if (key->AsArrayIndex(&index)) {
3748 if (index < n) {
3749 return frame->GetParameter(index);
3750 } else {
3751 return Top::initial_object_prototype()->GetElement(index);
3752 }
3753 }
3754
3755 // Handle special arguments properties.
3756 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
3757 if (key->Equals(Heap::callee_symbol())) return frame->function();
3758
3759 // Lookup in the initial Object.prototype object.
3760 return Top::initial_object_prototype()->GetProperty(*key);
3761}
3762
3763
kasperl@chromium.org061ef742009-02-27 12:16:20 +00003764static Object* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003765 HandleScope scope;
3766
kasperl@chromium.org061ef742009-02-27 12:16:20 +00003767 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00003768 Handle<Object> object = args.at<Object>(0);
3769 if (object->IsJSObject()) {
3770 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00003771 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
3772 js_object->TransformToFastProperties(0);
3773 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00003774 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00003775 return *object;
3776}
3777
3778
3779static Object* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003780 HandleScope scope;
3781
kasperl@chromium.org061ef742009-02-27 12:16:20 +00003782 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00003783 Handle<Object> object = args.at<Object>(0);
3784 if (object->IsJSObject()) {
3785 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003786 js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00003787 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00003788 return *object;
3789}
3790
3791
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003792static Object* Runtime_ToBool(Arguments args) {
3793 NoHandleAllocation ha;
3794 ASSERT(args.length() == 1);
3795
3796 return args[0]->ToBoolean();
3797}
3798
3799
3800// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
3801// Possible optimizations: put the type string into the oddballs.
3802static Object* Runtime_Typeof(Arguments args) {
3803 NoHandleAllocation ha;
3804
3805 Object* obj = args[0];
3806 if (obj->IsNumber()) return Heap::number_symbol();
3807 HeapObject* heap_obj = HeapObject::cast(obj);
3808
3809 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003810 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003811
3812 InstanceType instance_type = heap_obj->map()->instance_type();
3813 if (instance_type < FIRST_NONSTRING_TYPE) {
3814 return Heap::string_symbol();
3815 }
3816
3817 switch (instance_type) {
3818 case ODDBALL_TYPE:
3819 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
3820 return Heap::boolean_symbol();
3821 }
3822 if (heap_obj->IsNull()) {
3823 return Heap::object_symbol();
3824 }
3825 ASSERT(heap_obj->IsUndefined());
3826 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00003827 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003828 return Heap::function_symbol();
3829 default:
3830 // For any kind of object not handled above, the spec rule for
3831 // host objects gives that it is okay to return "object"
3832 return Heap::object_symbol();
3833 }
3834}
3835
3836
3837static Object* Runtime_StringToNumber(Arguments args) {
3838 NoHandleAllocation ha;
3839 ASSERT(args.length() == 1);
3840 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003841 subject->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003842 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
3843}
3844
3845
3846static Object* Runtime_StringFromCharCodeArray(Arguments args) {
3847 NoHandleAllocation ha;
3848 ASSERT(args.length() == 1);
3849
3850 CONVERT_CHECKED(JSArray, codes, args[0]);
3851 int length = Smi::cast(codes->length())->value();
3852
3853 // Check if the string can be ASCII.
3854 int i;
3855 for (i = 0; i < length; i++) {
3856 Object* element = codes->GetElement(i);
3857 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
3858 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
3859 break;
3860 }
3861
3862 Object* object = NULL;
3863 if (i == length) { // The string is ASCII.
3864 object = Heap::AllocateRawAsciiString(length);
3865 } else { // The string is not ASCII.
3866 object = Heap::AllocateRawTwoByteString(length);
3867 }
3868
3869 if (object->IsFailure()) return object;
3870 String* result = String::cast(object);
3871 for (int i = 0; i < length; i++) {
3872 Object* element = codes->GetElement(i);
3873 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003874 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003875 }
3876 return result;
3877}
3878
3879
3880// kNotEscaped is generated by the following:
3881//
3882// #!/bin/perl
3883// for (my $i = 0; $i < 256; $i++) {
3884// print "\n" if $i % 16 == 0;
3885// my $c = chr($i);
3886// my $escaped = 1;
3887// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
3888// print $escaped ? "0, " : "1, ";
3889// }
3890
3891
3892static bool IsNotEscaped(uint16_t character) {
3893 // Only for 8 bit characters, the rest are always escaped (in a different way)
3894 ASSERT(character < 256);
3895 static const char kNotEscaped[256] = {
3896 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3897 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3898 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
3899 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
3900 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3901 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
3902 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3903 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
3904 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3905 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3906 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3907 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3908 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3909 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3910 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3911 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3912 };
3913 return kNotEscaped[character] != 0;
3914}
3915
3916
3917static Object* Runtime_URIEscape(Arguments args) {
3918 const char hex_chars[] = "0123456789ABCDEF";
3919 NoHandleAllocation ha;
3920 ASSERT(args.length() == 1);
3921 CONVERT_CHECKED(String, source, args[0]);
3922
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003923 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003924
3925 int escaped_length = 0;
3926 int length = source->length();
3927 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003928 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003929 buffer->Reset(source);
3930 while (buffer->has_more()) {
3931 uint16_t character = buffer->GetNext();
3932 if (character >= 256) {
3933 escaped_length += 6;
3934 } else if (IsNotEscaped(character)) {
3935 escaped_length++;
3936 } else {
3937 escaped_length += 3;
3938 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003939 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003940 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003941 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003942 Top::context()->mark_out_of_memory();
3943 return Failure::OutOfMemoryException();
3944 }
3945 }
3946 }
3947 // No length change implies no change. Return original string if no change.
3948 if (escaped_length == length) {
3949 return source;
3950 }
3951 Object* o = Heap::AllocateRawAsciiString(escaped_length);
3952 if (o->IsFailure()) return o;
3953 String* destination = String::cast(o);
3954 int dest_position = 0;
3955
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003956 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003957 buffer->Rewind();
3958 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00003959 uint16_t chr = buffer->GetNext();
3960 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003961 destination->Set(dest_position, '%');
3962 destination->Set(dest_position+1, 'u');
3963 destination->Set(dest_position+2, hex_chars[chr >> 12]);
3964 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
3965 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
3966 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003967 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00003968 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003969 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970 dest_position++;
3971 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003972 destination->Set(dest_position, '%');
3973 destination->Set(dest_position+1, hex_chars[chr >> 4]);
3974 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003975 dest_position += 3;
3976 }
3977 }
3978 return destination;
3979}
3980
3981
3982static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
3983 static const signed char kHexValue['g'] = {
3984 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3985 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3986 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3987 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
3988 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3989 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3990 -1, 10, 11, 12, 13, 14, 15 };
3991
3992 if (character1 > 'f') return -1;
3993 int hi = kHexValue[character1];
3994 if (hi == -1) return -1;
3995 if (character2 > 'f') return -1;
3996 int lo = kHexValue[character2];
3997 if (lo == -1) return -1;
3998 return (hi << 4) + lo;
3999}
4000
4001
ager@chromium.org870a0b62008-11-04 11:43:05 +00004002static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004003 int i,
4004 int length,
4005 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004006 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004007 int32_t hi = 0;
4008 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 if (character == '%' &&
4010 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004011 source->Get(i + 1) == 'u' &&
4012 (hi = TwoDigitHex(source->Get(i + 2),
4013 source->Get(i + 3))) != -1 &&
4014 (lo = TwoDigitHex(source->Get(i + 4),
4015 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 *step = 6;
4017 return (hi << 8) + lo;
4018 } else if (character == '%' &&
4019 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004020 (lo = TwoDigitHex(source->Get(i + 1),
4021 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022 *step = 3;
4023 return lo;
4024 } else {
4025 *step = 1;
4026 return character;
4027 }
4028}
4029
4030
4031static Object* Runtime_URIUnescape(Arguments args) {
4032 NoHandleAllocation ha;
4033 ASSERT(args.length() == 1);
4034 CONVERT_CHECKED(String, source, args[0]);
4035
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004036 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004037
4038 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004039 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040
4041 int unescaped_length = 0;
4042 for (int i = 0; i < length; unescaped_length++) {
4043 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004044 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004046 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 i += step;
4048 }
4049
4050 // No length change implies no change. Return original string if no change.
4051 if (unescaped_length == length)
4052 return source;
4053
4054 Object* o = ascii ?
4055 Heap::AllocateRawAsciiString(unescaped_length) :
4056 Heap::AllocateRawTwoByteString(unescaped_length);
4057 if (o->IsFailure()) return o;
4058 String* destination = String::cast(o);
4059
4060 int dest_position = 0;
4061 for (int i = 0; i < length; dest_position++) {
4062 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004063 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004064 i += step;
4065 }
4066 return destination;
4067}
4068
4069
4070static Object* Runtime_StringParseInt(Arguments args) {
4071 NoHandleAllocation ha;
4072
4073 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004074 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004076 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004078 int len = s->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 int i;
4080
4081 // Skip leading white space.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004082 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004083 if (i == len) return Heap::nan_value();
4084
4085 // Compute the sign (default to +).
4086 int sign = 1;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004087 if (s->Get(i) == '-') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 sign = -1;
4089 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004090 } else if (s->Get(i) == '+') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 i++;
4092 }
4093
4094 // Compute the radix if 0.
4095 if (radix == 0) {
4096 radix = 10;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004097 if (i < len && s->Get(i) == '0') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 radix = 8;
4099 if (i + 1 < len) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004100 int c = s->Get(i + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 if (c == 'x' || c == 'X') {
4102 radix = 16;
4103 i += 2;
4104 }
4105 }
4106 }
4107 } else if (radix == 16) {
4108 // Allow 0x or 0X prefix if radix is 16.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004109 if (i + 1 < len && s->Get(i) == '0') {
4110 int c = s->Get(i + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 if (c == 'x' || c == 'X') i += 2;
4112 }
4113 }
4114
4115 RUNTIME_ASSERT(2 <= radix && radix <= 36);
4116 double value;
4117 int end_index = StringToInt(s, i, radix, &value);
4118 if (end_index != i) {
4119 return Heap::NumberFromDouble(sign * value);
4120 }
4121 return Heap::nan_value();
4122}
4123
4124
4125static Object* Runtime_StringParseFloat(Arguments args) {
4126 NoHandleAllocation ha;
4127 CONVERT_CHECKED(String, str, args[0]);
4128
4129 // ECMA-262 section 15.1.2.3, empty string is NaN
4130 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4131
4132 // Create a number object from the value.
4133 return Heap::NumberFromDouble(value);
4134}
4135
4136
4137static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4138static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4139
4140
4141template <class Converter>
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004142static Object* ConvertCaseHelper(String* s,
4143 int length,
4144 int input_string_length,
4145 unibrow::Mapping<Converter, 128>* mapping) {
4146 // We try this twice, once with the assumption that the result is no longer
4147 // than the input and, if that assumption breaks, again with the exact
4148 // length. This may not be pretty, but it is nicer than what was here before
4149 // and I hereby claim my vaffel-is.
4150 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004151 // Allocate the resulting string.
4152 //
4153 // NOTE: This assumes that the upper/lower case of an ascii
4154 // character is also ascii. This is currently the case, but it
4155 // might break in the future if we implement more context and locale
4156 // dependent upper/lower conversions.
ager@chromium.org5ec48922009-05-05 07:25:34 +00004157 Object* o = s->IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004158 ? Heap::AllocateRawAsciiString(length)
4159 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004160 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004161 String* result = String::cast(o);
4162 bool has_changed_character = false;
4163
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 // Convert all characters to upper case, assuming that they will fit
4165 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004166 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004167 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004168 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169 // We can assume that the string is not empty
4170 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004171 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004172 bool has_next = buffer->has_more();
4173 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004174 int char_length = mapping->get(current, next, chars);
4175 if (char_length == 0) {
4176 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004177 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004178 i++;
4179 } else if (char_length == 1) {
4180 // Common case: converting the letter resulted in one character.
4181 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004182 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004183 has_changed_character = true;
4184 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004185 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004186 // We've assumed that the result would be as long as the
4187 // input but here is a character that converts to several
4188 // characters. No matter, we calculate the exact length
4189 // of the result and try the whole thing again.
4190 //
4191 // Note that this leaves room for optimization. We could just
4192 // memcpy what we already have to the result string. Also,
4193 // the result string is the last object allocated we could
4194 // "realloc" it and probably, in the vast majority of cases,
4195 // extend the existing string to be able to hold the full
4196 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004197 int next_length = 0;
4198 if (has_next) {
4199 next_length = mapping->get(next, 0, chars);
4200 if (next_length == 0) next_length = 1;
4201 }
4202 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 while (buffer->has_more()) {
4204 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004205 // NOTE: we use 0 as the next character here because, while
4206 // the next character may affect what a character converts to,
4207 // it does not in any case affect the length of what it convert
4208 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 int char_length = mapping->get(current, 0, chars);
4210 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004211 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004212 if (current_length > Smi::kMaxValue) {
4213 Top::context()->mark_out_of_memory();
4214 return Failure::OutOfMemoryException();
4215 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004217 // Try again with the real length.
4218 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219 } else {
4220 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004221 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004222 i++;
4223 }
4224 has_changed_character = true;
4225 }
4226 current = next;
4227 }
4228 if (has_changed_character) {
4229 return result;
4230 } else {
4231 // If we didn't actually change anything in doing the conversion
4232 // we simple return the result and let the converted string
4233 // become garbage; there is no reason to keep two identical strings
4234 // alive.
4235 return s;
4236 }
4237}
4238
4239
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004240static inline SeqAsciiString* TryGetSeqAsciiString(String* s) {
4241 if (!s->IsFlat() || !s->IsAsciiRepresentation()) return NULL;
4242 if (s->IsConsString()) {
4243 ASSERT(ConsString::cast(s)->second()->length() == 0);
4244 return SeqAsciiString::cast(ConsString::cast(s)->first());
4245 }
4246 return SeqAsciiString::cast(s);
4247}
4248
4249
4250namespace {
4251
4252struct ToLowerTraits {
4253 typedef unibrow::ToLowercase UnibrowConverter;
4254
4255 static bool ConvertAscii(char* dst, char* src, int length) {
4256 bool changed = false;
4257 for (int i = 0; i < length; ++i) {
4258 char c = src[i];
4259 if ('A' <= c && c <= 'Z') {
4260 c += ('a' - 'A');
4261 changed = true;
4262 }
4263 dst[i] = c;
4264 }
4265 return changed;
4266 }
4267};
4268
4269
4270struct ToUpperTraits {
4271 typedef unibrow::ToUppercase UnibrowConverter;
4272
4273 static bool ConvertAscii(char* dst, char* src, int length) {
4274 bool changed = false;
4275 for (int i = 0; i < length; ++i) {
4276 char c = src[i];
4277 if ('a' <= c && c <= 'z') {
4278 c -= ('a' - 'A');
4279 changed = true;
4280 }
4281 dst[i] = c;
4282 }
4283 return changed;
4284 }
4285};
4286
4287} // namespace
4288
4289
4290template <typename ConvertTraits>
4291static Object* ConvertCase(
4292 Arguments args,
4293 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004294 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004295 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004296 s->TryFlatten();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004297
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004298 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004299 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004300 if (length == 0) return s;
4301
4302 // Simpler handling of ascii strings.
4303 //
4304 // NOTE: This assumes that the upper/lower case of an ascii
4305 // character is also ascii. This is currently the case, but it
4306 // might break in the future if we implement more context and locale
4307 // dependent upper/lower conversions.
4308 SeqAsciiString* seq_ascii = TryGetSeqAsciiString(s);
4309 if (seq_ascii != NULL) {
4310 Object* o = Heap::AllocateRawAsciiString(length);
4311 if (o->IsFailure()) return o;
4312 SeqAsciiString* result = SeqAsciiString::cast(o);
4313 bool has_changed_character = ConvertTraits::ConvertAscii(
4314 result->GetChars(), seq_ascii->GetChars(), length);
4315 return has_changed_character ? result : s;
4316 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004317
4318 Object* answer = ConvertCaseHelper(s, length, length, mapping);
4319 if (answer->IsSmi()) {
4320 // Retry with correct length.
4321 answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
4322 }
4323 return answer; // This may be a failure.
4324}
4325
4326
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004327static Object* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004328 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004329}
4330
4331
4332static Object* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004333 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334}
4335
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004336
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004337static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
4338 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
4339}
4340
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004341
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004342static Object* Runtime_StringTrim(Arguments args) {
4343 NoHandleAllocation ha;
4344 ASSERT(args.length() == 3);
4345
4346 CONVERT_CHECKED(String, s, args[0]);
4347 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
4348 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
4349
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004350 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004351 int length = s->length();
4352
4353 int left = 0;
4354 if (trimLeft) {
4355 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
4356 left++;
4357 }
4358 }
4359
4360 int right = length;
4361 if (trimRight) {
4362 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
4363 right--;
4364 }
4365 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004366 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004367}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004368
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004369
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004370template <typename schar, typename pchar>
4371void FindStringIndices(Vector<const schar> subject,
4372 Vector<const pchar> pattern,
4373 ZoneList<int>* indices,
4374 unsigned int limit) {
4375 ASSERT(limit > 0);
4376 // Collect indices of pattern in subject, and the end-of-string index.
4377 // Stop after finding at most limit values.
4378 StringSearchStrategy strategy =
4379 InitializeStringSearch(pattern, sizeof(schar) == 1);
4380 switch (strategy) {
4381 case SEARCH_FAIL: return;
4382 case SEARCH_SHORT: {
4383 int pattern_length = pattern.length();
4384 int index = 0;
4385 while (limit > 0) {
4386 index = SimpleIndexOf(subject, pattern, index);
4387 if (index < 0) return;
4388 indices->Add(index);
4389 index += pattern_length;
4390 limit--;
4391 }
4392 return;
4393 }
4394 case SEARCH_LONG: {
4395 int pattern_length = pattern.length();
4396 int index = 0;
4397 while (limit > 0) {
4398 index = ComplexIndexOf(subject, pattern, index);
4399 if (index < 0) return;
4400 indices->Add(index);
4401 index += pattern_length;
4402 limit--;
4403 }
4404 return;
4405 }
4406 default:
4407 UNREACHABLE();
4408 return;
4409 }
4410}
4411
4412template <typename schar>
4413inline void FindCharIndices(Vector<const schar> subject,
4414 const schar pattern_char,
4415 ZoneList<int>* indices,
4416 unsigned int limit) {
4417 // Collect indices of pattern_char in subject, and the end-of-string index.
4418 // Stop after finding at most limit values.
4419 int index = 0;
4420 while (limit > 0) {
4421 index = SingleCharIndexOf(subject, pattern_char, index);
4422 if (index < 0) return;
4423 indices->Add(index);
4424 index++;
4425 limit--;
4426 }
4427}
4428
4429
4430static Object* Runtime_StringSplit(Arguments args) {
4431 ASSERT(args.length() == 3);
4432 HandleScope handle_scope;
4433 CONVERT_ARG_CHECKED(String, subject, 0);
4434 CONVERT_ARG_CHECKED(String, pattern, 1);
4435 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
4436
4437 int subject_length = subject->length();
4438 int pattern_length = pattern->length();
4439 RUNTIME_ASSERT(pattern_length > 0);
4440
4441 // The limit can be very large (0xffffffffu), but since the pattern
4442 // isn't empty, we can never create more parts than ~half the length
4443 // of the subject.
4444
4445 if (!subject->IsFlat()) FlattenString(subject);
4446
4447 static const int kMaxInitialListCapacity = 16;
4448
4449 ZoneScope scope(DELETE_ON_EXIT);
4450
4451 // Find (up to limit) indices of separator and end-of-string in subject
4452 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
4453 ZoneList<int> indices(initial_capacity);
4454 if (pattern_length == 1) {
4455 // Special case, go directly to fast single-character split.
4456 AssertNoAllocation nogc;
4457 uc16 pattern_char = pattern->Get(0);
4458 if (subject->IsTwoByteRepresentation()) {
4459 FindCharIndices(subject->ToUC16Vector(), pattern_char,
4460 &indices,
4461 limit);
4462 } else if (pattern_char <= String::kMaxAsciiCharCode) {
4463 FindCharIndices(subject->ToAsciiVector(),
4464 static_cast<char>(pattern_char),
4465 &indices,
4466 limit);
4467 }
4468 } else {
4469 if (!pattern->IsFlat()) FlattenString(pattern);
4470 AssertNoAllocation nogc;
4471 if (subject->IsAsciiRepresentation()) {
4472 Vector<const char> subject_vector = subject->ToAsciiVector();
4473 if (pattern->IsAsciiRepresentation()) {
4474 FindStringIndices(subject_vector,
4475 pattern->ToAsciiVector(),
4476 &indices,
4477 limit);
4478 } else {
4479 FindStringIndices(subject_vector,
4480 pattern->ToUC16Vector(),
4481 &indices,
4482 limit);
4483 }
4484 } else {
4485 Vector<const uc16> subject_vector = subject->ToUC16Vector();
4486 if (pattern->IsAsciiRepresentation()) {
4487 FindStringIndices(subject_vector,
4488 pattern->ToAsciiVector(),
4489 &indices,
4490 limit);
4491 } else {
4492 FindStringIndices(subject_vector,
4493 pattern->ToUC16Vector(),
4494 &indices,
4495 limit);
4496 }
4497 }
4498 }
4499 if (static_cast<uint32_t>(indices.length()) < limit) {
4500 indices.Add(subject_length);
4501 }
4502 // The list indices now contains the end of each part to create.
4503
4504
4505 // Create JSArray of substrings separated by separator.
4506 int part_count = indices.length();
4507
4508 Handle<JSArray> result = Factory::NewJSArray(part_count);
4509 result->set_length(Smi::FromInt(part_count));
4510
4511 ASSERT(result->HasFastElements());
4512
4513 if (part_count == 1 && indices.at(0) == subject_length) {
4514 FixedArray::cast(result->elements())->set(0, *subject);
4515 return *result;
4516 }
4517
4518 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
4519 int part_start = 0;
4520 for (int i = 0; i < part_count; i++) {
4521 HandleScope local_loop_handle;
4522 int part_end = indices.at(i);
4523 Handle<String> substring =
4524 Factory::NewSubString(subject, part_start, part_end);
4525 elements->set(i, *substring);
4526 part_start = part_end + pattern_length;
4527 }
4528
4529 return *result;
4530}
4531
4532
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004533// Copies ascii characters to the given fixed array looking up
4534// one-char strings in the cache. Gives up on the first char that is
4535// not in the cache and fills the remainder with smi zeros. Returns
4536// the length of the successfully copied prefix.
4537static int CopyCachedAsciiCharsToArray(const char* chars,
4538 FixedArray* elements,
4539 int length) {
4540 AssertNoAllocation nogc;
4541 FixedArray* ascii_cache = Heap::single_character_string_cache();
4542 Object* undefined = Heap::undefined_value();
4543 int i;
4544 for (i = 0; i < length; ++i) {
4545 Object* value = ascii_cache->get(chars[i]);
4546 if (value == undefined) break;
4547 ASSERT(!Heap::InNewSpace(value));
4548 elements->set(i, value, SKIP_WRITE_BARRIER);
4549 }
4550 if (i < length) {
4551 ASSERT(Smi::FromInt(0) == 0);
4552 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
4553 }
4554#ifdef DEBUG
4555 for (int j = 0; j < length; ++j) {
4556 Object* element = elements->get(j);
4557 ASSERT(element == Smi::FromInt(0) ||
4558 (element->IsString() && String::cast(element)->LooksValid()));
4559 }
4560#endif
4561 return i;
4562}
4563
4564
4565// Converts a String to JSArray.
4566// For example, "foo" => ["f", "o", "o"].
4567static Object* Runtime_StringToArray(Arguments args) {
4568 HandleScope scope;
4569 ASSERT(args.length() == 1);
4570 CONVERT_ARG_CHECKED(String, s, 0);
4571
4572 s->TryFlatten();
4573 const int length = s->length();
4574
4575 Handle<FixedArray> elements;
4576 if (s->IsFlat() && s->IsAsciiRepresentation()) {
4577 Object* obj = Heap::AllocateUninitializedFixedArray(length);
4578 if (obj->IsFailure()) return obj;
4579 elements = Handle<FixedArray>(FixedArray::cast(obj));
4580
4581 Vector<const char> chars = s->ToAsciiVector();
4582 // Note, this will initialize all elements (not only the prefix)
4583 // to prevent GC from seeing partially initialized array.
4584 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
4585 *elements,
4586 length);
4587
4588 for (int i = num_copied_from_cache; i < length; ++i) {
4589 elements->set(i, *LookupSingleCharacterStringFromCode(chars[i]));
4590 }
4591 } else {
4592 elements = Factory::NewFixedArray(length);
4593 for (int i = 0; i < length; ++i) {
4594 elements->set(i, *LookupSingleCharacterStringFromCode(s->Get(i)));
4595 }
4596 }
4597
4598#ifdef DEBUG
4599 for (int i = 0; i < length; ++i) {
4600 ASSERT(String::cast(elements->get(i))->length() == 1);
4601 }
4602#endif
4603
4604 return *Factory::NewJSArrayWithElements(elements);
4605}
4606
4607
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00004608bool Runtime::IsUpperCaseChar(uint16_t ch) {
4609 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
4610 int char_length = to_upper_mapping.get(ch, 0, chars);
4611 return char_length == 0;
4612}
4613
4614
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004615static Object* Runtime_NumberToString(Arguments args) {
4616 NoHandleAllocation ha;
4617 ASSERT(args.length() == 1);
4618
4619 Object* number = args[0];
4620 RUNTIME_ASSERT(number->IsNumber());
4621
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004622 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004623}
4624
4625
4626static Object* Runtime_NumberToInteger(Arguments args) {
4627 NoHandleAllocation ha;
4628 ASSERT(args.length() == 1);
4629
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004630 CONVERT_DOUBLE_CHECKED(number, args[0]);
4631
4632 // We do not include 0 so that we don't have to treat +0 / -0 cases.
4633 if (number > 0 && number <= Smi::kMaxValue) {
4634 return Smi::FromInt(static_cast<int>(number));
4635 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004636 return Heap::NumberFromDouble(DoubleToInteger(number));
4637}
4638
4639
4640static Object* Runtime_NumberToJSUint32(Arguments args) {
4641 NoHandleAllocation ha;
4642 ASSERT(args.length() == 1);
4643
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004644 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004645 return Heap::NumberFromUint32(number);
4646}
4647
4648
4649static Object* Runtime_NumberToJSInt32(Arguments args) {
4650 NoHandleAllocation ha;
4651 ASSERT(args.length() == 1);
4652
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004653 CONVERT_DOUBLE_CHECKED(number, args[0]);
4654
4655 // We do not include 0 so that we don't have to treat +0 / -0 cases.
4656 if (number > 0 && number <= Smi::kMaxValue) {
4657 return Smi::FromInt(static_cast<int>(number));
4658 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004659 return Heap::NumberFromInt32(DoubleToInt32(number));
4660}
4661
4662
ager@chromium.org870a0b62008-11-04 11:43:05 +00004663// Converts a Number to a Smi, if possible. Returns NaN if the number is not
4664// a small integer.
4665static Object* Runtime_NumberToSmi(Arguments args) {
4666 NoHandleAllocation ha;
4667 ASSERT(args.length() == 1);
4668
4669 Object* obj = args[0];
4670 if (obj->IsSmi()) {
4671 return obj;
4672 }
4673 if (obj->IsHeapNumber()) {
4674 double value = HeapNumber::cast(obj)->value();
4675 int int_value = FastD2I(value);
4676 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
4677 return Smi::FromInt(int_value);
4678 }
4679 }
4680 return Heap::nan_value();
4681}
4682
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004683
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004684static Object* Runtime_NumberAdd(Arguments args) {
4685 NoHandleAllocation ha;
4686 ASSERT(args.length() == 2);
4687
4688 CONVERT_DOUBLE_CHECKED(x, args[0]);
4689 CONVERT_DOUBLE_CHECKED(y, args[1]);
4690 return Heap::AllocateHeapNumber(x + y);
4691}
4692
4693
4694static Object* Runtime_NumberSub(Arguments args) {
4695 NoHandleAllocation ha;
4696 ASSERT(args.length() == 2);
4697
4698 CONVERT_DOUBLE_CHECKED(x, args[0]);
4699 CONVERT_DOUBLE_CHECKED(y, args[1]);
4700 return Heap::AllocateHeapNumber(x - y);
4701}
4702
4703
4704static Object* Runtime_NumberMul(Arguments args) {
4705 NoHandleAllocation ha;
4706 ASSERT(args.length() == 2);
4707
4708 CONVERT_DOUBLE_CHECKED(x, args[0]);
4709 CONVERT_DOUBLE_CHECKED(y, args[1]);
4710 return Heap::AllocateHeapNumber(x * y);
4711}
4712
4713
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714static Object* Runtime_NumberUnaryMinus(Arguments args) {
4715 NoHandleAllocation ha;
4716 ASSERT(args.length() == 1);
4717
4718 CONVERT_DOUBLE_CHECKED(x, args[0]);
4719 return Heap::AllocateHeapNumber(-x);
4720}
4721
4722
4723static Object* Runtime_NumberDiv(Arguments args) {
4724 NoHandleAllocation ha;
4725 ASSERT(args.length() == 2);
4726
4727 CONVERT_DOUBLE_CHECKED(x, args[0]);
4728 CONVERT_DOUBLE_CHECKED(y, args[1]);
4729 return Heap::NewNumberFromDouble(x / y);
4730}
4731
4732
4733static Object* Runtime_NumberMod(Arguments args) {
4734 NoHandleAllocation ha;
4735 ASSERT(args.length() == 2);
4736
4737 CONVERT_DOUBLE_CHECKED(x, args[0]);
4738 CONVERT_DOUBLE_CHECKED(y, args[1]);
4739
ager@chromium.org3811b432009-10-28 14:53:37 +00004740 x = modulo(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004741 // NewNumberFromDouble may return a Smi instead of a Number object
4742 return Heap::NewNumberFromDouble(x);
4743}
4744
4745
4746static Object* Runtime_StringAdd(Arguments args) {
4747 NoHandleAllocation ha;
4748 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004749 CONVERT_CHECKED(String, str1, args[0]);
4750 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004751 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004752 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004753}
4754
4755
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004756template<typename sinkchar>
4757static inline void StringBuilderConcatHelper(String* special,
4758 sinkchar* sink,
4759 FixedArray* fixed_array,
4760 int array_length) {
4761 int position = 0;
4762 for (int i = 0; i < array_length; i++) {
4763 Object* element = fixed_array->get(i);
4764 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004765 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004766 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004767 int pos;
4768 int len;
4769 if (encoded_slice > 0) {
4770 // Position and length encoded in one smi.
4771 pos = StringBuilderSubstringPosition::decode(encoded_slice);
4772 len = StringBuilderSubstringLength::decode(encoded_slice);
4773 } else {
4774 // Position and length encoded in two smis.
4775 Object* obj = fixed_array->get(++i);
4776 ASSERT(obj->IsSmi());
4777 pos = Smi::cast(obj)->value();
4778 len = -encoded_slice;
4779 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00004780 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004781 sink + position,
4782 pos,
4783 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004784 position += len;
4785 } else {
4786 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004787 int element_length = string->length();
4788 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004789 position += element_length;
4790 }
4791 }
4792}
4793
4794
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795static Object* Runtime_StringBuilderConcat(Arguments args) {
4796 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004797 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004799 if (!args[1]->IsSmi()) {
4800 Top::context()->mark_out_of_memory();
4801 return Failure::OutOfMemoryException();
4802 }
4803 int array_length = Smi::cast(args[1])->value();
4804 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004805
4806 // This assumption is used by the slice encoding in one or two smis.
4807 ASSERT(Smi::kMaxValue >= String::kMaxLength);
4808
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004809 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004810 if (!array->HasFastElements()) {
4811 return Top::Throw(Heap::illegal_argument_symbol());
4812 }
4813 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004814 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004815 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004816 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004817
4818 if (array_length == 0) {
4819 return Heap::empty_string();
4820 } else if (array_length == 1) {
4821 Object* first = fixed_array->get(0);
4822 if (first->IsString()) return first;
4823 }
4824
ager@chromium.org5ec48922009-05-05 07:25:34 +00004825 bool ascii = special->IsAsciiRepresentation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 int position = 0;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004827 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004828 for (int i = 0; i < array_length; i++) {
4829 Object* elt = fixed_array->get(i);
4830 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004831 // Smi encoding of position and length.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004832 int len = Smi::cast(elt)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004833 if (len > 0) {
4834 // Position and length encoded in one smi.
4835 int pos = len >> 11;
4836 len &= 0x7ff;
4837 if (pos + len > special_length) {
4838 return Top::Throw(Heap::illegal_argument_symbol());
4839 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004840 increment = len;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004841 } else {
4842 // Position and length encoded in two smis.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004843 increment = (-len);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004844 // Get the position and check that it is also a smi.
4845 i++;
4846 if (i >= array_length) {
4847 return Top::Throw(Heap::illegal_argument_symbol());
4848 }
4849 Object* pos = fixed_array->get(i);
4850 if (!pos->IsSmi()) {
4851 return Top::Throw(Heap::illegal_argument_symbol());
4852 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004853 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004854 } else if (elt->IsString()) {
4855 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004856 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004857 increment = element_length;
ager@chromium.org5ec48922009-05-05 07:25:34 +00004858 if (ascii && !element->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004859 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004860 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004861 } else {
4862 return Top::Throw(Heap::illegal_argument_symbol());
4863 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004864 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004865 Top::context()->mark_out_of_memory();
4866 return Failure::OutOfMemoryException();
4867 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004868 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004869 }
4870
4871 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004873
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004874 if (ascii) {
4875 object = Heap::AllocateRawAsciiString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004876 if (object->IsFailure()) return object;
4877 SeqAsciiString* answer = SeqAsciiString::cast(object);
4878 StringBuilderConcatHelper(special,
4879 answer->GetChars(),
4880 fixed_array,
4881 array_length);
4882 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004883 } else {
4884 object = Heap::AllocateRawTwoByteString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004885 if (object->IsFailure()) return object;
4886 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
4887 StringBuilderConcatHelper(special,
4888 answer->GetChars(),
4889 fixed_array,
4890 array_length);
4891 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004892 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893}
4894
4895
4896static Object* Runtime_NumberOr(Arguments args) {
4897 NoHandleAllocation ha;
4898 ASSERT(args.length() == 2);
4899
4900 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
4901 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
4902 return Heap::NumberFromInt32(x | y);
4903}
4904
4905
4906static Object* Runtime_NumberAnd(Arguments args) {
4907 NoHandleAllocation ha;
4908 ASSERT(args.length() == 2);
4909
4910 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
4911 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
4912 return Heap::NumberFromInt32(x & y);
4913}
4914
4915
4916static Object* Runtime_NumberXor(Arguments args) {
4917 NoHandleAllocation ha;
4918 ASSERT(args.length() == 2);
4919
4920 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
4921 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
4922 return Heap::NumberFromInt32(x ^ y);
4923}
4924
4925
4926static Object* Runtime_NumberNot(Arguments args) {
4927 NoHandleAllocation ha;
4928 ASSERT(args.length() == 1);
4929
4930 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
4931 return Heap::NumberFromInt32(~x);
4932}
4933
4934
4935static Object* Runtime_NumberShl(Arguments args) {
4936 NoHandleAllocation ha;
4937 ASSERT(args.length() == 2);
4938
4939 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
4940 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
4941 return Heap::NumberFromInt32(x << (y & 0x1f));
4942}
4943
4944
4945static Object* Runtime_NumberShr(Arguments args) {
4946 NoHandleAllocation ha;
4947 ASSERT(args.length() == 2);
4948
4949 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
4950 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
4951 return Heap::NumberFromUint32(x >> (y & 0x1f));
4952}
4953
4954
4955static Object* Runtime_NumberSar(Arguments args) {
4956 NoHandleAllocation ha;
4957 ASSERT(args.length() == 2);
4958
4959 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
4960 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
4961 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
4962}
4963
4964
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004965static Object* Runtime_NumberEquals(Arguments args) {
4966 NoHandleAllocation ha;
4967 ASSERT(args.length() == 2);
4968
4969 CONVERT_DOUBLE_CHECKED(x, args[0]);
4970 CONVERT_DOUBLE_CHECKED(y, args[1]);
4971 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
4972 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
4973 if (x == y) return Smi::FromInt(EQUAL);
4974 Object* result;
4975 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
4976 result = Smi::FromInt(EQUAL);
4977 } else {
4978 result = Smi::FromInt(NOT_EQUAL);
4979 }
4980 return result;
4981}
4982
4983
4984static Object* Runtime_StringEquals(Arguments args) {
4985 NoHandleAllocation ha;
4986 ASSERT(args.length() == 2);
4987
4988 CONVERT_CHECKED(String, x, args[0]);
4989 CONVERT_CHECKED(String, y, args[1]);
4990
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004991 bool not_equal = !x->Equals(y);
4992 // This is slightly convoluted because the value that signifies
4993 // equality is 0 and inequality is 1 so we have to negate the result
4994 // from String::Equals.
4995 ASSERT(not_equal == 0 || not_equal == 1);
4996 STATIC_CHECK(EQUAL == 0);
4997 STATIC_CHECK(NOT_EQUAL == 1);
4998 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004999}
5000
5001
5002static Object* Runtime_NumberCompare(Arguments args) {
5003 NoHandleAllocation ha;
5004 ASSERT(args.length() == 3);
5005
5006 CONVERT_DOUBLE_CHECKED(x, args[0]);
5007 CONVERT_DOUBLE_CHECKED(y, args[1]);
5008 if (isnan(x) || isnan(y)) return args[2];
5009 if (x == y) return Smi::FromInt(EQUAL);
5010 if (isless(x, y)) return Smi::FromInt(LESS);
5011 return Smi::FromInt(GREATER);
5012}
5013
5014
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005015// Compare two Smis as if they were converted to strings and then
5016// compared lexicographically.
5017static Object* Runtime_SmiLexicographicCompare(Arguments args) {
5018 NoHandleAllocation ha;
5019 ASSERT(args.length() == 2);
5020
5021 // Arrays for the individual characters of the two Smis. Smis are
5022 // 31 bit integers and 10 decimal digits are therefore enough.
5023 static int x_elms[10];
5024 static int y_elms[10];
5025
5026 // Extract the integer values from the Smis.
5027 CONVERT_CHECKED(Smi, x, args[0]);
5028 CONVERT_CHECKED(Smi, y, args[1]);
5029 int x_value = x->value();
5030 int y_value = y->value();
5031
5032 // If the integers are equal so are the string representations.
5033 if (x_value == y_value) return Smi::FromInt(EQUAL);
5034
5035 // If one of the integers are zero the normal integer order is the
5036 // same as the lexicographic order of the string representations.
5037 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5038
ager@chromium.org32912102009-01-16 10:38:43 +00005039 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005040 // smallest because the char code of '-' is less than the char code
5041 // of any digit. Otherwise, we make both values positive.
5042 if (x_value < 0 || y_value < 0) {
5043 if (y_value >= 0) return Smi::FromInt(LESS);
5044 if (x_value >= 0) return Smi::FromInt(GREATER);
5045 x_value = -x_value;
5046 y_value = -y_value;
5047 }
5048
5049 // Convert the integers to arrays of their decimal digits.
5050 int x_index = 0;
5051 int y_index = 0;
5052 while (x_value > 0) {
5053 x_elms[x_index++] = x_value % 10;
5054 x_value /= 10;
5055 }
5056 while (y_value > 0) {
5057 y_elms[y_index++] = y_value % 10;
5058 y_value /= 10;
5059 }
5060
5061 // Loop through the arrays of decimal digits finding the first place
5062 // where they differ.
5063 while (--x_index >= 0 && --y_index >= 0) {
5064 int diff = x_elms[x_index] - y_elms[y_index];
5065 if (diff != 0) return Smi::FromInt(diff);
5066 }
5067
5068 // If one array is a suffix of the other array, the longest array is
5069 // the representation of the largest of the Smis in the
5070 // lexicographic ordering.
5071 return Smi::FromInt(x_index - y_index);
5072}
5073
5074
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005075static Object* StringInputBufferCompare(String* x, String* y) {
5076 static StringInputBuffer bufx;
5077 static StringInputBuffer bufy;
5078 bufx.Reset(x);
5079 bufy.Reset(y);
5080 while (bufx.has_more() && bufy.has_more()) {
5081 int d = bufx.GetNext() - bufy.GetNext();
5082 if (d < 0) return Smi::FromInt(LESS);
5083 else if (d > 0) return Smi::FromInt(GREATER);
5084 }
5085
5086 // x is (non-trivial) prefix of y:
5087 if (bufy.has_more()) return Smi::FromInt(LESS);
5088 // y is prefix of x:
5089 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5090}
5091
5092
5093static Object* FlatStringCompare(String* x, String* y) {
5094 ASSERT(x->IsFlat());
5095 ASSERT(y->IsFlat());
5096 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5097 int prefix_length = x->length();
5098 if (y->length() < prefix_length) {
5099 prefix_length = y->length();
5100 equal_prefix_result = Smi::FromInt(GREATER);
5101 } else if (y->length() > prefix_length) {
5102 equal_prefix_result = Smi::FromInt(LESS);
5103 }
5104 int r;
5105 if (x->IsAsciiRepresentation()) {
5106 Vector<const char> x_chars = x->ToAsciiVector();
5107 if (y->IsAsciiRepresentation()) {
5108 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005109 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005110 } else {
5111 Vector<const uc16> y_chars = y->ToUC16Vector();
5112 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5113 }
5114 } else {
5115 Vector<const uc16> x_chars = x->ToUC16Vector();
5116 if (y->IsAsciiRepresentation()) {
5117 Vector<const char> y_chars = y->ToAsciiVector();
5118 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5119 } else {
5120 Vector<const uc16> y_chars = y->ToUC16Vector();
5121 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5122 }
5123 }
5124 Object* result;
5125 if (r == 0) {
5126 result = equal_prefix_result;
5127 } else {
5128 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5129 }
5130 ASSERT(result == StringInputBufferCompare(x, y));
5131 return result;
5132}
5133
5134
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005135static Object* Runtime_StringCompare(Arguments args) {
5136 NoHandleAllocation ha;
5137 ASSERT(args.length() == 2);
5138
5139 CONVERT_CHECKED(String, x, args[0]);
5140 CONVERT_CHECKED(String, y, args[1]);
5141
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005142 Counters::string_compare_runtime.Increment();
5143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005144 // A few fast case tests before we flatten.
5145 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005146 if (y->length() == 0) {
5147 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005148 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005149 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005150 return Smi::FromInt(LESS);
5151 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005152
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005153 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005154 if (d < 0) return Smi::FromInt(LESS);
5155 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005156
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005157 Object* obj = Heap::PrepareForCompare(x);
5158 if (obj->IsFailure()) return obj;
5159 obj = Heap::PrepareForCompare(y);
5160 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005161
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005162 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5163 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005164}
5165
5166
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005167static Object* Runtime_Math_acos(Arguments args) {
5168 NoHandleAllocation ha;
5169 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005170 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005171
5172 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005173 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005174}
5175
5176
5177static Object* Runtime_Math_asin(Arguments args) {
5178 NoHandleAllocation ha;
5179 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005180 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181
5182 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005183 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005184}
5185
5186
5187static Object* Runtime_Math_atan(Arguments args) {
5188 NoHandleAllocation ha;
5189 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005190 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005191
5192 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005193 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005194}
5195
5196
5197static Object* Runtime_Math_atan2(Arguments args) {
5198 NoHandleAllocation ha;
5199 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005200 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201
5202 CONVERT_DOUBLE_CHECKED(x, args[0]);
5203 CONVERT_DOUBLE_CHECKED(y, args[1]);
5204 double result;
5205 if (isinf(x) && isinf(y)) {
5206 // Make sure that the result in case of two infinite arguments
5207 // is a multiple of Pi / 4. The sign of the result is determined
5208 // by the first argument (x) and the sign of the second argument
5209 // determines the multiplier: one or three.
5210 static double kPiDividedBy4 = 0.78539816339744830962;
5211 int multiplier = (x < 0) ? -1 : 1;
5212 if (y < 0) multiplier *= 3;
5213 result = multiplier * kPiDividedBy4;
5214 } else {
5215 result = atan2(x, y);
5216 }
5217 return Heap::AllocateHeapNumber(result);
5218}
5219
5220
5221static Object* Runtime_Math_ceil(Arguments args) {
5222 NoHandleAllocation ha;
5223 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005224 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005225
5226 CONVERT_DOUBLE_CHECKED(x, args[0]);
5227 return Heap::NumberFromDouble(ceiling(x));
5228}
5229
5230
5231static Object* Runtime_Math_cos(Arguments args) {
5232 NoHandleAllocation ha;
5233 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005234 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005235
5236 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005237 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005238}
5239
5240
5241static Object* Runtime_Math_exp(Arguments args) {
5242 NoHandleAllocation ha;
5243 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005244 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005245
5246 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005247 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005248}
5249
5250
5251static Object* Runtime_Math_floor(Arguments args) {
5252 NoHandleAllocation ha;
5253 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005254 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005255
5256 CONVERT_DOUBLE_CHECKED(x, args[0]);
5257 return Heap::NumberFromDouble(floor(x));
5258}
5259
5260
5261static Object* Runtime_Math_log(Arguments args) {
5262 NoHandleAllocation ha;
5263 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005264 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005265
5266 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005267 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005268}
5269
5270
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005271// Helper function to compute x^y, where y is known to be an
5272// integer. Uses binary decomposition to limit the number of
5273// multiplications; see the discussion in "Hacker's Delight" by Henry
5274// S. Warren, Jr., figure 11-6, page 213.
5275static double powi(double x, int y) {
5276 ASSERT(y != kMinInt);
5277 unsigned n = (y < 0) ? -y : y;
5278 double m = x;
5279 double p = 1;
5280 while (true) {
5281 if ((n & 1) != 0) p *= m;
5282 n >>= 1;
5283 if (n == 0) {
5284 if (y < 0) {
5285 // Unfortunately, we have to be careful when p has reached
5286 // infinity in the computation, because sometimes the higher
5287 // internal precision in the pow() implementation would have
5288 // given us a finite p. This happens very rarely.
5289 double result = 1.0 / p;
5290 return (result == 0 && isinf(p))
5291 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
5292 : result;
5293 } else {
5294 return p;
5295 }
5296 }
5297 m *= m;
5298 }
5299}
5300
5301
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005302static Object* Runtime_Math_pow(Arguments args) {
5303 NoHandleAllocation ha;
5304 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005305 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005306
5307 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005308
5309 // If the second argument is a smi, it is much faster to call the
5310 // custom powi() function than the generic pow().
5311 if (args[1]->IsSmi()) {
5312 int y = Smi::cast(args[1])->value();
5313 return Heap::AllocateHeapNumber(powi(x, y));
5314 }
5315
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005316 CONVERT_DOUBLE_CHECKED(y, args[1]);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005317
5318 if (!isinf(x)) {
5319 if (y == 0.5) {
5320 // It's not uncommon to use Math.pow(x, 0.5) to compute the
5321 // square root of a number. To speed up such computations, we
5322 // explictly check for this case and use the sqrt() function
5323 // which is faster than pow().
5324 return Heap::AllocateHeapNumber(sqrt(x));
5325 } else if (y == -0.5) {
5326 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
5327 return Heap::AllocateHeapNumber(1.0 / sqrt(x));
5328 }
5329 }
5330
5331 if (y == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005332 return Smi::FromInt(1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005333 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5334 return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005335 } else {
5336 return Heap::AllocateHeapNumber(pow(x, y));
5337 }
5338}
5339
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005340// Fast version of Math.pow if we know that y is not an integer and
5341// y is not -0.5 or 0.5. Used as slowcase from codegen.
5342static Object* Runtime_Math_pow_cfunction(Arguments args) {
5343 NoHandleAllocation ha;
5344 ASSERT(args.length() == 2);
5345 CONVERT_DOUBLE_CHECKED(x, args[0]);
5346 CONVERT_DOUBLE_CHECKED(y, args[1]);
5347 if (y == 0) {
5348 return Smi::FromInt(1);
5349 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5350 return Heap::nan_value();
5351 } else {
5352 return Heap::AllocateHeapNumber(pow(x, y));
5353 }
5354}
5355
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005356
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005357static Object* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005358 NoHandleAllocation ha;
5359 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005360 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005361
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005362 if (!args[0]->IsHeapNumber()) {
5363 // Must be smi. Return the argument unchanged for all the other types
5364 // to make fuzz-natives test happy.
5365 return args[0];
5366 }
5367
5368 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
5369
5370 double value = number->value();
5371 int exponent = number->get_exponent();
5372 int sign = number->get_sign();
5373
5374 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
5375 // should be rounded to 2^30, which is not smi.
5376 if (!sign && exponent <= kSmiValueSize - 3) {
5377 return Smi::FromInt(static_cast<int>(value + 0.5));
5378 }
5379
5380 // If the magnitude is big enough, there's no place for fraction part. If we
5381 // try to add 0.5 to this number, 1.0 will be added instead.
5382 if (exponent >= 52) {
5383 return number;
5384 }
5385
5386 if (sign && value >= -0.5) return Heap::minus_zero_value();
5387
5388 return Heap::NumberFromDouble(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005389}
5390
5391
5392static Object* Runtime_Math_sin(Arguments args) {
5393 NoHandleAllocation ha;
5394 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005395 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005396
5397 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005398 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005399}
5400
5401
5402static Object* Runtime_Math_sqrt(Arguments args) {
5403 NoHandleAllocation ha;
5404 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005405 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005406
5407 CONVERT_DOUBLE_CHECKED(x, args[0]);
5408 return Heap::AllocateHeapNumber(sqrt(x));
5409}
5410
5411
5412static Object* Runtime_Math_tan(Arguments args) {
5413 NoHandleAllocation ha;
5414 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005415 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005416
5417 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005418 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005419}
5420
5421
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005422static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005423 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
5424 181, 212, 243, 273, 304, 334};
5425 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
5426 182, 213, 244, 274, 305, 335};
5427
5428 year += month / 12;
5429 month %= 12;
5430 if (month < 0) {
5431 year--;
5432 month += 12;
5433 }
5434
5435 ASSERT(month >= 0);
5436 ASSERT(month < 12);
5437
5438 // year_delta is an arbitrary number such that:
5439 // a) year_delta = -1 (mod 400)
5440 // b) year + year_delta > 0 for years in the range defined by
5441 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
5442 // Jan 1 1970. This is required so that we don't run into integer
5443 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005444 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005445 // operations.
5446 static const int year_delta = 399999;
5447 static const int base_day = 365 * (1970 + year_delta) +
5448 (1970 + year_delta) / 4 -
5449 (1970 + year_delta) / 100 +
5450 (1970 + year_delta) / 400;
5451
5452 int year1 = year + year_delta;
5453 int day_from_year = 365 * year1 +
5454 year1 / 4 -
5455 year1 / 100 +
5456 year1 / 400 -
5457 base_day;
5458
5459 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005460 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005461 }
5462
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005463 return day_from_year + day_from_month_leap[month] + day - 1;
5464}
5465
5466
5467static Object* Runtime_DateMakeDay(Arguments args) {
5468 NoHandleAllocation ha;
5469 ASSERT(args.length() == 3);
5470
5471 CONVERT_SMI_CHECKED(year, args[0]);
5472 CONVERT_SMI_CHECKED(month, args[1]);
5473 CONVERT_SMI_CHECKED(date, args[2]);
5474
5475 return Smi::FromInt(MakeDay(year, month, date));
5476}
5477
5478
5479static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
5480static const int kDaysIn4Years = 4 * 365 + 1;
5481static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
5482static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
5483static const int kDays1970to2000 = 30 * 365 + 7;
5484static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
5485 kDays1970to2000;
5486static const int kYearsOffset = 400000;
5487
5488static const char kDayInYear[] = {
5489 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5490 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5491 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5492 22, 23, 24, 25, 26, 27, 28,
5493 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5494 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5495 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5496 22, 23, 24, 25, 26, 27, 28, 29, 30,
5497 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5498 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5499 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5500 22, 23, 24, 25, 26, 27, 28, 29, 30,
5501 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5502 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5503 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5504 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5505 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5506 22, 23, 24, 25, 26, 27, 28, 29, 30,
5507 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5508 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5509 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5510 22, 23, 24, 25, 26, 27, 28, 29, 30,
5511 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5512 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5513
5514 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5515 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5516 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5517 22, 23, 24, 25, 26, 27, 28,
5518 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5519 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5520 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5521 22, 23, 24, 25, 26, 27, 28, 29, 30,
5522 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5523 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5524 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5525 22, 23, 24, 25, 26, 27, 28, 29, 30,
5526 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5527 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5528 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5529 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5530 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5531 22, 23, 24, 25, 26, 27, 28, 29, 30,
5532 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5533 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5534 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5535 22, 23, 24, 25, 26, 27, 28, 29, 30,
5536 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5537 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5538
5539 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5540 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5541 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5542 22, 23, 24, 25, 26, 27, 28, 29,
5543 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5544 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5545 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5546 22, 23, 24, 25, 26, 27, 28, 29, 30,
5547 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5548 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5549 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5550 22, 23, 24, 25, 26, 27, 28, 29, 30,
5551 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5552 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5553 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5554 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5555 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5556 22, 23, 24, 25, 26, 27, 28, 29, 30,
5557 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5558 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5559 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5560 22, 23, 24, 25, 26, 27, 28, 29, 30,
5561 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5562 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5563
5564 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5565 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5566 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5567 22, 23, 24, 25, 26, 27, 28,
5568 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5569 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5570 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5571 22, 23, 24, 25, 26, 27, 28, 29, 30,
5572 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5573 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5574 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5575 22, 23, 24, 25, 26, 27, 28, 29, 30,
5576 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5577 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5578 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5579 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5580 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5581 22, 23, 24, 25, 26, 27, 28, 29, 30,
5582 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5583 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
5584 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5585 22, 23, 24, 25, 26, 27, 28, 29, 30,
5586 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
5587 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
5588
5589static const char kMonthInYear[] = {
5590 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,
5591 0, 0, 0, 0, 0, 0,
5592 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,
5593 1, 1, 1,
5594 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,
5595 2, 2, 2, 2, 2, 2,
5596 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,
5597 3, 3, 3, 3, 3,
5598 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,
5599 4, 4, 4, 4, 4, 4,
5600 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,
5601 5, 5, 5, 5, 5,
5602 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,
5603 6, 6, 6, 6, 6, 6,
5604 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,
5605 7, 7, 7, 7, 7, 7,
5606 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,
5607 8, 8, 8, 8, 8,
5608 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,
5609 9, 9, 9, 9, 9, 9,
5610 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
5611 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
5612 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
5613 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
5614
5615 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,
5616 0, 0, 0, 0, 0, 0,
5617 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,
5618 1, 1, 1,
5619 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,
5620 2, 2, 2, 2, 2, 2,
5621 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,
5622 3, 3, 3, 3, 3,
5623 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,
5624 4, 4, 4, 4, 4, 4,
5625 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,
5626 5, 5, 5, 5, 5,
5627 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,
5628 6, 6, 6, 6, 6, 6,
5629 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,
5630 7, 7, 7, 7, 7, 7,
5631 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,
5632 8, 8, 8, 8, 8,
5633 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,
5634 9, 9, 9, 9, 9, 9,
5635 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
5636 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
5637 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
5638 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
5639
5640 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,
5641 0, 0, 0, 0, 0, 0,
5642 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,
5643 1, 1, 1, 1,
5644 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,
5645 2, 2, 2, 2, 2, 2,
5646 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,
5647 3, 3, 3, 3, 3,
5648 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,
5649 4, 4, 4, 4, 4, 4,
5650 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,
5651 5, 5, 5, 5, 5,
5652 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,
5653 6, 6, 6, 6, 6, 6,
5654 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,
5655 7, 7, 7, 7, 7, 7,
5656 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,
5657 8, 8, 8, 8, 8,
5658 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,
5659 9, 9, 9, 9, 9, 9,
5660 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
5661 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
5662 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
5663 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
5664
5665 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,
5666 0, 0, 0, 0, 0, 0,
5667 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,
5668 1, 1, 1,
5669 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,
5670 2, 2, 2, 2, 2, 2,
5671 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,
5672 3, 3, 3, 3, 3,
5673 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,
5674 4, 4, 4, 4, 4, 4,
5675 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,
5676 5, 5, 5, 5, 5,
5677 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,
5678 6, 6, 6, 6, 6, 6,
5679 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,
5680 7, 7, 7, 7, 7, 7,
5681 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,
5682 8, 8, 8, 8, 8,
5683 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,
5684 9, 9, 9, 9, 9, 9,
5685 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
5686 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
5687 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
5688 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
5689
5690
5691// This function works for dates from 1970 to 2099.
5692static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005693 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005694#ifdef DEBUG
5695 int save_date = date; // Need this for ASSERT in the end.
5696#endif
5697
5698 year = 1970 + (4 * date + 2) / kDaysIn4Years;
5699 date %= kDaysIn4Years;
5700
5701 month = kMonthInYear[date];
5702 day = kDayInYear[date];
5703
5704 ASSERT(MakeDay(year, month, day) == save_date);
5705}
5706
5707
5708static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005709 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005710#ifdef DEBUG
5711 int save_date = date; // Need this for ASSERT in the end.
5712#endif
5713
5714 date += kDaysOffset;
5715 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
5716 date %= kDaysIn400Years;
5717
5718 ASSERT(MakeDay(year, 0, 1) + date == save_date);
5719
5720 date--;
5721 int yd1 = date / kDaysIn100Years;
5722 date %= kDaysIn100Years;
5723 year += 100 * yd1;
5724
5725 date++;
5726 int yd2 = date / kDaysIn4Years;
5727 date %= kDaysIn4Years;
5728 year += 4 * yd2;
5729
5730 date--;
5731 int yd3 = date / 365;
5732 date %= 365;
5733 year += yd3;
5734
5735 bool is_leap = (!yd1 || yd2) && !yd3;
5736
5737 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005738 ASSERT(is_leap || (date >= 0));
5739 ASSERT((date < 365) || (is_leap && (date < 366)));
5740 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
5741 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
5742 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005743
5744 if (is_leap) {
5745 day = kDayInYear[2*365 + 1 + date];
5746 month = kMonthInYear[2*365 + 1 + date];
5747 } else {
5748 day = kDayInYear[date];
5749 month = kMonthInYear[date];
5750 }
5751
5752 ASSERT(MakeDay(year, month, day) == save_date);
5753}
5754
5755
5756static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005757 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00005758 if (date >= 0 && date < 32 * kDaysIn4Years) {
5759 DateYMDFromTimeAfter1970(date, year, month, day);
5760 } else {
5761 DateYMDFromTimeSlow(date, year, month, day);
5762 }
5763}
5764
5765
5766static Object* Runtime_DateYMDFromTime(Arguments args) {
5767 NoHandleAllocation ha;
5768 ASSERT(args.length() == 2);
5769
5770 CONVERT_DOUBLE_CHECKED(t, args[0]);
5771 CONVERT_CHECKED(JSArray, res_array, args[1]);
5772
5773 int year, month, day;
5774 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
5775
5776 res_array->SetElement(0, Smi::FromInt(year));
5777 res_array->SetElement(1, Smi::FromInt(month));
5778 res_array->SetElement(2, Smi::FromInt(day));
5779
5780 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005781}
5782
5783
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005784static Object* Runtime_NewArgumentsFast(Arguments args) {
5785 NoHandleAllocation ha;
5786 ASSERT(args.length() == 3);
5787
5788 JSFunction* callee = JSFunction::cast(args[0]);
5789 Object** parameters = reinterpret_cast<Object**>(args[1]);
5790 const int length = Smi::cast(args[2])->value();
5791
5792 Object* result = Heap::AllocateArgumentsObject(callee, length);
5793 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005794 // Allocate the elements if needed.
5795 if (length > 0) {
5796 // Allocate the fixed array.
5797 Object* obj = Heap::AllocateRawFixedArray(length);
5798 if (obj->IsFailure()) return obj;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005799
5800 AssertNoAllocation no_gc;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005801 reinterpret_cast<Array*>(obj)->set_map(Heap::fixed_array_map());
5802 FixedArray* array = FixedArray::cast(obj);
5803 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005804
5805 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005806 for (int i = 0; i < length; i++) {
5807 array->set(i, *--parameters, mode);
5808 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005809 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005810 }
5811 return result;
5812}
5813
5814
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005815static Object* Runtime_NewClosure(Arguments args) {
5816 HandleScope scope;
5817 ASSERT(args.length() == 2);
ager@chromium.org3811b432009-10-28 14:53:37 +00005818 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00005819 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005820
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00005821 PretenureFlag pretenure = (context->global_context() == *context)
5822 ? TENURED // Allocate global closures in old space.
5823 : NOT_TENURED; // Allocate local closures in new space.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005824 Handle<JSFunction> result =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00005825 Factory::NewFunctionFromSharedFunctionInfo(shared, context, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005826 return *result;
5827}
5828
5829
ager@chromium.org5c838252010-02-19 08:53:10 +00005830static Code* ComputeConstructStub(Handle<JSFunction> function) {
5831 Handle<Object> prototype = Factory::null_value();
5832 if (function->has_instance_prototype()) {
5833 prototype = Handle<Object>(function->instance_prototype());
5834 }
5835 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005836 ConstructStubCompiler compiler;
ager@chromium.org5c838252010-02-19 08:53:10 +00005837 Object* code = compiler.CompileConstructStub(function->shared());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005838 if (code->IsFailure()) {
5839 return Builtins::builtin(Builtins::JSConstructStubGeneric);
5840 }
5841 return Code::cast(code);
5842 }
5843
ager@chromium.org5c838252010-02-19 08:53:10 +00005844 return function->shared()->construct_stub();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005845}
5846
5847
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005848static Object* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005849 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005850 ASSERT(args.length() == 1);
5851
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005852 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005853
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005854 // If the constructor isn't a proper function we throw a type error.
5855 if (!constructor->IsJSFunction()) {
5856 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
5857 Handle<Object> type_error =
5858 Factory::NewTypeError("not_constructor", arguments);
5859 return Top::Throw(*type_error);
5860 }
5861
5862 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005863#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005864 // Handle stepping into constructors if step into is active.
5865 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005866 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005867 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005868#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005869
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005870 if (function->has_initial_map()) {
5871 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005872 // The 'Function' function ignores the receiver object when
5873 // called using 'new' and creates a new JSFunction object that
5874 // is returned. The receiver object is only used for error
5875 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005876 // JSFunction. Factory::NewJSObject() should not be used to
5877 // allocate JSFunctions since it does not properly initialize
5878 // the shared part of the function. Since the receiver is
5879 // ignored anyway, we use the global object as the receiver
5880 // instead of a new JSFunction object. This way, errors are
5881 // reported the same way whether or not 'Function' is called
5882 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005883 return Top::context()->global();
5884 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005885 }
5886
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005887 // The function should be compiled for the optimization hints to be available.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005888 Handle<SharedFunctionInfo> shared(function->shared());
5889 EnsureCompiled(shared, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005890
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005891 bool first_allocation = !function->has_initial_map();
5892 Handle<JSObject> result = Factory::NewJSObject(function);
5893 if (first_allocation) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005894 Handle<Code> stub = Handle<Code>(
ager@chromium.org5c838252010-02-19 08:53:10 +00005895 ComputeConstructStub(Handle<JSFunction>(function)));
5896 shared->set_construct_stub(*stub);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005897 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005898
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00005899 Counters::constructed_objects.Increment();
5900 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005901
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005902 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005903}
5904
5905
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005906static Object* Runtime_LazyCompile(Arguments args) {
5907 HandleScope scope;
5908 ASSERT(args.length() == 1);
5909
5910 Handle<JSFunction> function = args.at<JSFunction>(0);
5911#ifdef DEBUG
5912 if (FLAG_trace_lazy) {
5913 PrintF("[lazy: ");
5914 function->shared()->name()->Print();
5915 PrintF("]\n");
5916 }
5917#endif
5918
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005919 // Compile the target function. Here we compile using CompileLazyInLoop in
5920 // order to get the optimized version. This helps code like delta-blue
5921 // that calls performance-critical routines through constructors. A
5922 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
5923 // direct call. Since the in-loop tracking takes place through CallICs
5924 // this means that things called through constructors are never known to
5925 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005926 ASSERT(!function->is_compiled());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005927 if (!CompileLazyInLoop(function, Handle<Object>::null(), KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928 return Failure::Exception();
5929 }
5930
5931 return function->code();
5932}
5933
5934
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005935static Object* Runtime_GetFunctionDelegate(Arguments args) {
5936 HandleScope scope;
5937 ASSERT(args.length() == 1);
5938 RUNTIME_ASSERT(!args[0]->IsJSFunction());
5939 return *Execution::GetFunctionDelegate(args.at<Object>(0));
5940}
5941
5942
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00005943static Object* Runtime_GetConstructorDelegate(Arguments args) {
5944 HandleScope scope;
5945 ASSERT(args.length() == 1);
5946 RUNTIME_ASSERT(!args[0]->IsJSFunction());
5947 return *Execution::GetConstructorDelegate(args.at<Object>(0));
5948}
5949
5950
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005951static Object* Runtime_NewContext(Arguments args) {
5952 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00005953 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954
kasper.lund7276f142008-07-30 08:49:36 +00005955 CONVERT_CHECKED(JSFunction, function, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956 int length = ScopeInfo<>::NumberOfContextSlots(function->code());
5957 Object* result = Heap::AllocateFunctionContext(length, function);
5958 if (result->IsFailure()) return result;
5959
5960 Top::set_context(Context::cast(result));
5961
kasper.lund7276f142008-07-30 08:49:36 +00005962 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005963}
5964
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005965static Object* PushContextHelper(Object* object, bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005966 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005967 Object* js_object = object;
5968 if (!js_object->IsJSObject()) {
5969 js_object = js_object->ToObject();
5970 if (js_object->IsFailure()) {
5971 if (!Failure::cast(js_object)->IsInternalError()) return js_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005972 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005973 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974 Handle<Object> result =
5975 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
5976 return Top::Throw(*result);
5977 }
5978 }
5979
5980 Object* result =
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005981 Heap::AllocateWithContext(Top::context(),
5982 JSObject::cast(js_object),
5983 is_catch_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005984 if (result->IsFailure()) return result;
5985
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005986 Context* context = Context::cast(result);
5987 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988
kasper.lund7276f142008-07-30 08:49:36 +00005989 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990}
5991
5992
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005993static Object* Runtime_PushContext(Arguments args) {
5994 NoHandleAllocation ha;
5995 ASSERT(args.length() == 1);
5996 return PushContextHelper(args[0], false);
5997}
5998
5999
6000static Object* Runtime_PushCatchContext(Arguments args) {
6001 NoHandleAllocation ha;
6002 ASSERT(args.length() == 1);
6003 return PushContextHelper(args[0], true);
6004}
6005
6006
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007static Object* Runtime_LookupContext(Arguments args) {
6008 HandleScope scope;
6009 ASSERT(args.length() == 2);
6010
6011 CONVERT_ARG_CHECKED(Context, context, 0);
6012 CONVERT_ARG_CHECKED(String, name, 1);
6013
6014 int index;
6015 PropertyAttributes attributes;
6016 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006017 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006018 context->Lookup(name, flags, &index, &attributes);
6019
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006020 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006021 ASSERT(holder->IsJSObject());
6022 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023 }
6024
6025 // No intermediate context found. Use global object by default.
6026 return Top::context()->global();
6027}
6028
6029
ager@chromium.orga1645e22009-09-09 19:27:10 +00006030// A mechanism to return a pair of Object pointers in registers (if possible).
6031// How this is achieved is calling convention-dependent.
6032// All currently supported x86 compiles uses calling conventions that are cdecl
6033// variants where a 64-bit value is returned in two 32-bit registers
6034// (edx:eax on ia32, r1:r0 on ARM).
6035// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
6036// In Win64 calling convention, a struct of two pointers is returned in memory,
6037// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006038#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006039struct ObjectPair {
6040 Object* x;
6041 Object* y;
6042};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006043
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006044static inline ObjectPair MakePair(Object* x, Object* y) {
6045 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006046 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
6047 // In Win64 they are assigned to a hidden first argument.
6048 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006049}
6050#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006051typedef uint64_t ObjectPair;
6052static inline ObjectPair MakePair(Object* x, Object* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006054 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006055}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006056#endif
6057
6058
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006059static inline Object* Unhole(Object* x, PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
6061 USE(attributes);
6062 return x->IsTheHole() ? Heap::undefined_value() : x;
6063}
6064
6065
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006066static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
6067 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006068 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006069 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006070 JSFunction* context_extension_function =
6071 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006072 // If the holder isn't a context extension object, we just return it
6073 // as the receiver. This allows arguments objects to be used as
6074 // receivers, but only if they are put in the context scope chain
6075 // explicitly via a with-statement.
6076 Object* constructor = holder->map()->constructor();
6077 if (constructor != context_extension_function) return holder;
6078 // Fall back to using the global object as the receiver if the
6079 // property turns out to be a local variable allocated in a context
6080 // extension object - introduced via eval.
6081 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006082}
6083
6084
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006085static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006086 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006087 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006088
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006089 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00006090 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006091 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006092 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006093 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006094
6095 int index;
6096 PropertyAttributes attributes;
6097 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006098 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006099 context->Lookup(name, flags, &index, &attributes);
6100
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006101 // If the index is non-negative, the slot has been found in a local
6102 // variable or a parameter. Read it from the context object or the
6103 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006104 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006105 // If the "property" we were looking for is a local variable or an
6106 // argument in a context, the receiver is the global object; see
6107 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
6108 JSObject* receiver = Top::context()->global()->global_receiver();
6109 Object* value = (holder->IsContext())
6110 ? Context::cast(*holder)->get(index)
6111 : JSObject::cast(*holder)->GetElement(index);
6112 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006113 }
6114
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006115 // If the holder is found, we read the property from it.
6116 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006117 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006118 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006119 JSObject* receiver;
6120 if (object->IsGlobalObject()) {
6121 receiver = GlobalObject::cast(object)->global_receiver();
6122 } else if (context->is_exception_holder(*holder)) {
6123 receiver = Top::context()->global()->global_receiver();
6124 } else {
6125 receiver = ComputeReceiverForNonGlobal(object);
6126 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006127 // No need to unhole the value here. This is taken care of by the
6128 // GetProperty function.
6129 Object* value = object->GetProperty(*name);
6130 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006131 }
6132
6133 if (throw_error) {
6134 // The property doesn't exist - throw exception.
6135 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006136 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006137 return MakePair(Top::Throw(*reference_error), NULL);
6138 } else {
6139 // The property doesn't exist - return undefined
6140 return MakePair(Heap::undefined_value(), Heap::undefined_value());
6141 }
6142}
6143
6144
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006145static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006146 return LoadContextSlotHelper(args, true);
6147}
6148
6149
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006150static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006151 return LoadContextSlotHelper(args, false);
6152}
6153
6154
6155static Object* Runtime_StoreContextSlot(Arguments args) {
6156 HandleScope scope;
6157 ASSERT(args.length() == 3);
6158
6159 Handle<Object> value(args[0]);
6160 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006161 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006162
6163 int index;
6164 PropertyAttributes attributes;
6165 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006166 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006167 context->Lookup(name, flags, &index, &attributes);
6168
6169 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006170 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006171 // Ignore if read_only variable.
6172 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006173 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006174 }
6175 } else {
6176 ASSERT((attributes & READ_ONLY) == 0);
6177 Object* result =
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006178 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006179 USE(result);
6180 ASSERT(!result->IsFailure());
6181 }
6182 return *value;
6183 }
6184
6185 // Slow case: The property is not in a FixedArray context.
6186 // It is either in an JSObject extension context or it was not found.
6187 Handle<JSObject> context_ext;
6188
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006189 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006190 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006191 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006192 } else {
6193 // The property was not found. It needs to be stored in the global context.
6194 ASSERT(attributes == ABSENT);
6195 attributes = NONE;
6196 context_ext = Handle<JSObject>(Top::context()->global());
6197 }
6198
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006199 // Set the property, but ignore if read_only variable on the context
6200 // extension object itself.
6201 if ((attributes & READ_ONLY) == 0 ||
6202 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
6204 if (set.is_null()) {
6205 // Failure::Exception is converted to a null handle in the
6206 // handle-based methods such as SetProperty. We therefore need
6207 // to convert null handles back to exceptions.
6208 ASSERT(Top::has_pending_exception());
6209 return Failure::Exception();
6210 }
6211 }
6212 return *value;
6213}
6214
6215
6216static Object* Runtime_Throw(Arguments args) {
6217 HandleScope scope;
6218 ASSERT(args.length() == 1);
6219
6220 return Top::Throw(args[0]);
6221}
6222
6223
6224static Object* Runtime_ReThrow(Arguments args) {
6225 HandleScope scope;
6226 ASSERT(args.length() == 1);
6227
6228 return Top::ReThrow(args[0]);
6229}
6230
6231
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006232static Object* Runtime_PromoteScheduledException(Arguments args) {
6233 ASSERT_EQ(0, args.length());
6234 return Top::PromoteScheduledException();
6235}
6236
6237
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006238static Object* Runtime_ThrowReferenceError(Arguments args) {
6239 HandleScope scope;
6240 ASSERT(args.length() == 1);
6241
6242 Handle<Object> name(args[0]);
6243 Handle<Object> reference_error =
6244 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
6245 return Top::Throw(*reference_error);
6246}
6247
6248
6249static Object* Runtime_StackOverflow(Arguments args) {
6250 NoHandleAllocation na;
6251 return Top::StackOverflow();
6252}
6253
6254
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006255static Object* Runtime_StackGuard(Arguments args) {
6256 ASSERT(args.length() == 1);
6257
6258 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00006259 if (StackGuard::IsStackOverflow()) {
6260 return Runtime_StackOverflow(args);
6261 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006263 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006264}
6265
6266
6267// NOTE: These PrintXXX functions are defined for all builds (not just
6268// DEBUG builds) because we may want to be able to trace function
6269// calls in all modes.
6270static void PrintString(String* str) {
6271 // not uncommon to have empty strings
6272 if (str->length() > 0) {
6273 SmartPointer<char> s =
6274 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
6275 PrintF("%s", *s);
6276 }
6277}
6278
6279
6280static void PrintObject(Object* obj) {
6281 if (obj->IsSmi()) {
6282 PrintF("%d", Smi::cast(obj)->value());
6283 } else if (obj->IsString() || obj->IsSymbol()) {
6284 PrintString(String::cast(obj));
6285 } else if (obj->IsNumber()) {
6286 PrintF("%g", obj->Number());
6287 } else if (obj->IsFailure()) {
6288 PrintF("<failure>");
6289 } else if (obj->IsUndefined()) {
6290 PrintF("<undefined>");
6291 } else if (obj->IsNull()) {
6292 PrintF("<null>");
6293 } else if (obj->IsTrue()) {
6294 PrintF("<true>");
6295 } else if (obj->IsFalse()) {
6296 PrintF("<false>");
6297 } else {
6298 PrintF("%p", obj);
6299 }
6300}
6301
6302
6303static int StackSize() {
6304 int n = 0;
6305 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
6306 return n;
6307}
6308
6309
6310static void PrintTransition(Object* result) {
6311 // indentation
6312 { const int nmax = 80;
6313 int n = StackSize();
6314 if (n <= nmax)
6315 PrintF("%4d:%*s", n, n, "");
6316 else
6317 PrintF("%4d:%*s", n, nmax, "...");
6318 }
6319
6320 if (result == NULL) {
6321 // constructor calls
6322 JavaScriptFrameIterator it;
6323 JavaScriptFrame* frame = it.frame();
6324 if (frame->IsConstructor()) PrintF("new ");
6325 // function name
6326 Object* fun = frame->function();
6327 if (fun->IsJSFunction()) {
6328 PrintObject(JSFunction::cast(fun)->shared()->name());
6329 } else {
6330 PrintObject(fun);
6331 }
6332 // function arguments
6333 // (we are intentionally only printing the actually
6334 // supplied parameters, not all parameters required)
6335 PrintF("(this=");
6336 PrintObject(frame->receiver());
6337 const int length = frame->GetProvidedParametersCount();
6338 for (int i = 0; i < length; i++) {
6339 PrintF(", ");
6340 PrintObject(frame->GetParameter(i));
6341 }
6342 PrintF(") {\n");
6343
6344 } else {
6345 // function result
6346 PrintF("} -> ");
6347 PrintObject(result);
6348 PrintF("\n");
6349 }
6350}
6351
6352
6353static Object* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006354 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006355 NoHandleAllocation ha;
6356 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006357 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006358}
6359
6360
6361static Object* Runtime_TraceExit(Arguments args) {
6362 NoHandleAllocation ha;
6363 PrintTransition(args[0]);
6364 return args[0]; // return TOS
6365}
6366
6367
6368static Object* Runtime_DebugPrint(Arguments args) {
6369 NoHandleAllocation ha;
6370 ASSERT(args.length() == 1);
6371
6372#ifdef DEBUG
6373 if (args[0]->IsString()) {
6374 // If we have a string, assume it's a code "marker"
6375 // and print some interesting cpu debugging info.
6376 JavaScriptFrameIterator it;
6377 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00006378 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
6379 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006380 } else {
6381 PrintF("DebugPrint: ");
6382 }
6383 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006384 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006385 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006386 HeapObject::cast(args[0])->map()->Print();
6387 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006388#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006389 // ShortPrint is available in release mode. Print is not.
6390 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006391#endif
6392 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00006393 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006394
6395 return args[0]; // return TOS
6396}
6397
6398
6399static Object* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006400 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006401 NoHandleAllocation ha;
6402 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006403 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006404}
6405
6406
mads.s.ager31e71382008-08-13 09:32:07 +00006407static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006408 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00006409 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006410
6411 // According to ECMA-262, section 15.9.1, page 117, the precision of
6412 // the number in a Date object representing a particular instant in
6413 // time is milliseconds. Therefore, we floor the result of getting
6414 // the OS time.
6415 double millis = floor(OS::TimeCurrentMillis());
6416 return Heap::NumberFromDouble(millis);
6417}
6418
6419
6420static Object* Runtime_DateParseString(Arguments args) {
6421 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006422 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006423
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006424 CONVERT_ARG_CHECKED(String, str, 0);
6425 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006426
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006427 CONVERT_ARG_CHECKED(JSArray, output, 1);
6428 RUNTIME_ASSERT(output->HasFastElements());
6429
6430 AssertNoAllocation no_allocation;
6431
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006432 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006433 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
6434 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00006435 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006436 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006437 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00006438 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006439 result = DateParser::Parse(str->ToUC16Vector(), output_array);
6440 }
6441
6442 if (result) {
6443 return *output;
6444 } else {
6445 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006446 }
6447}
6448
6449
6450static Object* Runtime_DateLocalTimezone(Arguments args) {
6451 NoHandleAllocation ha;
6452 ASSERT(args.length() == 1);
6453
6454 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00006455 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006456 return Heap::AllocateStringFromUtf8(CStrVector(zone));
6457}
6458
6459
6460static Object* Runtime_DateLocalTimeOffset(Arguments args) {
6461 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00006462 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006463
6464 return Heap::NumberFromDouble(OS::LocalTimeOffset());
6465}
6466
6467
6468static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
6469 NoHandleAllocation ha;
6470 ASSERT(args.length() == 1);
6471
6472 CONVERT_DOUBLE_CHECKED(x, args[0]);
6473 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
6474}
6475
6476
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006477static Object* Runtime_NumberIsFinite(Arguments args) {
6478 NoHandleAllocation ha;
6479 ASSERT(args.length() == 1);
6480
6481 CONVERT_DOUBLE_CHECKED(value, args[0]);
6482 Object* result;
6483 if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
6484 result = Heap::false_value();
6485 } else {
6486 result = Heap::true_value();
6487 }
6488 return result;
6489}
6490
6491
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006492static Object* Runtime_GlobalReceiver(Arguments args) {
6493 ASSERT(args.length() == 1);
6494 Object* global = args[0];
6495 if (!global->IsJSGlobalObject()) return Heap::null_value();
6496 return JSGlobalObject::cast(global)->global_receiver();
6497}
6498
6499
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006500static Object* Runtime_CompileString(Arguments args) {
6501 HandleScope scope;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006502 ASSERT_EQ(2, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006503 CONVERT_ARG_CHECKED(String, source, 0);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006504 CONVERT_ARG_CHECKED(Oddball, is_json, 1)
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006505
ager@chromium.org381abbb2009-02-25 13:23:22 +00006506 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006507 Handle<Context> context(Top::context()->global_context());
ager@chromium.orgadd848f2009-08-13 12:44:13 +00006508 Compiler::ValidationState validate = (is_json->IsTrue())
6509 ? Compiler::VALIDATE_JSON : Compiler::DONT_VALIDATE_JSON;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006510 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
6511 context,
6512 true,
6513 validate);
6514 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006516 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006517 return *fun;
6518}
6519
6520
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006521static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
6522 ASSERT(args.length() == 3);
6523 if (!args[0]->IsJSFunction()) {
6524 return MakePair(Top::ThrowIllegalOperation(), NULL);
6525 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006526
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006527 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006528 Handle<JSFunction> callee = args.at<JSFunction>(0);
6529 Handle<Object> receiver; // Will be overwritten.
6530
6531 // Compute the calling context.
6532 Handle<Context> context = Handle<Context>(Top::context());
6533#ifdef DEBUG
6534 // Make sure Top::context() agrees with the old code that traversed
6535 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006536 StackFrameLocator locator;
6537 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006538 ASSERT(Context::cast(frame->context()) == *context);
6539#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006540
6541 // Find where the 'eval' symbol is bound. It is unaliased only if
6542 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006543 int index = -1;
6544 PropertyAttributes attributes = ABSENT;
6545 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006546 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
6547 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00006548 // Stop search when eval is found or when the global context is
6549 // reached.
6550 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006551 if (context->is_function_context()) {
6552 context = Handle<Context>(Context::cast(context->closure()->context()));
6553 } else {
6554 context = Handle<Context>(context->previous());
6555 }
6556 }
6557
iposva@chromium.org245aa852009-02-10 00:49:54 +00006558 // If eval could not be resolved, it has been deleted and we need to
6559 // throw a reference error.
6560 if (attributes == ABSENT) {
6561 Handle<Object> name = Factory::eval_symbol();
6562 Handle<Object> reference_error =
6563 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006564 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00006565 }
6566
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006567 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006568 // 'eval' is not bound in the global context. Just call the function
6569 // with the given arguments. This is not necessarily the global eval.
6570 if (receiver->IsContext()) {
6571 context = Handle<Context>::cast(receiver);
6572 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006573 } else if (receiver->IsJSContextExtensionObject()) {
6574 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006575 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006576 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006577 }
6578
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006579 // 'eval' is bound in the global context, but it may have been overwritten.
6580 // Compare it to the builtin 'GlobalEval' function to make sure.
6581 if (*callee != Top::global_context()->global_eval_fun() ||
6582 !args[1]->IsString()) {
6583 return MakePair(*callee, Top::context()->global()->global_receiver());
6584 }
6585
6586 // Deal with a normal eval call with a string argument. Compile it
6587 // and return the compiled function bound in the local context.
6588 Handle<String> source = args.at<String>(1);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006589 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006590 source,
6591 Handle<Context>(Top::context()),
6592 Top::context()->IsGlobalContext(),
6593 Compiler::DONT_VALIDATE_JSON);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006594 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
6595 callee = Factory::NewFunctionFromSharedFunctionInfo(
6596 shared,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006597 Handle<Context>(Top::context()),
6598 NOT_TENURED);
6599 return MakePair(*callee, args[2]);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006600}
6601
6602
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006603static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
6604 // This utility adjusts the property attributes for newly created Function
6605 // object ("new Function(...)") by changing the map.
6606 // All it does is changing the prototype property to enumerable
6607 // as specified in ECMA262, 15.3.5.2.
6608 HandleScope scope;
6609 ASSERT(args.length() == 1);
6610 CONVERT_ARG_CHECKED(JSFunction, func, 0);
6611 ASSERT(func->map()->instance_type() ==
6612 Top::function_instance_map()->instance_type());
6613 ASSERT(func->map()->instance_size() ==
6614 Top::function_instance_map()->instance_size());
6615 func->set_map(*Top::function_instance_map());
6616 return *func;
6617}
6618
6619
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006620// Push an array unto an array of arrays if it is not already in the
6621// array. Returns true if the element was pushed on the stack and
6622// false otherwise.
6623static Object* Runtime_PushIfAbsent(Arguments args) {
6624 ASSERT(args.length() == 2);
6625 CONVERT_CHECKED(JSArray, array, args[0]);
6626 CONVERT_CHECKED(JSArray, element, args[1]);
6627 RUNTIME_ASSERT(array->HasFastElements());
6628 int length = Smi::cast(array->length())->value();
6629 FixedArray* elements = FixedArray::cast(array->elements());
6630 for (int i = 0; i < length; i++) {
6631 if (elements->get(i) == element) return Heap::false_value();
6632 }
6633 Object* obj = array->SetFastElement(length, element);
6634 if (obj->IsFailure()) return obj;
6635 return Heap::true_value();
6636}
6637
6638
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006639/**
6640 * A simple visitor visits every element of Array's.
6641 * The backend storage can be a fixed array for fast elements case,
6642 * or a dictionary for sparse array. Since Dictionary is a subtype
6643 * of FixedArray, the class can be used by both fast and slow cases.
6644 * The second parameter of the constructor, fast_elements, specifies
6645 * whether the storage is a FixedArray or Dictionary.
6646 *
6647 * An index limit is used to deal with the situation that a result array
6648 * length overflows 32-bit non-negative integer.
6649 */
6650class ArrayConcatVisitor {
6651 public:
6652 ArrayConcatVisitor(Handle<FixedArray> storage,
6653 uint32_t index_limit,
6654 bool fast_elements) :
6655 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006656 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006657
6658 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006659 if (i >= index_limit_ - index_offset_) return;
6660 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006661
6662 if (fast_elements_) {
6663 ASSERT(index < static_cast<uint32_t>(storage_->length()));
6664 storage_->set(index, *elm);
6665
6666 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00006667 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
6668 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006669 Factory::DictionaryAtNumberPut(dict, index, elm);
6670 if (!result.is_identical_to(dict))
6671 storage_ = result;
6672 }
6673 }
6674
6675 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006676 if (index_limit_ - index_offset_ < delta) {
6677 index_offset_ = index_limit_;
6678 } else {
6679 index_offset_ += delta;
6680 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006681 }
6682
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00006683 Handle<FixedArray> storage() { return storage_; }
6684
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006685 private:
6686 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006687 // Limit on the accepted indices. Elements with indices larger than the
6688 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006689 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006690 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006691 uint32_t index_offset_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006692 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006693};
6694
6695
ager@chromium.org3811b432009-10-28 14:53:37 +00006696template<class ExternalArrayClass, class ElementType>
6697static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
6698 bool elements_are_ints,
6699 bool elements_are_guaranteed_smis,
6700 uint32_t range,
6701 ArrayConcatVisitor* visitor) {
6702 Handle<ExternalArrayClass> array(
6703 ExternalArrayClass::cast(receiver->elements()));
6704 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
6705
6706 if (visitor != NULL) {
6707 if (elements_are_ints) {
6708 if (elements_are_guaranteed_smis) {
6709 for (uint32_t j = 0; j < len; j++) {
6710 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
6711 visitor->visit(j, e);
6712 }
6713 } else {
6714 for (uint32_t j = 0; j < len; j++) {
6715 int64_t val = static_cast<int64_t>(array->get(j));
6716 if (Smi::IsValid(static_cast<intptr_t>(val))) {
6717 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
6718 visitor->visit(j, e);
6719 } else {
6720 Handle<Object> e(
6721 Heap::AllocateHeapNumber(static_cast<ElementType>(val)));
6722 visitor->visit(j, e);
6723 }
6724 }
6725 }
6726 } else {
6727 for (uint32_t j = 0; j < len; j++) {
6728 Handle<Object> e(Heap::AllocateHeapNumber(array->get(j)));
6729 visitor->visit(j, e);
6730 }
6731 }
6732 }
6733
6734 return len;
6735}
6736
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006737/**
6738 * A helper function that visits elements of a JSObject. Only elements
6739 * whose index between 0 and range (exclusive) are visited.
6740 *
6741 * If the third parameter, visitor, is not NULL, the visitor is called
6742 * with parameters, 'visitor_index_offset + element index' and the element.
6743 *
6744 * It returns the number of visisted elements.
6745 */
6746static uint32_t IterateElements(Handle<JSObject> receiver,
6747 uint32_t range,
6748 ArrayConcatVisitor* visitor) {
6749 uint32_t num_of_elements = 0;
6750
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006751 switch (receiver->GetElementsKind()) {
6752 case JSObject::FAST_ELEMENTS: {
6753 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
6754 uint32_t len = elements->length();
6755 if (range < len) {
6756 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006757 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006758
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006759 for (uint32_t j = 0; j < len; j++) {
6760 Handle<Object> e(elements->get(j));
6761 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006762 num_of_elements++;
6763 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006764 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006765 }
6766 }
6767 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006768 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006769 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006770 case JSObject::PIXEL_ELEMENTS: {
6771 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
6772 uint32_t len = pixels->length();
6773 if (range < len) {
6774 len = range;
6775 }
6776
6777 for (uint32_t j = 0; j < len; j++) {
6778 num_of_elements++;
6779 if (visitor != NULL) {
6780 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
6781 visitor->visit(j, e);
6782 }
6783 }
6784 break;
6785 }
ager@chromium.org3811b432009-10-28 14:53:37 +00006786 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
6787 num_of_elements =
6788 IterateExternalArrayElements<ExternalByteArray, int8_t>(
6789 receiver, true, true, range, visitor);
6790 break;
6791 }
6792 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
6793 num_of_elements =
6794 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
6795 receiver, true, true, range, visitor);
6796 break;
6797 }
6798 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
6799 num_of_elements =
6800 IterateExternalArrayElements<ExternalShortArray, int16_t>(
6801 receiver, true, true, range, visitor);
6802 break;
6803 }
6804 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
6805 num_of_elements =
6806 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
6807 receiver, true, true, range, visitor);
6808 break;
6809 }
6810 case JSObject::EXTERNAL_INT_ELEMENTS: {
6811 num_of_elements =
6812 IterateExternalArrayElements<ExternalIntArray, int32_t>(
6813 receiver, true, false, range, visitor);
6814 break;
6815 }
6816 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
6817 num_of_elements =
6818 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
6819 receiver, true, false, range, visitor);
6820 break;
6821 }
6822 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
6823 num_of_elements =
6824 IterateExternalArrayElements<ExternalFloatArray, float>(
6825 receiver, false, false, range, visitor);
6826 break;
6827 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006828 case JSObject::DICTIONARY_ELEMENTS: {
6829 Handle<NumberDictionary> dict(receiver->element_dictionary());
6830 uint32_t capacity = dict->Capacity();
6831 for (uint32_t j = 0; j < capacity; j++) {
6832 Handle<Object> k(dict->KeyAt(j));
6833 if (dict->IsKey(*k)) {
6834 ASSERT(k->IsNumber());
6835 uint32_t index = static_cast<uint32_t>(k->Number());
6836 if (index < range) {
6837 num_of_elements++;
6838 if (visitor) {
6839 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
6840 }
6841 }
6842 }
6843 }
6844 break;
6845 }
6846 default:
6847 UNREACHABLE();
6848 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006849 }
6850
6851 return num_of_elements;
6852}
6853
6854
6855/**
6856 * A helper function that visits elements of an Array object, and elements
6857 * on its prototypes.
6858 *
6859 * Elements on prototypes are visited first, and only elements whose indices
6860 * less than Array length are visited.
6861 *
6862 * If a ArrayConcatVisitor object is given, the visitor is called with
6863 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006864 *
6865 * The returned number of elements is an upper bound on the actual number
6866 * of elements added. If the same element occurs in more than one object
6867 * in the array's prototype chain, it will be counted more than once, but
6868 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006869 */
6870static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
6871 ArrayConcatVisitor* visitor) {
6872 uint32_t range = static_cast<uint32_t>(array->length()->Number());
6873 Handle<Object> obj = array;
6874
6875 static const int kEstimatedPrototypes = 3;
6876 List< Handle<JSObject> > objects(kEstimatedPrototypes);
6877
6878 // Visit prototype first. If an element on the prototype is shadowed by
6879 // the inheritor using the same index, the ArrayConcatVisitor visits
6880 // the prototype element before the shadowing element.
6881 // The visitor can simply overwrite the old value by new value using
6882 // the same index. This follows Array::concat semantics.
6883 while (!obj->IsNull()) {
6884 objects.Add(Handle<JSObject>::cast(obj));
6885 obj = Handle<Object>(obj->GetPrototype());
6886 }
6887
6888 uint32_t nof_elements = 0;
6889 for (int i = objects.length() - 1; i >= 0; i--) {
6890 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006891 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006892 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006893
6894 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
6895 nof_elements = JSObject::kMaxElementCount;
6896 } else {
6897 nof_elements += encountered_elements;
6898 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006899 }
6900
6901 return nof_elements;
6902}
6903
6904
6905/**
6906 * A helper function of Runtime_ArrayConcat.
6907 *
6908 * The first argument is an Array of arrays and objects. It is the
6909 * same as the arguments array of Array::concat JS function.
6910 *
6911 * If an argument is an Array object, the function visits array
6912 * elements. If an argument is not an Array object, the function
6913 * visits the object as if it is an one-element array.
6914 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006915 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006916 * non-negative number is used as new length. For example, if one
6917 * array length is 2^32 - 1, second array length is 1, the
6918 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006919 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
6920 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006921 */
6922static uint32_t IterateArguments(Handle<JSArray> arguments,
6923 ArrayConcatVisitor* visitor) {
6924 uint32_t visited_elements = 0;
6925 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
6926
6927 for (uint32_t i = 0; i < num_of_args; i++) {
6928 Handle<Object> obj(arguments->GetElement(i));
6929 if (obj->IsJSArray()) {
6930 Handle<JSArray> array = Handle<JSArray>::cast(obj);
6931 uint32_t len = static_cast<uint32_t>(array->length()->Number());
6932 uint32_t nof_elements =
6933 IterateArrayAndPrototypeElements(array, visitor);
6934 // Total elements of array and its prototype chain can be more than
6935 // the array length, but ArrayConcat can only concatenate at most
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006936 // the array length number of elements. We use the length as an estimate
6937 // for the actual number of elements added.
6938 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
6939 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
6940 visited_elements = JSArray::kMaxElementCount;
6941 } else {
6942 visited_elements += added_elements;
6943 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006944 if (visitor) visitor->increase_index_offset(len);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006945 } else {
6946 if (visitor) {
6947 visitor->visit(0, obj);
6948 visitor->increase_index_offset(1);
6949 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006950 if (visited_elements < JSArray::kMaxElementCount) {
6951 visited_elements++;
6952 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006953 }
6954 }
6955 return visited_elements;
6956}
6957
6958
6959/**
6960 * Array::concat implementation.
6961 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006962 * TODO(lrn): Fix non-compliance for very large concatenations and update to
6963 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006964 */
6965static Object* Runtime_ArrayConcat(Arguments args) {
6966 ASSERT(args.length() == 1);
6967 HandleScope handle_scope;
6968
6969 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
6970 Handle<JSArray> arguments(arg_arrays);
6971
6972 // Pass 1: estimate the number of elements of the result
6973 // (it could be more than real numbers if prototype has elements).
6974 uint32_t result_length = 0;
6975 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
6976
6977 { AssertNoAllocation nogc;
6978 for (uint32_t i = 0; i < num_of_args; i++) {
6979 Object* obj = arguments->GetElement(i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006980 uint32_t length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006981 if (obj->IsJSArray()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006982 length_estimate =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006983 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
6984 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006985 length_estimate = 1;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006986 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006987 if (JSObject::kMaxElementCount - result_length < length_estimate) {
6988 result_length = JSObject::kMaxElementCount;
6989 break;
6990 }
6991 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006992 }
6993 }
6994
6995 // Allocate an empty array, will set length and content later.
6996 Handle<JSArray> result = Factory::NewJSArray(0);
6997
6998 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
6999 // If estimated number of elements is more than half of length, a
7000 // fixed array (fast case) is more time and space-efficient than a
7001 // dictionary.
7002 bool fast_case = (estimate_nof_elements * 2) >= result_length;
7003
7004 Handle<FixedArray> storage;
7005 if (fast_case) {
7006 // The backing storage array must have non-existing elements to
7007 // preserve holes across concat operations.
7008 storage = Factory::NewFixedArrayWithHoles(result_length);
7009
7010 } else {
7011 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
7012 uint32_t at_least_space_for = estimate_nof_elements +
7013 (estimate_nof_elements >> 2);
7014 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007015 Factory::NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007016 }
7017
7018 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
7019
7020 ArrayConcatVisitor visitor(storage, result_length, fast_case);
7021
7022 IterateArguments(arguments, &visitor);
7023
7024 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007025 // Please note the storage might have changed in the visitor.
7026 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007027
7028 return *result;
7029}
7030
7031
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007032// This will not allocate (flatten the string), but it may run
7033// very slowly for very deeply nested ConsStrings. For debugging use only.
7034static Object* Runtime_GlobalPrint(Arguments args) {
7035 NoHandleAllocation ha;
7036 ASSERT(args.length() == 1);
7037
7038 CONVERT_CHECKED(String, string, args[0]);
7039 StringInputBuffer buffer(string);
7040 while (buffer.has_more()) {
7041 uint16_t character = buffer.GetNext();
7042 PrintF("%c", character);
7043 }
7044 return string;
7045}
7046
ager@chromium.org5ec48922009-05-05 07:25:34 +00007047// Moves all own elements of an object, that are below a limit, to positions
7048// starting at zero. All undefined values are placed after non-undefined values,
7049// and are followed by non-existing element. Does not change the length
7050// property.
7051// Returns the number of non-undefined elements collected.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007052static Object* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007053 ASSERT(args.length() == 2);
7054 CONVERT_CHECKED(JSObject, object, args[0]);
7055 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
7056 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007057}
7058
7059
7060// Move contents of argument 0 (an array) to argument 1 (an array)
7061static Object* Runtime_MoveArrayContents(Arguments args) {
7062 ASSERT(args.length() == 2);
7063 CONVERT_CHECKED(JSArray, from, args[0]);
7064 CONVERT_CHECKED(JSArray, to, args[1]);
7065 to->SetContent(FixedArray::cast(from->elements()));
7066 to->set_length(from->length());
7067 from->SetContent(Heap::empty_fixed_array());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007068 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007069 return to;
7070}
7071
7072
7073// How many elements does this array have?
7074static Object* Runtime_EstimateNumberOfElements(Arguments args) {
7075 ASSERT(args.length() == 1);
7076 CONVERT_CHECKED(JSArray, array, args[0]);
7077 HeapObject* elements = array->elements();
7078 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007079 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007080 } else {
7081 return array->length();
7082 }
7083}
7084
7085
7086// Returns an array that tells you where in the [0, length) interval an array
7087// might have elements. Can either return keys or intervals. Keys can have
7088// gaps in (undefined). Intervals can also span over some undefined keys.
7089static Object* Runtime_GetArrayKeys(Arguments args) {
7090 ASSERT(args.length() == 2);
7091 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007092 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007094 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007095 // Create an array and get all the keys into it, then remove all the
7096 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007097 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098 int keys_length = keys->length();
7099 for (int i = 0; i < keys_length; i++) {
7100 Object* key = keys->get(i);
7101 uint32_t index;
7102 if (!Array::IndexFromObject(key, &index) || index >= length) {
7103 // Zap invalid keys.
7104 keys->set_undefined(i);
7105 }
7106 }
7107 return *Factory::NewJSArrayWithElements(keys);
7108 } else {
7109 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
7110 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007111 single_interval->set(0, Smi::FromInt(-1));
ager@chromium.org5ec48922009-05-05 07:25:34 +00007112 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
7113 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007114 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00007115 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007116 single_interval->set(1, *length_object);
7117 return *Factory::NewJSArrayWithElements(single_interval);
7118 }
7119}
7120
7121
7122// DefineAccessor takes an optional final argument which is the
7123// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
7124// to the way accessors are implemented, it is set for both the getter
7125// and setter on the first call to DefineAccessor and ignored on
7126// subsequent calls.
7127static Object* Runtime_DefineAccessor(Arguments args) {
7128 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
7129 // Compute attributes.
7130 PropertyAttributes attributes = NONE;
7131 if (args.length() == 5) {
7132 CONVERT_CHECKED(Smi, attrs, args[4]);
7133 int value = attrs->value();
7134 // Only attribute bits should be set.
7135 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
7136 attributes = static_cast<PropertyAttributes>(value);
7137 }
7138
7139 CONVERT_CHECKED(JSObject, obj, args[0]);
7140 CONVERT_CHECKED(String, name, args[1]);
7141 CONVERT_CHECKED(Smi, flag, args[2]);
7142 CONVERT_CHECKED(JSFunction, fun, args[3]);
7143 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
7144}
7145
7146
7147static Object* Runtime_LookupAccessor(Arguments args) {
7148 ASSERT(args.length() == 3);
7149 CONVERT_CHECKED(JSObject, obj, args[0]);
7150 CONVERT_CHECKED(String, name, args[1]);
7151 CONVERT_CHECKED(Smi, flag, args[2]);
7152 return obj->LookupAccessor(name, flag->value() == 0);
7153}
7154
7155
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007156#ifdef ENABLE_DEBUGGER_SUPPORT
7157static Object* Runtime_DebugBreak(Arguments args) {
7158 ASSERT(args.length() == 0);
7159 return Execution::DebugBreakHelper();
7160}
7161
7162
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007163// Helper functions for wrapping and unwrapping stack frame ids.
7164static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007165 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007166 return Smi::FromInt(id >> 2);
7167}
7168
7169
7170static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
7171 return static_cast<StackFrame::Id>(wrapped->value() << 2);
7172}
7173
7174
7175// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00007176// args[0]: debug event listener function to set or null or undefined for
7177// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007178// args[1]: object supplied during callback
iposva@chromium.org245aa852009-02-10 00:49:54 +00007179static Object* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007180 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007181 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
7182 args[0]->IsUndefined() ||
7183 args[0]->IsNull());
7184 Handle<Object> callback = args.at<Object>(0);
7185 Handle<Object> data = args.at<Object>(1);
7186 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007187
7188 return Heap::undefined_value();
7189}
7190
7191
7192static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00007193 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007194 StackGuard::DebugBreak();
7195 return Heap::undefined_value();
7196}
7197
7198
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007199static Object* DebugLookupResultValue(Object* receiver, String* name,
7200 LookupResult* result,
ager@chromium.org32912102009-01-16 10:38:43 +00007201 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007202 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007203 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007204 case NORMAL:
7205 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007206 if (value->IsTheHole()) {
7207 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007208 }
7209 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007210 case FIELD:
7211 value =
7212 JSObject::cast(
7213 result->holder())->FastPropertyAt(result->GetFieldIndex());
7214 if (value->IsTheHole()) {
7215 return Heap::undefined_value();
7216 }
7217 return value;
7218 case CONSTANT_FUNCTION:
7219 return result->GetConstantFunction();
7220 case CALLBACKS: {
7221 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007222 if (structure->IsProxy() || structure->IsAccessorInfo()) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007223 value = receiver->GetPropertyWithCallback(
7224 receiver, structure, name, result->holder());
ager@chromium.org381abbb2009-02-25 13:23:22 +00007225 if (value->IsException()) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007226 value = Top::pending_exception();
7227 Top::clear_pending_exception();
7228 if (caught_exception != NULL) {
7229 *caught_exception = true;
7230 }
7231 }
7232 return value;
7233 } else {
7234 return Heap::undefined_value();
7235 }
7236 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007237 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007238 case MAP_TRANSITION:
7239 case CONSTANT_TRANSITION:
7240 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007241 return Heap::undefined_value();
7242 default:
7243 UNREACHABLE();
7244 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007245 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007246 return Heap::undefined_value();
7247}
7248
7249
ager@chromium.org32912102009-01-16 10:38:43 +00007250// Get debugger related details for an object property.
7251// args[0]: object holding property
7252// args[1]: name of the property
7253//
7254// The array returned contains the following information:
7255// 0: Property value
7256// 1: Property details
7257// 2: Property value is exception
7258// 3: Getter function if defined
7259// 4: Setter function if defined
7260// Items 2-4 are only filled if the property has either a getter or a setter
7261// defined through __defineGetter__ and/or __defineSetter__.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007262static Object* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007263 HandleScope scope;
7264
7265 ASSERT(args.length() == 2);
7266
7267 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7268 CONVERT_ARG_CHECKED(String, name, 1);
7269
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007270 // Make sure to set the current context to the context before the debugger was
7271 // entered (if the debugger is entered). The reason for switching context here
7272 // is that for some property lookups (accessors and interceptors) callbacks
7273 // into the embedding application can occour, and the embedding application
7274 // could have the assumption that its own global context is the current
7275 // context and not some internal debugger context.
7276 SaveContext save;
7277 if (Debug::InDebugger()) {
7278 Top::set_context(*Debug::debugger_entry()->GetContext());
7279 }
7280
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007281 // Skip the global proxy as it has no properties and always delegates to the
7282 // real global object.
7283 if (obj->IsJSGlobalProxy()) {
7284 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
7285 }
7286
7287
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007288 // Check if the name is trivially convertible to an index and get the element
7289 // if so.
7290 uint32_t index;
7291 if (name->AsArrayIndex(&index)) {
7292 Handle<FixedArray> details = Factory::NewFixedArray(2);
7293 details->set(0, Runtime::GetElementOrCharAt(obj, index));
7294 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
7295 return *Factory::NewJSArrayWithElements(details);
7296 }
7297
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007298 // Find the number of objects making up this.
7299 int length = LocalPrototypeChainLength(*obj);
7300
7301 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007302 Handle<JSObject> jsproto = obj;
7303 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007304 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007305 jsproto->LocalLookup(*name, &result);
7306 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007307 // LookupResult is not GC safe as it holds raw object pointers.
7308 // GC can happen later in this code so put the required fields into
7309 // local variables using handles when required for later use.
7310 PropertyType result_type = result.type();
7311 Handle<Object> result_callback_obj;
7312 if (result_type == CALLBACKS) {
7313 result_callback_obj = Handle<Object>(result.GetCallbackObject());
7314 }
7315 Smi* property_details = result.GetPropertyDetails().AsSmi();
7316 // DebugLookupResultValue can cause GC so details from LookupResult needs
7317 // to be copied to handles before this.
7318 bool caught_exception = false;
7319 Object* raw_value = DebugLookupResultValue(*obj, *name, &result,
7320 &caught_exception);
7321 if (raw_value->IsFailure()) return raw_value;
7322 Handle<Object> value(raw_value);
7323
7324 // If the callback object is a fixed array then it contains JavaScript
7325 // getter and/or setter.
7326 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
7327 result_callback_obj->IsFixedArray();
7328 Handle<FixedArray> details =
7329 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
7330 details->set(0, *value);
7331 details->set(1, property_details);
7332 if (hasJavaScriptAccessors) {
7333 details->set(2,
7334 caught_exception ? Heap::true_value()
7335 : Heap::false_value());
7336 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
7337 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
7338 }
7339
7340 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007341 }
7342 if (i < length - 1) {
7343 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
7344 }
7345 }
7346
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007347 return Heap::undefined_value();
7348}
7349
7350
7351static Object* Runtime_DebugGetProperty(Arguments args) {
7352 HandleScope scope;
7353
7354 ASSERT(args.length() == 2);
7355
7356 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7357 CONVERT_ARG_CHECKED(String, name, 1);
7358
7359 LookupResult result;
7360 obj->Lookup(*name, &result);
7361 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007362 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363 }
7364 return Heap::undefined_value();
7365}
7366
7367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007368// Return the property type calculated from the property details.
7369// args[0]: smi with property details.
7370static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
7371 ASSERT(args.length() == 1);
7372 CONVERT_CHECKED(Smi, details, args[0]);
7373 PropertyType type = PropertyDetails(details).type();
7374 return Smi::FromInt(static_cast<int>(type));
7375}
7376
7377
7378// Return the property attribute calculated from the property details.
7379// args[0]: smi with property details.
7380static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
7381 ASSERT(args.length() == 1);
7382 CONVERT_CHECKED(Smi, details, args[0]);
7383 PropertyAttributes attributes = PropertyDetails(details).attributes();
7384 return Smi::FromInt(static_cast<int>(attributes));
7385}
7386
7387
7388// Return the property insertion index calculated from the property details.
7389// args[0]: smi with property details.
7390static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
7391 ASSERT(args.length() == 1);
7392 CONVERT_CHECKED(Smi, details, args[0]);
7393 int index = PropertyDetails(details).index();
7394 return Smi::FromInt(index);
7395}
7396
7397
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007398// Return property value from named interceptor.
7399// args[0]: object
7400// args[1]: property name
7401static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
7402 HandleScope scope;
7403 ASSERT(args.length() == 2);
7404 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7405 RUNTIME_ASSERT(obj->HasNamedInterceptor());
7406 CONVERT_ARG_CHECKED(String, name, 1);
7407
7408 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007409 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410}
7411
7412
7413// Return element value from indexed interceptor.
7414// args[0]: object
7415// args[1]: index
7416static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
7417 HandleScope scope;
7418 ASSERT(args.length() == 2);
7419 CONVERT_ARG_CHECKED(JSObject, obj, 0);
7420 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
7421 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
7422
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007423 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007424}
7425
7426
7427static Object* Runtime_CheckExecutionState(Arguments args) {
7428 ASSERT(args.length() >= 1);
7429 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007430 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007431 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007432 return Top::Throw(Heap::illegal_execution_state_symbol());
7433 }
7434
7435 return Heap::true_value();
7436}
7437
7438
7439static Object* Runtime_GetFrameCount(Arguments args) {
7440 HandleScope scope;
7441 ASSERT(args.length() == 1);
7442
7443 // Check arguments.
7444 Object* result = Runtime_CheckExecutionState(args);
7445 if (result->IsFailure()) return result;
7446
7447 // Count all frames which are relevant to debugging stack trace.
7448 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007449 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00007450 if (id == StackFrame::NO_ID) {
7451 // If there is no JavaScript stack frame count is 0.
7452 return Smi::FromInt(0);
7453 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
7455 return Smi::FromInt(n);
7456}
7457
7458
7459static const int kFrameDetailsFrameIdIndex = 0;
7460static const int kFrameDetailsReceiverIndex = 1;
7461static const int kFrameDetailsFunctionIndex = 2;
7462static const int kFrameDetailsArgumentCountIndex = 3;
7463static const int kFrameDetailsLocalCountIndex = 4;
7464static const int kFrameDetailsSourcePositionIndex = 5;
7465static const int kFrameDetailsConstructCallIndex = 6;
7466static const int kFrameDetailsDebuggerFrameIndex = 7;
7467static const int kFrameDetailsFirstDynamicIndex = 8;
7468
7469// Return an array with frame details
7470// args[0]: number: break id
7471// args[1]: number: frame index
7472//
7473// The array returned contains the following information:
7474// 0: Frame id
7475// 1: Receiver
7476// 2: Function
7477// 3: Argument count
7478// 4: Local count
7479// 5: Source position
7480// 6: Constructor call
7481// 7: Debugger frame
7482// Arguments name, value
7483// Locals name, value
7484static Object* Runtime_GetFrameDetails(Arguments args) {
7485 HandleScope scope;
7486 ASSERT(args.length() == 2);
7487
7488 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007489 Object* check = Runtime_CheckExecutionState(args);
7490 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007491 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
7492
7493 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007494 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00007495 if (id == StackFrame::NO_ID) {
7496 // If there are no JavaScript stack frames return undefined.
7497 return Heap::undefined_value();
7498 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007499 int count = 0;
7500 JavaScriptFrameIterator it(id);
7501 for (; !it.done(); it.Advance()) {
7502 if (count == index) break;
7503 count++;
7504 }
7505 if (it.done()) return Heap::undefined_value();
7506
7507 // Traverse the saved contexts chain to find the active context for the
7508 // selected frame.
7509 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007510 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007511 save = save->prev();
7512 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007513 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007514
7515 // Get the frame id.
7516 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
7517
7518 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00007519 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007520
7521 // Check for constructor frame.
7522 bool constructor = it.frame()->IsConstructor();
7523
7524 // Get code and read scope info from it for local variable information.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00007525 Handle<Code> code(it.frame()->code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007526 ScopeInfo<> info(*code);
7527
7528 // Get the context.
7529 Handle<Context> context(Context::cast(it.frame()->context()));
7530
7531 // Get the locals names and values into a temporary array.
7532 //
7533 // TODO(1240907): Hide compiler-introduced stack variables
7534 // (e.g. .result)? For users of the debugger, they will probably be
7535 // confusing.
7536 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
7537 for (int i = 0; i < info.NumberOfLocals(); i++) {
7538 // Name of the local.
7539 locals->set(i * 2, *info.LocalName(i));
7540
7541 // Fetch the value of the local - either from the stack or from a
7542 // heap-allocated context.
7543 if (i < info.number_of_stack_slots()) {
7544 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
7545 } else {
7546 Handle<String> name = info.LocalName(i);
7547 // Traverse the context chain to the function context as all local
7548 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007549 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007550 context = Handle<Context>(context->previous());
7551 }
7552 ASSERT(context->is_function_context());
7553 locals->set(i * 2 + 1,
7554 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name,
7555 NULL)));
7556 }
7557 }
7558
7559 // Now advance to the arguments adapter frame (if any). If contains all
7560 // the provided parameters and
7561
7562 // Now advance to the arguments adapter frame (if any). It contains all
7563 // the provided parameters whereas the function frame always have the number
7564 // of arguments matching the functions parameters. The rest of the
7565 // information (except for what is collected above) is the same.
7566 it.AdvanceToArgumentsFrame();
7567
7568 // Find the number of arguments to fill. At least fill the number of
7569 // parameters for the function and fill more if more parameters are provided.
7570 int argument_count = info.number_of_parameters();
7571 if (argument_count < it.frame()->GetProvidedParametersCount()) {
7572 argument_count = it.frame()->GetProvidedParametersCount();
7573 }
7574
7575 // Calculate the size of the result.
7576 int details_size = kFrameDetailsFirstDynamicIndex +
7577 2 * (argument_count + info.NumberOfLocals());
7578 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
7579
7580 // Add the frame id.
7581 details->set(kFrameDetailsFrameIdIndex, *frame_id);
7582
7583 // Add the function (same as in function frame).
7584 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
7585
7586 // Add the arguments count.
7587 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
7588
7589 // Add the locals count
7590 details->set(kFrameDetailsLocalCountIndex,
7591 Smi::FromInt(info.NumberOfLocals()));
7592
7593 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00007594 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007595 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
7596 } else {
7597 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
7598 }
7599
7600 // Add the constructor information.
7601 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
7602
7603 // Add information on whether this frame is invoked in the debugger context.
7604 details->set(kFrameDetailsDebuggerFrameIndex,
7605 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
7606
7607 // Fill the dynamic part.
7608 int details_index = kFrameDetailsFirstDynamicIndex;
7609
7610 // Add arguments name and value.
7611 for (int i = 0; i < argument_count; i++) {
7612 // Name of the argument.
7613 if (i < info.number_of_parameters()) {
7614 details->set(details_index++, *info.parameter_name(i));
7615 } else {
7616 details->set(details_index++, Heap::undefined_value());
7617 }
7618
7619 // Parameter value.
7620 if (i < it.frame()->GetProvidedParametersCount()) {
7621 details->set(details_index++, it.frame()->GetParameter(i));
7622 } else {
7623 details->set(details_index++, Heap::undefined_value());
7624 }
7625 }
7626
7627 // Add locals name and value from the temporary copy from the function frame.
7628 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
7629 details->set(details_index++, locals->get(i));
7630 }
7631
7632 // Add the receiver (same as in function frame).
7633 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
7634 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
7635 Handle<Object> receiver(it.frame()->receiver());
7636 if (!receiver->IsJSObject()) {
7637 // If the receiver is NOT a JSObject we have hit an optimization
7638 // where a value object is not converted into a wrapped JS objects.
7639 // To hide this optimization from the debugger, we wrap the receiver
7640 // by creating correct wrapper object based on the calling frame's
7641 // global context.
7642 it.Advance();
7643 Handle<Context> calling_frames_global_context(
7644 Context::cast(Context::cast(it.frame()->context())->global_context()));
7645 receiver = Factory::ToObject(receiver, calling_frames_global_context);
7646 }
7647 details->set(kFrameDetailsReceiverIndex, *receiver);
7648
7649 ASSERT_EQ(details_size, details_index);
7650 return *Factory::NewJSArrayWithElements(details);
7651}
7652
7653
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007654// Copy all the context locals into an object used to materialize a scope.
7655static void CopyContextLocalsToScopeObject(Handle<Code> code,
7656 ScopeInfo<>& scope_info,
7657 Handle<Context> context,
7658 Handle<JSObject> scope_object) {
7659 // Fill all context locals to the context extension.
7660 for (int i = Context::MIN_CONTEXT_SLOTS;
7661 i < scope_info.number_of_context_slots();
7662 i++) {
7663 int context_index =
7664 ScopeInfo<>::ContextSlotIndex(*code,
7665 *scope_info.context_slot_name(i),
7666 NULL);
7667
7668 // Don't include the arguments shadow (.arguments) context variable.
7669 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
7670 SetProperty(scope_object,
7671 scope_info.context_slot_name(i),
7672 Handle<Object>(context->get(context_index)), NONE);
7673 }
7674 }
7675}
7676
7677
7678// Create a plain JSObject which materializes the local scope for the specified
7679// frame.
7680static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
7681 Handle<JSFunction> function(JSFunction::cast(frame->function()));
7682 Handle<Code> code(function->code());
7683 ScopeInfo<> scope_info(*code);
7684
7685 // Allocate and initialize a JSObject with all the arguments, stack locals
7686 // heap locals and extension properties of the debugged function.
7687 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
7688
7689 // First fill all parameters.
7690 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
7691 SetProperty(local_scope,
7692 scope_info.parameter_name(i),
7693 Handle<Object>(frame->GetParameter(i)), NONE);
7694 }
7695
7696 // Second fill all stack locals.
7697 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
7698 SetProperty(local_scope,
7699 scope_info.stack_slot_name(i),
7700 Handle<Object>(frame->GetExpression(i)), NONE);
7701 }
7702
7703 // Third fill all context locals.
7704 Handle<Context> frame_context(Context::cast(frame->context()));
7705 Handle<Context> function_context(frame_context->fcontext());
7706 CopyContextLocalsToScopeObject(code, scope_info,
7707 function_context, local_scope);
7708
7709 // Finally copy any properties from the function context extension. This will
7710 // be variables introduced by eval.
7711 if (function_context->closure() == *function) {
7712 if (function_context->has_extension() &&
7713 !function_context->IsGlobalContext()) {
7714 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007715 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007716 for (int i = 0; i < keys->length(); i++) {
7717 // Names of variables introduced by eval are strings.
7718 ASSERT(keys->get(i)->IsString());
7719 Handle<String> key(String::cast(keys->get(i)));
7720 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
7721 }
7722 }
7723 }
7724 return local_scope;
7725}
7726
7727
7728// Create a plain JSObject which materializes the closure content for the
7729// context.
7730static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
7731 ASSERT(context->is_function_context());
7732
7733 Handle<Code> code(context->closure()->code());
7734 ScopeInfo<> scope_info(*code);
7735
7736 // Allocate and initialize a JSObject with all the content of theis function
7737 // closure.
7738 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
7739
7740 // Check whether the arguments shadow object exists.
7741 int arguments_shadow_index =
7742 ScopeInfo<>::ContextSlotIndex(*code,
7743 Heap::arguments_shadow_symbol(),
7744 NULL);
7745 if (arguments_shadow_index >= 0) {
7746 // In this case all the arguments are available in the arguments shadow
7747 // object.
7748 Handle<JSObject> arguments_shadow(
7749 JSObject::cast(context->get(arguments_shadow_index)));
7750 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
7751 SetProperty(closure_scope,
7752 scope_info.parameter_name(i),
7753 Handle<Object>(arguments_shadow->GetElement(i)), NONE);
7754 }
7755 }
7756
7757 // Fill all context locals to the context extension.
7758 CopyContextLocalsToScopeObject(code, scope_info, context, closure_scope);
7759
7760 // Finally copy any properties from the function context extension. This will
7761 // be variables introduced by eval.
7762 if (context->has_extension()) {
7763 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007764 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007765 for (int i = 0; i < keys->length(); i++) {
7766 // Names of variables introduced by eval are strings.
7767 ASSERT(keys->get(i)->IsString());
7768 Handle<String> key(String::cast(keys->get(i)));
7769 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
7770 }
7771 }
7772
7773 return closure_scope;
7774}
7775
7776
7777// Iterate over the actual scopes visible from a stack frame. All scopes are
7778// backed by an actual context except the local scope, which is inserted
7779// "artifically" in the context chain.
7780class ScopeIterator {
7781 public:
7782 enum ScopeType {
7783 ScopeTypeGlobal = 0,
7784 ScopeTypeLocal,
7785 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00007786 ScopeTypeClosure,
7787 // Every catch block contains an implicit with block (its parameter is
7788 // a JSContextExtensionObject) that extends current scope with a variable
7789 // holding exception object. Such with blocks are treated as scopes of their
7790 // own type.
7791 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007792 };
7793
7794 explicit ScopeIterator(JavaScriptFrame* frame)
7795 : frame_(frame),
7796 function_(JSFunction::cast(frame->function())),
7797 context_(Context::cast(frame->context())),
7798 local_done_(false),
7799 at_local_(false) {
7800
7801 // Check whether the first scope is actually a local scope.
7802 if (context_->IsGlobalContext()) {
7803 // If there is a stack slot for .result then this local scope has been
7804 // created for evaluating top level code and it is not a real local scope.
7805 // Checking for the existence of .result seems fragile, but the scope info
7806 // saved with the code object does not otherwise have that information.
7807 Handle<Code> code(function_->code());
7808 int index = ScopeInfo<>::StackSlotIndex(*code, Heap::result_symbol());
7809 at_local_ = index < 0;
7810 } else if (context_->is_function_context()) {
7811 at_local_ = true;
7812 }
7813 }
7814
7815 // More scopes?
7816 bool Done() { return context_.is_null(); }
7817
7818 // Move to the next scope.
7819 void Next() {
7820 // If at a local scope mark the local scope as passed.
7821 if (at_local_) {
7822 at_local_ = false;
7823 local_done_ = true;
7824
7825 // If the current context is not associated with the local scope the
7826 // current context is the next real scope, so don't move to the next
7827 // context in this case.
7828 if (context_->closure() != *function_) {
7829 return;
7830 }
7831 }
7832
7833 // The global scope is always the last in the chain.
7834 if (context_->IsGlobalContext()) {
7835 context_ = Handle<Context>();
7836 return;
7837 }
7838
7839 // Move to the next context.
7840 if (context_->is_function_context()) {
7841 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
7842 } else {
7843 context_ = Handle<Context>(context_->previous());
7844 }
7845
7846 // If passing the local scope indicate that the current scope is now the
7847 // local scope.
7848 if (!local_done_ &&
7849 (context_->IsGlobalContext() || (context_->is_function_context()))) {
7850 at_local_ = true;
7851 }
7852 }
7853
7854 // Return the type of the current scope.
7855 int Type() {
7856 if (at_local_) {
7857 return ScopeTypeLocal;
7858 }
7859 if (context_->IsGlobalContext()) {
7860 ASSERT(context_->global()->IsGlobalObject());
7861 return ScopeTypeGlobal;
7862 }
7863 if (context_->is_function_context()) {
7864 return ScopeTypeClosure;
7865 }
7866 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00007867 // Current scope is either an explicit with statement or a with statement
7868 // implicitely generated for a catch block.
7869 // If the extension object here is a JSContextExtensionObject then
7870 // current with statement is one frome a catch block otherwise it's a
7871 // regular with statement.
7872 if (context_->extension()->IsJSContextExtensionObject()) {
7873 return ScopeTypeCatch;
7874 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007875 return ScopeTypeWith;
7876 }
7877
7878 // Return the JavaScript object with the content of the current scope.
7879 Handle<JSObject> ScopeObject() {
7880 switch (Type()) {
7881 case ScopeIterator::ScopeTypeGlobal:
7882 return Handle<JSObject>(CurrentContext()->global());
7883 break;
7884 case ScopeIterator::ScopeTypeLocal:
7885 // Materialize the content of the local scope into a JSObject.
7886 return MaterializeLocalScope(frame_);
7887 break;
7888 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00007889 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007890 // Return the with object.
7891 return Handle<JSObject>(CurrentContext()->extension());
7892 break;
7893 case ScopeIterator::ScopeTypeClosure:
7894 // Materialize the content of the closure scope into a JSObject.
7895 return MaterializeClosure(CurrentContext());
7896 break;
7897 }
7898 UNREACHABLE();
7899 return Handle<JSObject>();
7900 }
7901
7902 // Return the context for this scope. For the local context there might not
7903 // be an actual context.
7904 Handle<Context> CurrentContext() {
7905 if (at_local_ && context_->closure() != *function_) {
7906 return Handle<Context>();
7907 }
7908 return context_;
7909 }
7910
7911#ifdef DEBUG
7912 // Debug print of the content of the current scope.
7913 void DebugPrint() {
7914 switch (Type()) {
7915 case ScopeIterator::ScopeTypeGlobal:
7916 PrintF("Global:\n");
7917 CurrentContext()->Print();
7918 break;
7919
7920 case ScopeIterator::ScopeTypeLocal: {
7921 PrintF("Local:\n");
7922 Handle<Code> code(function_->code());
7923 ScopeInfo<> scope_info(*code);
7924 scope_info.Print();
7925 if (!CurrentContext().is_null()) {
7926 CurrentContext()->Print();
7927 if (CurrentContext()->has_extension()) {
7928 Handle<JSObject> extension =
7929 Handle<JSObject>(CurrentContext()->extension());
7930 if (extension->IsJSContextExtensionObject()) {
7931 extension->Print();
7932 }
7933 }
7934 }
7935 break;
7936 }
7937
7938 case ScopeIterator::ScopeTypeWith: {
7939 PrintF("With:\n");
7940 Handle<JSObject> extension =
7941 Handle<JSObject>(CurrentContext()->extension());
7942 extension->Print();
7943 break;
7944 }
7945
ager@chromium.orga1645e22009-09-09 19:27:10 +00007946 case ScopeIterator::ScopeTypeCatch: {
7947 PrintF("Catch:\n");
7948 Handle<JSObject> extension =
7949 Handle<JSObject>(CurrentContext()->extension());
7950 extension->Print();
7951 break;
7952 }
7953
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007954 case ScopeIterator::ScopeTypeClosure: {
7955 PrintF("Closure:\n");
7956 CurrentContext()->Print();
7957 if (CurrentContext()->has_extension()) {
7958 Handle<JSObject> extension =
7959 Handle<JSObject>(CurrentContext()->extension());
7960 if (extension->IsJSContextExtensionObject()) {
7961 extension->Print();
7962 }
7963 }
7964 break;
7965 }
7966
7967 default:
7968 UNREACHABLE();
7969 }
7970 PrintF("\n");
7971 }
7972#endif
7973
7974 private:
7975 JavaScriptFrame* frame_;
7976 Handle<JSFunction> function_;
7977 Handle<Context> context_;
7978 bool local_done_;
7979 bool at_local_;
7980
7981 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
7982};
7983
7984
7985static Object* Runtime_GetScopeCount(Arguments args) {
7986 HandleScope scope;
7987 ASSERT(args.length() == 2);
7988
7989 // Check arguments.
7990 Object* check = Runtime_CheckExecutionState(args);
7991 if (check->IsFailure()) return check;
7992 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
7993
7994 // Get the frame where the debugging is performed.
7995 StackFrame::Id id = UnwrapFrameId(wrapped_id);
7996 JavaScriptFrameIterator it(id);
7997 JavaScriptFrame* frame = it.frame();
7998
7999 // Count the visible scopes.
8000 int n = 0;
8001 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8002 n++;
8003 }
8004
8005 return Smi::FromInt(n);
8006}
8007
8008
8009static const int kScopeDetailsTypeIndex = 0;
8010static const int kScopeDetailsObjectIndex = 1;
8011static const int kScopeDetailsSize = 2;
8012
8013// Return an array with scope details
8014// args[0]: number: break id
8015// args[1]: number: frame index
8016// args[2]: number: scope index
8017//
8018// The array returned contains the following information:
8019// 0: Scope type
8020// 1: Scope object
8021static Object* Runtime_GetScopeDetails(Arguments args) {
8022 HandleScope scope;
8023 ASSERT(args.length() == 3);
8024
8025 // Check arguments.
8026 Object* check = Runtime_CheckExecutionState(args);
8027 if (check->IsFailure()) return check;
8028 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8029 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
8030
8031 // Get the frame where the debugging is performed.
8032 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8033 JavaScriptFrameIterator frame_it(id);
8034 JavaScriptFrame* frame = frame_it.frame();
8035
8036 // Find the requested scope.
8037 int n = 0;
8038 ScopeIterator it(frame);
8039 for (; !it.Done() && n < index; it.Next()) {
8040 n++;
8041 }
8042 if (it.Done()) {
8043 return Heap::undefined_value();
8044 }
8045
8046 // Calculate the size of the result.
8047 int details_size = kScopeDetailsSize;
8048 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8049
8050 // Fill in scope details.
8051 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
8052 details->set(kScopeDetailsObjectIndex, *it.ScopeObject());
8053
8054 return *Factory::NewJSArrayWithElements(details);
8055}
8056
8057
8058static Object* Runtime_DebugPrintScopes(Arguments args) {
8059 HandleScope scope;
8060 ASSERT(args.length() == 0);
8061
8062#ifdef DEBUG
8063 // Print the scopes for the top frame.
8064 StackFrameLocator locator;
8065 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
8066 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8067 it.DebugPrint();
8068 }
8069#endif
8070 return Heap::undefined_value();
8071}
8072
8073
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008074static Object* Runtime_GetCFrames(Arguments args) {
8075 HandleScope scope;
8076 ASSERT(args.length() == 1);
8077 Object* result = Runtime_CheckExecutionState(args);
8078 if (result->IsFailure()) return result;
8079
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00008080#if V8_HOST_ARCH_64_BIT
8081 UNIMPLEMENTED();
8082 return Heap::undefined_value();
8083#else
8084
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008085 static const int kMaxCFramesSize = 200;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008086 ScopedVector<OS::StackFrame> frames(kMaxCFramesSize);
8087 int frames_count = OS::StackWalk(frames);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008088 if (frames_count == OS::kStackWalkError) {
8089 return Heap::undefined_value();
8090 }
8091
8092 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
8093 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
8094 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
8095 for (int i = 0; i < frames_count; i++) {
8096 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
8097 frame_value->SetProperty(
8098 *address_str,
8099 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
8100 NONE);
8101
8102 // Get the stack walk text for this frame.
8103 Handle<String> frame_text;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008104 int frame_text_length = StrLength(frames[i].text);
8105 if (frame_text_length > 0) {
8106 Vector<const char> str(frames[i].text, frame_text_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008107 frame_text = Factory::NewStringFromAscii(str);
8108 }
8109
8110 if (!frame_text.is_null()) {
8111 frame_value->SetProperty(*text_str, *frame_text, NONE);
8112 }
8113
8114 frames_array->set(i, *frame_value);
8115 }
8116 return *Factory::NewJSArrayWithElements(frames_array);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00008117#endif // V8_HOST_ARCH_64_BIT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008118}
8119
8120
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008121static Object* Runtime_GetThreadCount(Arguments args) {
8122 HandleScope scope;
8123 ASSERT(args.length() == 1);
8124
8125 // Check arguments.
8126 Object* result = Runtime_CheckExecutionState(args);
8127 if (result->IsFailure()) return result;
8128
8129 // Count all archived V8 threads.
8130 int n = 0;
8131 for (ThreadState* thread = ThreadState::FirstInUse();
8132 thread != NULL;
8133 thread = thread->Next()) {
8134 n++;
8135 }
8136
8137 // Total number of threads is current thread and archived threads.
8138 return Smi::FromInt(n + 1);
8139}
8140
8141
8142static const int kThreadDetailsCurrentThreadIndex = 0;
8143static const int kThreadDetailsThreadIdIndex = 1;
8144static const int kThreadDetailsSize = 2;
8145
8146// Return an array with thread details
8147// args[0]: number: break id
8148// args[1]: number: thread index
8149//
8150// The array returned contains the following information:
8151// 0: Is current thread?
8152// 1: Thread id
8153static Object* Runtime_GetThreadDetails(Arguments args) {
8154 HandleScope scope;
8155 ASSERT(args.length() == 2);
8156
8157 // Check arguments.
8158 Object* check = Runtime_CheckExecutionState(args);
8159 if (check->IsFailure()) return check;
8160 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8161
8162 // Allocate array for result.
8163 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
8164
8165 // Thread index 0 is current thread.
8166 if (index == 0) {
8167 // Fill the details.
8168 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
8169 details->set(kThreadDetailsThreadIdIndex,
8170 Smi::FromInt(ThreadManager::CurrentId()));
8171 } else {
8172 // Find the thread with the requested index.
8173 int n = 1;
8174 ThreadState* thread = ThreadState::FirstInUse();
8175 while (index != n && thread != NULL) {
8176 thread = thread->Next();
8177 n++;
8178 }
8179 if (thread == NULL) {
8180 return Heap::undefined_value();
8181 }
8182
8183 // Fill the details.
8184 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
8185 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
8186 }
8187
8188 // Convert to JS array and return.
8189 return *Factory::NewJSArrayWithElements(details);
8190}
8191
8192
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008193static Object* Runtime_GetBreakLocations(Arguments args) {
8194 HandleScope scope;
8195 ASSERT(args.length() == 1);
8196
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008197 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8198 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008199 // Find the number of break points
8200 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
8201 if (break_locations->IsUndefined()) return Heap::undefined_value();
8202 // Return array as JS array
8203 return *Factory::NewJSArrayWithElements(
8204 Handle<FixedArray>::cast(break_locations));
8205}
8206
8207
8208// Set a break point in a function
8209// args[0]: function
8210// args[1]: number: break source position (within the function source)
8211// args[2]: number: break point object
8212static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
8213 HandleScope scope;
8214 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008215 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8216 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008217 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
8218 RUNTIME_ASSERT(source_position >= 0);
8219 Handle<Object> break_point_object_arg = args.at<Object>(2);
8220
8221 // Set break point.
8222 Debug::SetBreakPoint(shared, source_position, break_point_object_arg);
8223
8224 return Heap::undefined_value();
8225}
8226
8227
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00008228Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
8229 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008230 // Iterate the heap looking for SharedFunctionInfo generated from the
8231 // script. The inner most SharedFunctionInfo containing the source position
8232 // for the requested break point is found.
8233 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
8234 // which is found is not compiled it is compiled and the heap is iterated
8235 // again as the compilation might create inner functions from the newly
8236 // compiled function and the actual requested break point might be in one of
8237 // these functions.
8238 bool done = false;
8239 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00008240 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241 Handle<SharedFunctionInfo> target;
8242 // The current candidate for the last function in script:
8243 Handle<SharedFunctionInfo> last;
8244 while (!done) {
8245 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008246 for (HeapObject* obj = iterator.next();
8247 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008248 if (obj->IsSharedFunctionInfo()) {
8249 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
8250 if (shared->script() == *script) {
8251 // If the SharedFunctionInfo found has the requested script data and
8252 // contains the source position it is a candidate.
8253 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00008254 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008255 start_position = shared->start_position();
8256 }
8257 if (start_position <= position &&
8258 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00008259 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008260 // candidate this is the new candidate.
8261 if (target.is_null()) {
8262 target_start_position = start_position;
8263 target = shared;
8264 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00008265 if (target_start_position == start_position &&
8266 shared->end_position() == target->end_position()) {
8267 // If a top-level function contain only one function
8268 // declartion the source for the top-level and the function is
8269 // the same. In that case prefer the non top-level function.
8270 if (!shared->is_toplevel()) {
8271 target_start_position = start_position;
8272 target = shared;
8273 }
8274 } else if (target_start_position <= start_position &&
8275 shared->end_position() <= target->end_position()) {
8276 // This containment check includes equality as a function inside
8277 // a top-level function can share either start or end position
8278 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008279 target_start_position = start_position;
8280 target = shared;
8281 }
8282 }
8283 }
8284
8285 // Keep track of the last function in the script.
8286 if (last.is_null() ||
8287 shared->end_position() > last->start_position()) {
8288 last = shared;
8289 }
8290 }
8291 }
8292 }
8293
8294 // Make sure some candidate is selected.
8295 if (target.is_null()) {
8296 if (!last.is_null()) {
8297 // Position after the last function - use last.
8298 target = last;
8299 } else {
8300 // Unable to find function - possibly script without any function.
8301 return Heap::undefined_value();
8302 }
8303 }
8304
8305 // If the candidate found is compiled we are done. NOTE: when lazy
8306 // compilation of inner functions is introduced some additional checking
8307 // needs to be done here to compile inner functions.
8308 done = target->is_compiled();
8309 if (!done) {
8310 // If the candidate is not compiled compile it to reveal any inner
8311 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008312 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008313 }
8314 }
8315
8316 return *target;
8317}
8318
8319
8320// Change the state of a break point in a script. NOTE: Regarding performance
8321// see the NOTE for GetScriptFromScriptData.
8322// args[0]: script to set break point in
8323// args[1]: number: break source position (within the script source)
8324// args[2]: number: break point object
8325static Object* Runtime_SetScriptBreakPoint(Arguments args) {
8326 HandleScope scope;
8327 ASSERT(args.length() == 3);
8328 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
8329 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
8330 RUNTIME_ASSERT(source_position >= 0);
8331 Handle<Object> break_point_object_arg = args.at<Object>(2);
8332
8333 // Get the script from the script wrapper.
8334 RUNTIME_ASSERT(wrapper->value()->IsScript());
8335 Handle<Script> script(Script::cast(wrapper->value()));
8336
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00008337 Object* result = Runtime::FindSharedFunctionInfoInScript(
8338 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008339 if (!result->IsUndefined()) {
8340 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
8341 // Find position within function. The script position might be before the
8342 // source position of the first function.
8343 int position;
8344 if (shared->start_position() > source_position) {
8345 position = 0;
8346 } else {
8347 position = source_position - shared->start_position();
8348 }
8349 Debug::SetBreakPoint(shared, position, break_point_object_arg);
8350 }
8351 return Heap::undefined_value();
8352}
8353
8354
8355// Clear a break point
8356// args[0]: number: break point object
8357static Object* Runtime_ClearBreakPoint(Arguments args) {
8358 HandleScope scope;
8359 ASSERT(args.length() == 1);
8360 Handle<Object> break_point_object_arg = args.at<Object>(0);
8361
8362 // Clear break point.
8363 Debug::ClearBreakPoint(break_point_object_arg);
8364
8365 return Heap::undefined_value();
8366}
8367
8368
8369// Change the state of break on exceptions
8370// args[0]: boolean indicating uncaught exceptions
8371// args[1]: boolean indicating on/off
8372static Object* Runtime_ChangeBreakOnException(Arguments args) {
8373 HandleScope scope;
8374 ASSERT(args.length() == 2);
8375 ASSERT(args[0]->IsNumber());
8376 ASSERT(args[1]->IsBoolean());
8377
8378 // Update break point state
8379 ExceptionBreakType type =
8380 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
8381 bool enable = args[1]->ToBoolean()->IsTrue();
8382 Debug::ChangeBreakOnException(type, enable);
8383 return Heap::undefined_value();
8384}
8385
8386
8387// Prepare for stepping
8388// args[0]: break id for checking execution state
8389// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00008390// args[2]: number of times to perform the step, for step out it is the number
8391// of frames to step down.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008392static Object* Runtime_PrepareStep(Arguments args) {
8393 HandleScope scope;
8394 ASSERT(args.length() == 3);
8395 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008396 Object* check = Runtime_CheckExecutionState(args);
8397 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008398 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
8399 return Top::Throw(Heap::illegal_argument_symbol());
8400 }
8401
8402 // Get the step action and check validity.
8403 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
8404 if (step_action != StepIn &&
8405 step_action != StepNext &&
8406 step_action != StepOut &&
8407 step_action != StepInMin &&
8408 step_action != StepMin) {
8409 return Top::Throw(Heap::illegal_argument_symbol());
8410 }
8411
8412 // Get the number of steps.
8413 int step_count = NumberToInt32(args[2]);
8414 if (step_count < 1) {
8415 return Top::Throw(Heap::illegal_argument_symbol());
8416 }
8417
ager@chromium.orga1645e22009-09-09 19:27:10 +00008418 // Clear all current stepping setup.
8419 Debug::ClearStepping();
8420
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008421 // Prepare step.
8422 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
8423 return Heap::undefined_value();
8424}
8425
8426
8427// Clear all stepping set by PrepareStep.
8428static Object* Runtime_ClearStepping(Arguments args) {
8429 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00008430 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008431 Debug::ClearStepping();
8432 return Heap::undefined_value();
8433}
8434
8435
8436// Creates a copy of the with context chain. The copy of the context chain is
8437// is linked to the function context supplied.
8438static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
8439 Handle<Context> function_context) {
8440 // At the bottom of the chain. Return the function context to link to.
8441 if (context_chain->is_function_context()) {
8442 return function_context;
8443 }
8444
8445 // Recursively copy the with contexts.
8446 Handle<Context> previous(context_chain->previous());
8447 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
8448 return Factory::NewWithContext(
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008449 CopyWithContextChain(function_context, previous),
8450 extension,
8451 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008452}
8453
8454
8455// Helper function to find or create the arguments object for
8456// Runtime_DebugEvaluate.
8457static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
8458 Handle<JSFunction> function,
8459 Handle<Code> code,
8460 const ScopeInfo<>* sinfo,
8461 Handle<Context> function_context) {
8462 // Try to find the value of 'arguments' to pass as parameter. If it is not
8463 // found (that is the debugged function does not reference 'arguments' and
8464 // does not support eval) then create an 'arguments' object.
8465 int index;
8466 if (sinfo->number_of_stack_slots() > 0) {
8467 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol());
8468 if (index != -1) {
8469 return Handle<Object>(frame->GetExpression(index));
8470 }
8471 }
8472
8473 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
8474 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(),
8475 NULL);
8476 if (index != -1) {
8477 return Handle<Object>(function_context->get(index));
8478 }
8479 }
8480
8481 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008482 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
8483 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008484
8485 AssertNoAllocation no_gc;
8486 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008487 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008488 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008489 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008490 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008491 return arguments;
8492}
8493
8494
8495// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00008496// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008497// extension part has all the parameters and locals of the function on the
8498// stack frame. A function which calls eval with the code to evaluate is then
8499// compiled in this context and called in this context. As this context
8500// replaces the context of the function on the stack frame a new (empty)
8501// function is created as well to be used as the closure for the context.
8502// This function and the context acts as replacements for the function on the
8503// stack frame presenting the same view of the values of parameters and
8504// local variables as if the piece of JavaScript was evaluated at the point
8505// where the function on the stack frame is currently stopped.
8506static Object* Runtime_DebugEvaluate(Arguments args) {
8507 HandleScope scope;
8508
8509 // Check the execution state and decode arguments frame and source to be
8510 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00008511 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008512 Object* check_result = Runtime_CheckExecutionState(args);
8513 if (check_result->IsFailure()) return check_result;
8514 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8515 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00008516 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
8517
8518 // Handle the processing of break.
8519 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008520
8521 // Get the frame where the debugging is performed.
8522 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8523 JavaScriptFrameIterator it(id);
8524 JavaScriptFrame* frame = it.frame();
8525 Handle<JSFunction> function(JSFunction::cast(frame->function()));
8526 Handle<Code> code(function->code());
8527 ScopeInfo<> sinfo(*code);
8528
8529 // Traverse the saved contexts chain to find the active context for the
8530 // selected frame.
8531 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008532 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008533 save = save->prev();
8534 }
8535 ASSERT(save != NULL);
8536 SaveContext savex;
8537 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008538
8539 // Create the (empty) function replacing the function on the stack frame for
8540 // the purpose of evaluating in the context created below. It is important
8541 // that this function does not describe any parameters and local variables
8542 // in the context. If it does then this will cause problems with the lookup
8543 // in Context::Lookup, where context slots for parameters and local variables
8544 // are looked at before the extension object.
8545 Handle<JSFunction> go_between =
8546 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
8547 go_between->set_context(function->context());
8548#ifdef DEBUG
8549 ScopeInfo<> go_between_sinfo(go_between->shared()->code());
8550 ASSERT(go_between_sinfo.number_of_parameters() == 0);
8551 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
8552#endif
8553
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008554 // Materialize the content of the local scope into a JSObject.
8555 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008556
8557 // Allocate a new context for the debug evaluation and set the extension
8558 // object build.
8559 Handle<Context> context =
8560 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008561 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008562 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008563 Handle<Context> frame_context(Context::cast(frame->context()));
8564 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008565 context = CopyWithContextChain(frame_context, context);
8566
8567 // Wrap the evaluation statement in a new function compiled in the newly
8568 // created context. The function has one parameter which has to be called
8569 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00008570 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008571 // function(arguments,__source__) {return eval(__source__);}
8572 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008573 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008574 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008575 Handle<String> function_source =
8576 Factory::NewStringFromAscii(Vector<const char>(source_str,
8577 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008578 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00008579 Compiler::CompileEval(function_source,
8580 context,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00008581 context->IsGlobalContext(),
ager@chromium.orgadd848f2009-08-13 12:44:13 +00008582 Compiler::DONT_VALIDATE_JSON);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008583 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008584 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008585 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008586
8587 // Invoke the result of the compilation to get the evaluation function.
8588 bool has_pending_exception;
8589 Handle<Object> receiver(frame->receiver());
8590 Handle<Object> evaluation_function =
8591 Execution::Call(compiled_function, receiver, 0, NULL,
8592 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008593 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008594
8595 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
8596 function_context);
8597
8598 // Invoke the evaluation function and return the result.
8599 const int argc = 2;
8600 Object** argv[argc] = { arguments.location(),
8601 Handle<Object>::cast(source).location() };
8602 Handle<Object> result =
8603 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
8604 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008605 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008606
8607 // Skip the global proxy as it has no properties and always delegates to the
8608 // real global object.
8609 if (result->IsJSGlobalProxy()) {
8610 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
8611 }
8612
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008613 return *result;
8614}
8615
8616
8617static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
8618 HandleScope scope;
8619
8620 // Check the execution state and decode arguments frame and source to be
8621 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00008622 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008623 Object* check_result = Runtime_CheckExecutionState(args);
8624 if (check_result->IsFailure()) return check_result;
8625 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00008626 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
8627
8628 // Handle the processing of break.
8629 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008630
8631 // Enter the top context from before the debugger was invoked.
8632 SaveContext save;
8633 SaveContext* top = &save;
8634 while (top != NULL && *top->context() == *Debug::debug_context()) {
8635 top = top->prev();
8636 }
8637 if (top != NULL) {
8638 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008639 }
8640
8641 // Get the global context now set to the top context from before the
8642 // debugger was invoked.
8643 Handle<Context> context = Top::global_context();
8644
8645 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008646 Handle<SharedFunctionInfo> shared =
8647 Compiler::CompileEval(source,
8648 context,
8649 true,
8650 Compiler::DONT_VALIDATE_JSON);
8651 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008652 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008653 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
8654 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008655
8656 // Invoke the result of the compilation to get the evaluation function.
8657 bool has_pending_exception;
8658 Handle<Object> receiver = Top::global();
8659 Handle<Object> result =
8660 Execution::Call(compiled_function, receiver, 0, NULL,
8661 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008662 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008663 return *result;
8664}
8665
8666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008667static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
8668 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00008669 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008670
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008671 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008672 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008673
8674 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008675 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00008676 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
8677 // Get the script wrapper in a local handle before calling GetScriptWrapper,
8678 // because using
8679 // instances->set(i, *GetScriptWrapper(script))
8680 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
8681 // already have deferenced the instances handle.
8682 Handle<JSValue> wrapper = GetScriptWrapper(script);
8683 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008684 }
8685
8686 // Return result as a JS array.
8687 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
8688 Handle<JSArray>::cast(result)->SetContent(*instances);
8689 return *result;
8690}
8691
8692
8693// Helper function used by Runtime_DebugReferencedBy below.
8694static int DebugReferencedBy(JSObject* target,
8695 Object* instance_filter, int max_references,
8696 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008697 JSFunction* arguments_function) {
8698 NoHandleAllocation ha;
8699 AssertNoAllocation no_alloc;
8700
8701 // Iterate the heap.
8702 int count = 0;
8703 JSObject* last = NULL;
8704 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008705 HeapObject* heap_obj = NULL;
8706 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008707 (max_references == 0 || count < max_references)) {
8708 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008709 if (heap_obj->IsJSObject()) {
8710 // Skip context extension objects and argument arrays as these are
8711 // checked in the context of functions using them.
8712 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008713 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008714 obj->map()->constructor() == arguments_function) {
8715 continue;
8716 }
8717
8718 // Check if the JS object has a reference to the object looked for.
8719 if (obj->ReferencesObject(target)) {
8720 // Check instance filter if supplied. This is normally used to avoid
8721 // references from mirror objects (see Runtime_IsInPrototypeChain).
8722 if (!instance_filter->IsUndefined()) {
8723 Object* V = obj;
8724 while (true) {
8725 Object* prototype = V->GetPrototype();
8726 if (prototype->IsNull()) {
8727 break;
8728 }
8729 if (instance_filter == prototype) {
8730 obj = NULL; // Don't add this object.
8731 break;
8732 }
8733 V = prototype;
8734 }
8735 }
8736
8737 if (obj != NULL) {
8738 // Valid reference found add to instance array if supplied an update
8739 // count.
8740 if (instances != NULL && count < instances_size) {
8741 instances->set(count, obj);
8742 }
8743 last = obj;
8744 count++;
8745 }
8746 }
8747 }
8748 }
8749
8750 // Check for circular reference only. This can happen when the object is only
8751 // referenced from mirrors and has a circular reference in which case the
8752 // object is not really alive and would have been garbage collected if not
8753 // referenced from the mirror.
8754 if (count == 1 && last == target) {
8755 count = 0;
8756 }
8757
8758 // Return the number of referencing objects found.
8759 return count;
8760}
8761
8762
8763// Scan the heap for objects with direct references to an object
8764// args[0]: the object to find references to
8765// args[1]: constructor function for instances to exclude (Mirror)
8766// args[2]: the the maximum number of objects to return
8767static Object* Runtime_DebugReferencedBy(Arguments args) {
8768 ASSERT(args.length() == 3);
8769
8770 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008771 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008772
8773 // Check parameters.
8774 CONVERT_CHECKED(JSObject, target, args[0]);
8775 Object* instance_filter = args[1];
8776 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
8777 instance_filter->IsJSObject());
8778 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
8779 RUNTIME_ASSERT(max_references >= 0);
8780
8781 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008782 JSObject* arguments_boilerplate =
8783 Top::context()->global_context()->arguments_boilerplate();
8784 JSFunction* arguments_function =
8785 JSFunction::cast(arguments_boilerplate->map()->constructor());
8786
8787 // Get the number of referencing objects.
8788 int count;
8789 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00008790 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008791
8792 // Allocate an array to hold the result.
8793 Object* object = Heap::AllocateFixedArray(count);
8794 if (object->IsFailure()) return object;
8795 FixedArray* instances = FixedArray::cast(object);
8796
8797 // Fill the referencing objects.
8798 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00008799 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008800
8801 // Return result as JS array.
8802 Object* result =
8803 Heap::AllocateJSObject(
8804 Top::context()->global_context()->array_function());
8805 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
8806 return result;
8807}
8808
8809
8810// Helper function used by Runtime_DebugConstructedBy below.
8811static int DebugConstructedBy(JSFunction* constructor, int max_references,
8812 FixedArray* instances, int instances_size) {
8813 AssertNoAllocation no_alloc;
8814
8815 // Iterate the heap.
8816 int count = 0;
8817 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008818 HeapObject* heap_obj = NULL;
8819 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008820 (max_references == 0 || count < max_references)) {
8821 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008822 if (heap_obj->IsJSObject()) {
8823 JSObject* obj = JSObject::cast(heap_obj);
8824 if (obj->map()->constructor() == constructor) {
8825 // Valid reference found add to instance array if supplied an update
8826 // count.
8827 if (instances != NULL && count < instances_size) {
8828 instances->set(count, obj);
8829 }
8830 count++;
8831 }
8832 }
8833 }
8834
8835 // Return the number of referencing objects found.
8836 return count;
8837}
8838
8839
8840// Scan the heap for objects constructed by a specific function.
8841// args[0]: the constructor to find instances of
8842// args[1]: the the maximum number of objects to return
8843static Object* Runtime_DebugConstructedBy(Arguments args) {
8844 ASSERT(args.length() == 2);
8845
8846 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008847 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008848
8849 // Check parameters.
8850 CONVERT_CHECKED(JSFunction, constructor, args[0]);
8851 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
8852 RUNTIME_ASSERT(max_references >= 0);
8853
8854 // Get the number of referencing objects.
8855 int count;
8856 count = DebugConstructedBy(constructor, max_references, NULL, 0);
8857
8858 // Allocate an array to hold the result.
8859 Object* object = Heap::AllocateFixedArray(count);
8860 if (object->IsFailure()) return object;
8861 FixedArray* instances = FixedArray::cast(object);
8862
8863 // Fill the referencing objects.
8864 count = DebugConstructedBy(constructor, max_references, instances, count);
8865
8866 // Return result as JS array.
8867 Object* result =
8868 Heap::AllocateJSObject(
8869 Top::context()->global_context()->array_function());
8870 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
8871 return result;
8872}
8873
8874
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008875// Find the effective prototype object as returned by __proto__.
8876// args[0]: the object to find the prototype for.
8877static Object* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008878 ASSERT(args.length() == 1);
8879
8880 CONVERT_CHECKED(JSObject, obj, args[0]);
8881
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008882 // Use the __proto__ accessor.
8883 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008884}
8885
8886
8887static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008888 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008889 CPU::DebugBreak();
8890 return Heap::undefined_value();
8891}
8892
8893
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008894static Object* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008895#ifdef DEBUG
8896 HandleScope scope;
8897 ASSERT(args.length() == 1);
8898 // Get the function and make sure it is compiled.
8899 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008900 Handle<SharedFunctionInfo> shared(func->shared());
8901 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008902 return Failure::Exception();
8903 }
8904 func->code()->PrintLn();
8905#endif // DEBUG
8906 return Heap::undefined_value();
8907}
ager@chromium.org9085a012009-05-11 19:22:57 +00008908
8909
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008910static Object* Runtime_DebugDisassembleConstructor(Arguments args) {
8911#ifdef DEBUG
8912 HandleScope scope;
8913 ASSERT(args.length() == 1);
8914 // Get the function and make sure it is compiled.
8915 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008916 Handle<SharedFunctionInfo> shared(func->shared());
8917 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008918 return Failure::Exception();
8919 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008920 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008921#endif // DEBUG
8922 return Heap::undefined_value();
8923}
8924
8925
ager@chromium.org9085a012009-05-11 19:22:57 +00008926static Object* Runtime_FunctionGetInferredName(Arguments args) {
8927 NoHandleAllocation ha;
8928 ASSERT(args.length() == 1);
8929
8930 CONVERT_CHECKED(JSFunction, f, args[0]);
8931 return f->shared()->inferred_name();
8932}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008933
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008934
8935static int FindSharedFunctionInfosForScript(Script* script,
8936 FixedArray* buffer) {
8937 AssertNoAllocation no_allocations;
8938
8939 int counter = 0;
8940 int buffer_size = buffer->length();
8941 HeapIterator iterator;
8942 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
8943 ASSERT(obj != NULL);
8944 if (!obj->IsSharedFunctionInfo()) {
8945 continue;
8946 }
8947 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
8948 if (shared->script() != script) {
8949 continue;
8950 }
8951 if (counter < buffer_size) {
8952 buffer->set(counter, shared);
8953 }
8954 counter++;
8955 }
8956 return counter;
8957}
8958
8959// For a script finds all SharedFunctionInfo's in the heap that points
8960// to this script. Returns JSArray of SharedFunctionInfo wrapped
8961// in OpaqueReferences.
8962static Object* Runtime_LiveEditFindSharedFunctionInfosForScript(
8963 Arguments args) {
8964 ASSERT(args.length() == 1);
8965 HandleScope scope;
8966 CONVERT_CHECKED(JSValue, script_value, args[0]);
8967
8968 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
8969
8970 const int kBufferSize = 32;
8971
8972 Handle<FixedArray> array;
8973 array = Factory::NewFixedArray(kBufferSize);
8974 int number = FindSharedFunctionInfosForScript(*script, *array);
8975 if (number > kBufferSize) {
8976 array = Factory::NewFixedArray(number);
8977 FindSharedFunctionInfosForScript(*script, *array);
8978 }
8979
8980 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
8981 result->set_length(Smi::FromInt(number));
8982
8983 LiveEdit::WrapSharedFunctionInfos(result);
8984
8985 return *result;
8986}
8987
8988// For a script calculates compilation information about all its functions.
8989// The script source is explicitly specified by the second argument.
8990// The source of the actual script is not used, however it is important that
8991// all generated code keeps references to this particular instance of script.
8992// Returns a JSArray of compilation infos. The array is ordered so that
8993// each function with all its descendant is always stored in a continues range
8994// with the function itself going first. The root function is a script function.
8995static Object* Runtime_LiveEditGatherCompileInfo(Arguments args) {
8996 ASSERT(args.length() == 2);
8997 HandleScope scope;
8998 CONVERT_CHECKED(JSValue, script, args[0]);
8999 CONVERT_ARG_CHECKED(String, source, 1);
9000 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
9001
9002 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
9003
9004 if (Top::has_pending_exception()) {
9005 return Failure::Exception();
9006 }
9007
9008 return result;
9009}
9010
9011// Changes the source of the script to a new_source and creates a new
9012// script representing the old version of the script source.
9013static Object* Runtime_LiveEditReplaceScript(Arguments args) {
9014 ASSERT(args.length() == 3);
9015 HandleScope scope;
9016 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
9017 CONVERT_ARG_CHECKED(String, new_source, 1);
9018 CONVERT_ARG_CHECKED(String, old_script_name, 2);
9019 Handle<Script> original_script =
9020 Handle<Script>(Script::cast(original_script_value->value()));
9021
9022 Handle<String> original_source(String::cast(original_script->source()));
9023
9024 original_script->set_source(*new_source);
9025 Handle<Script> old_script = Factory::NewScript(original_source);
9026 old_script->set_name(*old_script_name);
9027 old_script->set_line_offset(original_script->line_offset());
9028 old_script->set_column_offset(original_script->column_offset());
9029 old_script->set_data(original_script->data());
9030 old_script->set_type(original_script->type());
9031 old_script->set_context_data(original_script->context_data());
9032 old_script->set_compilation_type(original_script->compilation_type());
9033 old_script->set_eval_from_shared(original_script->eval_from_shared());
9034 old_script->set_eval_from_instructions_offset(
9035 original_script->eval_from_instructions_offset());
9036
9037
9038 Debugger::OnAfterCompile(old_script, Debugger::SEND_WHEN_DEBUGGING);
9039
9040 return *(GetScriptWrapper(old_script));
9041}
9042
9043// Replaces code of SharedFunctionInfo with a new one.
9044static Object* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
9045 ASSERT(args.length() == 2);
9046 HandleScope scope;
9047 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
9048 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
9049
9050 LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
9051
9052 return Heap::undefined_value();
9053}
9054
9055// Connects SharedFunctionInfo to another script.
9056static Object* Runtime_LiveEditRelinkFunctionToScript(Arguments args) {
9057 ASSERT(args.length() == 2);
9058 HandleScope scope;
9059 CONVERT_ARG_CHECKED(JSArray, shared_info_array, 0);
9060 CONVERT_ARG_CHECKED(JSValue, script_value, 1);
9061 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
9062
9063 LiveEdit::RelinkFunctionToScript(shared_info_array, script);
9064
9065 return Heap::undefined_value();
9066}
9067
9068// Updates positions of a shared function info (first parameter) according
9069// to script source change. Text change is described in second parameter as
9070// array of groups of 3 numbers:
9071// (change_begin, change_end, change_end_new_position).
9072// Each group describes a change in text; groups are sorted by change_begin.
9073static Object* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
9074 ASSERT(args.length() == 2);
9075 HandleScope scope;
9076 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
9077 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
9078
9079 LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
9080
9081 return Heap::undefined_value();
9082}
9083
9084
9085static LiveEdit::FunctionPatchabilityStatus FindFunctionCodeOnStacks(
9086 Handle<SharedFunctionInfo> shared) {
9087 // TODO(635): check all threads, not only the current one.
9088 for (StackFrameIterator it; !it.done(); it.Advance()) {
9089 StackFrame* frame = it.frame();
9090 if (frame->code() == shared->code()) {
9091 return LiveEdit::FUNCTION_BLOCKED_ON_STACK;
9092 }
9093 }
9094 return LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH;
9095}
9096
9097// For array of SharedFunctionInfo's (each wrapped in JSValue)
9098// checks that none of them have activations on stacks (of any thread).
9099// Returns array of the same length with corresponding results of
9100// LiveEdit::FunctionPatchabilityStatus type.
9101static Object* Runtime_LiveEditCheckStackActivations(Arguments args) {
9102 ASSERT(args.length() == 1);
9103 HandleScope scope;
9104 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
9105
9106
9107 int len = Smi::cast(shared_array->length())->value();
9108 Handle<JSArray> result = Factory::NewJSArray(len);
9109
9110 for (int i = 0; i < len; i++) {
9111 JSValue* wrapper = JSValue::cast(shared_array->GetElement(i));
9112 Handle<SharedFunctionInfo> shared(
9113 SharedFunctionInfo::cast(wrapper->value()));
9114 LiveEdit::FunctionPatchabilityStatus check_res =
9115 FindFunctionCodeOnStacks(shared);
9116 SetElement(result, i, Handle<Smi>(Smi::FromInt(check_res)));
9117 }
9118
9119 return *result;
9120}
9121
9122
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009123// A testing entry. Returns statement position which is the closest to
9124// source_position.
9125static Object* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
9126 ASSERT(args.length() == 2);
9127 HandleScope scope;
9128 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9129 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9130
9131 Handle<Code> code(function->code());
9132
9133 RelocIterator it(*code, 1 << RelocInfo::STATEMENT_POSITION);
9134 int closest_pc = 0;
9135 int distance = kMaxInt;
9136 while (!it.done()) {
9137 int statement_position = static_cast<int>(it.rinfo()->data());
9138 // Check if this break point is closer that what was previously found.
9139 if (source_position <= statement_position &&
9140 statement_position - source_position < distance) {
9141 closest_pc = it.rinfo()->pc() - code->instruction_start();
9142 distance = statement_position - source_position;
9143 // Check whether we can't get any closer.
9144 if (distance == 0) break;
9145 }
9146 it.next();
9147 }
9148
9149 return Smi::FromInt(closest_pc);
9150}
9151
9152
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009153#endif // ENABLE_DEBUGGER_SUPPORT
9154
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009155#ifdef ENABLE_LOGGING_AND_PROFILING
9156
9157static Object* Runtime_ProfilerResume(Arguments args) {
9158 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009159 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009160
9161 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00009162 CONVERT_CHECKED(Smi, smi_tag, args[1]);
9163 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009164 return Heap::undefined_value();
9165}
9166
9167
9168static Object* Runtime_ProfilerPause(Arguments args) {
9169 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009170 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009171
9172 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00009173 CONVERT_CHECKED(Smi, smi_tag, args[1]);
9174 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009175 return Heap::undefined_value();
9176}
9177
9178#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009179
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180// Finds the script object from the script data. NOTE: This operation uses
9181// heap traversal to find the function generated for the source position
9182// for the requested break point. For lazily compiled functions several heap
9183// traversals might be required rendering this operation as a rather slow
9184// operation. However for setting break points which is normally done through
9185// some kind of user interaction the performance is not crucial.
9186static Handle<Object> Runtime_GetScriptFromScriptName(
9187 Handle<String> script_name) {
9188 // Scan the heap for Script objects to find the script with the requested
9189 // script data.
9190 Handle<Script> script;
9191 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009192 HeapObject* obj = NULL;
9193 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009194 // If a script is found check if it has the script data requested.
9195 if (obj->IsScript()) {
9196 if (Script::cast(obj)->name()->IsString()) {
9197 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
9198 script = Handle<Script>(Script::cast(obj));
9199 }
9200 }
9201 }
9202 }
9203
9204 // If no script with the requested script data is found return undefined.
9205 if (script.is_null()) return Factory::undefined_value();
9206
9207 // Return the script found.
9208 return GetScriptWrapper(script);
9209}
9210
9211
9212// Get the script object from script data. NOTE: Regarding performance
9213// see the NOTE for GetScriptFromScriptData.
9214// args[0]: script data for the script to find the source for
9215static Object* Runtime_GetScript(Arguments args) {
9216 HandleScope scope;
9217
9218 ASSERT(args.length() == 1);
9219
9220 CONVERT_CHECKED(String, script_name, args[0]);
9221
9222 // Find the requested script.
9223 Handle<Object> result =
9224 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
9225 return *result;
9226}
9227
9228
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009229// Determines whether the given stack frame should be displayed in
9230// a stack trace. The caller is the error constructor that asked
9231// for the stack trace to be collected. The first time a construct
9232// call to this function is encountered it is skipped. The seen_caller
9233// in/out parameter is used to remember if the caller has been seen
9234// yet.
9235static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
9236 bool* seen_caller) {
9237 // Only display JS frames.
9238 if (!raw_frame->is_java_script())
9239 return false;
9240 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
9241 Object* raw_fun = frame->function();
9242 // Not sure when this can happen but skip it just in case.
9243 if (!raw_fun->IsJSFunction())
9244 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009245 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009246 *seen_caller = true;
9247 return false;
9248 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009249 // Skip all frames until we've seen the caller. Also, skip the most
9250 // obvious builtin calls. Some builtin calls (such as Number.ADD
9251 // which is invoked using 'call') are very difficult to recognize
9252 // so we're leaving them in for now.
9253 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009254}
9255
9256
9257// Collect the raw data for a stack trace. Returns an array of three
9258// element segments each containing a receiver, function and native
9259// code offset.
9260static Object* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009261 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009262 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009263 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
9264
9265 HandleScope scope;
9266
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00009267 limit = Max(limit, 0); // Ensure that limit is not negative.
9268 int initial_size = Min(limit, 10);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009269 Handle<JSArray> result = Factory::NewJSArray(initial_size * 3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009270
9271 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009272 // If the caller parameter is a function we skip frames until we're
9273 // under it before starting to collect.
9274 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009275 int cursor = 0;
9276 int frames_seen = 0;
9277 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009278 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009279 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009280 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009281 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009282 Object* recv = frame->receiver();
9283 Object* fun = frame->function();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009284 Address pc = frame->pc();
9285 Address start = frame->code()->address();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009286 Smi* offset = Smi::FromInt(static_cast<int>(pc - start));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009287 FixedArray* elements = FixedArray::cast(result->elements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009288 if (cursor + 2 < elements->length()) {
9289 elements->set(cursor++, recv);
9290 elements->set(cursor++, fun);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009291 elements->set(cursor++, offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009292 } else {
9293 HandleScope scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009294 Handle<Object> recv_handle(recv);
9295 Handle<Object> fun_handle(fun);
9296 SetElement(result, cursor++, recv_handle);
9297 SetElement(result, cursor++, fun_handle);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009298 SetElement(result, cursor++, Handle<Smi>(offset));
9299 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009300 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009301 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009302 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009303
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009304 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009305 return *result;
9306}
9307
9308
ager@chromium.org3811b432009-10-28 14:53:37 +00009309// Returns V8 version as a string.
9310static Object* Runtime_GetV8Version(Arguments args) {
9311 ASSERT_EQ(args.length(), 0);
9312
9313 NoHandleAllocation ha;
9314
9315 const char* version_string = v8::V8::GetVersion();
9316
9317 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
9318}
9319
9320
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009321static Object* Runtime_Abort(Arguments args) {
9322 ASSERT(args.length() == 2);
9323 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
9324 Smi::cast(args[1])->value());
9325 Top::PrintStack();
9326 OS::Abort();
9327 UNREACHABLE();
9328 return NULL;
9329}
9330
9331
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009332static Object* Runtime_DeleteHandleScopeExtensions(Arguments args) {
9333 ASSERT(args.length() == 0);
9334 HandleScope::DeleteExtensions();
9335 return Heap::undefined_value();
9336}
9337
9338
kasper.lund44510672008-07-25 07:37:58 +00009339#ifdef DEBUG
9340// ListNatives is ONLY used by the fuzz-natives.js in debug mode
9341// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009342static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00009343 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009344 HandleScope scope;
9345 Handle<JSArray> result = Factory::NewJSArray(0);
9346 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00009347 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00009348#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009349 { \
9350 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00009351 Handle<String> name; \
9352 /* Inline runtime functions have an underscore in front of the name. */ \
9353 if (inline_runtime_functions) { \
9354 name = Factory::NewStringFromAscii( \
9355 Vector<const char>("_" #Name, StrLength("_" #Name))); \
9356 } else { \
9357 name = Factory::NewStringFromAscii( \
9358 Vector<const char>(#Name, StrLength(#Name))); \
9359 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009360 Handle<JSArray> pair = Factory::NewJSArray(0); \
9361 SetElement(pair, 0, name); \
9362 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
9363 SetElement(result, index++, pair); \
9364 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00009365 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009366 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00009367 inline_runtime_functions = true;
9368 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009369#undef ADD_ENTRY
9370 return *result;
9371}
kasper.lund44510672008-07-25 07:37:58 +00009372#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009373
9374
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009375static Object* Runtime_Log(Arguments args) {
9376 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +00009377 CONVERT_CHECKED(String, format, args[0]);
9378 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009379 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009380 Logger::LogRuntime(chars, elms);
9381 return Heap::undefined_value();
9382}
9383
9384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009385static Object* Runtime_IS_VAR(Arguments args) {
9386 UNREACHABLE(); // implemented as macro in the parser
9387 return NULL;
9388}
9389
9390
9391// ----------------------------------------------------------------------------
9392// Implementation of Runtime
9393
ager@chromium.orga1645e22009-09-09 19:27:10 +00009394#define F(name, nargs, ressize) \
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009395 { #name, FUNCTION_ADDR(Runtime_##name), nargs, \
ager@chromium.orga1645e22009-09-09 19:27:10 +00009396 static_cast<int>(Runtime::k##name), ressize },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009397
9398static Runtime::Function Runtime_functions[] = {
9399 RUNTIME_FUNCTION_LIST(F)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009400 { NULL, NULL, 0, -1, 0 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009401};
9402
9403#undef F
9404
9405
9406Runtime::Function* Runtime::FunctionForId(FunctionId fid) {
9407 ASSERT(0 <= fid && fid < kNofFunctions);
9408 return &Runtime_functions[fid];
9409}
9410
9411
9412Runtime::Function* Runtime::FunctionForName(const char* name) {
9413 for (Function* f = Runtime_functions; f->name != NULL; f++) {
9414 if (strcmp(f->name, name) == 0) {
9415 return f;
9416 }
9417 }
9418 return NULL;
9419}
9420
9421
9422void Runtime::PerformGC(Object* result) {
9423 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009424 if (failure->IsRetryAfterGC()) {
9425 // Try to do a garbage collection; ignore it if it fails. The C
9426 // entry stub will throw an out-of-memory exception in that case.
9427 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
9428 } else {
9429 // Handle last resort GC and make sure to allow future allocations
9430 // to grow the heap without causing GCs (if possible).
9431 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009432 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009433 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009434}
9435
9436
9437} } // namespace v8::internal