blob: 0c15f60f30677bc02c172b4f6929e5ac559273cd [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 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"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000045#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000046#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000047#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include "platform.h"
49#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000052#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000053#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000054#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000055#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056
kasperl@chromium.org71affb52009-05-26 05:44:31 +000057namespace v8 {
58namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
60
ager@chromium.org3e875802009-06-29 08:26:34 +000061#define RUNTIME_ASSERT(value) \
62 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64// Cast the given object to a value of the specified type and store
65// it in a variable with the given name. If the object is not of the
66// expected type call IllegalOperation and return.
67#define CONVERT_CHECKED(Type, name, obj) \
68 RUNTIME_ASSERT(obj->Is##Type()); \
69 Type* name = Type::cast(obj);
70
71#define CONVERT_ARG_CHECKED(Type, name, index) \
72 RUNTIME_ASSERT(args[index]->Is##Type()); \
73 Handle<Type> name = args.at<Type>(index);
74
kasper.lundbd3ec4e2008-07-09 11:06:54 +000075// Cast the given object to a boolean and store it in a variable with
76// the given name. If the object is not a boolean call IllegalOperation
77// and return.
78#define CONVERT_BOOLEAN_CHECKED(name, obj) \
79 RUNTIME_ASSERT(obj->IsBoolean()); \
80 bool name = (obj)->IsTrue();
81
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000082// Cast the given object to a Smi and store its value in an int variable
83// with the given name. If the object is not a Smi call IllegalOperation
84// and return.
85#define CONVERT_SMI_CHECKED(name, obj) \
86 RUNTIME_ASSERT(obj->IsSmi()); \
87 int name = Smi::cast(obj)->value();
88
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089// Cast the given object to a double and store it in a variable with
90// the given name. If the object is not a number (as opposed to
91// the number not-a-number) call IllegalOperation and return.
92#define CONVERT_DOUBLE_CHECKED(name, obj) \
93 RUNTIME_ASSERT(obj->IsNumber()); \
94 double name = (obj)->Number();
95
96// Call the specified converter on the object *comand store the result in
97// a variable of the specified type with the given name. If the
98// object is not a Number call IllegalOperation and return.
99#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
100 RUNTIME_ASSERT(obj->IsNumber()); \
101 type name = NumberTo##Type(obj);
102
103// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000104static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105
106
lrn@chromium.org303ada72010-10-27 09:33:13 +0000107MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000108 StackLimitCheck check;
109 if (check.HasOverflowed()) return Top::StackOverflow();
110
lrn@chromium.org303ada72010-10-27 09:33:13 +0000111 Object* result;
112 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
113 if (!maybe_result->ToObject(&result)) return maybe_result;
114 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000115 JSObject* copy = JSObject::cast(result);
116
117 // Deep copy local properties.
118 if (copy->HasFastProperties()) {
119 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000120 for (int i = 0; i < properties->length(); i++) {
121 Object* value = properties->get(i);
122 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000123 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000124 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
125 if (!maybe_result->ToObject(&result)) return maybe_result;
126 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000128 }
129 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000130 int nof = copy->map()->inobject_properties();
131 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000132 Object* value = copy->InObjectPropertyAt(i);
133 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000134 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000135 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
136 if (!maybe_result->ToObject(&result)) return maybe_result;
137 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000138 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000139 }
140 }
141 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000142 { MaybeObject* maybe_result =
143 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
144 if (!maybe_result->ToObject(&result)) return maybe_result;
145 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 FixedArray* names = FixedArray::cast(result);
147 copy->GetLocalPropertyNames(names, 0);
148 for (int i = 0; i < names->length(); i++) {
149 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 // Only deep copy fields from the object literal expression.
154 // In particular, don't try to copy the length attribute of
155 // an array.
156 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000157 Object* value =
158 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000159 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
162 if (!maybe_result->ToObject(&result)) return maybe_result;
163 }
164 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000165 // Creating object copy for literals. No strict mode needed.
166 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 if (!maybe_result->ToObject(&result)) return maybe_result;
168 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000169 }
170 }
171 }
172
173 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000174 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000175 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 switch (copy->GetElementsKind()) {
177 case JSObject::FAST_ELEMENTS: {
178 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000179 if (elements->map() == Heap::fixed_cow_array_map()) {
180 Counters::cow_arrays_created_runtime.Increment();
181#ifdef DEBUG
182 for (int i = 0; i < elements->length(); i++) {
183 ASSERT(!elements->get(i)->IsJSObject());
184 }
185#endif
186 } else {
187 for (int i = 0; i < elements->length(); i++) {
188 Object* value = elements->get(i);
189 if (value->IsJSObject()) {
190 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000194 elements->set(i, result);
195 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
197 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000198 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 case JSObject::DICTIONARY_ELEMENTS: {
201 NumberDictionary* element_dictionary = copy->element_dictionary();
202 int capacity = element_dictionary->Capacity();
203 for (int i = 0; i < capacity; i++) {
204 Object* k = element_dictionary->KeyAt(i);
205 if (element_dictionary->IsKey(k)) {
206 Object* value = element_dictionary->ValueAt(i);
207 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000208 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
210 if (!maybe_result->ToObject(&result)) return maybe_result;
211 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000212 element_dictionary->ValueAtPut(i, result);
213 }
214 }
215 }
216 break;
217 }
218 default:
219 UNREACHABLE();
220 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000221 }
222 return copy;
223}
224
225
lrn@chromium.org303ada72010-10-27 09:33:13 +0000226static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000227 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
228 return DeepCopyBoilerplate(boilerplate);
229}
230
231
lrn@chromium.org303ada72010-10-27 09:33:13 +0000232static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000234 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235}
236
237
ager@chromium.org236ad962008-09-25 09:45:57 +0000238static Handle<Map> ComputeObjectLiteralMap(
239 Handle<Context> context,
240 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000241 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000242 int properties_length = constant_properties->length();
243 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000244 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000245 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000246 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000247 for (int p = 0; p != properties_length; p += 2) {
248 Object* key = constant_properties->get(p);
249 uint32_t element_index = 0;
250 if (key->IsSymbol()) {
251 number_of_symbol_keys++;
252 } else if (key->ToArrayIndex(&element_index)) {
253 // An index key does not require space in the property backing store.
254 number_of_properties--;
255 } else {
256 // Bail out as a non-symbol non-index key makes caching impossible.
257 // ASSERT to make sure that the if condition after the loop is false.
258 ASSERT(number_of_symbol_keys != number_of_properties);
259 break;
260 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000262 // If we only have symbols and array indices among keys then we can
263 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000265 if ((number_of_symbol_keys == number_of_properties) &&
266 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 // Create the fixed array with the key.
268 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000269 if (number_of_symbol_keys > 0) {
270 int index = 0;
271 for (int p = 0; p < properties_length; p += 2) {
272 Object* key = constant_properties->get(p);
273 if (key->IsSymbol()) {
274 keys->set(index++, key);
275 }
276 }
277 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000279 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000280 return Factory::ObjectLiteralMapFromCache(context, keys);
281 }
282 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000284 return Factory::CopyMap(
285 Handle<Map>(context->object_function()->initial_map()),
286 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000287}
288
289
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000290static Handle<Object> CreateLiteralBoilerplate(
291 Handle<FixedArray> literals,
292 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000293
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000294
295static Handle<Object> CreateObjectLiteralBoilerplate(
296 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000297 Handle<FixedArray> constant_properties,
298 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299 // Get the global context from the literals array. This is the
300 // context in which the function was created and we use the object
301 // function from this context to create the object literal. We do
302 // not use the object function from the current global context
303 // because this might be the object function from another context
304 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000305 Handle<Context> context =
306 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
307
308 bool is_result_from_cache;
309 Handle<Map> map = ComputeObjectLiteralMap(context,
310 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000311 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000312
ager@chromium.org236ad962008-09-25 09:45:57 +0000313 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000314
315 // Normalize the elements of the boilerplate to save space if needed.
316 if (!should_have_fast_elements) NormalizeElements(boilerplate);
317
ager@chromium.org32912102009-01-16 10:38:43 +0000318 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000320 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000321 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000322 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323 for (int index = 0; index < length; index +=2) {
324 Handle<Object> key(constant_properties->get(index+0));
325 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000326 if (value->IsFixedArray()) {
327 // The value contains the constant_properties of a
328 // simple object literal.
329 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
330 value = CreateLiteralBoilerplate(literals, array);
331 if (value.is_null()) return value;
332 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000333 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000335 if (key->IsSymbol()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000336 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
337 // Array index as string (uint32).
338 result = SetOwnElement(boilerplate, element_index, value);
339 } else {
340 Handle<String> name(String::cast(*key));
341 ASSERT(!name->AsArrayIndex(&element_index));
342 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
343 value, NONE);
344 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000345 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346 // Array index (uint32).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000347 result = SetOwnElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000348 } else {
349 // Non-uint32 number.
350 ASSERT(key->IsNumber());
351 double num = key->Number();
352 char arr[100];
353 Vector<char> buffer(arr, ARRAY_SIZE(arr));
354 const char* str = DoubleToCString(num, buffer);
355 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000356 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
357 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000358 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000359 // If setting the property on the boilerplate throws an
360 // exception, the exception is converted to an empty handle in
361 // the handle based operations. In that case, we need to
362 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000363 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 }
365 }
366
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000367 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000368}
369
370
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000371static Handle<Object> CreateArrayLiteralBoilerplate(
372 Handle<FixedArray> literals,
373 Handle<FixedArray> elements) {
374 // Create the JSArray.
375 Handle<JSFunction> constructor(
376 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
377 Handle<Object> object = Factory::NewJSObject(constructor);
378
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000379 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
380 Handle<FixedArray> copied_elements =
381 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000382
383 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000384 if (is_cow) {
385#ifdef DEBUG
386 // Copy-on-write arrays must be shallow (and simple).
387 for (int i = 0; i < content->length(); i++) {
388 ASSERT(!content->get(i)->IsFixedArray());
389 }
390#endif
391 } else {
392 for (int i = 0; i < content->length(); i++) {
393 if (content->get(i)->IsFixedArray()) {
394 // The value contains the constant_properties of a
395 // simple object literal.
396 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
397 Handle<Object> result =
398 CreateLiteralBoilerplate(literals, fa);
399 if (result.is_null()) return result;
400 content->set(i, *result);
401 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000402 }
403 }
404
405 // Set the elements.
406 Handle<JSArray>::cast(object)->SetContent(*content);
407 return object;
408}
409
410
411static Handle<Object> CreateLiteralBoilerplate(
412 Handle<FixedArray> literals,
413 Handle<FixedArray> array) {
414 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
415 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000416 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
417 return CreateObjectLiteralBoilerplate(literals, elements, true);
418 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
419 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000420 case CompileTimeValue::ARRAY_LITERAL:
421 return CreateArrayLiteralBoilerplate(literals, elements);
422 default:
423 UNREACHABLE();
424 return Handle<Object>::null();
425 }
426}
427
428
lrn@chromium.org303ada72010-10-27 09:33:13 +0000429static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000430 // Takes a FixedArray of elements containing the literal elements of
431 // the array literal and produces JSArray with those elements.
432 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000433 // which contains the context from which to get the Array function
434 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000435 HandleScope scope;
436 ASSERT(args.length() == 3);
437 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
438 CONVERT_SMI_CHECKED(literals_index, args[1]);
439 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000441 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
442 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000443
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000444 // Update the functions literal and return the boilerplate.
445 literals->set(literals_index, *object);
446 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000447}
448
449
lrn@chromium.org303ada72010-10-27 09:33:13 +0000450static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000451 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000452 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000453 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
454 CONVERT_SMI_CHECKED(literals_index, args[1]);
455 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000456 CONVERT_SMI_CHECKED(fast_elements, args[3]);
457 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000458
459 // Check if boilerplate exists. If not, create it first.
460 Handle<Object> boilerplate(literals->get(literals_index));
461 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000462 boilerplate = CreateObjectLiteralBoilerplate(literals,
463 constant_properties,
464 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000465 if (boilerplate.is_null()) return Failure::Exception();
466 // Update the functions literal and return the boilerplate.
467 literals->set(literals_index, *boilerplate);
468 }
469 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
470}
471
472
lrn@chromium.org303ada72010-10-27 09:33:13 +0000473static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000474 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000475 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000476 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
477 CONVERT_SMI_CHECKED(literals_index, args[1]);
478 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000479 CONVERT_SMI_CHECKED(fast_elements, args[3]);
480 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000481
482 // Check if boilerplate exists. If not, create it first.
483 Handle<Object> boilerplate(literals->get(literals_index));
484 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000485 boilerplate = CreateObjectLiteralBoilerplate(literals,
486 constant_properties,
487 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000488 if (boilerplate.is_null()) return Failure::Exception();
489 // Update the functions literal and return the boilerplate.
490 literals->set(literals_index, *boilerplate);
491 }
492 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
493}
494
495
lrn@chromium.org303ada72010-10-27 09:33:13 +0000496static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000497 HandleScope scope;
498 ASSERT(args.length() == 3);
499 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
500 CONVERT_SMI_CHECKED(literals_index, args[1]);
501 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
502
503 // Check if boilerplate exists. If not, create it first.
504 Handle<Object> boilerplate(literals->get(literals_index));
505 if (*boilerplate == Heap::undefined_value()) {
506 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
507 if (boilerplate.is_null()) return Failure::Exception();
508 // Update the functions literal and return the boilerplate.
509 literals->set(literals_index, *boilerplate);
510 }
511 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
512}
513
514
lrn@chromium.org303ada72010-10-27 09:33:13 +0000515static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 HandleScope scope;
517 ASSERT(args.length() == 3);
518 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
519 CONVERT_SMI_CHECKED(literals_index, args[1]);
520 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
521
522 // Check if boilerplate exists. If not, create it first.
523 Handle<Object> boilerplate(literals->get(literals_index));
524 if (*boilerplate == Heap::undefined_value()) {
525 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
526 if (boilerplate.is_null()) return Failure::Exception();
527 // Update the functions literal and return the boilerplate.
528 literals->set(literals_index, *boilerplate);
529 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000530 if (JSObject::cast(*boilerplate)->elements()->map() ==
531 Heap::fixed_cow_array_map()) {
532 Counters::cow_arrays_created_runtime.Increment();
533 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000534 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
535}
536
537
lrn@chromium.org303ada72010-10-27 09:33:13 +0000538static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000539 ASSERT(args.length() == 2);
540 CONVERT_CHECKED(String, key, args[0]);
541 Object* value = args[1];
542 // Create a catch context extension object.
543 JSFunction* constructor =
544 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000545 Object* object;
546 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
547 if (!maybe_object->ToObject(&object)) return maybe_object;
548 }
ager@chromium.org32912102009-01-16 10:38:43 +0000549 // Assign the exception value to the catch variable and make sure
550 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000551 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000552 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
553 JSObject::cast(object)->SetProperty(
554 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000555 if (!maybe_value->ToObject(&value)) return maybe_value;
556 }
ager@chromium.org32912102009-01-16 10:38:43 +0000557 return object;
558}
559
560
lrn@chromium.org303ada72010-10-27 09:33:13 +0000561static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000562 NoHandleAllocation ha;
563 ASSERT(args.length() == 1);
564 Object* obj = args[0];
565 if (!obj->IsJSObject()) return Heap::null_value();
566 return JSObject::cast(obj)->class_name();
567}
568
ager@chromium.org7c537e22008-10-16 08:43:32 +0000569
lrn@chromium.org303ada72010-10-27 09:33:13 +0000570static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000571 NoHandleAllocation ha;
572 ASSERT(args.length() == 2);
573 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
574 Object* O = args[0];
575 Object* V = args[1];
576 while (true) {
577 Object* prototype = V->GetPrototype();
578 if (prototype->IsNull()) return Heap::false_value();
579 if (O == prototype) return Heap::true_value();
580 V = prototype;
581 }
582}
583
584
ager@chromium.org9085a012009-05-11 19:22:57 +0000585// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000586static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000587 NoHandleAllocation ha;
588 ASSERT(args.length() == 2);
589 CONVERT_CHECKED(JSObject, jsobject, args[0]);
590 CONVERT_CHECKED(JSObject, proto, args[1]);
591
592 // Sanity checks. The old prototype (that we are replacing) could
593 // theoretically be null, but if it is not null then check that we
594 // didn't already install a hidden prototype here.
595 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
596 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
597 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
598
599 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000600 Object* map_or_failure;
601 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
602 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
603 return maybe_map_or_failure;
604 }
605 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000606 Map* new_proto_map = Map::cast(map_or_failure);
607
lrn@chromium.org303ada72010-10-27 09:33:13 +0000608 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
609 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
610 return maybe_map_or_failure;
611 }
612 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000613 Map* new_map = Map::cast(map_or_failure);
614
615 // Set proto's prototype to be the old prototype of the object.
616 new_proto_map->set_prototype(jsobject->GetPrototype());
617 proto->set_map(new_proto_map);
618 new_proto_map->set_is_hidden_prototype();
619
620 // Set the object's prototype to proto.
621 new_map->set_prototype(proto);
622 jsobject->set_map(new_map);
623
624 return Heap::undefined_value();
625}
626
627
lrn@chromium.org303ada72010-10-27 09:33:13 +0000628static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000629 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000630 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631 JavaScriptFrameIterator it;
632 return Heap::ToBoolean(it.frame()->IsConstructor());
633}
634
635
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000636// Recursively traverses hidden prototypes if property is not found
637static void GetOwnPropertyImplementation(JSObject* obj,
638 String* name,
639 LookupResult* result) {
640 obj->LocalLookupRealNamedProperty(name, result);
641
642 if (!result->IsProperty()) {
643 Object* proto = obj->GetPrototype();
644 if (proto->IsJSObject() &&
645 JSObject::cast(proto)->map()->is_hidden_prototype())
646 GetOwnPropertyImplementation(JSObject::cast(proto),
647 name, result);
648 }
649}
650
651
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000652static bool CheckAccessException(LookupResult* result,
653 v8::AccessType access_type) {
654 if (result->type() == CALLBACKS) {
655 Object* callback = result->GetCallbackObject();
656 if (callback->IsAccessorInfo()) {
657 AccessorInfo* info = AccessorInfo::cast(callback);
658 bool can_access =
659 (access_type == v8::ACCESS_HAS &&
660 (info->all_can_read() || info->all_can_write())) ||
661 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
662 (access_type == v8::ACCESS_SET && info->all_can_write());
663 return can_access;
664 }
665 }
666
667 return false;
668}
669
670
671static bool CheckAccess(JSObject* obj,
672 String* name,
673 LookupResult* result,
674 v8::AccessType access_type) {
675 ASSERT(result->IsProperty());
676
677 JSObject* holder = result->holder();
678 JSObject* current = obj;
679 while (true) {
680 if (current->IsAccessCheckNeeded() &&
681 !Top::MayNamedAccess(current, name, access_type)) {
682 // Access check callback denied the access, but some properties
683 // can have a special permissions which override callbacks descision
684 // (currently see v8::AccessControl).
685 break;
686 }
687
688 if (current == holder) {
689 return true;
690 }
691
692 current = JSObject::cast(current->GetPrototype());
693 }
694
695 // API callbacks can have per callback access exceptions.
696 switch (result->type()) {
697 case CALLBACKS: {
698 if (CheckAccessException(result, access_type)) {
699 return true;
700 }
701 break;
702 }
703 case INTERCEPTOR: {
704 // If the object has an interceptor, try real named properties.
705 // Overwrite the result to fetch the correct property later.
706 holder->LookupRealNamedProperty(name, result);
707 if (result->IsProperty()) {
708 if (CheckAccessException(result, access_type)) {
709 return true;
710 }
711 }
712 break;
713 }
714 default:
715 break;
716 }
717
718 Top::ReportFailedAccessCheck(current, access_type);
719 return false;
720}
721
722
723// TODO(1095): we should traverse hidden prototype hierachy as well.
724static bool CheckElementAccess(JSObject* obj,
725 uint32_t index,
726 v8::AccessType access_type) {
727 if (obj->IsAccessCheckNeeded() &&
728 !Top::MayIndexedAccess(obj, index, access_type)) {
729 return false;
730 }
731
732 return true;
733}
734
735
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000736// Enumerator used as indices into the array returned from GetOwnProperty
737enum PropertyDescriptorIndices {
738 IS_ACCESSOR_INDEX,
739 VALUE_INDEX,
740 GETTER_INDEX,
741 SETTER_INDEX,
742 WRITABLE_INDEX,
743 ENUMERABLE_INDEX,
744 CONFIGURABLE_INDEX,
745 DESCRIPTOR_SIZE
746};
747
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000748// Returns an array with the property description:
749// if args[1] is not a property on args[0]
750// returns undefined
751// if args[1] is a data property on args[0]
752// [false, value, Writeable, Enumerable, Configurable]
753// if args[1] is an accessor on args[0]
754// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000755static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000756 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000757 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000758 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000759 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
760 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000761 CONVERT_ARG_CHECKED(JSObject, obj, 0);
762 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000763
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000764 // This could be an element.
765 uint32_t index;
766 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000767 switch (obj->HasLocalElement(index)) {
768 case JSObject::UNDEFINED_ELEMENT:
769 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000770
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000771 case JSObject::STRING_CHARACTER_ELEMENT: {
772 // Special handling of string objects according to ECMAScript 5
773 // 15.5.5.2. Note that this might be a string object with elements
774 // other than the actual string value. This is covered by the
775 // subsequent cases.
776 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
777 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000778 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000779
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000780 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
781 elms->set(VALUE_INDEX, *substr);
782 elms->set(WRITABLE_INDEX, Heap::false_value());
783 elms->set(ENUMERABLE_INDEX, Heap::false_value());
784 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
785 return *desc;
786 }
787
788 case JSObject::INTERCEPTED_ELEMENT:
789 case JSObject::FAST_ELEMENT: {
790 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000791 Handle<Object> value = GetElement(obj, index);
792 elms->set(VALUE_INDEX, *value);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000793 elms->set(WRITABLE_INDEX, Heap::true_value());
794 elms->set(ENUMERABLE_INDEX, Heap::true_value());
795 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
796 return *desc;
797 }
798
799 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000800 Handle<JSObject> holder = obj;
801 if (obj->IsJSGlobalProxy()) {
802 Object* proto = obj->GetPrototype();
803 if (proto->IsNull()) return Heap::undefined_value();
804 ASSERT(proto->IsJSGlobalObject());
805 holder = Handle<JSObject>(JSObject::cast(proto));
806 }
807 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000808 int entry = dictionary->FindEntry(index);
809 ASSERT(entry != NumberDictionary::kNotFound);
810 PropertyDetails details = dictionary->DetailsAt(entry);
811 switch (details.type()) {
812 case CALLBACKS: {
813 // This is an accessor property with getter and/or setter.
814 FixedArray* callbacks =
815 FixedArray::cast(dictionary->ValueAt(entry));
816 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000817 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
818 elms->set(GETTER_INDEX, callbacks->get(0));
819 }
820 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
821 elms->set(SETTER_INDEX, callbacks->get(1));
822 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000823 break;
824 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000825 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000826 // This is a data property.
827 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000828 Handle<Object> value = GetElement(obj, index);
829 elms->set(VALUE_INDEX, *value);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000830 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
831 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000832 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000833 default:
834 UNREACHABLE();
835 break;
836 }
837 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
838 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
839 return *desc;
840 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000841 }
842 }
843
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000844 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000845 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000846
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000847 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000848 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000849 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000850
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000851 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
852 return Heap::false_value();
853 }
854
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000855 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
856 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000857
858 bool is_js_accessor = (result.type() == CALLBACKS) &&
859 (result.GetCallbackObject()->IsFixedArray());
860
861 if (is_js_accessor) {
862 // __defineGetter__/__defineSetter__ callback.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000863 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000864
865 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
866 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
867 elms->set(GETTER_INDEX, structure->get(0));
868 }
869 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
870 elms->set(SETTER_INDEX, structure->get(1));
871 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000872 } else {
873 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
874 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
875
876 PropertyAttributes attrs;
877 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000878 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000879 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
880 if (!maybe_value->ToObject(&value)) return maybe_value;
881 }
882 elms->set(VALUE_INDEX, value);
883 }
884
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000885 return *desc;
886}
887
888
lrn@chromium.org303ada72010-10-27 09:33:13 +0000889static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000890 ASSERT(args.length() == 1);
891 CONVERT_CHECKED(JSObject, obj, args[0]);
892 return obj->PreventExtensions();
893}
894
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000895
lrn@chromium.org303ada72010-10-27 09:33:13 +0000896static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000897 ASSERT(args.length() == 1);
898 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000899 if (obj->IsJSGlobalProxy()) {
900 Object* proto = obj->GetPrototype();
901 if (proto->IsNull()) return Heap::false_value();
902 ASSERT(proto->IsJSGlobalObject());
903 obj = JSObject::cast(proto);
904 }
905 return obj->map()->is_extensible() ? Heap::true_value()
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000906 : Heap::false_value();
907}
908
909
lrn@chromium.org303ada72010-10-27 09:33:13 +0000910static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000911 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000912 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000913 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
914 CONVERT_ARG_CHECKED(String, pattern, 1);
915 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000916 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
917 if (result.is_null()) return Failure::Exception();
918 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919}
920
921
lrn@chromium.org303ada72010-10-27 09:33:13 +0000922static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923 HandleScope scope;
924 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000925 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 return *Factory::CreateApiFunction(data);
927}
928
929
lrn@chromium.org303ada72010-10-27 09:33:13 +0000930static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 ASSERT(args.length() == 1);
932 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000933 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934 return Heap::ToBoolean(result);
935}
936
937
lrn@chromium.org303ada72010-10-27 09:33:13 +0000938static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000939 ASSERT(args.length() == 2);
940 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000941 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000942 int index = field->value();
943 int offset = index * kPointerSize + HeapObject::kHeaderSize;
944 InstanceType type = templ->map()->instance_type();
945 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
946 type == OBJECT_TEMPLATE_INFO_TYPE);
947 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000948 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000949 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
950 } else {
951 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
952 }
953 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000954}
955
956
lrn@chromium.org303ada72010-10-27 09:33:13 +0000957static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000958 ASSERT(args.length() == 1);
959 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000960 Map* old_map = object->map();
961 bool needs_access_checks = old_map->is_access_check_needed();
962 if (needs_access_checks) {
963 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000964 Object* new_map;
965 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
966 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
967 }
ager@chromium.org32912102009-01-16 10:38:43 +0000968
969 Map::cast(new_map)->set_is_access_check_needed(false);
970 object->set_map(Map::cast(new_map));
971 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000972 return needs_access_checks ? Heap::true_value() : Heap::false_value();
973}
974
975
lrn@chromium.org303ada72010-10-27 09:33:13 +0000976static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000977 ASSERT(args.length() == 1);
978 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000979 Map* old_map = object->map();
980 if (!old_map->is_access_check_needed()) {
981 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000982 Object* new_map;
983 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
984 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
985 }
ager@chromium.org32912102009-01-16 10:38:43 +0000986
987 Map::cast(new_map)->set_is_access_check_needed(true);
988 object->set_map(Map::cast(new_map));
989 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000990 return Heap::undefined_value();
991}
992
993
lrn@chromium.org303ada72010-10-27 09:33:13 +0000994static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000995 HandleScope scope;
996 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
997 Handle<Object> args[2] = { type_handle, name };
998 Handle<Object> error =
999 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
1000 return Top::Throw(*error);
1001}
1002
1003
lrn@chromium.org303ada72010-10-27 09:33:13 +00001004static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001005 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006 HandleScope scope;
1007 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
1008
ager@chromium.org3811b432009-10-28 14:53:37 +00001009 Handle<Context> context = args.at<Context>(0);
1010 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001012 StrictModeFlag strict_mode =
1013 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1014 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015
1016 // Compute the property attributes. According to ECMA-262, section
1017 // 13, page 71, the property must be read-only and
1018 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1019 // property as read-only, so we don't either.
1020 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1021
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022 // Traverse the name/value pairs and set the properties.
1023 int length = pairs->length();
1024 for (int i = 0; i < length; i += 2) {
1025 HandleScope scope;
1026 Handle<String> name(String::cast(pairs->get(i)));
1027 Handle<Object> value(pairs->get(i + 1));
1028
1029 // We have to declare a global const property. To capture we only
1030 // assign to it when evaluating the assignment for "const x =
1031 // <expr>" the initial value is the hole.
1032 bool is_const_property = value->IsTheHole();
1033
1034 if (value->IsUndefined() || is_const_property) {
1035 // Lookup the property in the global object, and don't set the
1036 // value of the variable if the property is already there.
1037 LookupResult lookup;
1038 global->Lookup(*name, &lookup);
1039 if (lookup.IsProperty()) {
1040 // Determine if the property is local by comparing the holder
1041 // against the global object. The information will be used to
1042 // avoid throwing re-declaration errors when declaring
1043 // variables or constants that exist in the prototype chain.
1044 bool is_local = (*global == lookup.holder());
1045 // Get the property attributes and determine if the property is
1046 // read-only.
1047 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1048 bool is_read_only = (attributes & READ_ONLY) != 0;
1049 if (lookup.type() == INTERCEPTOR) {
1050 // If the interceptor says the property is there, we
1051 // just return undefined without overwriting the property.
1052 // Otherwise, we continue to setting the property.
1053 if (attributes != ABSENT) {
1054 // Check if the existing property conflicts with regards to const.
1055 if (is_local && (is_read_only || is_const_property)) {
1056 const char* type = (is_read_only) ? "const" : "var";
1057 return ThrowRedeclarationError(type, name);
1058 };
1059 // The property already exists without conflicting: Go to
1060 // the next declaration.
1061 continue;
1062 }
1063 // Fall-through and introduce the absent property by using
1064 // SetProperty.
1065 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001066 // For const properties, we treat a callback with this name
1067 // even in the prototype as a conflicting declaration.
1068 if (is_const_property && (lookup.type() == CALLBACKS)) {
1069 return ThrowRedeclarationError("const", name);
1070 }
1071 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072 if (is_local && (is_read_only || is_const_property)) {
1073 const char* type = (is_read_only) ? "const" : "var";
1074 return ThrowRedeclarationError(type, name);
1075 }
1076 // The property already exists without conflicting: Go to
1077 // the next declaration.
1078 continue;
1079 }
1080 }
1081 } else {
1082 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001083 Handle<SharedFunctionInfo> shared =
1084 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001086 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001087 value = function;
1088 }
1089
1090 LookupResult lookup;
1091 global->LocalLookup(*name, &lookup);
1092
1093 PropertyAttributes attributes = is_const_property
1094 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1095 : base;
1096
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001097 // There's a local property that we need to overwrite because
1098 // we're either declaring a function or there's an interceptor
1099 // that claims the property is absent.
1100 //
1101 // Check for conflicting re-declarations. We cannot have
1102 // conflicting types in case of intercepted properties because
1103 // they are absent.
1104 if (lookup.IsProperty() &&
1105 (lookup.type() != INTERCEPTOR) &&
1106 (lookup.IsReadOnly() || is_const_property)) {
1107 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
1108 return ThrowRedeclarationError(type, name);
1109 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001110
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001111 // Safari does not allow the invocation of callback setters for
1112 // function declarations. To mimic this behavior, we do not allow
1113 // the invocation of setters for function values. This makes a
1114 // difference for global functions with the same names as event
1115 // handlers such as "function onload() {}". Firefox does call the
1116 // onload setter in those case and Safari does not. We follow
1117 // Safari for compatibility.
1118 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001119 // Do not change DONT_DELETE to false from true.
1120 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1121 attributes = static_cast<PropertyAttributes>(
1122 attributes | (lookup.GetAttributes() & DONT_DELETE));
1123 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001124 RETURN_IF_EMPTY_HANDLE(SetLocalPropertyIgnoreAttributes(global,
1125 name,
1126 value,
1127 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001128 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001129 RETURN_IF_EMPTY_HANDLE(SetProperty(global,
1130 name,
1131 value,
1132 attributes,
1133 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 }
1135 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001136
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001137 ASSERT(!Top::has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138 return Heap::undefined_value();
1139}
1140
1141
lrn@chromium.org303ada72010-10-27 09:33:13 +00001142static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001143 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001144 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001145
ager@chromium.org7c537e22008-10-16 08:43:32 +00001146 CONVERT_ARG_CHECKED(Context, context, 0);
1147 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001149 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001150 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001151 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001152
1153 // Declarations are always done in the function context.
1154 context = Handle<Context>(context->fcontext());
1155
1156 int index;
1157 PropertyAttributes attributes;
1158 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001159 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001160 context->Lookup(name, flags, &index, &attributes);
1161
1162 if (attributes != ABSENT) {
1163 // The name was declared before; check for conflicting
1164 // re-declarations: This is similar to the code in parser.cc in
1165 // the AstBuildingParser::Declare function.
1166 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1167 // Functions are not read-only.
1168 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1169 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1170 return ThrowRedeclarationError(type, name);
1171 }
1172
1173 // Initialize it if necessary.
1174 if (*initial_value != NULL) {
1175 if (index >= 0) {
1176 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001177 // the function context or the arguments object.
1178 if (holder->IsContext()) {
1179 ASSERT(holder.is_identical_to(context));
1180 if (((attributes & READ_ONLY) == 0) ||
1181 context->get(index)->IsTheHole()) {
1182 context->set(index, *initial_value);
1183 }
1184 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001185 // The holder is an arguments object.
1186 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001187 Handle<Object> result = SetElement(arguments, index, initial_value);
1188 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189 }
1190 } else {
1191 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001192 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001193 RETURN_IF_EMPTY_HANDLE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001194 SetProperty(context_ext, name, initial_value,
1195 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001196 }
1197 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001199 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001200 // The property is not in the function context. It needs to be
1201 // "declared" in the function context's extension context, or in the
1202 // global context.
1203 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001204 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001205 // The function context's extension context exists - use it.
1206 context_ext = Handle<JSObject>(context->extension());
1207 } else {
1208 // The function context's extension context does not exists - allocate
1209 // it.
1210 context_ext = Factory::NewJSObject(Top::context_extension_function());
1211 // And store it in the extension slot.
1212 context->set_extension(*context_ext);
1213 }
1214 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215
ager@chromium.org7c537e22008-10-16 08:43:32 +00001216 // Declare the property by setting it to the initial value if provided,
1217 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1218 // constant declarations).
1219 ASSERT(!context_ext->HasLocalProperty(*name));
1220 Handle<Object> value(Heap::undefined_value());
1221 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001222 // Declaring a const context slot is a conflicting declaration if
1223 // there is a callback with that name in a prototype. It is
1224 // allowed to introduce const variables in
1225 // JSContextExtensionObjects. They are treated specially in
1226 // SetProperty and no setters are invoked for those since they are
1227 // not real JSObjects.
1228 if (initial_value->IsTheHole() &&
1229 !context_ext->IsJSContextExtensionObject()) {
1230 LookupResult lookup;
1231 context_ext->Lookup(*name, &lookup);
1232 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
1233 return ThrowRedeclarationError("const", name);
1234 }
1235 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001236 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode,
1237 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001238 }
1239
1240 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241}
1242
1243
lrn@chromium.org303ada72010-10-27 09:33:13 +00001244static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001246 // args[0] == name
1247 // args[1] == strict_mode
1248 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249
1250 // Determine if we need to assign to the variable if it already
1251 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001252 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1253 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254
1255 CONVERT_ARG_CHECKED(String, name, 0);
1256 GlobalObject* global = Top::context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001257 RUNTIME_ASSERT(args[1]->IsSmi());
1258 StrictModeFlag strict_mode =
1259 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1260 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261
1262 // According to ECMA-262, section 12.2, page 62, the property must
1263 // not be deletable.
1264 PropertyAttributes attributes = DONT_DELETE;
1265
1266 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001267 // there, there is a property with this name in the prototype chain.
1268 // We follow Safari and Firefox behavior and only set the property
1269 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001270 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001271 // Note that objects can have hidden prototypes, so we need to traverse
1272 // the whole chain of hidden prototypes to do a 'local' lookup.
1273 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001275 while (true) {
1276 real_holder->LocalLookup(*name, &lookup);
1277 if (lookup.IsProperty()) {
1278 // Determine if this is a redeclaration of something read-only.
1279 if (lookup.IsReadOnly()) {
1280 // If we found readonly property on one of hidden prototypes,
1281 // just shadow it.
1282 if (real_holder != Top::context()->global()) break;
1283 return ThrowRedeclarationError("const", name);
1284 }
1285
1286 // Determine if this is a redeclaration of an intercepted read-only
1287 // property and figure out if the property exists at all.
1288 bool found = true;
1289 PropertyType type = lookup.type();
1290 if (type == INTERCEPTOR) {
1291 HandleScope handle_scope;
1292 Handle<JSObject> holder(real_holder);
1293 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1294 real_holder = *holder;
1295 if (intercepted == ABSENT) {
1296 // The interceptor claims the property isn't there. We need to
1297 // make sure to introduce it.
1298 found = false;
1299 } else if ((intercepted & READ_ONLY) != 0) {
1300 // The property is present, but read-only. Since we're trying to
1301 // overwrite it with a variable declaration we must throw a
1302 // re-declaration error. However if we found readonly property
1303 // on one of hidden prototypes, just shadow it.
1304 if (real_holder != Top::context()->global()) break;
1305 return ThrowRedeclarationError("const", name);
1306 }
1307 }
1308
1309 if (found && !assign) {
1310 // The global property is there and we're not assigning any value
1311 // to it. Just return.
1312 return Heap::undefined_value();
1313 }
1314
1315 // Assign the value (or undefined) to the property.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001316 Object* value = (assign) ? args[2] : Heap::undefined_value();
1317 return real_holder->SetProperty(
1318 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001319 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001320
1321 Object* proto = real_holder->GetPrototype();
1322 if (!proto->IsJSObject())
1323 break;
1324
1325 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1326 break;
1327
1328 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 }
1330
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001331 global = Top::context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001332 if (assign) {
1333 return global->SetProperty(*name, args[2], attributes, strict_mode);
1334 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001335 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336}
1337
1338
lrn@chromium.org303ada72010-10-27 09:33:13 +00001339static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340 // All constants are declared with an initial value. The name
1341 // of the constant is the first argument and the initial value
1342 // is the second.
1343 RUNTIME_ASSERT(args.length() == 2);
1344 CONVERT_ARG_CHECKED(String, name, 0);
1345 Handle<Object> value = args.at<Object>(1);
1346
1347 // Get the current global object from top.
1348 GlobalObject* global = Top::context()->global();
1349
1350 // According to ECMA-262, section 12.2, page 62, the property must
1351 // not be deletable. Since it's a const, it must be READ_ONLY too.
1352 PropertyAttributes attributes =
1353 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1354
1355 // Lookup the property locally in the global object. If it isn't
1356 // there, we add the property and take special precautions to always
1357 // add it as a local property even in case of callbacks in the
1358 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001359 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360 LookupResult lookup;
1361 global->LocalLookup(*name, &lookup);
1362 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001363 return global->SetLocalPropertyIgnoreAttributes(*name,
1364 *value,
1365 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366 }
1367
1368 // Determine if this is a redeclaration of something not
1369 // read-only. In case the result is hidden behind an interceptor we
1370 // need to ask it for the property attributes.
1371 if (!lookup.IsReadOnly()) {
1372 if (lookup.type() != INTERCEPTOR) {
1373 return ThrowRedeclarationError("var", name);
1374 }
1375
1376 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1377
1378 // Throw re-declaration error if the intercepted property is present
1379 // but not read-only.
1380 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1381 return ThrowRedeclarationError("var", name);
1382 }
1383
1384 // Restore global object from context (in case of GC) and continue
1385 // with setting the value because the property is either absent or
1386 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001387 HandleScope handle_scope;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001388 Handle<GlobalObject> global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001390 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391 // property through an interceptor and only do it if it's
1392 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001393 // Passing non-strict mode because the property is writable.
1394 RETURN_IF_EMPTY_HANDLE(SetProperty(global,
1395 name,
1396 value,
1397 attributes,
1398 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 return *value;
1400 }
1401
1402 // Set the value, but only we're assigning the initial value to a
1403 // constant. For now, we determine this by checking if the
1404 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001405 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406 PropertyType type = lookup.type();
1407 if (type == FIELD) {
1408 FixedArray* properties = global->properties();
1409 int index = lookup.GetFieldIndex();
1410 if (properties->get(index)->IsTheHole()) {
1411 properties->set(index, *value);
1412 }
1413 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001414 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1415 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001416 }
1417 } else {
1418 // Ignore re-initialization of constants that have already been
1419 // assigned a function value.
1420 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1421 }
1422
1423 // Use the set value as the result of the operation.
1424 return *value;
1425}
1426
1427
lrn@chromium.org303ada72010-10-27 09:33:13 +00001428static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001429 HandleScope scope;
1430 ASSERT(args.length() == 3);
1431
1432 Handle<Object> value(args[0]);
1433 ASSERT(!value->IsTheHole());
1434 CONVERT_ARG_CHECKED(Context, context, 1);
1435 Handle<String> name(String::cast(args[2]));
1436
1437 // Initializations are always done in the function context.
1438 context = Handle<Context>(context->fcontext());
1439
1440 int index;
1441 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001442 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001443 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 context->Lookup(name, flags, &index, &attributes);
1445
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001446 // In most situations, the property introduced by the const
1447 // declaration should be present in the context extension object.
1448 // However, because declaration and initialization are separate, the
1449 // property might have been deleted (if it was introduced by eval)
1450 // before we reach the initialization point.
1451 //
1452 // Example:
1453 //
1454 // function f() { eval("delete x; const x;"); }
1455 //
1456 // In that case, the initialization behaves like a normal assignment
1457 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001459 // Property was found in a context.
1460 if (holder->IsContext()) {
1461 // The holder cannot be the function context. If it is, there
1462 // should have been a const redeclaration error when declaring
1463 // the const property.
1464 ASSERT(!holder.is_identical_to(context));
1465 if ((attributes & READ_ONLY) == 0) {
1466 Handle<Context>::cast(holder)->set(index, *value);
1467 }
1468 } else {
1469 // The holder is an arguments object.
1470 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001471 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1472 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473 }
1474 return *value;
1475 }
1476
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001477 // The property could not be found, we introduce it in the global
1478 // context.
1479 if (attributes == ABSENT) {
1480 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001481 // Strict mode not needed (const disallowed in strict mode).
1482 RETURN_IF_EMPTY_HANDLE(
1483 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001484 return *value;
1485 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001487 // The property was present in a context extension object.
1488 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001490 if (*context_ext == context->extension()) {
1491 // This is the property that was introduced by the const
1492 // declaration. Set it if it hasn't been set before. NOTE: We
1493 // cannot use GetProperty() to get the current value as it
1494 // 'unholes' the value.
1495 LookupResult lookup;
1496 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1497 ASSERT(lookup.IsProperty()); // the property was declared
1498 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1499
1500 PropertyType type = lookup.type();
1501 if (type == FIELD) {
1502 FixedArray* properties = context_ext->properties();
1503 int index = lookup.GetFieldIndex();
1504 if (properties->get(index)->IsTheHole()) {
1505 properties->set(index, *value);
1506 }
1507 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001508 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1509 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001510 }
1511 } else {
1512 // We should not reach here. Any real, named property should be
1513 // either a field or a dictionary slot.
1514 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 }
1516 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001517 // The property was found in a different context extension object.
1518 // Set it if it is not a read-only property.
1519 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001520 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001521 RETURN_IF_EMPTY_HANDLE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001522 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001523 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001525
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526 return *value;
1527}
1528
1529
lrn@chromium.org303ada72010-10-27 09:33:13 +00001530static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001531 Arguments args) {
1532 HandleScope scope;
1533 ASSERT(args.length() == 2);
1534 CONVERT_ARG_CHECKED(JSObject, object, 0);
1535 CONVERT_SMI_CHECKED(properties, args[1]);
1536 if (object->HasFastProperties()) {
1537 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1538 }
1539 return *object;
1540}
1541
1542
lrn@chromium.org303ada72010-10-27 09:33:13 +00001543static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001545 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001546 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1547 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001548 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001549 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001550 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001551 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001552 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001553 RUNTIME_ASSERT(index >= 0);
1554 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001555 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001556 Handle<Object> result = RegExpImpl::Exec(regexp,
1557 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001558 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001559 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001560 if (result.is_null()) return Failure::Exception();
1561 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562}
1563
1564
lrn@chromium.org303ada72010-10-27 09:33:13 +00001565static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001566 ASSERT(args.length() == 3);
1567 CONVERT_SMI_CHECKED(elements_count, args[0]);
1568 if (elements_count > JSArray::kMaxFastElementsLength) {
1569 return Top::ThrowIllegalOperation();
1570 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001571 Object* new_object;
1572 { MaybeObject* maybe_new_object =
1573 Heap::AllocateFixedArrayWithHoles(elements_count);
1574 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1575 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001576 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001577 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1578 NEW_SPACE,
1579 OLD_POINTER_SPACE);
1580 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1581 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001582 {
1583 AssertNoAllocation no_gc;
1584 HandleScope scope;
1585 reinterpret_cast<HeapObject*>(new_object)->
1586 set_map(Top::global_context()->regexp_result_map());
1587 }
1588 JSArray* array = JSArray::cast(new_object);
1589 array->set_properties(Heap::empty_fixed_array());
1590 array->set_elements(elements);
1591 array->set_length(Smi::FromInt(elements_count));
1592 // Write in-object properties after the length of the array.
1593 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1594 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1595 return array;
1596}
1597
1598
lrn@chromium.org303ada72010-10-27 09:33:13 +00001599static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001600 AssertNoAllocation no_alloc;
1601 ASSERT(args.length() == 5);
1602 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1603 CONVERT_CHECKED(String, source, args[1]);
1604
1605 Object* global = args[2];
1606 if (!global->IsTrue()) global = Heap::false_value();
1607
1608 Object* ignoreCase = args[3];
1609 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1610
1611 Object* multiline = args[4];
1612 if (!multiline->IsTrue()) multiline = Heap::false_value();
1613
1614 Map* map = regexp->map();
1615 Object* constructor = map->constructor();
1616 if (constructor->IsJSFunction() &&
1617 JSFunction::cast(constructor)->initial_map() == map) {
1618 // If we still have the original map, set in-object properties directly.
1619 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1620 // TODO(lrn): Consider skipping write barrier on booleans as well.
1621 // Both true and false should be in oldspace at all times.
1622 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1623 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1624 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1625 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1626 Smi::FromInt(0),
1627 SKIP_WRITE_BARRIER);
1628 return regexp;
1629 }
1630
lrn@chromium.org303ada72010-10-27 09:33:13 +00001631 // Map has changed, so use generic, but slower, method. Since these
1632 // properties were all added as DONT_DELETE they must be present and
1633 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001634 PropertyAttributes final =
1635 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1636 PropertyAttributes writable =
1637 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001638 MaybeObject* result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001639 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1640 source,
1641 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001642 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001643 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1644 global,
1645 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001646 ASSERT(!result->IsFailure());
1647 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001648 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1649 ignoreCase,
1650 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001651 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001652 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1653 multiline,
1654 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001655 ASSERT(!result->IsFailure());
1656 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001657 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1658 Smi::FromInt(0),
1659 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001660 ASSERT(!result->IsFailure());
1661 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001662 return regexp;
1663}
1664
1665
lrn@chromium.org303ada72010-10-27 09:33:13 +00001666static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001667 HandleScope scope;
1668 ASSERT(args.length() == 1);
1669 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1670 // This is necessary to enable fast checks for absence of elements
1671 // on Array.prototype and below.
1672 prototype->set_elements(Heap::empty_fixed_array());
1673 return Smi::FromInt(0);
1674}
1675
1676
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001677static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1678 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001679 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001680 Handle<String> key = Factory::LookupAsciiSymbol(name);
1681 Handle<Code> code(Builtins::builtin(builtin_name));
1682 Handle<JSFunction> optimized = Factory::NewFunction(key,
1683 JS_OBJECT_TYPE,
1684 JSObject::kHeaderSize,
1685 code,
1686 false);
1687 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001688 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001689 return optimized;
1690}
1691
1692
lrn@chromium.org303ada72010-10-27 09:33:13 +00001693static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001694 HandleScope scope;
1695 ASSERT(args.length() == 1);
1696 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1697
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001698 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1699 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001700 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1701 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1702 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1703 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001704 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001705
1706 return *holder;
1707}
1708
1709
lrn@chromium.org303ada72010-10-27 09:33:13 +00001710static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001711 // Returns a real global receiver, not one of builtins object.
1712 Context* global_context = Top::context()->global()->global_context();
1713 return global_context->global()->global_receiver();
1714}
1715
1716
lrn@chromium.org303ada72010-10-27 09:33:13 +00001717static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001718 HandleScope scope;
1719 ASSERT(args.length() == 4);
1720 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1721 int index = Smi::cast(args[1])->value();
1722 Handle<String> pattern = args.at<String>(2);
1723 Handle<String> flags = args.at<String>(3);
1724
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001725 // Get the RegExp function from the context in the literals array.
1726 // This is the RegExp function from the context in which the
1727 // function was created. We do not use the RegExp function from the
1728 // current global context because this might be the RegExp function
1729 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001730 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001731 Handle<JSFunction>(
1732 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 // Compute the regular expression literal.
1734 bool has_pending_exception;
1735 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001736 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1737 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001738 if (has_pending_exception) {
1739 ASSERT(Top::has_pending_exception());
1740 return Failure::Exception();
1741 }
1742 literals->set(index, *regexp);
1743 return *regexp;
1744}
1745
1746
lrn@chromium.org303ada72010-10-27 09:33:13 +00001747static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001748 NoHandleAllocation ha;
1749 ASSERT(args.length() == 1);
1750
1751 CONVERT_CHECKED(JSFunction, f, args[0]);
1752 return f->shared()->name();
1753}
1754
1755
lrn@chromium.org303ada72010-10-27 09:33:13 +00001756static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001757 NoHandleAllocation ha;
1758 ASSERT(args.length() == 2);
1759
1760 CONVERT_CHECKED(JSFunction, f, args[0]);
1761 CONVERT_CHECKED(String, name, args[1]);
1762 f->shared()->set_name(name);
1763 return Heap::undefined_value();
1764}
1765
1766
lrn@chromium.org303ada72010-10-27 09:33:13 +00001767static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001768 NoHandleAllocation ha;
1769 ASSERT(args.length() == 1);
1770
1771 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001772 Object* obj;
1773 { MaybeObject* maybe_obj = f->RemovePrototype();
1774 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1775 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001776
1777 return Heap::undefined_value();
1778}
1779
1780
lrn@chromium.org303ada72010-10-27 09:33:13 +00001781static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001782 HandleScope scope;
1783 ASSERT(args.length() == 1);
1784
1785 CONVERT_CHECKED(JSFunction, fun, args[0]);
1786 Handle<Object> script = Handle<Object>(fun->shared()->script());
1787 if (!script->IsScript()) return Heap::undefined_value();
1788
1789 return *GetScriptWrapper(Handle<Script>::cast(script));
1790}
1791
1792
lrn@chromium.org303ada72010-10-27 09:33:13 +00001793static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001794 NoHandleAllocation ha;
1795 ASSERT(args.length() == 1);
1796
1797 CONVERT_CHECKED(JSFunction, f, args[0]);
1798 return f->shared()->GetSourceCode();
1799}
1800
1801
lrn@chromium.org303ada72010-10-27 09:33:13 +00001802static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001803 NoHandleAllocation ha;
1804 ASSERT(args.length() == 1);
1805
1806 CONVERT_CHECKED(JSFunction, fun, args[0]);
1807 int pos = fun->shared()->start_position();
1808 return Smi::FromInt(pos);
1809}
1810
1811
lrn@chromium.org303ada72010-10-27 09:33:13 +00001812static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001813 ASSERT(args.length() == 2);
1814
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001815 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001816 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1817
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001818 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1819
1820 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001821 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001822}
1823
1824
1825
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827 NoHandleAllocation ha;
1828 ASSERT(args.length() == 2);
1829
1830 CONVERT_CHECKED(JSFunction, fun, args[0]);
1831 CONVERT_CHECKED(String, name, args[1]);
1832 fun->SetInstanceClassName(name);
1833 return Heap::undefined_value();
1834}
1835
1836
lrn@chromium.org303ada72010-10-27 09:33:13 +00001837static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001838 NoHandleAllocation ha;
1839 ASSERT(args.length() == 2);
1840
1841 CONVERT_CHECKED(JSFunction, fun, args[0]);
1842 CONVERT_CHECKED(Smi, length, args[1]);
1843 fun->shared()->set_length(length->value());
1844 return length;
1845}
1846
1847
lrn@chromium.org303ada72010-10-27 09:33:13 +00001848static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001849 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001850 ASSERT(args.length() == 2);
1851
1852 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001853 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001854 Object* obj;
1855 { MaybeObject* maybe_obj =
1856 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1857 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1858 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001859 return args[0]; // return TOS
1860}
1861
1862
lrn@chromium.org303ada72010-10-27 09:33:13 +00001863static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001864 NoHandleAllocation ha;
1865 ASSERT(args.length() == 1);
1866
1867 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001868 return f->shared()->IsApiFunction() ? Heap::true_value()
1869 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001870}
1871
lrn@chromium.org303ada72010-10-27 09:33:13 +00001872static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001873 NoHandleAllocation ha;
1874 ASSERT(args.length() == 1);
1875
1876 CONVERT_CHECKED(JSFunction, f, args[0]);
1877 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1878}
1879
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001880
lrn@chromium.org303ada72010-10-27 09:33:13 +00001881static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001882 HandleScope scope;
1883 ASSERT(args.length() == 2);
1884
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001885 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001886 Handle<Object> code = args.at<Object>(1);
1887
1888 Handle<Context> context(target->context());
1889
1890 if (!code->IsNull()) {
1891 RUNTIME_ASSERT(code->IsJSFunction());
1892 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001893 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001894
1895 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 return Failure::Exception();
1897 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001898 // Since we don't store the source for this we should never
1899 // optimize this.
1900 shared->code()->set_optimizable(false);
1901
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001902 // Set the code, scope info, formal parameter count,
1903 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001904 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001905 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001906 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001907 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001908 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001909 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001910 // Set the source code of the target function to undefined.
1911 // SetCode is only used for built-in constructors like String,
1912 // Array, and Object, and some web code
1913 // doesn't like seeing source code for constructors.
1914 target->shared()->set_script(Heap::undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001915 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001916 // Clear the optimization hints related to the compiled code as these are no
1917 // longer valid when the code is overwritten.
1918 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 context = Handle<Context>(fun->context());
1920
1921 // Make sure we get a fresh copy of the literal vector to avoid
1922 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001923 int number_of_literals = fun->NumberOfLiterals();
1924 Handle<FixedArray> literals =
1925 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001927 // Insert the object, regexp and array functions in the literals
1928 // array prefix. These are the functions that will be used when
1929 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001930 literals->set(JSFunction::kLiteralGlobalContextIndex,
1931 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001933 // It's okay to skip the write barrier here because the literals
1934 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001935 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001936 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001937 }
1938
1939 target->set_context(*context);
1940 return *target;
1941}
1942
1943
lrn@chromium.org303ada72010-10-27 09:33:13 +00001944static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001945 HandleScope scope;
1946 ASSERT(args.length() == 2);
1947 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1948 CONVERT_SMI_CHECKED(num, args[1]);
1949 RUNTIME_ASSERT(num >= 0);
1950 SetExpectedNofProperties(function, num);
1951 return Heap::undefined_value();
1952}
1953
1954
lrn@chromium.org303ada72010-10-27 09:33:13 +00001955MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001956 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001957 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001958 if (code <= 0xffff) {
1959 return Heap::LookupSingleCharacterStringFromCode(code);
1960 }
1961 }
1962 return Heap::empty_string();
1963}
1964
1965
lrn@chromium.org303ada72010-10-27 09:33:13 +00001966static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 2);
1969
1970 CONVERT_CHECKED(String, subject, args[0]);
1971 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001972 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001973
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001974 uint32_t i = 0;
1975 if (index->IsSmi()) {
1976 int value = Smi::cast(index)->value();
1977 if (value < 0) return Heap::nan_value();
1978 i = value;
1979 } else {
1980 ASSERT(index->IsHeapNumber());
1981 double value = HeapNumber::cast(index)->value();
1982 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001983 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001984
1985 // Flatten the string. If someone wants to get a char at an index
1986 // in a cons string, it is likely that more indices will be
1987 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001988 Object* flat;
1989 { MaybeObject* maybe_flat = subject->TryFlatten();
1990 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1991 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001992 subject = String::cast(flat);
1993
1994 if (i >= static_cast<uint32_t>(subject->length())) {
1995 return Heap::nan_value();
1996 }
1997
1998 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001999}
2000
2001
lrn@chromium.org303ada72010-10-27 09:33:13 +00002002static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002003 NoHandleAllocation ha;
2004 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002005 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002006}
2007
lrn@chromium.org25156de2010-04-06 13:10:27 +00002008
2009class FixedArrayBuilder {
2010 public:
2011 explicit FixedArrayBuilder(int initial_capacity)
2012 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
2013 length_(0) {
2014 // Require a non-zero initial size. Ensures that doubling the size to
2015 // extend the array will work.
2016 ASSERT(initial_capacity > 0);
2017 }
2018
2019 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2020 : array_(backing_store),
2021 length_(0) {
2022 // Require a non-zero initial size. Ensures that doubling the size to
2023 // extend the array will work.
2024 ASSERT(backing_store->length() > 0);
2025 }
2026
2027 bool HasCapacity(int elements) {
2028 int length = array_->length();
2029 int required_length = length_ + elements;
2030 return (length >= required_length);
2031 }
2032
2033 void EnsureCapacity(int elements) {
2034 int length = array_->length();
2035 int required_length = length_ + elements;
2036 if (length < required_length) {
2037 int new_length = length;
2038 do {
2039 new_length *= 2;
2040 } while (new_length < required_length);
2041 Handle<FixedArray> extended_array =
2042 Factory::NewFixedArrayWithHoles(new_length);
2043 array_->CopyTo(0, *extended_array, 0, length_);
2044 array_ = extended_array;
2045 }
2046 }
2047
2048 void Add(Object* value) {
2049 ASSERT(length_ < capacity());
2050 array_->set(length_, value);
2051 length_++;
2052 }
2053
2054 void Add(Smi* value) {
2055 ASSERT(length_ < capacity());
2056 array_->set(length_, value);
2057 length_++;
2058 }
2059
2060 Handle<FixedArray> array() {
2061 return array_;
2062 }
2063
2064 int length() {
2065 return length_;
2066 }
2067
2068 int capacity() {
2069 return array_->length();
2070 }
2071
2072 Handle<JSArray> ToJSArray() {
2073 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
2074 result_array->set_length(Smi::FromInt(length_));
2075 return result_array;
2076 }
2077
2078 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2079 target_array->set_elements(*array_);
2080 target_array->set_length(Smi::FromInt(length_));
2081 return target_array;
2082 }
2083
2084 private:
2085 Handle<FixedArray> array_;
2086 int length_;
2087};
2088
2089
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002090// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002091const int kStringBuilderConcatHelperLengthBits = 11;
2092const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002093
2094template <typename schar>
2095static inline void StringBuilderConcatHelper(String*,
2096 schar*,
2097 FixedArray*,
2098 int);
2099
lrn@chromium.org25156de2010-04-06 13:10:27 +00002100typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2101 StringBuilderSubstringLength;
2102typedef BitField<int,
2103 kStringBuilderConcatHelperLengthBits,
2104 kStringBuilderConcatHelperPositionBits>
2105 StringBuilderSubstringPosition;
2106
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002107
2108class ReplacementStringBuilder {
2109 public:
2110 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00002111 : array_builder_(estimated_part_count),
2112 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002113 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002114 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002115 // Require a non-zero initial size. Ensures that doubling the size to
2116 // extend the array will work.
2117 ASSERT(estimated_part_count > 0);
2118 }
2119
lrn@chromium.org25156de2010-04-06 13:10:27 +00002120 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2121 int from,
2122 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002123 ASSERT(from >= 0);
2124 int length = to - from;
2125 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002126 if (StringBuilderSubstringLength::is_valid(length) &&
2127 StringBuilderSubstringPosition::is_valid(from)) {
2128 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2129 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002130 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002131 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002132 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002133 builder->Add(Smi::FromInt(-length));
2134 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002135 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002136 }
2137
2138
2139 void EnsureCapacity(int elements) {
2140 array_builder_.EnsureCapacity(elements);
2141 }
2142
2143
2144 void AddSubjectSlice(int from, int to) {
2145 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002146 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002147 }
2148
2149
2150 void AddString(Handle<String> string) {
2151 int length = string->length();
2152 ASSERT(length > 0);
2153 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002154 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002155 is_ascii_ = false;
2156 }
2157 IncrementCharacterCount(length);
2158 }
2159
2160
2161 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002162 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002163 return Factory::empty_string();
2164 }
2165
2166 Handle<String> joined_string;
2167 if (is_ascii_) {
2168 joined_string = NewRawAsciiString(character_count_);
2169 AssertNoAllocation no_alloc;
2170 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2171 char* char_buffer = seq->GetChars();
2172 StringBuilderConcatHelper(*subject_,
2173 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002174 *array_builder_.array(),
2175 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002176 } else {
2177 // Non-ASCII.
2178 joined_string = NewRawTwoByteString(character_count_);
2179 AssertNoAllocation no_alloc;
2180 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2181 uc16* char_buffer = seq->GetChars();
2182 StringBuilderConcatHelper(*subject_,
2183 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002184 *array_builder_.array(),
2185 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002186 }
2187 return joined_string;
2188 }
2189
2190
2191 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002192 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002193 V8::FatalProcessOutOfMemory("String.replace result too large.");
2194 }
2195 character_count_ += by;
2196 }
2197
lrn@chromium.org25156de2010-04-06 13:10:27 +00002198 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002199 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002200 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002201
lrn@chromium.org25156de2010-04-06 13:10:27 +00002202 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002203 Handle<String> NewRawAsciiString(int size) {
2204 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2205 }
2206
2207
2208 Handle<String> NewRawTwoByteString(int size) {
2209 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2210 }
2211
2212
2213 void AddElement(Object* element) {
2214 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002215 ASSERT(array_builder_.capacity() > array_builder_.length());
2216 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002217 }
2218
lrn@chromium.org25156de2010-04-06 13:10:27 +00002219 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002220 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002221 int character_count_;
2222 bool is_ascii_;
2223};
2224
2225
2226class CompiledReplacement {
2227 public:
2228 CompiledReplacement()
2229 : parts_(1), replacement_substrings_(0) {}
2230
2231 void Compile(Handle<String> replacement,
2232 int capture_count,
2233 int subject_length);
2234
2235 void Apply(ReplacementStringBuilder* builder,
2236 int match_from,
2237 int match_to,
2238 Handle<JSArray> last_match_info);
2239
2240 // Number of distinct parts of the replacement pattern.
2241 int parts() {
2242 return parts_.length();
2243 }
2244 private:
2245 enum PartType {
2246 SUBJECT_PREFIX = 1,
2247 SUBJECT_SUFFIX,
2248 SUBJECT_CAPTURE,
2249 REPLACEMENT_SUBSTRING,
2250 REPLACEMENT_STRING,
2251
2252 NUMBER_OF_PART_TYPES
2253 };
2254
2255 struct ReplacementPart {
2256 static inline ReplacementPart SubjectMatch() {
2257 return ReplacementPart(SUBJECT_CAPTURE, 0);
2258 }
2259 static inline ReplacementPart SubjectCapture(int capture_index) {
2260 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2261 }
2262 static inline ReplacementPart SubjectPrefix() {
2263 return ReplacementPart(SUBJECT_PREFIX, 0);
2264 }
2265 static inline ReplacementPart SubjectSuffix(int subject_length) {
2266 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2267 }
2268 static inline ReplacementPart ReplacementString() {
2269 return ReplacementPart(REPLACEMENT_STRING, 0);
2270 }
2271 static inline ReplacementPart ReplacementSubString(int from, int to) {
2272 ASSERT(from >= 0);
2273 ASSERT(to > from);
2274 return ReplacementPart(-from, to);
2275 }
2276
2277 // If tag <= 0 then it is the negation of a start index of a substring of
2278 // the replacement pattern, otherwise it's a value from PartType.
2279 ReplacementPart(int tag, int data)
2280 : tag(tag), data(data) {
2281 // Must be non-positive or a PartType value.
2282 ASSERT(tag < NUMBER_OF_PART_TYPES);
2283 }
2284 // Either a value of PartType or a non-positive number that is
2285 // the negation of an index into the replacement string.
2286 int tag;
2287 // The data value's interpretation depends on the value of tag:
2288 // tag == SUBJECT_PREFIX ||
2289 // tag == SUBJECT_SUFFIX: data is unused.
2290 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2291 // tag == REPLACEMENT_SUBSTRING ||
2292 // tag == REPLACEMENT_STRING: data is index into array of substrings
2293 // of the replacement string.
2294 // tag <= 0: Temporary representation of the substring of the replacement
2295 // string ranging over -tag .. data.
2296 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2297 // substring objects.
2298 int data;
2299 };
2300
2301 template<typename Char>
2302 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2303 Vector<Char> characters,
2304 int capture_count,
2305 int subject_length) {
2306 int length = characters.length();
2307 int last = 0;
2308 for (int i = 0; i < length; i++) {
2309 Char c = characters[i];
2310 if (c == '$') {
2311 int next_index = i + 1;
2312 if (next_index == length) { // No next character!
2313 break;
2314 }
2315 Char c2 = characters[next_index];
2316 switch (c2) {
2317 case '$':
2318 if (i > last) {
2319 // There is a substring before. Include the first "$".
2320 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2321 last = next_index + 1; // Continue after the second "$".
2322 } else {
2323 // Let the next substring start with the second "$".
2324 last = next_index;
2325 }
2326 i = next_index;
2327 break;
2328 case '`':
2329 if (i > last) {
2330 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2331 }
2332 parts->Add(ReplacementPart::SubjectPrefix());
2333 i = next_index;
2334 last = i + 1;
2335 break;
2336 case '\'':
2337 if (i > last) {
2338 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2339 }
2340 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2341 i = next_index;
2342 last = i + 1;
2343 break;
2344 case '&':
2345 if (i > last) {
2346 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2347 }
2348 parts->Add(ReplacementPart::SubjectMatch());
2349 i = next_index;
2350 last = i + 1;
2351 break;
2352 case '0':
2353 case '1':
2354 case '2':
2355 case '3':
2356 case '4':
2357 case '5':
2358 case '6':
2359 case '7':
2360 case '8':
2361 case '9': {
2362 int capture_ref = c2 - '0';
2363 if (capture_ref > capture_count) {
2364 i = next_index;
2365 continue;
2366 }
2367 int second_digit_index = next_index + 1;
2368 if (second_digit_index < length) {
2369 // Peek ahead to see if we have two digits.
2370 Char c3 = characters[second_digit_index];
2371 if ('0' <= c3 && c3 <= '9') { // Double digits.
2372 int double_digit_ref = capture_ref * 10 + c3 - '0';
2373 if (double_digit_ref <= capture_count) {
2374 next_index = second_digit_index;
2375 capture_ref = double_digit_ref;
2376 }
2377 }
2378 }
2379 if (capture_ref > 0) {
2380 if (i > last) {
2381 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2382 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002383 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002384 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2385 last = next_index + 1;
2386 }
2387 i = next_index;
2388 break;
2389 }
2390 default:
2391 i = next_index;
2392 break;
2393 }
2394 }
2395 }
2396 if (length > last) {
2397 if (last == 0) {
2398 parts->Add(ReplacementPart::ReplacementString());
2399 } else {
2400 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2401 }
2402 }
2403 }
2404
2405 ZoneList<ReplacementPart> parts_;
2406 ZoneList<Handle<String> > replacement_substrings_;
2407};
2408
2409
2410void CompiledReplacement::Compile(Handle<String> replacement,
2411 int capture_count,
2412 int subject_length) {
2413 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002414 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 AssertNoAllocation no_alloc;
2416 ParseReplacementPattern(&parts_,
2417 replacement->ToAsciiVector(),
2418 capture_count,
2419 subject_length);
2420 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002421 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002422 AssertNoAllocation no_alloc;
2423
2424 ParseReplacementPattern(&parts_,
2425 replacement->ToUC16Vector(),
2426 capture_count,
2427 subject_length);
2428 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002429 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002430 int substring_index = 0;
2431 for (int i = 0, n = parts_.length(); i < n; i++) {
2432 int tag = parts_[i].tag;
2433 if (tag <= 0) { // A replacement string slice.
2434 int from = -tag;
2435 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002436 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002437 parts_[i].tag = REPLACEMENT_SUBSTRING;
2438 parts_[i].data = substring_index;
2439 substring_index++;
2440 } else if (tag == REPLACEMENT_STRING) {
2441 replacement_substrings_.Add(replacement);
2442 parts_[i].data = substring_index;
2443 substring_index++;
2444 }
2445 }
2446}
2447
2448
2449void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2450 int match_from,
2451 int match_to,
2452 Handle<JSArray> last_match_info) {
2453 for (int i = 0, n = parts_.length(); i < n; i++) {
2454 ReplacementPart part = parts_[i];
2455 switch (part.tag) {
2456 case SUBJECT_PREFIX:
2457 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2458 break;
2459 case SUBJECT_SUFFIX: {
2460 int subject_length = part.data;
2461 if (match_to < subject_length) {
2462 builder->AddSubjectSlice(match_to, subject_length);
2463 }
2464 break;
2465 }
2466 case SUBJECT_CAPTURE: {
2467 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002468 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002469 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2470 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2471 if (from >= 0 && to > from) {
2472 builder->AddSubjectSlice(from, to);
2473 }
2474 break;
2475 }
2476 case REPLACEMENT_SUBSTRING:
2477 case REPLACEMENT_STRING:
2478 builder->AddString(replacement_substrings_[part.data]);
2479 break;
2480 default:
2481 UNREACHABLE();
2482 }
2483 }
2484}
2485
2486
2487
lrn@chromium.org303ada72010-10-27 09:33:13 +00002488MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2489 String* subject,
2490 JSRegExp* regexp,
2491 String* replacement,
2492 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002493 ASSERT(subject->IsFlat());
2494 ASSERT(replacement->IsFlat());
2495
2496 HandleScope handles;
2497
2498 int length = subject->length();
2499 Handle<String> subject_handle(subject);
2500 Handle<JSRegExp> regexp_handle(regexp);
2501 Handle<String> replacement_handle(replacement);
2502 Handle<JSArray> last_match_info_handle(last_match_info);
2503 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2504 subject_handle,
2505 0,
2506 last_match_info_handle);
2507 if (match.is_null()) {
2508 return Failure::Exception();
2509 }
2510 if (match->IsNull()) {
2511 return *subject_handle;
2512 }
2513
2514 int capture_count = regexp_handle->CaptureCount();
2515
2516 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002517 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002518 CompiledReplacement compiled_replacement;
2519 compiled_replacement.Compile(replacement_handle,
2520 capture_count,
2521 length);
2522
2523 bool is_global = regexp_handle->GetFlags().is_global();
2524
2525 // Guessing the number of parts that the final result string is built
2526 // from. Global regexps can match any number of times, so we guess
2527 // conservatively.
2528 int expected_parts =
2529 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2530 ReplacementStringBuilder builder(subject_handle, expected_parts);
2531
2532 // Index of end of last match.
2533 int prev = 0;
2534
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002535 // Number of parts added by compiled replacement plus preceeding
2536 // string and possibly suffix after last match. It is possible for
2537 // all components to use two elements when encoded as two smis.
2538 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002539 bool matched = true;
2540 do {
2541 ASSERT(last_match_info_handle->HasFastElements());
2542 // Increase the capacity of the builder before entering local handle-scope,
2543 // so its internal buffer can safely allocate a new handle if it grows.
2544 builder.EnsureCapacity(parts_added_per_loop);
2545
2546 HandleScope loop_scope;
2547 int start, end;
2548 {
2549 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002550 FixedArray* match_info_array =
2551 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002552
2553 ASSERT_EQ(capture_count * 2 + 2,
2554 RegExpImpl::GetLastCaptureCount(match_info_array));
2555 start = RegExpImpl::GetCapture(match_info_array, 0);
2556 end = RegExpImpl::GetCapture(match_info_array, 1);
2557 }
2558
2559 if (prev < start) {
2560 builder.AddSubjectSlice(prev, start);
2561 }
2562 compiled_replacement.Apply(&builder,
2563 start,
2564 end,
2565 last_match_info_handle);
2566 prev = end;
2567
2568 // Only continue checking for global regexps.
2569 if (!is_global) break;
2570
2571 // Continue from where the match ended, unless it was an empty match.
2572 int next = end;
2573 if (start == end) {
2574 next = end + 1;
2575 if (next > length) break;
2576 }
2577
2578 match = RegExpImpl::Exec(regexp_handle,
2579 subject_handle,
2580 next,
2581 last_match_info_handle);
2582 if (match.is_null()) {
2583 return Failure::Exception();
2584 }
2585 matched = !match->IsNull();
2586 } while (matched);
2587
2588 if (prev < length) {
2589 builder.AddSubjectSlice(prev, length);
2590 }
2591
2592 return *(builder.ToString());
2593}
2594
2595
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002596template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002597MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2598 String* subject,
2599 JSRegExp* regexp,
2600 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002601 ASSERT(subject->IsFlat());
2602
2603 HandleScope handles;
2604
2605 Handle<String> subject_handle(subject);
2606 Handle<JSRegExp> regexp_handle(regexp);
2607 Handle<JSArray> last_match_info_handle(last_match_info);
2608 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2609 subject_handle,
2610 0,
2611 last_match_info_handle);
2612 if (match.is_null()) return Failure::Exception();
2613 if (match->IsNull()) return *subject_handle;
2614
2615 ASSERT(last_match_info_handle->HasFastElements());
2616
2617 HandleScope loop_scope;
2618 int start, end;
2619 {
2620 AssertNoAllocation match_info_array_is_not_in_a_handle;
2621 FixedArray* match_info_array =
2622 FixedArray::cast(last_match_info_handle->elements());
2623
2624 start = RegExpImpl::GetCapture(match_info_array, 0);
2625 end = RegExpImpl::GetCapture(match_info_array, 1);
2626 }
2627
2628 int length = subject->length();
2629 int new_length = length - (end - start);
2630 if (new_length == 0) {
2631 return Heap::empty_string();
2632 }
2633 Handle<ResultSeqString> answer;
2634 if (ResultSeqString::kHasAsciiEncoding) {
2635 answer =
2636 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2637 } else {
2638 answer =
2639 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2640 }
2641
2642 // If the regexp isn't global, only match once.
2643 if (!regexp_handle->GetFlags().is_global()) {
2644 if (start > 0) {
2645 String::WriteToFlat(*subject_handle,
2646 answer->GetChars(),
2647 0,
2648 start);
2649 }
2650 if (end < length) {
2651 String::WriteToFlat(*subject_handle,
2652 answer->GetChars() + start,
2653 end,
2654 length);
2655 }
2656 return *answer;
2657 }
2658
2659 int prev = 0; // Index of end of last match.
2660 int next = 0; // Start of next search (prev unless last match was empty).
2661 int position = 0;
2662
2663 do {
2664 if (prev < start) {
2665 // Add substring subject[prev;start] to answer string.
2666 String::WriteToFlat(*subject_handle,
2667 answer->GetChars() + position,
2668 prev,
2669 start);
2670 position += start - prev;
2671 }
2672 prev = end;
2673 next = end;
2674 // Continue from where the match ended, unless it was an empty match.
2675 if (start == end) {
2676 next++;
2677 if (next > length) break;
2678 }
2679 match = RegExpImpl::Exec(regexp_handle,
2680 subject_handle,
2681 next,
2682 last_match_info_handle);
2683 if (match.is_null()) return Failure::Exception();
2684 if (match->IsNull()) break;
2685
2686 ASSERT(last_match_info_handle->HasFastElements());
2687 HandleScope loop_scope;
2688 {
2689 AssertNoAllocation match_info_array_is_not_in_a_handle;
2690 FixedArray* match_info_array =
2691 FixedArray::cast(last_match_info_handle->elements());
2692 start = RegExpImpl::GetCapture(match_info_array, 0);
2693 end = RegExpImpl::GetCapture(match_info_array, 1);
2694 }
2695 } while (true);
2696
2697 if (prev < length) {
2698 // Add substring subject[prev;length] to answer string.
2699 String::WriteToFlat(*subject_handle,
2700 answer->GetChars() + position,
2701 prev,
2702 length);
2703 position += length - prev;
2704 }
2705
2706 if (position == 0) {
2707 return Heap::empty_string();
2708 }
2709
2710 // Shorten string and fill
2711 int string_size = ResultSeqString::SizeFor(position);
2712 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2713 int delta = allocated_string_size - string_size;
2714
2715 answer->set_length(position);
2716 if (delta == 0) return *answer;
2717
2718 Address end_of_string = answer->address() + string_size;
2719 Heap::CreateFillerObjectAt(end_of_string, delta);
2720
2721 return *answer;
2722}
2723
2724
lrn@chromium.org303ada72010-10-27 09:33:13 +00002725static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002726 ASSERT(args.length() == 4);
2727
2728 CONVERT_CHECKED(String, subject, args[0]);
2729 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002730 Object* flat_subject;
2731 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2732 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2733 return maybe_flat_subject;
2734 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002735 }
2736 subject = String::cast(flat_subject);
2737 }
2738
2739 CONVERT_CHECKED(String, replacement, args[2]);
2740 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002741 Object* flat_replacement;
2742 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2743 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2744 return maybe_flat_replacement;
2745 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002746 }
2747 replacement = String::cast(flat_replacement);
2748 }
2749
2750 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2751 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2752
2753 ASSERT(last_match_info->HasFastElements());
2754
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002755 if (replacement->length() == 0) {
2756 if (subject->HasOnlyAsciiChars()) {
2757 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2758 subject, regexp, last_match_info);
2759 } else {
2760 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2761 subject, regexp, last_match_info);
2762 }
2763 }
2764
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002765 return StringReplaceRegExpWithString(subject,
2766 regexp,
2767 replacement,
2768 last_match_info);
2769}
2770
2771
ager@chromium.org7c537e22008-10-16 08:43:32 +00002772// Perform string match of pattern on subject, starting at start index.
2773// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002774// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002775int Runtime::StringMatch(Handle<String> sub,
2776 Handle<String> pat,
2777 int start_index) {
2778 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002779 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002780
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002781 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002782 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002783
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002784 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002785 if (start_index + pattern_length > subject_length) return -1;
2786
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002787 if (!sub->IsFlat()) FlattenString(sub);
2788 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002789
ager@chromium.org7c537e22008-10-16 08:43:32 +00002790 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002791 // Extract flattened substrings of cons strings before determining asciiness.
2792 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002793 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002794 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002795 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002796
ager@chromium.org7c537e22008-10-16 08:43:32 +00002797 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002798 if (seq_pat->IsAsciiRepresentation()) {
2799 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2800 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002801 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002802 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002803 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002804 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002805 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2806 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002807 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002808 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002809 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002810}
2811
2812
lrn@chromium.org303ada72010-10-27 09:33:13 +00002813static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002814 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002815 ASSERT(args.length() == 3);
2816
ager@chromium.org7c537e22008-10-16 08:43:32 +00002817 CONVERT_ARG_CHECKED(String, sub, 0);
2818 CONVERT_ARG_CHECKED(String, pat, 1);
2819
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002820 Object* index = args[2];
2821 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002822 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002823
ager@chromium.org870a0b62008-11-04 11:43:05 +00002824 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002825 int position = Runtime::StringMatch(sub, pat, start_index);
2826 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002827}
2828
2829
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002830template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002831static int StringMatchBackwards(Vector<const schar> subject,
2832 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002833 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002834 int pattern_length = pattern.length();
2835 ASSERT(pattern_length >= 1);
2836 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002837
2838 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002839 for (int i = 0; i < pattern_length; i++) {
2840 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002841 if (c > String::kMaxAsciiCharCode) {
2842 return -1;
2843 }
2844 }
2845 }
2846
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002847 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002848 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002849 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002850 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002851 while (j < pattern_length) {
2852 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002853 break;
2854 }
2855 j++;
2856 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002857 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002858 return i;
2859 }
2860 }
2861 return -1;
2862}
2863
lrn@chromium.org303ada72010-10-27 09:33:13 +00002864static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002865 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002866 ASSERT(args.length() == 3);
2867
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002868 CONVERT_ARG_CHECKED(String, sub, 0);
2869 CONVERT_ARG_CHECKED(String, pat, 1);
2870
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002871 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002872 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002873 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002874
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002875 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002876 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002877
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002878 if (start_index + pat_length > sub_length) {
2879 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002880 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002881
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002882 if (pat_length == 0) {
2883 return Smi::FromInt(start_index);
2884 }
2885
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002886 if (!sub->IsFlat()) FlattenString(sub);
2887 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002888
2889 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2890
2891 int position = -1;
2892
2893 if (pat->IsAsciiRepresentation()) {
2894 Vector<const char> pat_vector = pat->ToAsciiVector();
2895 if (sub->IsAsciiRepresentation()) {
2896 position = StringMatchBackwards(sub->ToAsciiVector(),
2897 pat_vector,
2898 start_index);
2899 } else {
2900 position = StringMatchBackwards(sub->ToUC16Vector(),
2901 pat_vector,
2902 start_index);
2903 }
2904 } else {
2905 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2906 if (sub->IsAsciiRepresentation()) {
2907 position = StringMatchBackwards(sub->ToAsciiVector(),
2908 pat_vector,
2909 start_index);
2910 } else {
2911 position = StringMatchBackwards(sub->ToUC16Vector(),
2912 pat_vector,
2913 start_index);
2914 }
2915 }
2916
2917 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002918}
2919
2920
lrn@chromium.org303ada72010-10-27 09:33:13 +00002921static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002922 NoHandleAllocation ha;
2923 ASSERT(args.length() == 2);
2924
2925 CONVERT_CHECKED(String, str1, args[0]);
2926 CONVERT_CHECKED(String, str2, args[1]);
2927
2928 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002929 int str1_length = str1->length();
2930 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002931
2932 // Decide trivial cases without flattening.
2933 if (str1_length == 0) {
2934 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2935 return Smi::FromInt(-str2_length);
2936 } else {
2937 if (str2_length == 0) return Smi::FromInt(str1_length);
2938 }
2939
2940 int end = str1_length < str2_length ? str1_length : str2_length;
2941
2942 // No need to flatten if we are going to find the answer on the first
2943 // character. At this point we know there is at least one character
2944 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002945 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002946 if (d != 0) return Smi::FromInt(d);
2947
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002948 str1->TryFlatten();
2949 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002950
2951 static StringInputBuffer buf1;
2952 static StringInputBuffer buf2;
2953
2954 buf1.Reset(str1);
2955 buf2.Reset(str2);
2956
2957 for (int i = 0; i < end; i++) {
2958 uint16_t char1 = buf1.GetNext();
2959 uint16_t char2 = buf2.GetNext();
2960 if (char1 != char2) return Smi::FromInt(char1 - char2);
2961 }
2962
2963 return Smi::FromInt(str1_length - str2_length);
2964}
2965
2966
lrn@chromium.org303ada72010-10-27 09:33:13 +00002967static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002968 NoHandleAllocation ha;
2969 ASSERT(args.length() == 3);
2970
2971 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002972 Object* from = args[1];
2973 Object* to = args[2];
2974 int start, end;
2975 // We have a fast integer-only case here to avoid a conversion to double in
2976 // the common case where from and to are Smis.
2977 if (from->IsSmi() && to->IsSmi()) {
2978 start = Smi::cast(from)->value();
2979 end = Smi::cast(to)->value();
2980 } else {
2981 CONVERT_DOUBLE_CHECKED(from_number, from);
2982 CONVERT_DOUBLE_CHECKED(to_number, to);
2983 start = FastD2I(from_number);
2984 end = FastD2I(to_number);
2985 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002986 RUNTIME_ASSERT(end >= start);
2987 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002988 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002989 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002990 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002991}
2992
2993
lrn@chromium.org303ada72010-10-27 09:33:13 +00002994static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002995 ASSERT_EQ(3, args.length());
2996
2997 CONVERT_ARG_CHECKED(String, subject, 0);
2998 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2999 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3000 HandleScope handles;
3001
3002 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3003
3004 if (match.is_null()) {
3005 return Failure::Exception();
3006 }
3007 if (match->IsNull()) {
3008 return Heap::null_value();
3009 }
3010 int length = subject->length();
3011
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003012 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003013 ZoneList<int> offsets(8);
3014 do {
3015 int start;
3016 int end;
3017 {
3018 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003019 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003020 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3021 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3022 }
3023 offsets.Add(start);
3024 offsets.Add(end);
3025 int index = start < end ? end : end + 1;
3026 if (index > length) break;
3027 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3028 if (match.is_null()) {
3029 return Failure::Exception();
3030 }
3031 } while (!match->IsNull());
3032 int matches = offsets.length() / 2;
3033 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
3034 for (int i = 0; i < matches ; i++) {
3035 int from = offsets.at(i * 2);
3036 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003037 Handle<String> match = Factory::NewSubString(subject, from, to);
3038 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003039 }
3040 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
3041 result->set_length(Smi::FromInt(matches));
3042 return *result;
3043}
3044
3045
lrn@chromium.org25156de2010-04-06 13:10:27 +00003046// Two smis before and after the match, for very long strings.
3047const int kMaxBuilderEntriesPerRegExpMatch = 5;
3048
3049
3050static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3051 Handle<JSArray> last_match_info,
3052 int match_start,
3053 int match_end) {
3054 // Fill last_match_info with a single capture.
3055 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3056 AssertNoAllocation no_gc;
3057 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3058 RegExpImpl::SetLastCaptureCount(elements, 2);
3059 RegExpImpl::SetLastInput(elements, *subject);
3060 RegExpImpl::SetLastSubject(elements, *subject);
3061 RegExpImpl::SetCapture(elements, 0, match_start);
3062 RegExpImpl::SetCapture(elements, 1, match_end);
3063}
3064
3065
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003066template <typename SubjectChar, typename PatternChar>
3067static bool SearchStringMultiple(Vector<const SubjectChar> subject,
3068 Vector<const PatternChar> pattern,
3069 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003070 FixedArrayBuilder* builder,
3071 int* match_pos) {
3072 int pos = *match_pos;
3073 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003074 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003075 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003076 StringSearch<PatternChar, SubjectChar> search(pattern);
3077 while (pos <= max_search_start) {
3078 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3079 *match_pos = pos;
3080 return false;
3081 }
3082 // Position of end of previous match.
3083 int match_end = pos + pattern_length;
3084 int new_pos = search.Search(subject, match_end);
3085 if (new_pos >= 0) {
3086 // A match.
3087 if (new_pos > match_end) {
3088 ReplacementStringBuilder::AddSubjectSlice(builder,
3089 match_end,
3090 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003091 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003092 pos = new_pos;
3093 builder->Add(pattern_string);
3094 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003095 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003096 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003097 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003098
lrn@chromium.org25156de2010-04-06 13:10:27 +00003099 if (pos < max_search_start) {
3100 ReplacementStringBuilder::AddSubjectSlice(builder,
3101 pos + pattern_length,
3102 subject_length);
3103 }
3104 *match_pos = pos;
3105 return true;
3106}
3107
3108
3109static bool SearchStringMultiple(Handle<String> subject,
3110 Handle<String> pattern,
3111 Handle<JSArray> last_match_info,
3112 FixedArrayBuilder* builder) {
3113 ASSERT(subject->IsFlat());
3114 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003115
3116 // Treating as if a previous match was before first character.
3117 int match_pos = -pattern->length();
3118
3119 for (;;) { // Break when search complete.
3120 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3121 AssertNoAllocation no_gc;
3122 if (subject->IsAsciiRepresentation()) {
3123 Vector<const char> subject_vector = subject->ToAsciiVector();
3124 if (pattern->IsAsciiRepresentation()) {
3125 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003126 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003127 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003128 builder,
3129 &match_pos)) break;
3130 } else {
3131 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003132 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003133 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003134 builder,
3135 &match_pos)) break;
3136 }
3137 } else {
3138 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3139 if (pattern->IsAsciiRepresentation()) {
3140 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003141 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003142 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003143 builder,
3144 &match_pos)) break;
3145 } else {
3146 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003147 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003148 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003149 builder,
3150 &match_pos)) break;
3151 }
3152 }
3153 }
3154
3155 if (match_pos >= 0) {
3156 SetLastMatchInfoNoCaptures(subject,
3157 last_match_info,
3158 match_pos,
3159 match_pos + pattern->length());
3160 return true;
3161 }
3162 return false; // No matches at all.
3163}
3164
3165
3166static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3167 Handle<String> subject,
3168 Handle<JSRegExp> regexp,
3169 Handle<JSArray> last_match_array,
3170 FixedArrayBuilder* builder) {
3171 ASSERT(subject->IsFlat());
3172 int match_start = -1;
3173 int match_end = 0;
3174 int pos = 0;
3175 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3176 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3177
3178 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003179 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003180 int subject_length = subject->length();
3181
3182 for (;;) { // Break on failure, return on exception.
3183 RegExpImpl::IrregexpResult result =
3184 RegExpImpl::IrregexpExecOnce(regexp,
3185 subject,
3186 pos,
3187 register_vector);
3188 if (result == RegExpImpl::RE_SUCCESS) {
3189 match_start = register_vector[0];
3190 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3191 if (match_end < match_start) {
3192 ReplacementStringBuilder::AddSubjectSlice(builder,
3193 match_end,
3194 match_start);
3195 }
3196 match_end = register_vector[1];
3197 HandleScope loop_scope;
3198 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3199 if (match_start != match_end) {
3200 pos = match_end;
3201 } else {
3202 pos = match_end + 1;
3203 if (pos > subject_length) break;
3204 }
3205 } else if (result == RegExpImpl::RE_FAILURE) {
3206 break;
3207 } else {
3208 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3209 return result;
3210 }
3211 }
3212
3213 if (match_start >= 0) {
3214 if (match_end < subject_length) {
3215 ReplacementStringBuilder::AddSubjectSlice(builder,
3216 match_end,
3217 subject_length);
3218 }
3219 SetLastMatchInfoNoCaptures(subject,
3220 last_match_array,
3221 match_start,
3222 match_end);
3223 return RegExpImpl::RE_SUCCESS;
3224 } else {
3225 return RegExpImpl::RE_FAILURE; // No matches at all.
3226 }
3227}
3228
3229
3230static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3231 Handle<String> subject,
3232 Handle<JSRegExp> regexp,
3233 Handle<JSArray> last_match_array,
3234 FixedArrayBuilder* builder) {
3235
3236 ASSERT(subject->IsFlat());
3237 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3238 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3239
3240 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003241 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003242
3243 RegExpImpl::IrregexpResult result =
3244 RegExpImpl::IrregexpExecOnce(regexp,
3245 subject,
3246 0,
3247 register_vector);
3248
3249 int capture_count = regexp->CaptureCount();
3250 int subject_length = subject->length();
3251
3252 // Position to search from.
3253 int pos = 0;
3254 // End of previous match. Differs from pos if match was empty.
3255 int match_end = 0;
3256 if (result == RegExpImpl::RE_SUCCESS) {
3257 // Need to keep a copy of the previous match for creating last_match_info
3258 // at the end, so we have two vectors that we swap between.
3259 OffsetsVector registers2(required_registers);
3260 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3261
3262 do {
3263 int match_start = register_vector[0];
3264 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3265 if (match_end < match_start) {
3266 ReplacementStringBuilder::AddSubjectSlice(builder,
3267 match_end,
3268 match_start);
3269 }
3270 match_end = register_vector[1];
3271
3272 {
3273 // Avoid accumulating new handles inside loop.
3274 HandleScope temp_scope;
3275 // Arguments array to replace function is match, captures, index and
3276 // subject, i.e., 3 + capture count in total.
3277 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003278 Handle<String> match = Factory::NewSubString(subject,
3279 match_start,
3280 match_end);
3281 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003282 for (int i = 1; i <= capture_count; i++) {
3283 int start = register_vector[i * 2];
3284 if (start >= 0) {
3285 int end = register_vector[i * 2 + 1];
3286 ASSERT(start <= end);
3287 Handle<String> substring = Factory::NewSubString(subject,
3288 start,
3289 end);
3290 elements->set(i, *substring);
3291 } else {
3292 ASSERT(register_vector[i * 2 + 1] < 0);
3293 elements->set(i, Heap::undefined_value());
3294 }
3295 }
3296 elements->set(capture_count + 1, Smi::FromInt(match_start));
3297 elements->set(capture_count + 2, *subject);
3298 builder->Add(*Factory::NewJSArrayWithElements(elements));
3299 }
3300 // Swap register vectors, so the last successful match is in
3301 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003302 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003303 prev_register_vector = register_vector;
3304 register_vector = tmp;
3305
3306 if (match_end > match_start) {
3307 pos = match_end;
3308 } else {
3309 pos = match_end + 1;
3310 if (pos > subject_length) {
3311 break;
3312 }
3313 }
3314
3315 result = RegExpImpl::IrregexpExecOnce(regexp,
3316 subject,
3317 pos,
3318 register_vector);
3319 } while (result == RegExpImpl::RE_SUCCESS);
3320
3321 if (result != RegExpImpl::RE_EXCEPTION) {
3322 // Finished matching, with at least one match.
3323 if (match_end < subject_length) {
3324 ReplacementStringBuilder::AddSubjectSlice(builder,
3325 match_end,
3326 subject_length);
3327 }
3328
3329 int last_match_capture_count = (capture_count + 1) * 2;
3330 int last_match_array_size =
3331 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3332 last_match_array->EnsureSize(last_match_array_size);
3333 AssertNoAllocation no_gc;
3334 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3335 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3336 RegExpImpl::SetLastSubject(elements, *subject);
3337 RegExpImpl::SetLastInput(elements, *subject);
3338 for (int i = 0; i < last_match_capture_count; i++) {
3339 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3340 }
3341 return RegExpImpl::RE_SUCCESS;
3342 }
3343 }
3344 // No matches at all, return failure or exception result directly.
3345 return result;
3346}
3347
3348
lrn@chromium.org303ada72010-10-27 09:33:13 +00003349static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003350 ASSERT(args.length() == 4);
3351 HandleScope handles;
3352
3353 CONVERT_ARG_CHECKED(String, subject, 1);
3354 if (!subject->IsFlat()) { FlattenString(subject); }
3355 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3356 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3357 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3358
3359 ASSERT(last_match_info->HasFastElements());
3360 ASSERT(regexp->GetFlags().is_global());
3361 Handle<FixedArray> result_elements;
3362 if (result_array->HasFastElements()) {
3363 result_elements =
3364 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3365 } else {
3366 result_elements = Factory::NewFixedArrayWithHoles(16);
3367 }
3368 FixedArrayBuilder builder(result_elements);
3369
3370 if (regexp->TypeTag() == JSRegExp::ATOM) {
3371 Handle<String> pattern(
3372 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003373 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003374 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3375 return *builder.ToJSArray(result_array);
3376 }
3377 return Heap::null_value();
3378 }
3379
3380 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3381
3382 RegExpImpl::IrregexpResult result;
3383 if (regexp->CaptureCount() == 0) {
3384 result = SearchRegExpNoCaptureMultiple(subject,
3385 regexp,
3386 last_match_info,
3387 &builder);
3388 } else {
3389 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3390 }
3391 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3392 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3393 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3394 return Failure::Exception();
3395}
3396
3397
lrn@chromium.org303ada72010-10-27 09:33:13 +00003398static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399 NoHandleAllocation ha;
3400 ASSERT(args.length() == 2);
3401
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003402 // Fast case where the result is a one character string.
3403 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3404 int value = Smi::cast(args[0])->value();
3405 int radix = Smi::cast(args[1])->value();
3406 if (value >= 0 && value < radix) {
3407 RUNTIME_ASSERT(radix <= 36);
3408 // Character array used for conversion.
3409 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3410 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3411 }
3412 }
3413
3414 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003415 CONVERT_DOUBLE_CHECKED(value, args[0]);
3416 if (isnan(value)) {
3417 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3418 }
3419 if (isinf(value)) {
3420 if (value < 0) {
3421 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3422 }
3423 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3424 }
3425 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3426 int radix = FastD2I(radix_number);
3427 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3428 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003429 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003430 DeleteArray(str);
3431 return result;
3432}
3433
3434
lrn@chromium.org303ada72010-10-27 09:33:13 +00003435static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003436 NoHandleAllocation ha;
3437 ASSERT(args.length() == 2);
3438
3439 CONVERT_DOUBLE_CHECKED(value, args[0]);
3440 if (isnan(value)) {
3441 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3442 }
3443 if (isinf(value)) {
3444 if (value < 0) {
3445 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3446 }
3447 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3448 }
3449 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3450 int f = FastD2I(f_number);
3451 RUNTIME_ASSERT(f >= 0);
3452 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003453 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003455 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003456}
3457
3458
lrn@chromium.org303ada72010-10-27 09:33:13 +00003459static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460 NoHandleAllocation ha;
3461 ASSERT(args.length() == 2);
3462
3463 CONVERT_DOUBLE_CHECKED(value, args[0]);
3464 if (isnan(value)) {
3465 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3466 }
3467 if (isinf(value)) {
3468 if (value < 0) {
3469 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3470 }
3471 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3472 }
3473 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3474 int f = FastD2I(f_number);
3475 RUNTIME_ASSERT(f >= -1 && f <= 20);
3476 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003477 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003478 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003479 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003480}
3481
3482
lrn@chromium.org303ada72010-10-27 09:33:13 +00003483static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003484 NoHandleAllocation ha;
3485 ASSERT(args.length() == 2);
3486
3487 CONVERT_DOUBLE_CHECKED(value, args[0]);
3488 if (isnan(value)) {
3489 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3490 }
3491 if (isinf(value)) {
3492 if (value < 0) {
3493 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3494 }
3495 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3496 }
3497 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3498 int f = FastD2I(f_number);
3499 RUNTIME_ASSERT(f >= 1 && f <= 21);
3500 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003501 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003502 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003503 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003504}
3505
3506
3507// Returns a single character string where first character equals
3508// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003509static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003510 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003511 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003512 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003513 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003514 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003515 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003516}
3517
3518
lrn@chromium.org303ada72010-10-27 09:33:13 +00003519MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3520 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521 // Handle [] indexing on Strings
3522 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003523 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3524 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003525 }
3526
3527 // Handle [] indexing on String objects
3528 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003529 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3530 Handle<Object> result =
3531 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3532 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003533 }
3534
3535 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003536 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537 return prototype->GetElement(index);
3538 }
3539
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003540 return GetElement(object, index);
3541}
3542
3543
lrn@chromium.org303ada72010-10-27 09:33:13 +00003544MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003545 return object->GetElement(index);
3546}
3547
3548
lrn@chromium.org303ada72010-10-27 09:33:13 +00003549MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3550 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003551 HandleScope scope;
3552
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003553 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003554 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003555 Handle<Object> error =
3556 Factory::NewTypeError("non_object_property_load",
3557 HandleVector(args, 2));
3558 return Top::Throw(*error);
3559 }
3560
3561 // Check if the given key is an array index.
3562 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003563 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003564 return GetElementOrCharAt(object, index);
3565 }
3566
3567 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003568 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003569 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003570 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572 bool has_pending_exception = false;
3573 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003574 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003575 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003576 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003577 }
3578
ager@chromium.org32912102009-01-16 10:38:43 +00003579 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580 // the element if so.
3581 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003582 return GetElementOrCharAt(object, index);
3583 } else {
3584 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003585 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003586 }
3587}
3588
3589
lrn@chromium.org303ada72010-10-27 09:33:13 +00003590static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 NoHandleAllocation ha;
3592 ASSERT(args.length() == 2);
3593
3594 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003595 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596
3597 return Runtime::GetObjectProperty(object, key);
3598}
3599
3600
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003601// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003602static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003603 NoHandleAllocation ha;
3604 ASSERT(args.length() == 2);
3605
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003606 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003607 // itself.
3608 //
3609 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003610 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003611 // global proxy object never has properties. This is the case
3612 // because the global proxy object forwards everything to its hidden
3613 // prototype including local lookups.
3614 //
3615 // Additionally, we need to make sure that we do not cache results
3616 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003617 if (args[0]->IsJSObject() &&
3618 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003619 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003620 args[1]->IsString()) {
3621 JSObject* receiver = JSObject::cast(args[0]);
3622 String* key = String::cast(args[1]);
3623 if (receiver->HasFastProperties()) {
3624 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003625 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003626 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3627 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003628 Object* value = receiver->FastPropertyAt(offset);
3629 return value->IsTheHole() ? Heap::undefined_value() : value;
3630 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003631 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003632 LookupResult result;
3633 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003634 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003635 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003636 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003637 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003638 }
3639 } else {
3640 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003641 StringDictionary* dictionary = receiver->property_dictionary();
3642 int entry = dictionary->FindEntry(key);
3643 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003644 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003645 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003646 if (!receiver->IsGlobalObject()) return value;
3647 value = JSGlobalPropertyCell::cast(value)->value();
3648 if (!value->IsTheHole()) return value;
3649 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003650 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003651 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003652 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3653 // Fast case for string indexing using [] with a smi index.
3654 HandleScope scope;
3655 Handle<String> str = args.at<String>(0);
3656 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003657 if (index >= 0 && index < str->length()) {
3658 Handle<Object> result = GetCharAt(str, index);
3659 return *result;
3660 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003661 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003662
3663 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003664 return Runtime::GetObjectProperty(args.at<Object>(0),
3665 args.at<Object>(1));
3666}
3667
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003668// Implements part of 8.12.9 DefineOwnProperty.
3669// There are 3 cases that lead here:
3670// Step 4b - define a new accessor property.
3671// Steps 9c & 12 - replace an existing data property with an accessor property.
3672// Step 12 - update an existing accessor property with an accessor or generic
3673// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003674static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003675 ASSERT(args.length() == 5);
3676 HandleScope scope;
3677 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3678 CONVERT_CHECKED(String, name, args[1]);
3679 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003680 Object* fun = args[3];
3681 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003682 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3683 int unchecked = flag_attr->value();
3684 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3685 RUNTIME_ASSERT(!obj->IsNull());
3686 LookupResult result;
3687 obj->LocalLookupRealNamedProperty(name, &result);
3688
3689 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3690 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3691 // delete it to avoid running into trouble in DefineAccessor, which
3692 // handles this incorrectly if the property is readonly (does nothing)
3693 if (result.IsProperty() &&
3694 (result.type() == FIELD || result.type() == NORMAL
3695 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003696 Object* ok;
3697 { MaybeObject* maybe_ok =
3698 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3699 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3700 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003701 }
3702 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3703}
3704
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003705// Implements part of 8.12.9 DefineOwnProperty.
3706// There are 3 cases that lead here:
3707// Step 4a - define a new data property.
3708// Steps 9b & 12 - replace an existing accessor property with a data property.
3709// Step 12 - update an existing data property with a data or generic
3710// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003711static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003712 ASSERT(args.length() == 4);
3713 HandleScope scope;
3714 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3715 CONVERT_ARG_CHECKED(String, name, 1);
3716 Handle<Object> obj_value = args.at<Object>(2);
3717
3718 CONVERT_CHECKED(Smi, flag, args[3]);
3719 int unchecked = flag->value();
3720 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3721
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003722 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3723
3724 // Check if this is an element.
3725 uint32_t index;
3726 bool is_element = name->AsArrayIndex(&index);
3727
3728 // Special case for elements if any of the flags are true.
3729 // If elements are in fast case we always implicitly assume that:
3730 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3731 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3732 is_element) {
3733 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003734 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003735 // We do not need to do access checks here since these has already
3736 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003737 Handle<Object> proto(js_object->GetPrototype());
3738 // If proxy is detached, ignore the assignment. Alternatively,
3739 // we could throw an exception.
3740 if (proto->IsNull()) return *obj_value;
3741 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003742 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003743 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003744 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003745 // Make sure that we never go back to fast case.
3746 dictionary->set_requires_slow_elements();
3747 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003748 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003749 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003750 }
3751
ager@chromium.org5c838252010-02-19 08:53:10 +00003752 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003753 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003754
ager@chromium.org5c838252010-02-19 08:53:10 +00003755 // Take special care when attributes are different and there is already
3756 // a property. For simplicity we normalize the property which enables us
3757 // to not worry about changing the instance_descriptor and creating a new
3758 // map. The current version of SetObjectProperty does not handle attributes
3759 // correctly in the case where a property is a field and is reset with
3760 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003761 if (result.IsProperty() &&
3762 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003763 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003764 if (js_object->IsJSGlobalProxy()) {
3765 // Since the result is a property, the prototype will exist so
3766 // we don't have to check for null.
3767 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003768 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003769 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003770 // Use IgnoreAttributes version since a readonly property may be
3771 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003772 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3773 *obj_value,
3774 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003775 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003776
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003777 return Runtime::ForceSetObjectProperty(js_object, name, obj_value, attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003778}
3779
3780
lrn@chromium.org303ada72010-10-27 09:33:13 +00003781MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3782 Handle<Object> key,
3783 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003784 PropertyAttributes attr,
3785 StrictModeFlag strict) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003786 HandleScope scope;
3787
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003789 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003790 Handle<Object> error =
3791 Factory::NewTypeError("non_object_property_store",
3792 HandleVector(args, 2));
3793 return Top::Throw(*error);
3794 }
3795
3796 // If the object isn't a JavaScript object, we ignore the store.
3797 if (!object->IsJSObject()) return *value;
3798
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003799 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3800
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003801 // Check if the given key is an array index.
3802 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003803 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003804 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3805 // of a string using [] notation. We need to support this too in
3806 // JavaScript.
3807 // In the case of a String object we just need to redirect the assignment to
3808 // the underlying string if the index is in range. Since the underlying
3809 // string does nothing with the assignment then we can ignore such
3810 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003811 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003813 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003814
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003815 // TODO(1220): Implement SetElement strict mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003816 Handle<Object> result = SetElement(js_object, index, value);
3817 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003818 return *value;
3819 }
3820
3821 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003822 Handle<Object> result;
3823 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003824 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003825 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003826 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003827 key_string->TryFlatten();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003828 result = SetProperty(js_object, key_string, value, attr, strict);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003829 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003830 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003831 return *value;
3832 }
3833
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003834 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003835 bool has_pending_exception = false;
3836 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3837 if (has_pending_exception) return Failure::Exception();
3838 Handle<String> name = Handle<String>::cast(converted);
3839
3840 if (name->AsArrayIndex(&index)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003841 // TODO(1220): Implement SetElement strict mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003842 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003843 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003844 return js_object->SetProperty(*name, *value, attr, strict);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003845 }
3846}
3847
3848
lrn@chromium.org303ada72010-10-27 09:33:13 +00003849MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3850 Handle<Object> key,
3851 Handle<Object> value,
3852 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003853 HandleScope scope;
3854
3855 // Check if the given key is an array index.
3856 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003857 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003858 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3859 // of a string using [] notation. We need to support this too in
3860 // JavaScript.
3861 // In the case of a String object we just need to redirect the assignment to
3862 // the underlying string if the index is in range. Since the underlying
3863 // string does nothing with the assignment then we can ignore such
3864 // assignments.
3865 if (js_object->IsStringObjectWithCharacterAt(index)) {
3866 return *value;
3867 }
3868
3869 return js_object->SetElement(index, *value);
3870 }
3871
3872 if (key->IsString()) {
3873 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003874 return js_object->SetElement(index, *value);
3875 } else {
3876 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003877 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003878 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3879 *value,
3880 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003881 }
3882 }
3883
3884 // Call-back into JavaScript to convert the key to a string.
3885 bool has_pending_exception = false;
3886 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3887 if (has_pending_exception) return Failure::Exception();
3888 Handle<String> name = Handle<String>::cast(converted);
3889
3890 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003891 return js_object->SetElement(index, *value);
3892 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003893 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003894 }
3895}
3896
3897
lrn@chromium.org303ada72010-10-27 09:33:13 +00003898MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3899 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003900 HandleScope scope;
3901
3902 // Check if the given key is an array index.
3903 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003904 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003905 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3906 // characters of a string using [] notation. In the case of a
3907 // String object we just need to redirect the deletion to the
3908 // underlying string if the index is in range. Since the
3909 // underlying string does nothing with the deletion, we can ignore
3910 // such deletions.
3911 if (js_object->IsStringObjectWithCharacterAt(index)) {
3912 return Heap::true_value();
3913 }
3914
3915 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3916 }
3917
3918 Handle<String> key_string;
3919 if (key->IsString()) {
3920 key_string = Handle<String>::cast(key);
3921 } else {
3922 // Call-back into JavaScript to convert the key to a string.
3923 bool has_pending_exception = false;
3924 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3925 if (has_pending_exception) return Failure::Exception();
3926 key_string = Handle<String>::cast(converted);
3927 }
3928
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003929 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003930 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3931}
3932
3933
lrn@chromium.org303ada72010-10-27 09:33:13 +00003934static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003935 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003936 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003937
3938 Handle<Object> object = args.at<Object>(0);
3939 Handle<Object> key = args.at<Object>(1);
3940 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003941 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
3942 RUNTIME_ASSERT(
3943 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003945 PropertyAttributes attributes =
3946 static_cast<PropertyAttributes>(unchecked_attributes);
3947
3948 StrictModeFlag strict = kNonStrictMode;
3949 if (args.length() == 5) {
3950 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
3951 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
3952 strict_unchecked == kNonStrictMode);
3953 strict = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003954 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003955
3956 return Runtime::SetObjectProperty(object, key, value, attributes, strict);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003957}
3958
3959
3960// Set a local property, even if it is READ_ONLY. If the property does not
3961// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003962static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003963 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003964 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003965 CONVERT_CHECKED(JSObject, object, args[0]);
3966 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003967 // Compute attributes.
3968 PropertyAttributes attributes = NONE;
3969 if (args.length() == 4) {
3970 CONVERT_CHECKED(Smi, value_obj, args[3]);
3971 int unchecked_value = value_obj->value();
3972 // Only attribute bits should be set.
3973 RUNTIME_ASSERT(
3974 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3975 attributes = static_cast<PropertyAttributes>(unchecked_value);
3976 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003978 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003979 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003980}
3981
3982
lrn@chromium.org303ada72010-10-27 09:33:13 +00003983static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003985 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986
3987 CONVERT_CHECKED(JSObject, object, args[0]);
3988 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003989 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003990 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003991 ? JSObject::STRICT_DELETION
3992 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003993}
3994
3995
ager@chromium.org9085a012009-05-11 19:22:57 +00003996static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3997 Handle<String> key) {
3998 if (object->HasLocalProperty(*key)) return Heap::true_value();
3999 // Handle hidden prototypes. If there's a hidden prototype above this thing
4000 // then we have to check it for properties, because they are supposed to
4001 // look like they are on this object.
4002 Handle<Object> proto(object->GetPrototype());
4003 if (proto->IsJSObject() &&
4004 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
4005 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
4006 }
4007 return Heap::false_value();
4008}
4009
4010
lrn@chromium.org303ada72010-10-27 09:33:13 +00004011static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004012 NoHandleAllocation ha;
4013 ASSERT(args.length() == 2);
4014 CONVERT_CHECKED(String, key, args[1]);
4015
ager@chromium.org9085a012009-05-11 19:22:57 +00004016 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004017 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004018 if (obj->IsJSObject()) {
4019 JSObject* object = JSObject::cast(obj);
4020 // Fast case - no interceptors.
4021 if (object->HasRealNamedProperty(key)) return Heap::true_value();
4022 // Slow case. Either it's not there or we have an interceptor. We should
4023 // have handles for this kind of deal.
4024 HandleScope scope;
4025 return HasLocalPropertyImplementation(Handle<JSObject>(object),
4026 Handle<String>(key));
4027 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004028 // Well, there is one exception: Handle [] on strings.
4029 uint32_t index;
4030 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004031 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004032 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 return Heap::true_value();
4034 }
4035 }
4036 return Heap::false_value();
4037}
4038
4039
lrn@chromium.org303ada72010-10-27 09:33:13 +00004040static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004041 NoHandleAllocation na;
4042 ASSERT(args.length() == 2);
4043
4044 // Only JS objects can have properties.
4045 if (args[0]->IsJSObject()) {
4046 JSObject* object = JSObject::cast(args[0]);
4047 CONVERT_CHECKED(String, key, args[1]);
4048 if (object->HasProperty(key)) return Heap::true_value();
4049 }
4050 return Heap::false_value();
4051}
4052
4053
lrn@chromium.org303ada72010-10-27 09:33:13 +00004054static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004055 NoHandleAllocation na;
4056 ASSERT(args.length() == 2);
4057
4058 // Only JS objects can have elements.
4059 if (args[0]->IsJSObject()) {
4060 JSObject* object = JSObject::cast(args[0]);
4061 CONVERT_CHECKED(Smi, index_obj, args[1]);
4062 uint32_t index = index_obj->value();
4063 if (object->HasElement(index)) return Heap::true_value();
4064 }
4065 return Heap::false_value();
4066}
4067
4068
lrn@chromium.org303ada72010-10-27 09:33:13 +00004069static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004070 NoHandleAllocation ha;
4071 ASSERT(args.length() == 2);
4072
4073 CONVERT_CHECKED(JSObject, object, args[0]);
4074 CONVERT_CHECKED(String, key, args[1]);
4075
4076 uint32_t index;
4077 if (key->AsArrayIndex(&index)) {
4078 return Heap::ToBoolean(object->HasElement(index));
4079 }
4080
ager@chromium.org870a0b62008-11-04 11:43:05 +00004081 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
4082 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004083}
4084
4085
lrn@chromium.org303ada72010-10-27 09:33:13 +00004086static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004087 HandleScope scope;
4088 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004089 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090 return *GetKeysFor(object);
4091}
4092
4093
4094// Returns either a FixedArray as Runtime_GetPropertyNames,
4095// or, if the given object has an enum cache that contains
4096// all enumerable properties of the object and its prototypes
4097// have none, the map of the object. This is used to speed up
4098// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004099static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 ASSERT(args.length() == 1);
4101
4102 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4103
4104 if (raw_object->IsSimpleEnum()) return raw_object->map();
4105
4106 HandleScope scope;
4107 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004108 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4109 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004110
4111 // Test again, since cache may have been built by preceding call.
4112 if (object->IsSimpleEnum()) return object->map();
4113
4114 return *content;
4115}
4116
4117
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004118// Find the length of the prototype chain that is to to handled as one. If a
4119// prototype object is hidden it is to be viewed as part of the the object it
4120// is prototype for.
4121static int LocalPrototypeChainLength(JSObject* obj) {
4122 int count = 1;
4123 Object* proto = obj->GetPrototype();
4124 while (proto->IsJSObject() &&
4125 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4126 count++;
4127 proto = JSObject::cast(proto)->GetPrototype();
4128 }
4129 return count;
4130}
4131
4132
4133// Return the names of the local named properties.
4134// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004135static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004136 HandleScope scope;
4137 ASSERT(args.length() == 1);
4138 if (!args[0]->IsJSObject()) {
4139 return Heap::undefined_value();
4140 }
4141 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4142
4143 // Skip the global proxy as it has no properties and always delegates to the
4144 // real global object.
4145 if (obj->IsJSGlobalProxy()) {
4146 // Only collect names if access is permitted.
4147 if (obj->IsAccessCheckNeeded() &&
4148 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
4149 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4150 return *Factory::NewJSArray(0);
4151 }
4152 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4153 }
4154
4155 // Find the number of objects making up this.
4156 int length = LocalPrototypeChainLength(*obj);
4157
4158 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004159 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004160 int total_property_count = 0;
4161 Handle<JSObject> jsproto = obj;
4162 for (int i = 0; i < length; i++) {
4163 // Only collect names if access is permitted.
4164 if (jsproto->IsAccessCheckNeeded() &&
4165 !Top::MayNamedAccess(*jsproto,
4166 Heap::undefined_value(),
4167 v8::ACCESS_KEYS)) {
4168 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4169 return *Factory::NewJSArray(0);
4170 }
4171 int n;
4172 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4173 local_property_count[i] = n;
4174 total_property_count += n;
4175 if (i < length - 1) {
4176 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4177 }
4178 }
4179
4180 // Allocate an array with storage for all the property names.
4181 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4182
4183 // Get the property names.
4184 jsproto = obj;
4185 int proto_with_hidden_properties = 0;
4186 for (int i = 0; i < length; i++) {
4187 jsproto->GetLocalPropertyNames(*names,
4188 i == 0 ? 0 : local_property_count[i - 1]);
4189 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4190 proto_with_hidden_properties++;
4191 }
4192 if (i < length - 1) {
4193 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4194 }
4195 }
4196
4197 // Filter out name of hidden propeties object.
4198 if (proto_with_hidden_properties > 0) {
4199 Handle<FixedArray> old_names = names;
4200 names = Factory::NewFixedArray(
4201 names->length() - proto_with_hidden_properties);
4202 int dest_pos = 0;
4203 for (int i = 0; i < total_property_count; i++) {
4204 Object* name = old_names->get(i);
4205 if (name == Heap::hidden_symbol()) {
4206 continue;
4207 }
4208 names->set(dest_pos++, name);
4209 }
4210 }
4211
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004212 return *Factory::NewJSArrayWithElements(names);
4213}
4214
4215
4216// Return the names of the local indexed properties.
4217// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004218static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004219 HandleScope scope;
4220 ASSERT(args.length() == 1);
4221 if (!args[0]->IsJSObject()) {
4222 return Heap::undefined_value();
4223 }
4224 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4225
4226 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4227 Handle<FixedArray> names = Factory::NewFixedArray(n);
4228 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4229 return *Factory::NewJSArrayWithElements(names);
4230}
4231
4232
4233// Return information on whether an object has a named or indexed interceptor.
4234// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004235static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004236 HandleScope scope;
4237 ASSERT(args.length() == 1);
4238 if (!args[0]->IsJSObject()) {
4239 return Smi::FromInt(0);
4240 }
4241 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4242
4243 int result = 0;
4244 if (obj->HasNamedInterceptor()) result |= 2;
4245 if (obj->HasIndexedInterceptor()) result |= 1;
4246
4247 return Smi::FromInt(result);
4248}
4249
4250
4251// Return property names from named interceptor.
4252// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004253static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004254 HandleScope scope;
4255 ASSERT(args.length() == 1);
4256 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4257
4258 if (obj->HasNamedInterceptor()) {
4259 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4260 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4261 }
4262 return Heap::undefined_value();
4263}
4264
4265
4266// Return element names from indexed interceptor.
4267// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004268static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004269 HandleScope scope;
4270 ASSERT(args.length() == 1);
4271 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4272
4273 if (obj->HasIndexedInterceptor()) {
4274 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4275 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4276 }
4277 return Heap::undefined_value();
4278}
4279
4280
lrn@chromium.org303ada72010-10-27 09:33:13 +00004281static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004282 ASSERT_EQ(args.length(), 1);
4283 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4284 HandleScope scope;
4285 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004286
4287 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004288 // Do access checks before going to the global object.
4289 if (object->IsAccessCheckNeeded() &&
4290 !Top::MayNamedAccess(*object, Heap::undefined_value(),
4291 v8::ACCESS_KEYS)) {
4292 Top::ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4293 return *Factory::NewJSArray(0);
4294 }
4295
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004296 Handle<Object> proto(object->GetPrototype());
4297 // If proxy is detached we simply return an empty array.
4298 if (proto->IsNull()) return *Factory::NewJSArray(0);
4299 object = Handle<JSObject>::cast(proto);
4300 }
4301
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004302 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4303 LOCAL_ONLY);
4304 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4305 // property array and since the result is mutable we have to create
4306 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004307 int length = contents->length();
4308 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4309 for (int i = 0; i < length; i++) {
4310 Object* entry = contents->get(i);
4311 if (entry->IsString()) {
4312 copy->set(i, entry);
4313 } else {
4314 ASSERT(entry->IsNumber());
4315 HandleScope scope;
4316 Handle<Object> entry_handle(entry);
4317 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4318 copy->set(i, *entry_str);
4319 }
4320 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004321 return *Factory::NewJSArrayWithElements(copy);
4322}
4323
4324
lrn@chromium.org303ada72010-10-27 09:33:13 +00004325static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004326 NoHandleAllocation ha;
4327 ASSERT(args.length() == 1);
4328
4329 // Compute the frame holding the arguments.
4330 JavaScriptFrameIterator it;
4331 it.AdvanceToArgumentsFrame();
4332 JavaScriptFrame* frame = it.frame();
4333
4334 // Get the actual number of provided arguments.
4335 const uint32_t n = frame->GetProvidedParametersCount();
4336
4337 // Try to convert the key to an index. If successful and within
4338 // index return the the argument from the frame.
4339 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004340 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004341 return frame->GetParameter(index);
4342 }
4343
4344 // Convert the key to a string.
4345 HandleScope scope;
4346 bool exception = false;
4347 Handle<Object> converted =
4348 Execution::ToString(args.at<Object>(0), &exception);
4349 if (exception) return Failure::Exception();
4350 Handle<String> key = Handle<String>::cast(converted);
4351
4352 // Try to convert the string key into an array index.
4353 if (key->AsArrayIndex(&index)) {
4354 if (index < n) {
4355 return frame->GetParameter(index);
4356 } else {
4357 return Top::initial_object_prototype()->GetElement(index);
4358 }
4359 }
4360
4361 // Handle special arguments properties.
4362 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4363 if (key->Equals(Heap::callee_symbol())) return frame->function();
4364
4365 // Lookup in the initial Object.prototype object.
4366 return Top::initial_object_prototype()->GetProperty(*key);
4367}
4368
4369
lrn@chromium.org303ada72010-10-27 09:33:13 +00004370static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004371 HandleScope scope;
4372
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004373 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004374 Handle<Object> object = args.at<Object>(0);
4375 if (object->IsJSObject()) {
4376 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004377 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004378 MaybeObject* ok = js_object->TransformToFastProperties(0);
4379 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004380 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004381 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004382 return *object;
4383}
4384
4385
lrn@chromium.org303ada72010-10-27 09:33:13 +00004386static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004387 HandleScope scope;
4388
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004389 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004390 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004391 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004392 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004393 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004394 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004395 return *object;
4396}
4397
4398
lrn@chromium.org303ada72010-10-27 09:33:13 +00004399static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004400 NoHandleAllocation ha;
4401 ASSERT(args.length() == 1);
4402
4403 return args[0]->ToBoolean();
4404}
4405
4406
4407// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4408// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004409static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004410 NoHandleAllocation ha;
4411
4412 Object* obj = args[0];
4413 if (obj->IsNumber()) return Heap::number_symbol();
4414 HeapObject* heap_obj = HeapObject::cast(obj);
4415
4416 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004417 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004418
4419 InstanceType instance_type = heap_obj->map()->instance_type();
4420 if (instance_type < FIRST_NONSTRING_TYPE) {
4421 return Heap::string_symbol();
4422 }
4423
4424 switch (instance_type) {
4425 case ODDBALL_TYPE:
4426 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4427 return Heap::boolean_symbol();
4428 }
4429 if (heap_obj->IsNull()) {
4430 return Heap::object_symbol();
4431 }
4432 ASSERT(heap_obj->IsUndefined());
4433 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004434 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004435 return Heap::function_symbol();
4436 default:
4437 // For any kind of object not handled above, the spec rule for
4438 // host objects gives that it is okay to return "object"
4439 return Heap::object_symbol();
4440 }
4441}
4442
4443
lrn@chromium.org25156de2010-04-06 13:10:27 +00004444static bool AreDigits(const char*s, int from, int to) {
4445 for (int i = from; i < to; i++) {
4446 if (s[i] < '0' || s[i] > '9') return false;
4447 }
4448
4449 return true;
4450}
4451
4452
4453static int ParseDecimalInteger(const char*s, int from, int to) {
4454 ASSERT(to - from < 10); // Overflow is not possible.
4455 ASSERT(from < to);
4456 int d = s[from] - '0';
4457
4458 for (int i = from + 1; i < to; i++) {
4459 d = 10 * d + (s[i] - '0');
4460 }
4461
4462 return d;
4463}
4464
4465
lrn@chromium.org303ada72010-10-27 09:33:13 +00004466static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467 NoHandleAllocation ha;
4468 ASSERT(args.length() == 1);
4469 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004470 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004471
4472 // Fast case: short integer or some sorts of junk values.
4473 int len = subject->length();
4474 if (subject->IsSeqAsciiString()) {
4475 if (len == 0) return Smi::FromInt(0);
4476
4477 char const* data = SeqAsciiString::cast(subject)->GetChars();
4478 bool minus = (data[0] == '-');
4479 int start_pos = (minus ? 1 : 0);
4480
4481 if (start_pos == len) {
4482 return Heap::nan_value();
4483 } else if (data[start_pos] > '9') {
4484 // Fast check for a junk value. A valid string may start from a
4485 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4486 // the 'I' character ('Infinity'). All of that have codes not greater than
4487 // '9' except 'I'.
4488 if (data[start_pos] != 'I') {
4489 return Heap::nan_value();
4490 }
4491 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4492 // The maximal/minimal smi has 10 digits. If the string has less digits we
4493 // know it will fit into the smi-data type.
4494 int d = ParseDecimalInteger(data, start_pos, len);
4495 if (minus) {
4496 if (d == 0) return Heap::minus_zero_value();
4497 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004498 } else if (!subject->HasHashCode() &&
4499 len <= String::kMaxArrayIndexSize &&
4500 (len == 1 || data[0] != '0')) {
4501 // String hash is not calculated yet but all the data are present.
4502 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004503 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004504#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004505 subject->Hash(); // Force hash calculation.
4506 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4507 static_cast<int>(hash));
4508#endif
4509 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004510 }
4511 return Smi::FromInt(d);
4512 }
4513 }
4514
4515 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004516 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4517}
4518
4519
lrn@chromium.org303ada72010-10-27 09:33:13 +00004520static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521 NoHandleAllocation ha;
4522 ASSERT(args.length() == 1);
4523
4524 CONVERT_CHECKED(JSArray, codes, args[0]);
4525 int length = Smi::cast(codes->length())->value();
4526
4527 // Check if the string can be ASCII.
4528 int i;
4529 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004530 Object* element;
4531 { MaybeObject* maybe_element = codes->GetElement(i);
4532 // We probably can't get an exception here, but just in order to enforce
4533 // the checking of inputs in the runtime calls we check here.
4534 if (!maybe_element->ToObject(&element)) return maybe_element;
4535 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004536 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4537 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4538 break;
4539 }
4540
lrn@chromium.org303ada72010-10-27 09:33:13 +00004541 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004542 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004543 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004544 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004545 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004546 }
4547
lrn@chromium.org303ada72010-10-27 09:33:13 +00004548 Object* object = NULL;
4549 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004550 String* result = String::cast(object);
4551 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004552 Object* element;
4553 { MaybeObject* maybe_element = codes->GetElement(i);
4554 if (!maybe_element->ToObject(&element)) return maybe_element;
4555 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004556 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004557 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004558 }
4559 return result;
4560}
4561
4562
4563// kNotEscaped is generated by the following:
4564//
4565// #!/bin/perl
4566// for (my $i = 0; $i < 256; $i++) {
4567// print "\n" if $i % 16 == 0;
4568// my $c = chr($i);
4569// my $escaped = 1;
4570// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4571// print $escaped ? "0, " : "1, ";
4572// }
4573
4574
4575static bool IsNotEscaped(uint16_t character) {
4576 // Only for 8 bit characters, the rest are always escaped (in a different way)
4577 ASSERT(character < 256);
4578 static const char kNotEscaped[256] = {
4579 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4580 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4581 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4582 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4583 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4584 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4585 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4586 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4587 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4588 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4589 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4590 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4591 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4592 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4593 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4594 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4595 };
4596 return kNotEscaped[character] != 0;
4597}
4598
4599
lrn@chromium.org303ada72010-10-27 09:33:13 +00004600static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601 const char hex_chars[] = "0123456789ABCDEF";
4602 NoHandleAllocation ha;
4603 ASSERT(args.length() == 1);
4604 CONVERT_CHECKED(String, source, args[0]);
4605
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004606 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004607
4608 int escaped_length = 0;
4609 int length = source->length();
4610 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004611 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004612 buffer->Reset(source);
4613 while (buffer->has_more()) {
4614 uint16_t character = buffer->GetNext();
4615 if (character >= 256) {
4616 escaped_length += 6;
4617 } else if (IsNotEscaped(character)) {
4618 escaped_length++;
4619 } else {
4620 escaped_length += 3;
4621 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004622 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004623 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004624 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004625 Top::context()->mark_out_of_memory();
4626 return Failure::OutOfMemoryException();
4627 }
4628 }
4629 }
4630 // No length change implies no change. Return original string if no change.
4631 if (escaped_length == length) {
4632 return source;
4633 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004634 Object* o;
4635 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4636 if (!maybe_o->ToObject(&o)) return maybe_o;
4637 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004638 String* destination = String::cast(o);
4639 int dest_position = 0;
4640
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004641 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004642 buffer->Rewind();
4643 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004644 uint16_t chr = buffer->GetNext();
4645 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004646 destination->Set(dest_position, '%');
4647 destination->Set(dest_position+1, 'u');
4648 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4649 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4650 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4651 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004652 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004653 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004654 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004655 dest_position++;
4656 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004657 destination->Set(dest_position, '%');
4658 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4659 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004660 dest_position += 3;
4661 }
4662 }
4663 return destination;
4664}
4665
4666
4667static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4668 static const signed char kHexValue['g'] = {
4669 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4670 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4671 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4672 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4673 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4674 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4675 -1, 10, 11, 12, 13, 14, 15 };
4676
4677 if (character1 > 'f') return -1;
4678 int hi = kHexValue[character1];
4679 if (hi == -1) return -1;
4680 if (character2 > 'f') return -1;
4681 int lo = kHexValue[character2];
4682 if (lo == -1) return -1;
4683 return (hi << 4) + lo;
4684}
4685
4686
ager@chromium.org870a0b62008-11-04 11:43:05 +00004687static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004688 int i,
4689 int length,
4690 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004691 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004692 int32_t hi = 0;
4693 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004694 if (character == '%' &&
4695 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004696 source->Get(i + 1) == 'u' &&
4697 (hi = TwoDigitHex(source->Get(i + 2),
4698 source->Get(i + 3))) != -1 &&
4699 (lo = TwoDigitHex(source->Get(i + 4),
4700 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701 *step = 6;
4702 return (hi << 8) + lo;
4703 } else if (character == '%' &&
4704 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004705 (lo = TwoDigitHex(source->Get(i + 1),
4706 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004707 *step = 3;
4708 return lo;
4709 } else {
4710 *step = 1;
4711 return character;
4712 }
4713}
4714
4715
lrn@chromium.org303ada72010-10-27 09:33:13 +00004716static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004717 NoHandleAllocation ha;
4718 ASSERT(args.length() == 1);
4719 CONVERT_CHECKED(String, source, args[0]);
4720
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004721 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722
4723 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004724 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725
4726 int unescaped_length = 0;
4727 for (int i = 0; i < length; unescaped_length++) {
4728 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004729 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004730 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004731 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004732 i += step;
4733 }
4734
4735 // No length change implies no change. Return original string if no change.
4736 if (unescaped_length == length)
4737 return source;
4738
lrn@chromium.org303ada72010-10-27 09:33:13 +00004739 Object* o;
4740 { MaybeObject* maybe_o = ascii ?
4741 Heap::AllocateRawAsciiString(unescaped_length) :
4742 Heap::AllocateRawTwoByteString(unescaped_length);
4743 if (!maybe_o->ToObject(&o)) return maybe_o;
4744 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004745 String* destination = String::cast(o);
4746
4747 int dest_position = 0;
4748 for (int i = 0; i < length; dest_position++) {
4749 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004750 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004751 i += step;
4752 }
4753 return destination;
4754}
4755
4756
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004757static const unsigned int kQuoteTableLength = 128u;
4758
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004759static const int kJsonQuotesCharactersPerEntry = 8;
4760static const char* const JsonQuotes =
4761 "\\u0000 \\u0001 \\u0002 \\u0003 "
4762 "\\u0004 \\u0005 \\u0006 \\u0007 "
4763 "\\b \\t \\n \\u000b "
4764 "\\f \\r \\u000e \\u000f "
4765 "\\u0010 \\u0011 \\u0012 \\u0013 "
4766 "\\u0014 \\u0015 \\u0016 \\u0017 "
4767 "\\u0018 \\u0019 \\u001a \\u001b "
4768 "\\u001c \\u001d \\u001e \\u001f "
4769 " ! \\\" # "
4770 "$ % & ' "
4771 "( ) * + "
4772 ", - . / "
4773 "0 1 2 3 "
4774 "4 5 6 7 "
4775 "8 9 : ; "
4776 "< = > ? "
4777 "@ A B C "
4778 "D E F G "
4779 "H I J K "
4780 "L M N O "
4781 "P Q R S "
4782 "T U V W "
4783 "X Y Z [ "
4784 "\\\\ ] ^ _ "
4785 "` a b c "
4786 "d e f g "
4787 "h i j k "
4788 "l m n o "
4789 "p q r s "
4790 "t u v w "
4791 "x y z { "
4792 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004793
4794
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004795// For a string that is less than 32k characters it should always be
4796// possible to allocate it in new space.
4797static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4798
4799
4800// Doing JSON quoting cannot make the string more than this many times larger.
4801static const int kJsonQuoteWorstCaseBlowup = 6;
4802
4803
4804// Covers the entire ASCII range (all other characters are unchanged by JSON
4805// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004806static const byte JsonQuoteLengths[kQuoteTableLength] = {
4807 6, 6, 6, 6, 6, 6, 6, 6,
4808 2, 2, 2, 6, 2, 2, 6, 6,
4809 6, 6, 6, 6, 6, 6, 6, 6,
4810 6, 6, 6, 6, 6, 6, 6, 6,
4811 1, 1, 2, 1, 1, 1, 1, 1,
4812 1, 1, 1, 1, 1, 1, 1, 1,
4813 1, 1, 1, 1, 1, 1, 1, 1,
4814 1, 1, 1, 1, 1, 1, 1, 1,
4815 1, 1, 1, 1, 1, 1, 1, 1,
4816 1, 1, 1, 1, 1, 1, 1, 1,
4817 1, 1, 1, 1, 1, 1, 1, 1,
4818 1, 1, 1, 1, 2, 1, 1, 1,
4819 1, 1, 1, 1, 1, 1, 1, 1,
4820 1, 1, 1, 1, 1, 1, 1, 1,
4821 1, 1, 1, 1, 1, 1, 1, 1,
4822 1, 1, 1, 1, 1, 1, 1, 1,
4823};
4824
4825
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004826template <typename StringType>
4827MaybeObject* AllocateRawString(int length);
4828
4829
4830template <>
4831MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4832 return Heap::AllocateRawTwoByteString(length);
4833}
4834
4835
4836template <>
4837MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4838 return Heap::AllocateRawAsciiString(length);
4839}
4840
4841
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004842template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004843static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004844 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004845 const Char* read_cursor = characters.start();
4846 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004847 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004848 int quoted_length = kSpaceForQuotes;
4849 while (read_cursor < end) {
4850 Char c = *(read_cursor++);
4851 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4852 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004853 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004854 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004855 }
4856 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004857 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4858 Object* new_object;
4859 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004860 return new_alloc;
4861 }
4862 StringType* new_string = StringType::cast(new_object);
4863
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004864 Char* write_cursor = reinterpret_cast<Char*>(
4865 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004866 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004867 *(write_cursor++) = '"';
4868
4869 read_cursor = characters.start();
4870 while (read_cursor < end) {
4871 Char c = *(read_cursor++);
4872 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4873 *(write_cursor++) = c;
4874 } else {
4875 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4876 const char* replacement = JsonQuotes +
4877 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4878 for (int i = 0; i < len; i++) {
4879 *write_cursor++ = *replacement++;
4880 }
4881 }
4882 }
4883 *(write_cursor++) = '"';
4884 return new_string;
4885}
4886
4887
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004888template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004889static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4890 int length = characters.length();
4891 Counters::quote_json_char_count.Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004892 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004893 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4894 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004895 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004896 }
4897
4898 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4899 Object* new_object;
4900 if (!new_alloc->ToObject(&new_object)) {
4901 return new_alloc;
4902 }
4903 if (!Heap::new_space()->Contains(new_object)) {
4904 // Even if our string is small enough to fit in new space we still have to
4905 // handle it being allocated in old space as may happen in the third
4906 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4907 // CEntryStub::GenerateCore.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004908 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004909 }
4910 StringType* new_string = StringType::cast(new_object);
4911 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004912
4913 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4914 Char* write_cursor = reinterpret_cast<Char*>(
4915 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004916 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004917 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004918
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004919 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004920 const Char* end = read_cursor + length;
4921 while (read_cursor < end) {
4922 Char c = *(read_cursor++);
4923 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4924 *(write_cursor++) = c;
4925 } else {
4926 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4927 const char* replacement = JsonQuotes +
4928 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4929 write_cursor[0] = replacement[0];
4930 if (len > 1) {
4931 write_cursor[1] = replacement[1];
4932 if (len > 2) {
4933 ASSERT(len == 6);
4934 write_cursor[2] = replacement[2];
4935 write_cursor[3] = replacement[3];
4936 write_cursor[4] = replacement[4];
4937 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004938 }
4939 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004940 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004941 }
4942 }
4943 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004944
4945 int final_length = static_cast<int>(
4946 write_cursor - reinterpret_cast<Char*>(
4947 new_string->address() + SeqAsciiString::kHeaderSize));
4948 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4949 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004950 return new_string;
4951}
4952
4953
4954static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4955 NoHandleAllocation ha;
4956 CONVERT_CHECKED(String, str, args[0]);
4957 if (!str->IsFlat()) {
4958 MaybeObject* try_flatten = str->TryFlatten();
4959 Object* flat;
4960 if (!try_flatten->ToObject(&flat)) {
4961 return try_flatten;
4962 }
4963 str = String::cast(flat);
4964 ASSERT(str->IsFlat());
4965 }
4966 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004967 return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004968 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004969 return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004970 }
4971}
4972
4973
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004974static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
4975 NoHandleAllocation ha;
4976 CONVERT_CHECKED(String, str, args[0]);
4977 if (!str->IsFlat()) {
4978 MaybeObject* try_flatten = str->TryFlatten();
4979 Object* flat;
4980 if (!try_flatten->ToObject(&flat)) {
4981 return try_flatten;
4982 }
4983 str = String::cast(flat);
4984 ASSERT(str->IsFlat());
4985 }
4986 if (str->IsTwoByteRepresentation()) {
4987 return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
4988 } else {
4989 return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
4990 }
4991}
4992
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004993
lrn@chromium.org303ada72010-10-27 09:33:13 +00004994static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004995 NoHandleAllocation ha;
4996
4997 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004998 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004999
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005000 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001
lrn@chromium.org25156de2010-04-06 13:10:27 +00005002 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
5003 double value = StringToInt(s, radix);
5004 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005005}
5006
5007
lrn@chromium.org303ada72010-10-27 09:33:13 +00005008static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005009 NoHandleAllocation ha;
5010 CONVERT_CHECKED(String, str, args[0]);
5011
5012 // ECMA-262 section 15.1.2.3, empty string is NaN
5013 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
5014
5015 // Create a number object from the value.
5016 return Heap::NumberFromDouble(value);
5017}
5018
5019
5020static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
5021static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
5022
5023
5024template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005025MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
5026 String* s,
5027 int length,
5028 int input_string_length,
5029 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005030 // We try this twice, once with the assumption that the result is no longer
5031 // than the input and, if that assumption breaks, again with the exact
5032 // length. This may not be pretty, but it is nicer than what was here before
5033 // and I hereby claim my vaffel-is.
5034 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005035 // Allocate the resulting string.
5036 //
5037 // NOTE: This assumes that the upper/lower case of an ascii
5038 // character is also ascii. This is currently the case, but it
5039 // might break in the future if we implement more context and locale
5040 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005041 Object* o;
5042 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
5043 ? Heap::AllocateRawAsciiString(length)
5044 : Heap::AllocateRawTwoByteString(length);
5045 if (!maybe_o->ToObject(&o)) return maybe_o;
5046 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005047 String* result = String::cast(o);
5048 bool has_changed_character = false;
5049
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005050 // Convert all characters to upper case, assuming that they will fit
5051 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005052 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005053 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005054 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005055 // We can assume that the string is not empty
5056 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005057 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005058 bool has_next = buffer->has_more();
5059 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005060 int char_length = mapping->get(current, next, chars);
5061 if (char_length == 0) {
5062 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005063 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005064 i++;
5065 } else if (char_length == 1) {
5066 // Common case: converting the letter resulted in one character.
5067 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005068 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005069 has_changed_character = true;
5070 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005071 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005072 // We've assumed that the result would be as long as the
5073 // input but here is a character that converts to several
5074 // characters. No matter, we calculate the exact length
5075 // of the result and try the whole thing again.
5076 //
5077 // Note that this leaves room for optimization. We could just
5078 // memcpy what we already have to the result string. Also,
5079 // the result string is the last object allocated we could
5080 // "realloc" it and probably, in the vast majority of cases,
5081 // extend the existing string to be able to hold the full
5082 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005083 int next_length = 0;
5084 if (has_next) {
5085 next_length = mapping->get(next, 0, chars);
5086 if (next_length == 0) next_length = 1;
5087 }
5088 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005089 while (buffer->has_more()) {
5090 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005091 // NOTE: we use 0 as the next character here because, while
5092 // the next character may affect what a character converts to,
5093 // it does not in any case affect the length of what it convert
5094 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005095 int char_length = mapping->get(current, 0, chars);
5096 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005097 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005098 if (current_length > Smi::kMaxValue) {
5099 Top::context()->mark_out_of_memory();
5100 return Failure::OutOfMemoryException();
5101 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005102 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005103 // Try again with the real length.
5104 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005105 } else {
5106 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005107 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005108 i++;
5109 }
5110 has_changed_character = true;
5111 }
5112 current = next;
5113 }
5114 if (has_changed_character) {
5115 return result;
5116 } else {
5117 // If we didn't actually change anything in doing the conversion
5118 // we simple return the result and let the converted string
5119 // become garbage; there is no reason to keep two identical strings
5120 // alive.
5121 return s;
5122 }
5123}
5124
5125
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005126namespace {
5127
lrn@chromium.org303ada72010-10-27 09:33:13 +00005128static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5129
5130
5131// Given a word and two range boundaries returns a word with high bit
5132// set in every byte iff the corresponding input byte was strictly in
5133// the range (m, n). All the other bits in the result are cleared.
5134// This function is only useful when it can be inlined and the
5135// boundaries are statically known.
5136// Requires: all bytes in the input word and the boundaries must be
5137// ascii (less than 0x7F).
5138static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5139 // Every byte in an ascii string is less than or equal to 0x7F.
5140 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5141 // Use strict inequalities since in edge cases the function could be
5142 // further simplified.
5143 ASSERT(0 < m && m < n && n < 0x7F);
5144 // Has high bit set in every w byte less than n.
5145 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5146 // Has high bit set in every w byte greater than m.
5147 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5148 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5149}
5150
5151
5152enum AsciiCaseConversion {
5153 ASCII_TO_LOWER,
5154 ASCII_TO_UPPER
5155};
5156
5157
5158template <AsciiCaseConversion dir>
5159struct FastAsciiConverter {
5160 static bool Convert(char* dst, char* src, int length) {
5161#ifdef DEBUG
5162 char* saved_dst = dst;
5163 char* saved_src = src;
5164#endif
5165 // We rely on the distance between upper and lower case letters
5166 // being a known power of 2.
5167 ASSERT('a' - 'A' == (1 << 5));
5168 // Boundaries for the range of input characters than require conversion.
5169 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5170 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5171 bool changed = false;
5172 char* const limit = src + length;
5173#ifdef V8_HOST_CAN_READ_UNALIGNED
5174 // Process the prefix of the input that requires no conversion one
5175 // (machine) word at a time.
5176 while (src <= limit - sizeof(uintptr_t)) {
5177 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5178 if (AsciiRangeMask(w, lo, hi) != 0) {
5179 changed = true;
5180 break;
5181 }
5182 *reinterpret_cast<uintptr_t*>(dst) = w;
5183 src += sizeof(uintptr_t);
5184 dst += sizeof(uintptr_t);
5185 }
5186 // Process the remainder of the input performing conversion when
5187 // required one word at a time.
5188 while (src <= limit - sizeof(uintptr_t)) {
5189 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5190 uintptr_t m = AsciiRangeMask(w, lo, hi);
5191 // The mask has high (7th) bit set in every byte that needs
5192 // conversion and we know that the distance between cases is
5193 // 1 << 5.
5194 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5195 src += sizeof(uintptr_t);
5196 dst += sizeof(uintptr_t);
5197 }
5198#endif
5199 // Process the last few bytes of the input (or the whole input if
5200 // unaligned access is not supported).
5201 while (src < limit) {
5202 char c = *src;
5203 if (lo < c && c < hi) {
5204 c ^= (1 << 5);
5205 changed = true;
5206 }
5207 *dst = c;
5208 ++src;
5209 ++dst;
5210 }
5211#ifdef DEBUG
5212 CheckConvert(saved_dst, saved_src, length, changed);
5213#endif
5214 return changed;
5215 }
5216
5217#ifdef DEBUG
5218 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5219 bool expected_changed = false;
5220 for (int i = 0; i < length; i++) {
5221 if (dst[i] == src[i]) continue;
5222 expected_changed = true;
5223 if (dir == ASCII_TO_LOWER) {
5224 ASSERT('A' <= src[i] && src[i] <= 'Z');
5225 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5226 } else {
5227 ASSERT(dir == ASCII_TO_UPPER);
5228 ASSERT('a' <= src[i] && src[i] <= 'z');
5229 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5230 }
5231 }
5232 ASSERT(expected_changed == changed);
5233 }
5234#endif
5235};
5236
5237
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005238struct ToLowerTraits {
5239 typedef unibrow::ToLowercase UnibrowConverter;
5240
lrn@chromium.org303ada72010-10-27 09:33:13 +00005241 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005242};
5243
5244
5245struct ToUpperTraits {
5246 typedef unibrow::ToUppercase UnibrowConverter;
5247
lrn@chromium.org303ada72010-10-27 09:33:13 +00005248 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005249};
5250
5251} // namespace
5252
5253
5254template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005255MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005256 Arguments args,
5257 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005258 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005259 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005260 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005261
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005262 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005263 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005264 if (length == 0) return s;
5265
5266 // Simpler handling of ascii strings.
5267 //
5268 // NOTE: This assumes that the upper/lower case of an ascii
5269 // character is also ascii. This is currently the case, but it
5270 // might break in the future if we implement more context and locale
5271 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005272 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005273 Object* o;
5274 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5275 if (!maybe_o->ToObject(&o)) return maybe_o;
5276 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005277 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005278 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005279 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005280 return has_changed_character ? result : s;
5281 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005282
lrn@chromium.org303ada72010-10-27 09:33:13 +00005283 Object* answer;
5284 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5285 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5286 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005287 if (answer->IsSmi()) {
5288 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005289 { MaybeObject* maybe_answer =
5290 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5291 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5292 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005293 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005294 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005295}
5296
5297
lrn@chromium.org303ada72010-10-27 09:33:13 +00005298static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005299 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005300}
5301
5302
lrn@chromium.org303ada72010-10-27 09:33:13 +00005303static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005304 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005305}
5306
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005307
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005308static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5309 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5310}
5311
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005312
lrn@chromium.org303ada72010-10-27 09:33:13 +00005313static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005314 NoHandleAllocation ha;
5315 ASSERT(args.length() == 3);
5316
5317 CONVERT_CHECKED(String, s, args[0]);
5318 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5319 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5320
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005321 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005322 int length = s->length();
5323
5324 int left = 0;
5325 if (trimLeft) {
5326 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5327 left++;
5328 }
5329 }
5330
5331 int right = length;
5332 if (trimRight) {
5333 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5334 right--;
5335 }
5336 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005337 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005338}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005339
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005340
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005341template <typename SubjectChar, typename PatternChar>
5342void FindStringIndices(Vector<const SubjectChar> subject,
5343 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005344 ZoneList<int>* indices,
5345 unsigned int limit) {
5346 ASSERT(limit > 0);
5347 // Collect indices of pattern in subject, and the end-of-string index.
5348 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005349 StringSearch<PatternChar, SubjectChar> search(pattern);
5350 int pattern_length = pattern.length();
5351 int index = 0;
5352 while (limit > 0) {
5353 index = search.Search(subject, index);
5354 if (index < 0) return;
5355 indices->Add(index);
5356 index += pattern_length;
5357 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005358 }
5359}
5360
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005361
lrn@chromium.org303ada72010-10-27 09:33:13 +00005362static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005363 ASSERT(args.length() == 3);
5364 HandleScope handle_scope;
5365 CONVERT_ARG_CHECKED(String, subject, 0);
5366 CONVERT_ARG_CHECKED(String, pattern, 1);
5367 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5368
5369 int subject_length = subject->length();
5370 int pattern_length = pattern->length();
5371 RUNTIME_ASSERT(pattern_length > 0);
5372
5373 // The limit can be very large (0xffffffffu), but since the pattern
5374 // isn't empty, we can never create more parts than ~half the length
5375 // of the subject.
5376
5377 if (!subject->IsFlat()) FlattenString(subject);
5378
5379 static const int kMaxInitialListCapacity = 16;
5380
5381 ZoneScope scope(DELETE_ON_EXIT);
5382
5383 // Find (up to limit) indices of separator and end-of-string in subject
5384 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5385 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005386 if (!pattern->IsFlat()) FlattenString(pattern);
5387
5388 // No allocation block.
5389 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005390 AssertNoAllocation nogc;
5391 if (subject->IsAsciiRepresentation()) {
5392 Vector<const char> subject_vector = subject->ToAsciiVector();
5393 if (pattern->IsAsciiRepresentation()) {
5394 FindStringIndices(subject_vector,
5395 pattern->ToAsciiVector(),
5396 &indices,
5397 limit);
5398 } else {
5399 FindStringIndices(subject_vector,
5400 pattern->ToUC16Vector(),
5401 &indices,
5402 limit);
5403 }
5404 } else {
5405 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5406 if (pattern->IsAsciiRepresentation()) {
5407 FindStringIndices(subject_vector,
5408 pattern->ToAsciiVector(),
5409 &indices,
5410 limit);
5411 } else {
5412 FindStringIndices(subject_vector,
5413 pattern->ToUC16Vector(),
5414 &indices,
5415 limit);
5416 }
5417 }
5418 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005419
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005420 if (static_cast<uint32_t>(indices.length()) < limit) {
5421 indices.Add(subject_length);
5422 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005423
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005424 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005425
5426 // Create JSArray of substrings separated by separator.
5427 int part_count = indices.length();
5428
5429 Handle<JSArray> result = Factory::NewJSArray(part_count);
5430 result->set_length(Smi::FromInt(part_count));
5431
5432 ASSERT(result->HasFastElements());
5433
5434 if (part_count == 1 && indices.at(0) == subject_length) {
5435 FixedArray::cast(result->elements())->set(0, *subject);
5436 return *result;
5437 }
5438
5439 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5440 int part_start = 0;
5441 for (int i = 0; i < part_count; i++) {
5442 HandleScope local_loop_handle;
5443 int part_end = indices.at(i);
5444 Handle<String> substring =
5445 Factory::NewSubString(subject, part_start, part_end);
5446 elements->set(i, *substring);
5447 part_start = part_end + pattern_length;
5448 }
5449
5450 return *result;
5451}
5452
5453
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005454// Copies ascii characters to the given fixed array looking up
5455// one-char strings in the cache. Gives up on the first char that is
5456// not in the cache and fills the remainder with smi zeros. Returns
5457// the length of the successfully copied prefix.
5458static int CopyCachedAsciiCharsToArray(const char* chars,
5459 FixedArray* elements,
5460 int length) {
5461 AssertNoAllocation nogc;
5462 FixedArray* ascii_cache = Heap::single_character_string_cache();
5463 Object* undefined = Heap::undefined_value();
5464 int i;
5465 for (i = 0; i < length; ++i) {
5466 Object* value = ascii_cache->get(chars[i]);
5467 if (value == undefined) break;
5468 ASSERT(!Heap::InNewSpace(value));
5469 elements->set(i, value, SKIP_WRITE_BARRIER);
5470 }
5471 if (i < length) {
5472 ASSERT(Smi::FromInt(0) == 0);
5473 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5474 }
5475#ifdef DEBUG
5476 for (int j = 0; j < length; ++j) {
5477 Object* element = elements->get(j);
5478 ASSERT(element == Smi::FromInt(0) ||
5479 (element->IsString() && String::cast(element)->LooksValid()));
5480 }
5481#endif
5482 return i;
5483}
5484
5485
5486// Converts a String to JSArray.
5487// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005488static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005489 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005490 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005491 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005492 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005493
5494 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005495 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005496
5497 Handle<FixedArray> elements;
5498 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005499 Object* obj;
5500 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5501 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5502 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005503 elements = Handle<FixedArray>(FixedArray::cast(obj));
5504
5505 Vector<const char> chars = s->ToAsciiVector();
5506 // Note, this will initialize all elements (not only the prefix)
5507 // to prevent GC from seeing partially initialized array.
5508 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5509 *elements,
5510 length);
5511
5512 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005513 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5514 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005515 }
5516 } else {
5517 elements = Factory::NewFixedArray(length);
5518 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005519 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5520 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005521 }
5522 }
5523
5524#ifdef DEBUG
5525 for (int i = 0; i < length; ++i) {
5526 ASSERT(String::cast(elements->get(i))->length() == 1);
5527 }
5528#endif
5529
5530 return *Factory::NewJSArrayWithElements(elements);
5531}
5532
5533
lrn@chromium.org303ada72010-10-27 09:33:13 +00005534static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005535 NoHandleAllocation ha;
5536 ASSERT(args.length() == 1);
5537 CONVERT_CHECKED(String, value, args[0]);
5538 return value->ToObject();
5539}
5540
5541
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005542bool Runtime::IsUpperCaseChar(uint16_t ch) {
5543 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5544 int char_length = to_upper_mapping.get(ch, 0, chars);
5545 return char_length == 0;
5546}
5547
5548
lrn@chromium.org303ada72010-10-27 09:33:13 +00005549static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005550 NoHandleAllocation ha;
5551 ASSERT(args.length() == 1);
5552
5553 Object* number = args[0];
5554 RUNTIME_ASSERT(number->IsNumber());
5555
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005556 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005557}
5558
5559
lrn@chromium.org303ada72010-10-27 09:33:13 +00005560static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005561 NoHandleAllocation ha;
5562 ASSERT(args.length() == 1);
5563
5564 Object* number = args[0];
5565 RUNTIME_ASSERT(number->IsNumber());
5566
5567 return Heap::NumberToString(number, false);
5568}
5569
5570
lrn@chromium.org303ada72010-10-27 09:33:13 +00005571static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005572 NoHandleAllocation ha;
5573 ASSERT(args.length() == 1);
5574
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005575 CONVERT_DOUBLE_CHECKED(number, args[0]);
5576
5577 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5578 if (number > 0 && number <= Smi::kMaxValue) {
5579 return Smi::FromInt(static_cast<int>(number));
5580 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005581 return Heap::NumberFromDouble(DoubleToInteger(number));
5582}
5583
5584
lrn@chromium.org303ada72010-10-27 09:33:13 +00005585static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005586 NoHandleAllocation ha;
5587 ASSERT(args.length() == 1);
5588
5589 CONVERT_DOUBLE_CHECKED(number, args[0]);
5590
5591 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5592 if (number > 0 && number <= Smi::kMaxValue) {
5593 return Smi::FromInt(static_cast<int>(number));
5594 }
5595
5596 double double_value = DoubleToInteger(number);
5597 // Map both -0 and +0 to +0.
5598 if (double_value == 0) double_value = 0;
5599
5600 return Heap::NumberFromDouble(double_value);
5601}
5602
5603
lrn@chromium.org303ada72010-10-27 09:33:13 +00005604static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005605 NoHandleAllocation ha;
5606 ASSERT(args.length() == 1);
5607
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005608 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005609 return Heap::NumberFromUint32(number);
5610}
5611
5612
lrn@chromium.org303ada72010-10-27 09:33:13 +00005613static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005614 NoHandleAllocation ha;
5615 ASSERT(args.length() == 1);
5616
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005617 CONVERT_DOUBLE_CHECKED(number, args[0]);
5618
5619 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5620 if (number > 0 && number <= Smi::kMaxValue) {
5621 return Smi::FromInt(static_cast<int>(number));
5622 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005623 return Heap::NumberFromInt32(DoubleToInt32(number));
5624}
5625
5626
ager@chromium.org870a0b62008-11-04 11:43:05 +00005627// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5628// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005629static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005630 NoHandleAllocation ha;
5631 ASSERT(args.length() == 1);
5632
5633 Object* obj = args[0];
5634 if (obj->IsSmi()) {
5635 return obj;
5636 }
5637 if (obj->IsHeapNumber()) {
5638 double value = HeapNumber::cast(obj)->value();
5639 int int_value = FastD2I(value);
5640 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5641 return Smi::FromInt(int_value);
5642 }
5643 }
5644 return Heap::nan_value();
5645}
5646
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005647
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005648static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5649 NoHandleAllocation ha;
5650 ASSERT(args.length() == 0);
5651 return Heap::AllocateHeapNumber(0);
5652}
5653
5654
lrn@chromium.org303ada72010-10-27 09:33:13 +00005655static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005656 NoHandleAllocation ha;
5657 ASSERT(args.length() == 2);
5658
5659 CONVERT_DOUBLE_CHECKED(x, args[0]);
5660 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005661 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005662}
5663
5664
lrn@chromium.org303ada72010-10-27 09:33:13 +00005665static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005666 NoHandleAllocation ha;
5667 ASSERT(args.length() == 2);
5668
5669 CONVERT_DOUBLE_CHECKED(x, args[0]);
5670 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005671 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005672}
5673
5674
lrn@chromium.org303ada72010-10-27 09:33:13 +00005675static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005676 NoHandleAllocation ha;
5677 ASSERT(args.length() == 2);
5678
5679 CONVERT_DOUBLE_CHECKED(x, args[0]);
5680 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005681 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005682}
5683
5684
lrn@chromium.org303ada72010-10-27 09:33:13 +00005685static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005686 NoHandleAllocation ha;
5687 ASSERT(args.length() == 1);
5688
5689 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005690 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005691}
5692
5693
lrn@chromium.org303ada72010-10-27 09:33:13 +00005694static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005695 NoHandleAllocation ha;
5696 ASSERT(args.length() == 0);
5697
5698 return Heap::NumberFromDouble(9876543210.0);
5699}
5700
5701
lrn@chromium.org303ada72010-10-27 09:33:13 +00005702static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005703 NoHandleAllocation ha;
5704 ASSERT(args.length() == 2);
5705
5706 CONVERT_DOUBLE_CHECKED(x, args[0]);
5707 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005708 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005709}
5710
5711
lrn@chromium.org303ada72010-10-27 09:33:13 +00005712static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005713 NoHandleAllocation ha;
5714 ASSERT(args.length() == 2);
5715
5716 CONVERT_DOUBLE_CHECKED(x, args[0]);
5717 CONVERT_DOUBLE_CHECKED(y, args[1]);
5718
ager@chromium.org3811b432009-10-28 14:53:37 +00005719 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005720 // NumberFromDouble may return a Smi instead of a Number object
5721 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005722}
5723
5724
lrn@chromium.org303ada72010-10-27 09:33:13 +00005725static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005726 NoHandleAllocation ha;
5727 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005728 CONVERT_CHECKED(String, str1, args[0]);
5729 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005730 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005731 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005732}
5733
5734
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005735template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005736static inline void StringBuilderConcatHelper(String* special,
5737 sinkchar* sink,
5738 FixedArray* fixed_array,
5739 int array_length) {
5740 int position = 0;
5741 for (int i = 0; i < array_length; i++) {
5742 Object* element = fixed_array->get(i);
5743 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005744 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005745 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005746 int pos;
5747 int len;
5748 if (encoded_slice > 0) {
5749 // Position and length encoded in one smi.
5750 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5751 len = StringBuilderSubstringLength::decode(encoded_slice);
5752 } else {
5753 // Position and length encoded in two smis.
5754 Object* obj = fixed_array->get(++i);
5755 ASSERT(obj->IsSmi());
5756 pos = Smi::cast(obj)->value();
5757 len = -encoded_slice;
5758 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005759 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005760 sink + position,
5761 pos,
5762 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005763 position += len;
5764 } else {
5765 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005766 int element_length = string->length();
5767 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005768 position += element_length;
5769 }
5770 }
5771}
5772
5773
lrn@chromium.org303ada72010-10-27 09:33:13 +00005774static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005775 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005776 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005777 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005778 if (!args[1]->IsSmi()) {
5779 Top::context()->mark_out_of_memory();
5780 return Failure::OutOfMemoryException();
5781 }
5782 int array_length = Smi::cast(args[1])->value();
5783 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005784
5785 // This assumption is used by the slice encoding in one or two smis.
5786 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5787
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005788 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005789 if (!array->HasFastElements()) {
5790 return Top::Throw(Heap::illegal_argument_symbol());
5791 }
5792 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005793 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005794 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005795 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005796
5797 if (array_length == 0) {
5798 return Heap::empty_string();
5799 } else if (array_length == 1) {
5800 Object* first = fixed_array->get(0);
5801 if (first->IsString()) return first;
5802 }
5803
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005804 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005805 int position = 0;
5806 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005807 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005808 Object* elt = fixed_array->get(i);
5809 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005810 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005811 int smi_value = Smi::cast(elt)->value();
5812 int pos;
5813 int len;
5814 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005815 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005816 pos = StringBuilderSubstringPosition::decode(smi_value);
5817 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005818 } else {
5819 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005820 len = -smi_value;
5821 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005822 i++;
5823 if (i >= array_length) {
5824 return Top::Throw(Heap::illegal_argument_symbol());
5825 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005826 Object* next_smi = fixed_array->get(i);
5827 if (!next_smi->IsSmi()) {
5828 return Top::Throw(Heap::illegal_argument_symbol());
5829 }
5830 pos = Smi::cast(next_smi)->value();
5831 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005832 return Top::Throw(Heap::illegal_argument_symbol());
5833 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005834 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005835 ASSERT(pos >= 0);
5836 ASSERT(len >= 0);
5837 if (pos > special_length || len > special_length - pos) {
5838 return Top::Throw(Heap::illegal_argument_symbol());
5839 }
5840 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005841 } else if (elt->IsString()) {
5842 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005843 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005844 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005845 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005846 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005847 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005848 } else {
5849 return Top::Throw(Heap::illegal_argument_symbol());
5850 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005851 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005852 Top::context()->mark_out_of_memory();
5853 return Failure::OutOfMemoryException();
5854 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005855 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005856 }
5857
5858 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005859 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005860
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005861 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005862 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5863 if (!maybe_object->ToObject(&object)) return maybe_object;
5864 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005865 SeqAsciiString* answer = SeqAsciiString::cast(object);
5866 StringBuilderConcatHelper(special,
5867 answer->GetChars(),
5868 fixed_array,
5869 array_length);
5870 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005871 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005872 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5873 if (!maybe_object->ToObject(&object)) return maybe_object;
5874 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005875 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5876 StringBuilderConcatHelper(special,
5877 answer->GetChars(),
5878 fixed_array,
5879 array_length);
5880 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005881 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005882}
5883
5884
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005885static MaybeObject* Runtime_StringBuilderJoin(Arguments args) {
5886 NoHandleAllocation ha;
5887 ASSERT(args.length() == 3);
5888 CONVERT_CHECKED(JSArray, array, args[0]);
5889 if (!args[1]->IsSmi()) {
5890 Top::context()->mark_out_of_memory();
5891 return Failure::OutOfMemoryException();
5892 }
5893 int array_length = Smi::cast(args[1])->value();
5894 CONVERT_CHECKED(String, separator, args[2]);
5895
5896 if (!array->HasFastElements()) {
5897 return Top::Throw(Heap::illegal_argument_symbol());
5898 }
5899 FixedArray* fixed_array = FixedArray::cast(array->elements());
5900 if (fixed_array->length() < array_length) {
5901 array_length = fixed_array->length();
5902 }
5903
5904 if (array_length == 0) {
5905 return Heap::empty_string();
5906 } else if (array_length == 1) {
5907 Object* first = fixed_array->get(0);
5908 if (first->IsString()) return first;
5909 }
5910
5911 int separator_length = separator->length();
5912 int max_nof_separators =
5913 (String::kMaxLength + separator_length - 1) / separator_length;
5914 if (max_nof_separators < (array_length - 1)) {
5915 Top::context()->mark_out_of_memory();
5916 return Failure::OutOfMemoryException();
5917 }
5918 int length = (array_length - 1) * separator_length;
5919 for (int i = 0; i < array_length; i++) {
5920 Object* element_obj = fixed_array->get(i);
5921 if (!element_obj->IsString()) {
5922 // TODO(1161): handle this case.
5923 return Top::Throw(Heap::illegal_argument_symbol());
5924 }
5925 String* element = String::cast(element_obj);
5926 int increment = element->length();
5927 if (increment > String::kMaxLength - length) {
5928 Top::context()->mark_out_of_memory();
5929 return Failure::OutOfMemoryException();
5930 }
5931 length += increment;
5932 }
5933
5934 Object* object;
5935 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5936 if (!maybe_object->ToObject(&object)) return maybe_object;
5937 }
5938 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5939
5940 uc16* sink = answer->GetChars();
5941#ifdef DEBUG
5942 uc16* end = sink + length;
5943#endif
5944
5945 String* first = String::cast(fixed_array->get(0));
5946 int first_length = first->length();
5947 String::WriteToFlat(first, sink, 0, first_length);
5948 sink += first_length;
5949
5950 for (int i = 1; i < array_length; i++) {
5951 ASSERT(sink + separator_length <= end);
5952 String::WriteToFlat(separator, sink, 0, separator_length);
5953 sink += separator_length;
5954
5955 String* element = String::cast(fixed_array->get(i));
5956 int element_length = element->length();
5957 ASSERT(sink + element_length <= end);
5958 String::WriteToFlat(element, sink, 0, element_length);
5959 sink += element_length;
5960 }
5961 ASSERT(sink == end);
5962
5963 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
5964 return answer;
5965}
5966
5967
lrn@chromium.org303ada72010-10-27 09:33:13 +00005968static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969 NoHandleAllocation ha;
5970 ASSERT(args.length() == 2);
5971
5972 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5973 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5974 return Heap::NumberFromInt32(x | y);
5975}
5976
5977
lrn@chromium.org303ada72010-10-27 09:33:13 +00005978static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 NoHandleAllocation ha;
5980 ASSERT(args.length() == 2);
5981
5982 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5983 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5984 return Heap::NumberFromInt32(x & y);
5985}
5986
5987
lrn@chromium.org303ada72010-10-27 09:33:13 +00005988static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 NoHandleAllocation ha;
5990 ASSERT(args.length() == 2);
5991
5992 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5993 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5994 return Heap::NumberFromInt32(x ^ y);
5995}
5996
5997
lrn@chromium.org303ada72010-10-27 09:33:13 +00005998static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005999 NoHandleAllocation ha;
6000 ASSERT(args.length() == 1);
6001
6002 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6003 return Heap::NumberFromInt32(~x);
6004}
6005
6006
lrn@chromium.org303ada72010-10-27 09:33:13 +00006007static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008 NoHandleAllocation ha;
6009 ASSERT(args.length() == 2);
6010
6011 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6012 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6013 return Heap::NumberFromInt32(x << (y & 0x1f));
6014}
6015
6016
lrn@chromium.org303ada72010-10-27 09:33:13 +00006017static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006018 NoHandleAllocation ha;
6019 ASSERT(args.length() == 2);
6020
6021 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6022 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6023 return Heap::NumberFromUint32(x >> (y & 0x1f));
6024}
6025
6026
lrn@chromium.org303ada72010-10-27 09:33:13 +00006027static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006028 NoHandleAllocation ha;
6029 ASSERT(args.length() == 2);
6030
6031 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6032 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6033 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
6034}
6035
6036
lrn@chromium.org303ada72010-10-27 09:33:13 +00006037static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 NoHandleAllocation ha;
6039 ASSERT(args.length() == 2);
6040
6041 CONVERT_DOUBLE_CHECKED(x, args[0]);
6042 CONVERT_DOUBLE_CHECKED(y, args[1]);
6043 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6044 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6045 if (x == y) return Smi::FromInt(EQUAL);
6046 Object* result;
6047 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6048 result = Smi::FromInt(EQUAL);
6049 } else {
6050 result = Smi::FromInt(NOT_EQUAL);
6051 }
6052 return result;
6053}
6054
6055
lrn@chromium.org303ada72010-10-27 09:33:13 +00006056static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006057 NoHandleAllocation ha;
6058 ASSERT(args.length() == 2);
6059
6060 CONVERT_CHECKED(String, x, args[0]);
6061 CONVERT_CHECKED(String, y, args[1]);
6062
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006063 bool not_equal = !x->Equals(y);
6064 // This is slightly convoluted because the value that signifies
6065 // equality is 0 and inequality is 1 so we have to negate the result
6066 // from String::Equals.
6067 ASSERT(not_equal == 0 || not_equal == 1);
6068 STATIC_CHECK(EQUAL == 0);
6069 STATIC_CHECK(NOT_EQUAL == 1);
6070 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006071}
6072
6073
lrn@chromium.org303ada72010-10-27 09:33:13 +00006074static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006075 NoHandleAllocation ha;
6076 ASSERT(args.length() == 3);
6077
6078 CONVERT_DOUBLE_CHECKED(x, args[0]);
6079 CONVERT_DOUBLE_CHECKED(y, args[1]);
6080 if (isnan(x) || isnan(y)) return args[2];
6081 if (x == y) return Smi::FromInt(EQUAL);
6082 if (isless(x, y)) return Smi::FromInt(LESS);
6083 return Smi::FromInt(GREATER);
6084}
6085
6086
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006087// Compare two Smis as if they were converted to strings and then
6088// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006089static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006090 NoHandleAllocation ha;
6091 ASSERT(args.length() == 2);
6092
6093 // Arrays for the individual characters of the two Smis. Smis are
6094 // 31 bit integers and 10 decimal digits are therefore enough.
6095 static int x_elms[10];
6096 static int y_elms[10];
6097
6098 // Extract the integer values from the Smis.
6099 CONVERT_CHECKED(Smi, x, args[0]);
6100 CONVERT_CHECKED(Smi, y, args[1]);
6101 int x_value = x->value();
6102 int y_value = y->value();
6103
6104 // If the integers are equal so are the string representations.
6105 if (x_value == y_value) return Smi::FromInt(EQUAL);
6106
6107 // If one of the integers are zero the normal integer order is the
6108 // same as the lexicographic order of the string representations.
6109 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6110
ager@chromium.org32912102009-01-16 10:38:43 +00006111 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006112 // smallest because the char code of '-' is less than the char code
6113 // of any digit. Otherwise, we make both values positive.
6114 if (x_value < 0 || y_value < 0) {
6115 if (y_value >= 0) return Smi::FromInt(LESS);
6116 if (x_value >= 0) return Smi::FromInt(GREATER);
6117 x_value = -x_value;
6118 y_value = -y_value;
6119 }
6120
6121 // Convert the integers to arrays of their decimal digits.
6122 int x_index = 0;
6123 int y_index = 0;
6124 while (x_value > 0) {
6125 x_elms[x_index++] = x_value % 10;
6126 x_value /= 10;
6127 }
6128 while (y_value > 0) {
6129 y_elms[y_index++] = y_value % 10;
6130 y_value /= 10;
6131 }
6132
6133 // Loop through the arrays of decimal digits finding the first place
6134 // where they differ.
6135 while (--x_index >= 0 && --y_index >= 0) {
6136 int diff = x_elms[x_index] - y_elms[y_index];
6137 if (diff != 0) return Smi::FromInt(diff);
6138 }
6139
6140 // If one array is a suffix of the other array, the longest array is
6141 // the representation of the largest of the Smis in the
6142 // lexicographic ordering.
6143 return Smi::FromInt(x_index - y_index);
6144}
6145
6146
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006147static Object* StringInputBufferCompare(String* x, String* y) {
6148 static StringInputBuffer bufx;
6149 static StringInputBuffer bufy;
6150 bufx.Reset(x);
6151 bufy.Reset(y);
6152 while (bufx.has_more() && bufy.has_more()) {
6153 int d = bufx.GetNext() - bufy.GetNext();
6154 if (d < 0) return Smi::FromInt(LESS);
6155 else if (d > 0) return Smi::FromInt(GREATER);
6156 }
6157
6158 // x is (non-trivial) prefix of y:
6159 if (bufy.has_more()) return Smi::FromInt(LESS);
6160 // y is prefix of x:
6161 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6162}
6163
6164
6165static Object* FlatStringCompare(String* x, String* y) {
6166 ASSERT(x->IsFlat());
6167 ASSERT(y->IsFlat());
6168 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6169 int prefix_length = x->length();
6170 if (y->length() < prefix_length) {
6171 prefix_length = y->length();
6172 equal_prefix_result = Smi::FromInt(GREATER);
6173 } else if (y->length() > prefix_length) {
6174 equal_prefix_result = Smi::FromInt(LESS);
6175 }
6176 int r;
6177 if (x->IsAsciiRepresentation()) {
6178 Vector<const char> x_chars = x->ToAsciiVector();
6179 if (y->IsAsciiRepresentation()) {
6180 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006181 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006182 } else {
6183 Vector<const uc16> y_chars = y->ToUC16Vector();
6184 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6185 }
6186 } else {
6187 Vector<const uc16> x_chars = x->ToUC16Vector();
6188 if (y->IsAsciiRepresentation()) {
6189 Vector<const char> y_chars = y->ToAsciiVector();
6190 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6191 } else {
6192 Vector<const uc16> y_chars = y->ToUC16Vector();
6193 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6194 }
6195 }
6196 Object* result;
6197 if (r == 0) {
6198 result = equal_prefix_result;
6199 } else {
6200 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6201 }
6202 ASSERT(result == StringInputBufferCompare(x, y));
6203 return result;
6204}
6205
6206
lrn@chromium.org303ada72010-10-27 09:33:13 +00006207static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006208 NoHandleAllocation ha;
6209 ASSERT(args.length() == 2);
6210
6211 CONVERT_CHECKED(String, x, args[0]);
6212 CONVERT_CHECKED(String, y, args[1]);
6213
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006214 Counters::string_compare_runtime.Increment();
6215
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006216 // A few fast case tests before we flatten.
6217 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006218 if (y->length() == 0) {
6219 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006221 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006222 return Smi::FromInt(LESS);
6223 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006224
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006225 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006226 if (d < 0) return Smi::FromInt(LESS);
6227 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006228
lrn@chromium.org303ada72010-10-27 09:33:13 +00006229 Object* obj;
6230 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
6231 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6232 }
6233 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
6234 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6235 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006236
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006237 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
6238 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006239}
6240
6241
lrn@chromium.org303ada72010-10-27 09:33:13 +00006242static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006243 NoHandleAllocation ha;
6244 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006245 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006246
6247 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006248 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006249}
6250
6251
lrn@chromium.org303ada72010-10-27 09:33:13 +00006252static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006253 NoHandleAllocation ha;
6254 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006255 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006256
6257 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006258 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006259}
6260
6261
lrn@chromium.org303ada72010-10-27 09:33:13 +00006262static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006263 NoHandleAllocation ha;
6264 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006265 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006266
6267 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006268 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006269}
6270
6271
lrn@chromium.org303ada72010-10-27 09:33:13 +00006272static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006273 NoHandleAllocation ha;
6274 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006275 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006276
6277 CONVERT_DOUBLE_CHECKED(x, args[0]);
6278 CONVERT_DOUBLE_CHECKED(y, args[1]);
6279 double result;
6280 if (isinf(x) && isinf(y)) {
6281 // Make sure that the result in case of two infinite arguments
6282 // is a multiple of Pi / 4. The sign of the result is determined
6283 // by the first argument (x) and the sign of the second argument
6284 // determines the multiplier: one or three.
6285 static double kPiDividedBy4 = 0.78539816339744830962;
6286 int multiplier = (x < 0) ? -1 : 1;
6287 if (y < 0) multiplier *= 3;
6288 result = multiplier * kPiDividedBy4;
6289 } else {
6290 result = atan2(x, y);
6291 }
6292 return Heap::AllocateHeapNumber(result);
6293}
6294
6295
lrn@chromium.org303ada72010-10-27 09:33:13 +00006296static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006297 NoHandleAllocation ha;
6298 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006299 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006300
6301 CONVERT_DOUBLE_CHECKED(x, args[0]);
6302 return Heap::NumberFromDouble(ceiling(x));
6303}
6304
6305
lrn@chromium.org303ada72010-10-27 09:33:13 +00006306static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006307 NoHandleAllocation ha;
6308 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006309 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006310
6311 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006312 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006313}
6314
6315
lrn@chromium.org303ada72010-10-27 09:33:13 +00006316static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006317 NoHandleAllocation ha;
6318 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006319 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320
6321 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006322 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006323}
6324
6325
lrn@chromium.org303ada72010-10-27 09:33:13 +00006326static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006327 NoHandleAllocation ha;
6328 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006329 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006330
6331 CONVERT_DOUBLE_CHECKED(x, args[0]);
6332 return Heap::NumberFromDouble(floor(x));
6333}
6334
6335
lrn@chromium.org303ada72010-10-27 09:33:13 +00006336static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006337 NoHandleAllocation ha;
6338 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006339 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006340
6341 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006342 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006343}
6344
6345
lrn@chromium.org303ada72010-10-27 09:33:13 +00006346static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006347 NoHandleAllocation ha;
6348 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006349 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006350
6351 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006352
6353 // If the second argument is a smi, it is much faster to call the
6354 // custom powi() function than the generic pow().
6355 if (args[1]->IsSmi()) {
6356 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006357 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006358 }
6359
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006360 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006361 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006362}
6363
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006364// Fast version of Math.pow if we know that y is not an integer and
6365// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006366static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006367 NoHandleAllocation ha;
6368 ASSERT(args.length() == 2);
6369 CONVERT_DOUBLE_CHECKED(x, args[0]);
6370 CONVERT_DOUBLE_CHECKED(y, args[1]);
6371 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006372 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006373 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006374 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006375 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006376 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006377 }
6378}
6379
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006380
lrn@chromium.org303ada72010-10-27 09:33:13 +00006381static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006382 NoHandleAllocation ha;
6383 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006384 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006385
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006386 if (!args[0]->IsHeapNumber()) {
6387 // Must be smi. Return the argument unchanged for all the other types
6388 // to make fuzz-natives test happy.
6389 return args[0];
6390 }
6391
6392 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6393
6394 double value = number->value();
6395 int exponent = number->get_exponent();
6396 int sign = number->get_sign();
6397
6398 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6399 // should be rounded to 2^30, which is not smi.
6400 if (!sign && exponent <= kSmiValueSize - 3) {
6401 return Smi::FromInt(static_cast<int>(value + 0.5));
6402 }
6403
6404 // If the magnitude is big enough, there's no place for fraction part. If we
6405 // try to add 0.5 to this number, 1.0 will be added instead.
6406 if (exponent >= 52) {
6407 return number;
6408 }
6409
6410 if (sign && value >= -0.5) return Heap::minus_zero_value();
6411
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006412 // Do not call NumberFromDouble() to avoid extra checks.
6413 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006414}
6415
6416
lrn@chromium.org303ada72010-10-27 09:33:13 +00006417static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006418 NoHandleAllocation ha;
6419 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006420 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006421
6422 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006423 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006424}
6425
6426
lrn@chromium.org303ada72010-10-27 09:33:13 +00006427static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006428 NoHandleAllocation ha;
6429 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006430 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006431
6432 CONVERT_DOUBLE_CHECKED(x, args[0]);
6433 return Heap::AllocateHeapNumber(sqrt(x));
6434}
6435
6436
lrn@chromium.org303ada72010-10-27 09:33:13 +00006437static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006438 NoHandleAllocation ha;
6439 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006440 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441
6442 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006443 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006444}
6445
6446
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006447static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006448 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6449 181, 212, 243, 273, 304, 334};
6450 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6451 182, 213, 244, 274, 305, 335};
6452
6453 year += month / 12;
6454 month %= 12;
6455 if (month < 0) {
6456 year--;
6457 month += 12;
6458 }
6459
6460 ASSERT(month >= 0);
6461 ASSERT(month < 12);
6462
6463 // year_delta is an arbitrary number such that:
6464 // a) year_delta = -1 (mod 400)
6465 // b) year + year_delta > 0 for years in the range defined by
6466 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6467 // Jan 1 1970. This is required so that we don't run into integer
6468 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006469 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006470 // operations.
6471 static const int year_delta = 399999;
6472 static const int base_day = 365 * (1970 + year_delta) +
6473 (1970 + year_delta) / 4 -
6474 (1970 + year_delta) / 100 +
6475 (1970 + year_delta) / 400;
6476
6477 int year1 = year + year_delta;
6478 int day_from_year = 365 * year1 +
6479 year1 / 4 -
6480 year1 / 100 +
6481 year1 / 400 -
6482 base_day;
6483
6484 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006485 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006486 }
6487
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006488 return day_from_year + day_from_month_leap[month] + day - 1;
6489}
6490
6491
lrn@chromium.org303ada72010-10-27 09:33:13 +00006492static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006493 NoHandleAllocation ha;
6494 ASSERT(args.length() == 3);
6495
6496 CONVERT_SMI_CHECKED(year, args[0]);
6497 CONVERT_SMI_CHECKED(month, args[1]);
6498 CONVERT_SMI_CHECKED(date, args[2]);
6499
6500 return Smi::FromInt(MakeDay(year, month, date));
6501}
6502
6503
6504static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6505static const int kDaysIn4Years = 4 * 365 + 1;
6506static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6507static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6508static const int kDays1970to2000 = 30 * 365 + 7;
6509static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6510 kDays1970to2000;
6511static const int kYearsOffset = 400000;
6512
6513static const char kDayInYear[] = {
6514 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6515 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6516 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6517 22, 23, 24, 25, 26, 27, 28,
6518 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6519 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6520 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6521 22, 23, 24, 25, 26, 27, 28, 29, 30,
6522 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6523 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6524 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6525 22, 23, 24, 25, 26, 27, 28, 29, 30,
6526 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6527 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6528 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6529 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6530 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6531 22, 23, 24, 25, 26, 27, 28, 29, 30,
6532 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6533 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6534 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6535 22, 23, 24, 25, 26, 27, 28, 29, 30,
6536 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6537 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6538
6539 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6540 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6541 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6542 22, 23, 24, 25, 26, 27, 28,
6543 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6544 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6545 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6546 22, 23, 24, 25, 26, 27, 28, 29, 30,
6547 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6548 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6549 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6550 22, 23, 24, 25, 26, 27, 28, 29, 30,
6551 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6552 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6553 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6554 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6555 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6556 22, 23, 24, 25, 26, 27, 28, 29, 30,
6557 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6558 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6559 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6560 22, 23, 24, 25, 26, 27, 28, 29, 30,
6561 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6562 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6563
6564 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6565 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6566 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6567 22, 23, 24, 25, 26, 27, 28, 29,
6568 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6569 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6570 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6571 22, 23, 24, 25, 26, 27, 28, 29, 30,
6572 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6573 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6574 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6575 22, 23, 24, 25, 26, 27, 28, 29, 30,
6576 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6577 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6578 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6579 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6580 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6581 22, 23, 24, 25, 26, 27, 28, 29, 30,
6582 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6583 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6584 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6585 22, 23, 24, 25, 26, 27, 28, 29, 30,
6586 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6587 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6588
6589 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6590 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6591 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6592 22, 23, 24, 25, 26, 27, 28,
6593 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6594 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6595 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6596 22, 23, 24, 25, 26, 27, 28, 29, 30,
6597 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6598 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6599 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6600 22, 23, 24, 25, 26, 27, 28, 29, 30,
6601 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6602 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6603 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6604 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6605 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6606 22, 23, 24, 25, 26, 27, 28, 29, 30,
6607 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6608 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6609 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6610 22, 23, 24, 25, 26, 27, 28, 29, 30,
6611 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6612 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6613
6614static const char kMonthInYear[] = {
6615 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,
6616 0, 0, 0, 0, 0, 0,
6617 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,
6618 1, 1, 1,
6619 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,
6620 2, 2, 2, 2, 2, 2,
6621 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,
6622 3, 3, 3, 3, 3,
6623 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,
6624 4, 4, 4, 4, 4, 4,
6625 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,
6626 5, 5, 5, 5, 5,
6627 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,
6628 6, 6, 6, 6, 6, 6,
6629 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,
6630 7, 7, 7, 7, 7, 7,
6631 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,
6632 8, 8, 8, 8, 8,
6633 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,
6634 9, 9, 9, 9, 9, 9,
6635 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6636 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6637 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6638 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6639
6640 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,
6641 0, 0, 0, 0, 0, 0,
6642 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,
6643 1, 1, 1,
6644 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,
6645 2, 2, 2, 2, 2, 2,
6646 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,
6647 3, 3, 3, 3, 3,
6648 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,
6649 4, 4, 4, 4, 4, 4,
6650 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,
6651 5, 5, 5, 5, 5,
6652 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,
6653 6, 6, 6, 6, 6, 6,
6654 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,
6655 7, 7, 7, 7, 7, 7,
6656 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,
6657 8, 8, 8, 8, 8,
6658 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,
6659 9, 9, 9, 9, 9, 9,
6660 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6661 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6662 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6663 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6664
6665 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,
6666 0, 0, 0, 0, 0, 0,
6667 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,
6668 1, 1, 1, 1,
6669 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,
6670 2, 2, 2, 2, 2, 2,
6671 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,
6672 3, 3, 3, 3, 3,
6673 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,
6674 4, 4, 4, 4, 4, 4,
6675 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,
6676 5, 5, 5, 5, 5,
6677 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,
6678 6, 6, 6, 6, 6, 6,
6679 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,
6680 7, 7, 7, 7, 7, 7,
6681 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,
6682 8, 8, 8, 8, 8,
6683 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,
6684 9, 9, 9, 9, 9, 9,
6685 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6686 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6687 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6688 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6689
6690 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,
6691 0, 0, 0, 0, 0, 0,
6692 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,
6693 1, 1, 1,
6694 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,
6695 2, 2, 2, 2, 2, 2,
6696 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,
6697 3, 3, 3, 3, 3,
6698 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,
6699 4, 4, 4, 4, 4, 4,
6700 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,
6701 5, 5, 5, 5, 5,
6702 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,
6703 6, 6, 6, 6, 6, 6,
6704 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,
6705 7, 7, 7, 7, 7, 7,
6706 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,
6707 8, 8, 8, 8, 8,
6708 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,
6709 9, 9, 9, 9, 9, 9,
6710 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6711 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6712 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6713 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6714
6715
6716// This function works for dates from 1970 to 2099.
6717static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006718 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006719#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006720 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006721#endif
6722
6723 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6724 date %= kDaysIn4Years;
6725
6726 month = kMonthInYear[date];
6727 day = kDayInYear[date];
6728
6729 ASSERT(MakeDay(year, month, day) == save_date);
6730}
6731
6732
6733static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006734 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006735#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006736 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006737#endif
6738
6739 date += kDaysOffset;
6740 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6741 date %= kDaysIn400Years;
6742
6743 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6744
6745 date--;
6746 int yd1 = date / kDaysIn100Years;
6747 date %= kDaysIn100Years;
6748 year += 100 * yd1;
6749
6750 date++;
6751 int yd2 = date / kDaysIn4Years;
6752 date %= kDaysIn4Years;
6753 year += 4 * yd2;
6754
6755 date--;
6756 int yd3 = date / 365;
6757 date %= 365;
6758 year += yd3;
6759
6760 bool is_leap = (!yd1 || yd2) && !yd3;
6761
6762 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006763 ASSERT(is_leap || (date >= 0));
6764 ASSERT((date < 365) || (is_leap && (date < 366)));
6765 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6766 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6767 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006768
6769 if (is_leap) {
6770 day = kDayInYear[2*365 + 1 + date];
6771 month = kMonthInYear[2*365 + 1 + date];
6772 } else {
6773 day = kDayInYear[date];
6774 month = kMonthInYear[date];
6775 }
6776
6777 ASSERT(MakeDay(year, month, day) == save_date);
6778}
6779
6780
6781static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006782 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006783 if (date >= 0 && date < 32 * kDaysIn4Years) {
6784 DateYMDFromTimeAfter1970(date, year, month, day);
6785 } else {
6786 DateYMDFromTimeSlow(date, year, month, day);
6787 }
6788}
6789
6790
lrn@chromium.org303ada72010-10-27 09:33:13 +00006791static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006792 NoHandleAllocation ha;
6793 ASSERT(args.length() == 2);
6794
6795 CONVERT_DOUBLE_CHECKED(t, args[0]);
6796 CONVERT_CHECKED(JSArray, res_array, args[1]);
6797
6798 int year, month, day;
6799 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6800
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006801 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6802 FixedArray* elms = FixedArray::cast(res_array->elements());
6803 RUNTIME_ASSERT(elms->length() == 3);
6804
6805 elms->set(0, Smi::FromInt(year));
6806 elms->set(1, Smi::FromInt(month));
6807 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006808
6809 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006810}
6811
6812
lrn@chromium.org303ada72010-10-27 09:33:13 +00006813static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006814 NoHandleAllocation ha;
6815 ASSERT(args.length() == 3);
6816
6817 JSFunction* callee = JSFunction::cast(args[0]);
6818 Object** parameters = reinterpret_cast<Object**>(args[1]);
6819 const int length = Smi::cast(args[2])->value();
6820
lrn@chromium.org303ada72010-10-27 09:33:13 +00006821 Object* result;
6822 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6823 if (!maybe_result->ToObject(&result)) return maybe_result;
6824 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006825 // Allocate the elements if needed.
6826 if (length > 0) {
6827 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006828 Object* obj;
6829 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6830 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6831 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006832
6833 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006834 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6835 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006836 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006837
6838 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006839 for (int i = 0; i < length; i++) {
6840 array->set(i, *--parameters, mode);
6841 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006842 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006843 }
6844 return result;
6845}
6846
6847
lrn@chromium.org303ada72010-10-27 09:33:13 +00006848static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006849 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006850 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006851 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006852 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006853 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006854
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006855 // Allocate global closures in old space and allocate local closures
6856 // in new space. Additionally pretenure closures that are assigned
6857 // directly to properties.
6858 pretenure = pretenure || (context->global_context() == *context);
6859 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006860 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006861 Factory::NewFunctionFromSharedFunctionInfo(shared,
6862 context,
6863 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006864 return *result;
6865}
6866
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006867
lrn@chromium.org303ada72010-10-27 09:33:13 +00006868static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006869 HandleScope scope;
6870 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006871 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006872 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006873
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006874 // Second argument is either null or an array of bound arguments.
6875 FixedArray* bound_args = NULL;
6876 int bound_argc = 0;
6877 if (!args[1]->IsNull()) {
6878 CONVERT_ARG_CHECKED(JSArray, params, 1);
6879 RUNTIME_ASSERT(params->HasFastElements());
6880 bound_args = FixedArray::cast(params->elements());
6881 bound_argc = Smi::cast(params->length())->value();
6882 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006883
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006884 // Find frame containing arguments passed to the caller.
6885 JavaScriptFrameIterator it;
6886 JavaScriptFrame* frame = it.frame();
6887 ASSERT(!frame->is_optimized());
6888 it.AdvanceToArgumentsFrame();
6889 frame = it.frame();
6890 int argc = frame->GetProvidedParametersCount();
6891
6892 // Prepend bound arguments to caller's arguments.
6893 int total_argc = bound_argc + argc;
6894 SmartPointer<Object**> param_data(NewArray<Object**>(total_argc));
6895 for (int i = 0; i < bound_argc; i++) {
6896 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006897 param_data[i] = val.location();
6898 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006899 for (int i = 0; i < argc; i++) {
6900 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
6901 param_data[bound_argc + i] = val.location();
6902 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006903
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006904 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006905 Handle<Object> result =
6906 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006907 if (exception) {
6908 return Failure::Exception();
6909 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006910
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006911 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006912 return *result;
6913}
6914
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006915
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006916static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006917 Handle<Object> prototype = Factory::null_value();
6918 if (function->has_instance_prototype()) {
6919 prototype = Handle<Object>(function->instance_prototype());
6920 }
6921 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006922 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006923 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006924 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006925 function->shared()->set_construct_stub(
6926 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006927 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006928 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006929}
6930
6931
lrn@chromium.org303ada72010-10-27 09:33:13 +00006932static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006933 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006934 ASSERT(args.length() == 1);
6935
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006936 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006937
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006938 // If the constructor isn't a proper function we throw a type error.
6939 if (!constructor->IsJSFunction()) {
6940 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6941 Handle<Object> type_error =
6942 Factory::NewTypeError("not_constructor", arguments);
6943 return Top::Throw(*type_error);
6944 }
6945
6946 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006947
6948 // If function should not have prototype, construction is not allowed. In this
6949 // case generated code bailouts here, since function has no initial_map.
6950 if (!function->should_have_prototype()) {
6951 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6952 Handle<Object> type_error =
6953 Factory::NewTypeError("not_constructor", arguments);
6954 return Top::Throw(*type_error);
6955 }
6956
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006957#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006958 // Handle stepping into constructors if step into is active.
6959 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006960 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006961 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006962#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006963
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006964 if (function->has_initial_map()) {
6965 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006966 // The 'Function' function ignores the receiver object when
6967 // called using 'new' and creates a new JSFunction object that
6968 // is returned. The receiver object is only used for error
6969 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006970 // JSFunction. Factory::NewJSObject() should not be used to
6971 // allocate JSFunctions since it does not properly initialize
6972 // the shared part of the function. Since the receiver is
6973 // ignored anyway, we use the global object as the receiver
6974 // instead of a new JSFunction object. This way, errors are
6975 // reported the same way whether or not 'Function' is called
6976 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006977 return Top::context()->global();
6978 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006979 }
6980
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006981 // The function should be compiled for the optimization hints to be
6982 // available. We cannot use EnsureCompiled because that forces a
6983 // compilation through the shared function info which makes it
6984 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006985 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006986 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006987
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006988 if (!function->has_initial_map() &&
6989 shared->IsInobjectSlackTrackingInProgress()) {
6990 // The tracking is already in progress for another function. We can only
6991 // track one initial_map at a time, so we force the completion before the
6992 // function is called as a constructor for the first time.
6993 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006994 }
6995
6996 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006997 Handle<JSObject> result = Factory::NewJSObject(function);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006998 RETURN_IF_EMPTY_HANDLE(result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006999 // Delay setting the stub if inobject slack tracking is in progress.
7000 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
7001 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007002 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007003
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007004 Counters::constructed_objects.Increment();
7005 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007006
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007007 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007008}
7009
7010
lrn@chromium.org303ada72010-10-27 09:33:13 +00007011static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007012 HandleScope scope;
7013 ASSERT(args.length() == 1);
7014
7015 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7016 function->shared()->CompleteInobjectSlackTracking();
7017 TrySettingInlineConstructStub(function);
7018
7019 return Heap::undefined_value();
7020}
7021
7022
lrn@chromium.org303ada72010-10-27 09:33:13 +00007023static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007024 HandleScope scope;
7025 ASSERT(args.length() == 1);
7026
7027 Handle<JSFunction> function = args.at<JSFunction>(0);
7028#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007029 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007030 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007031 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007032 PrintF("]\n");
7033 }
7034#endif
7035
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007036 // Compile the target function. Here we compile using CompileLazyInLoop in
7037 // order to get the optimized version. This helps code like delta-blue
7038 // that calls performance-critical routines through constructors. A
7039 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7040 // direct call. Since the in-loop tracking takes place through CallICs
7041 // this means that things called through constructors are never known to
7042 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007044 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045 return Failure::Exception();
7046 }
7047
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007048 // All done. Return the compiled code.
7049 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050 return function->code();
7051}
7052
7053
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007054static MaybeObject* Runtime_LazyRecompile(Arguments args) {
7055 HandleScope scope;
7056 ASSERT(args.length() == 1);
7057 Handle<JSFunction> function = args.at<JSFunction>(0);
7058 // If the function is not optimizable or debugger is active continue using the
7059 // code from the full compiler.
7060 if (!function->shared()->code()->optimizable() ||
7061 Debug::has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007062 if (FLAG_trace_opt) {
7063 PrintF("[failed to optimize ");
7064 function->PrintName();
7065 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7066 function->shared()->code()->optimizable() ? "T" : "F",
7067 Debug::has_break_points() ? "T" : "F");
7068 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007069 function->ReplaceCode(function->shared()->code());
7070 return function->code();
7071 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007072 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007073 return function->code();
7074 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007075 if (FLAG_trace_opt) {
7076 PrintF("[failed to optimize ");
7077 function->PrintName();
7078 PrintF(": optimized compilation failed]\n");
7079 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007080 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007081 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007082}
7083
7084
7085static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
7086 HandleScope scope;
7087 ASSERT(args.length() == 1);
7088 RUNTIME_ASSERT(args[0]->IsSmi());
7089 Deoptimizer::BailoutType type =
7090 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
7091 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7092 ASSERT(Heap::IsAllocationAllowed());
7093 int frames = deoptimizer->output_count();
7094
7095 JavaScriptFrameIterator it;
7096 JavaScriptFrame* frame = NULL;
7097 for (int i = 0; i < frames; i++) {
7098 if (i != 0) it.Advance();
7099 frame = it.frame();
7100 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
7101 }
7102 delete deoptimizer;
7103
7104 RUNTIME_ASSERT(frame->function()->IsJSFunction());
7105 Handle<JSFunction> function(JSFunction::cast(frame->function()));
7106 Handle<Object> arguments;
7107 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00007108 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007109 if (arguments.is_null()) {
7110 // FunctionGetArguments can't throw an exception, so cast away the
7111 // doubt with an assert.
7112 arguments = Handle<Object>(
7113 Accessors::FunctionGetArguments(*function,
7114 NULL)->ToObjectUnchecked());
7115 ASSERT(*arguments != Heap::null_value());
7116 ASSERT(*arguments != Heap::undefined_value());
7117 }
7118 frame->SetExpression(i, *arguments);
7119 }
7120 }
7121
7122 CompilationCache::MarkForLazyOptimizing(function);
7123 if (type == Deoptimizer::EAGER) {
7124 RUNTIME_ASSERT(function->IsOptimized());
7125 } else {
7126 RUNTIME_ASSERT(!function->IsOptimized());
7127 }
7128
7129 // Avoid doing too much work when running with --always-opt and keep
7130 // the optimized code around.
7131 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
7132 return Heap::undefined_value();
7133 }
7134
7135 // Count the number of optimized activations of the function.
7136 int activations = 0;
7137 while (!it.done()) {
7138 JavaScriptFrame* frame = it.frame();
7139 if (frame->is_optimized() && frame->function() == *function) {
7140 activations++;
7141 }
7142 it.Advance();
7143 }
7144
7145 // TODO(kasperl): For now, we cannot support removing the optimized
7146 // code when we have recursive invocations of the same function.
7147 if (activations == 0) {
7148 if (FLAG_trace_deopt) {
7149 PrintF("[removing optimized code for: ");
7150 function->PrintName();
7151 PrintF("]\n");
7152 }
7153 function->ReplaceCode(function->shared()->code());
7154 }
7155 return Heap::undefined_value();
7156}
7157
7158
7159static MaybeObject* Runtime_NotifyOSR(Arguments args) {
7160 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7161 delete deoptimizer;
7162 return Heap::undefined_value();
7163}
7164
7165
7166static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
7167 HandleScope scope;
7168 ASSERT(args.length() == 1);
7169 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7170 if (!function->IsOptimized()) return Heap::undefined_value();
7171
7172 Deoptimizer::DeoptimizeFunction(*function);
7173
7174 return Heap::undefined_value();
7175}
7176
7177
7178static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
7179 HandleScope scope;
7180 ASSERT(args.length() == 1);
7181 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7182
7183 // We're not prepared to handle a function with arguments object.
7184 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7185
7186 // We have hit a back edge in an unoptimized frame for a function that was
7187 // selected for on-stack replacement. Find the unoptimized code object.
7188 Handle<Code> unoptimized(function->shared()->code());
7189 // Keep track of whether we've succeeded in optimizing.
7190 bool succeeded = unoptimized->optimizable();
7191 if (succeeded) {
7192 // If we are trying to do OSR when there are already optimized
7193 // activations of the function, it means (a) the function is directly or
7194 // indirectly recursive and (b) an optimized invocation has been
7195 // deoptimized so that we are currently in an unoptimized activation.
7196 // Check for optimized activations of this function.
7197 JavaScriptFrameIterator it;
7198 while (succeeded && !it.done()) {
7199 JavaScriptFrame* frame = it.frame();
7200 succeeded = !frame->is_optimized() || frame->function() != *function;
7201 it.Advance();
7202 }
7203 }
7204
7205 int ast_id = AstNode::kNoNumber;
7206 if (succeeded) {
7207 // The top JS function is this one, the PC is somewhere in the
7208 // unoptimized code.
7209 JavaScriptFrameIterator it;
7210 JavaScriptFrame* frame = it.frame();
7211 ASSERT(frame->function() == *function);
7212 ASSERT(frame->code() == *unoptimized);
7213 ASSERT(unoptimized->contains(frame->pc()));
7214
7215 // Use linear search of the unoptimized code's stack check table to find
7216 // the AST id matching the PC.
7217 Address start = unoptimized->instruction_start();
7218 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007219 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007220 uint32_t table_length = Memory::uint32_at(table_cursor);
7221 table_cursor += kIntSize;
7222 for (unsigned i = 0; i < table_length; ++i) {
7223 // Table entries are (AST id, pc offset) pairs.
7224 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7225 if (pc_offset == target_pc_offset) {
7226 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7227 break;
7228 }
7229 table_cursor += 2 * kIntSize;
7230 }
7231 ASSERT(ast_id != AstNode::kNoNumber);
7232 if (FLAG_trace_osr) {
7233 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7234 function->PrintName();
7235 PrintF("]\n");
7236 }
7237
7238 // Try to compile the optimized code. A true return value from
7239 // CompileOptimized means that compilation succeeded, not necessarily
7240 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007241 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7242 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007243 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7244 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007245 if (data->OsrPcOffset()->value() >= 0) {
7246 if (FLAG_trace_osr) {
7247 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007248 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007249 }
7250 ASSERT(data->OsrAstId()->value() == ast_id);
7251 } else {
7252 // We may never generate the desired OSR entry if we emit an
7253 // early deoptimize.
7254 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007255 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007256 } else {
7257 succeeded = false;
7258 }
7259 }
7260
7261 // Revert to the original stack checks in the original unoptimized code.
7262 if (FLAG_trace_osr) {
7263 PrintF("[restoring original stack checks in ");
7264 function->PrintName();
7265 PrintF("]\n");
7266 }
7267 StackCheckStub check_stub;
7268 Handle<Code> check_code = check_stub.GetCode();
7269 Handle<Code> replacement_code(
7270 Builtins::builtin(Builtins::OnStackReplacement));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007271 Deoptimizer::RevertStackCheckCode(*unoptimized,
7272 *check_code,
7273 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007274
7275 // Allow OSR only at nesting level zero again.
7276 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7277
7278 // If the optimization attempt succeeded, return the AST id tagged as a
7279 // smi. This tells the builtin that we need to translate the unoptimized
7280 // frame to an optimized one.
7281 if (succeeded) {
7282 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7283 return Smi::FromInt(ast_id);
7284 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007285 if (function->IsMarkedForLazyRecompilation()) {
7286 function->ReplaceCode(function->shared()->code());
7287 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007288 return Smi::FromInt(-1);
7289 }
7290}
7291
7292
lrn@chromium.org303ada72010-10-27 09:33:13 +00007293static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294 HandleScope scope;
7295 ASSERT(args.length() == 1);
7296 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7297 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7298}
7299
7300
lrn@chromium.org303ada72010-10-27 09:33:13 +00007301static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007302 HandleScope scope;
7303 ASSERT(args.length() == 1);
7304 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7305 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7306}
7307
7308
lrn@chromium.org303ada72010-10-27 09:33:13 +00007309static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007310 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007311 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007312
kasper.lund7276f142008-07-30 08:49:36 +00007313 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007314 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007315 Object* result;
7316 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
7317 if (!maybe_result->ToObject(&result)) return maybe_result;
7318 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007319
7320 Top::set_context(Context::cast(result));
7321
kasper.lund7276f142008-07-30 08:49:36 +00007322 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007323}
7324
lrn@chromium.org303ada72010-10-27 09:33:13 +00007325
7326MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
7327 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007328 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007329 Object* js_object = object;
7330 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007331 MaybeObject* maybe_js_object = js_object->ToObject();
7332 if (!maybe_js_object->ToObject(&js_object)) {
7333 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7334 return maybe_js_object;
7335 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007336 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007337 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007338 Handle<Object> result =
7339 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
7340 return Top::Throw(*result);
7341 }
7342 }
7343
lrn@chromium.org303ada72010-10-27 09:33:13 +00007344 Object* result;
7345 { MaybeObject* maybe_result =
7346 Heap::AllocateWithContext(Top::context(),
7347 JSObject::cast(js_object),
7348 is_catch_context);
7349 if (!maybe_result->ToObject(&result)) return maybe_result;
7350 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007351
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007352 Context* context = Context::cast(result);
7353 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354
kasper.lund7276f142008-07-30 08:49:36 +00007355 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356}
7357
7358
lrn@chromium.org303ada72010-10-27 09:33:13 +00007359static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007360 NoHandleAllocation ha;
7361 ASSERT(args.length() == 1);
7362 return PushContextHelper(args[0], false);
7363}
7364
7365
lrn@chromium.org303ada72010-10-27 09:33:13 +00007366static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007367 NoHandleAllocation ha;
7368 ASSERT(args.length() == 1);
7369 return PushContextHelper(args[0], true);
7370}
7371
7372
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007373static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374 HandleScope scope;
7375 ASSERT(args.length() == 2);
7376
7377 CONVERT_ARG_CHECKED(Context, context, 0);
7378 CONVERT_ARG_CHECKED(String, name, 1);
7379
7380 int index;
7381 PropertyAttributes attributes;
7382 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007383 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007385 // If the slot was not found the result is true.
7386 if (holder.is_null()) {
7387 return Heap::true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007388 }
7389
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007390 // If the slot was found in a context, it should be DONT_DELETE.
7391 if (holder->IsContext()) {
7392 return Heap::false_value();
7393 }
7394
7395 // The slot was found in a JSObject, either a context extension object,
7396 // the global object, or an arguments object. Try to delete it
7397 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7398 // which allows deleting all parameters in functions that mention
7399 // 'arguments', we do this even for the case of slots found on an
7400 // arguments object. The slot was found on an arguments object if the
7401 // index is non-negative.
7402 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7403 if (index >= 0) {
7404 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7405 } else {
7406 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7407 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408}
7409
7410
ager@chromium.orga1645e22009-09-09 19:27:10 +00007411// A mechanism to return a pair of Object pointers in registers (if possible).
7412// How this is achieved is calling convention-dependent.
7413// All currently supported x86 compiles uses calling conventions that are cdecl
7414// variants where a 64-bit value is returned in two 32-bit registers
7415// (edx:eax on ia32, r1:r0 on ARM).
7416// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7417// In Win64 calling convention, a struct of two pointers is returned in memory,
7418// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007419#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007420struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007421 MaybeObject* x;
7422 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007423};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007424
lrn@chromium.org303ada72010-10-27 09:33:13 +00007425static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007426 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007427 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7428 // In Win64 they are assigned to a hidden first argument.
7429 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007430}
7431#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007432typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007433static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007434 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007435 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007436}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007437#endif
7438
7439
lrn@chromium.org303ada72010-10-27 09:33:13 +00007440static inline MaybeObject* Unhole(MaybeObject* x,
7441 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007442 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7443 USE(attributes);
7444 return x->IsTheHole() ? Heap::undefined_value() : x;
7445}
7446
7447
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007448static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7449 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007450 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007451 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007452 JSFunction* context_extension_function =
7453 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007454 // If the holder isn't a context extension object, we just return it
7455 // as the receiver. This allows arguments objects to be used as
7456 // receivers, but only if they are put in the context scope chain
7457 // explicitly via a with-statement.
7458 Object* constructor = holder->map()->constructor();
7459 if (constructor != context_extension_function) return holder;
7460 // Fall back to using the global object as the receiver if the
7461 // property turns out to be a local variable allocated in a context
7462 // extension object - introduced via eval.
7463 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007464}
7465
7466
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007467static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007468 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007469 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007470
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007471 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007472 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007473 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007474 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007475 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007476
7477 int index;
7478 PropertyAttributes attributes;
7479 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007480 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007481
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007482 // If the index is non-negative, the slot has been found in a local
7483 // variable or a parameter. Read it from the context object or the
7484 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007485 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007486 // If the "property" we were looking for is a local variable or an
7487 // argument in a context, the receiver is the global object; see
7488 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7489 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007490 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007491 ? Context::cast(*holder)->get(index)
7492 : JSObject::cast(*holder)->GetElement(index);
7493 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007494 }
7495
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007496 // If the holder is found, we read the property from it.
7497 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007498 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007499 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007500 JSObject* receiver;
7501 if (object->IsGlobalObject()) {
7502 receiver = GlobalObject::cast(object)->global_receiver();
7503 } else if (context->is_exception_holder(*holder)) {
7504 receiver = Top::context()->global()->global_receiver();
7505 } else {
7506 receiver = ComputeReceiverForNonGlobal(object);
7507 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007508 // No need to unhole the value here. This is taken care of by the
7509 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007510 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007511 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007512 }
7513
7514 if (throw_error) {
7515 // The property doesn't exist - throw exception.
7516 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007517 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007518 return MakePair(Top::Throw(*reference_error), NULL);
7519 } else {
7520 // The property doesn't exist - return undefined
7521 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7522 }
7523}
7524
7525
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007526static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007527 return LoadContextSlotHelper(args, true);
7528}
7529
7530
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007531static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007532 return LoadContextSlotHelper(args, false);
7533}
7534
7535
lrn@chromium.org303ada72010-10-27 09:33:13 +00007536static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007537 HandleScope scope;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007538 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007539
7540 Handle<Object> value(args[0]);
7541 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007542 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007543 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7544 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7545 strict_unchecked == kNonStrictMode);
7546 StrictModeFlag strict = static_cast<StrictModeFlag>(strict_unchecked);
7547
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007548
7549 int index;
7550 PropertyAttributes attributes;
7551 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007552 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007553
7554 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007555 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007556 // Ignore if read_only variable.
7557 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007558 // Context is a fixed array and set cannot fail.
7559 Context::cast(*holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007560 }
7561 } else {
7562 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007563 Handle<Object> result =
7564 SetElement(Handle<JSObject>::cast(holder), index, value);
7565 if (result.is_null()) {
7566 ASSERT(Top::has_pending_exception());
7567 return Failure::Exception();
7568 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007569 }
7570 return *value;
7571 }
7572
7573 // Slow case: The property is not in a FixedArray context.
7574 // It is either in an JSObject extension context or it was not found.
7575 Handle<JSObject> context_ext;
7576
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007577 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007578 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007579 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007580 } else {
7581 // The property was not found. It needs to be stored in the global context.
7582 ASSERT(attributes == ABSENT);
7583 attributes = NONE;
7584 context_ext = Handle<JSObject>(Top::context()->global());
7585 }
7586
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007587 // Set the property, but ignore if read_only variable on the context
7588 // extension object itself.
7589 if ((attributes & READ_ONLY) == 0 ||
7590 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007591 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, NONE, strict));
7592 } else if (strict == kStrictMode && (attributes & READ_ONLY) != 0) {
7593 // Setting read only property in strict mode.
7594 Handle<Object> error =
7595 Factory::NewTypeError("strict_cannot_assign", HandleVector(&name, 1));
7596 return Top::Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007597 }
7598 return *value;
7599}
7600
7601
lrn@chromium.org303ada72010-10-27 09:33:13 +00007602static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007603 HandleScope scope;
7604 ASSERT(args.length() == 1);
7605
7606 return Top::Throw(args[0]);
7607}
7608
7609
lrn@chromium.org303ada72010-10-27 09:33:13 +00007610static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007611 HandleScope scope;
7612 ASSERT(args.length() == 1);
7613
7614 return Top::ReThrow(args[0]);
7615}
7616
7617
lrn@chromium.org303ada72010-10-27 09:33:13 +00007618static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007619 ASSERT_EQ(0, args.length());
7620 return Top::PromoteScheduledException();
7621}
7622
7623
lrn@chromium.org303ada72010-10-27 09:33:13 +00007624static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007625 HandleScope scope;
7626 ASSERT(args.length() == 1);
7627
7628 Handle<Object> name(args[0]);
7629 Handle<Object> reference_error =
7630 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7631 return Top::Throw(*reference_error);
7632}
7633
7634
lrn@chromium.org303ada72010-10-27 09:33:13 +00007635static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007636 NoHandleAllocation na;
7637 return Top::StackOverflow();
7638}
7639
7640
lrn@chromium.org303ada72010-10-27 09:33:13 +00007641static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007642 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007643
7644 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007645 if (StackGuard::IsStackOverflow()) {
7646 return Runtime_StackOverflow(args);
7647 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007648
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007649 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007650}
7651
7652
7653// NOTE: These PrintXXX functions are defined for all builds (not just
7654// DEBUG builds) because we may want to be able to trace function
7655// calls in all modes.
7656static void PrintString(String* str) {
7657 // not uncommon to have empty strings
7658 if (str->length() > 0) {
7659 SmartPointer<char> s =
7660 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7661 PrintF("%s", *s);
7662 }
7663}
7664
7665
7666static void PrintObject(Object* obj) {
7667 if (obj->IsSmi()) {
7668 PrintF("%d", Smi::cast(obj)->value());
7669 } else if (obj->IsString() || obj->IsSymbol()) {
7670 PrintString(String::cast(obj));
7671 } else if (obj->IsNumber()) {
7672 PrintF("%g", obj->Number());
7673 } else if (obj->IsFailure()) {
7674 PrintF("<failure>");
7675 } else if (obj->IsUndefined()) {
7676 PrintF("<undefined>");
7677 } else if (obj->IsNull()) {
7678 PrintF("<null>");
7679 } else if (obj->IsTrue()) {
7680 PrintF("<true>");
7681 } else if (obj->IsFalse()) {
7682 PrintF("<false>");
7683 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007684 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007685 }
7686}
7687
7688
7689static int StackSize() {
7690 int n = 0;
7691 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7692 return n;
7693}
7694
7695
7696static void PrintTransition(Object* result) {
7697 // indentation
7698 { const int nmax = 80;
7699 int n = StackSize();
7700 if (n <= nmax)
7701 PrintF("%4d:%*s", n, n, "");
7702 else
7703 PrintF("%4d:%*s", n, nmax, "...");
7704 }
7705
7706 if (result == NULL) {
7707 // constructor calls
7708 JavaScriptFrameIterator it;
7709 JavaScriptFrame* frame = it.frame();
7710 if (frame->IsConstructor()) PrintF("new ");
7711 // function name
7712 Object* fun = frame->function();
7713 if (fun->IsJSFunction()) {
7714 PrintObject(JSFunction::cast(fun)->shared()->name());
7715 } else {
7716 PrintObject(fun);
7717 }
7718 // function arguments
7719 // (we are intentionally only printing the actually
7720 // supplied parameters, not all parameters required)
7721 PrintF("(this=");
7722 PrintObject(frame->receiver());
7723 const int length = frame->GetProvidedParametersCount();
7724 for (int i = 0; i < length; i++) {
7725 PrintF(", ");
7726 PrintObject(frame->GetParameter(i));
7727 }
7728 PrintF(") {\n");
7729
7730 } else {
7731 // function result
7732 PrintF("} -> ");
7733 PrintObject(result);
7734 PrintF("\n");
7735 }
7736}
7737
7738
lrn@chromium.org303ada72010-10-27 09:33:13 +00007739static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007740 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007741 NoHandleAllocation ha;
7742 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007743 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007744}
7745
7746
lrn@chromium.org303ada72010-10-27 09:33:13 +00007747static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748 NoHandleAllocation ha;
7749 PrintTransition(args[0]);
7750 return args[0]; // return TOS
7751}
7752
7753
lrn@chromium.org303ada72010-10-27 09:33:13 +00007754static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007755 NoHandleAllocation ha;
7756 ASSERT(args.length() == 1);
7757
7758#ifdef DEBUG
7759 if (args[0]->IsString()) {
7760 // If we have a string, assume it's a code "marker"
7761 // and print some interesting cpu debugging info.
7762 JavaScriptFrameIterator it;
7763 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007764 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7765 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007766 } else {
7767 PrintF("DebugPrint: ");
7768 }
7769 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007770 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007771 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007772 HeapObject::cast(args[0])->map()->Print();
7773 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007774#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007775 // ShortPrint is available in release mode. Print is not.
7776 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007777#endif
7778 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007779 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007780
7781 return args[0]; // return TOS
7782}
7783
7784
lrn@chromium.org303ada72010-10-27 09:33:13 +00007785static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007786 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007787 NoHandleAllocation ha;
7788 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007789 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007790}
7791
7792
lrn@chromium.org303ada72010-10-27 09:33:13 +00007793static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007794 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007795 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007796
7797 // According to ECMA-262, section 15.9.1, page 117, the precision of
7798 // the number in a Date object representing a particular instant in
7799 // time is milliseconds. Therefore, we floor the result of getting
7800 // the OS time.
7801 double millis = floor(OS::TimeCurrentMillis());
7802 return Heap::NumberFromDouble(millis);
7803}
7804
7805
lrn@chromium.org303ada72010-10-27 09:33:13 +00007806static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007807 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007808 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007809
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007810 CONVERT_ARG_CHECKED(String, str, 0);
7811 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007812
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007813 CONVERT_ARG_CHECKED(JSArray, output, 1);
7814 RUNTIME_ASSERT(output->HasFastElements());
7815
7816 AssertNoAllocation no_allocation;
7817
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007818 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007819 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7820 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007821 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007822 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007823 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007824 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007825 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7826 }
7827
7828 if (result) {
7829 return *output;
7830 } else {
7831 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007832 }
7833}
7834
7835
lrn@chromium.org303ada72010-10-27 09:33:13 +00007836static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007837 NoHandleAllocation ha;
7838 ASSERT(args.length() == 1);
7839
7840 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007841 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007842 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7843}
7844
7845
lrn@chromium.org303ada72010-10-27 09:33:13 +00007846static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007847 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007848 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007849
7850 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7851}
7852
7853
lrn@chromium.org303ada72010-10-27 09:33:13 +00007854static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007855 NoHandleAllocation ha;
7856 ASSERT(args.length() == 1);
7857
7858 CONVERT_DOUBLE_CHECKED(x, args[0]);
7859 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7860}
7861
7862
lrn@chromium.org303ada72010-10-27 09:33:13 +00007863static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007864 ASSERT(args.length() == 1);
7865 Object* global = args[0];
7866 if (!global->IsJSGlobalObject()) return Heap::null_value();
7867 return JSGlobalObject::cast(global)->global_receiver();
7868}
7869
7870
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007871static MaybeObject* Runtime_ParseJson(Arguments args) {
7872 HandleScope scope;
7873 ASSERT_EQ(1, args.length());
7874 CONVERT_ARG_CHECKED(String, source, 0);
7875
7876 Handle<Object> result = JsonParser::Parse(source);
7877 if (result.is_null()) {
7878 // Syntax error or stack overflow in scanner.
7879 ASSERT(Top::has_pending_exception());
7880 return Failure::Exception();
7881 }
7882 return *result;
7883}
7884
7885
lrn@chromium.org303ada72010-10-27 09:33:13 +00007886static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007887 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007888 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007889 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007890
ager@chromium.org381abbb2009-02-25 13:23:22 +00007891 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007892 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007893 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7894 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007895 true,
7896 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007897 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007898 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007899 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007900 return *fun;
7901}
7902
7903
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007904static ObjectPair CompileGlobalEval(Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007905 Handle<Object> receiver,
7906 StrictModeFlag mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007907 // Deal with a normal eval call with a string argument. Compile it
7908 // and return the compiled function bound in the local context.
7909 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7910 source,
7911 Handle<Context>(Top::context()),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007912 Top::context()->IsGlobalContext(),
7913 mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007914 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7915 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7916 shared,
7917 Handle<Context>(Top::context()),
7918 NOT_TENURED);
7919 return MakePair(*compiled, *receiver);
7920}
7921
7922
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007923static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007924 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007925
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007926 HandleScope scope;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007927 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007928 Handle<Object> receiver; // Will be overwritten.
7929
7930 // Compute the calling context.
7931 Handle<Context> context = Handle<Context>(Top::context());
7932#ifdef DEBUG
7933 // Make sure Top::context() agrees with the old code that traversed
7934 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007935 StackFrameLocator locator;
7936 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007937 ASSERT(Context::cast(frame->context()) == *context);
7938#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007939
7940 // Find where the 'eval' symbol is bound. It is unaliased only if
7941 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007942 int index = -1;
7943 PropertyAttributes attributes = ABSENT;
7944 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007945 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7946 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007947 // Stop search when eval is found or when the global context is
7948 // reached.
7949 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007950 if (context->is_function_context()) {
7951 context = Handle<Context>(Context::cast(context->closure()->context()));
7952 } else {
7953 context = Handle<Context>(context->previous());
7954 }
7955 }
7956
iposva@chromium.org245aa852009-02-10 00:49:54 +00007957 // If eval could not be resolved, it has been deleted and we need to
7958 // throw a reference error.
7959 if (attributes == ABSENT) {
7960 Handle<Object> name = Factory::eval_symbol();
7961 Handle<Object> reference_error =
7962 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007963 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007964 }
7965
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007966 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007967 // 'eval' is not bound in the global context. Just call the function
7968 // with the given arguments. This is not necessarily the global eval.
7969 if (receiver->IsContext()) {
7970 context = Handle<Context>::cast(receiver);
7971 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007972 } else if (receiver->IsJSContextExtensionObject()) {
7973 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007974 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007975 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007976 }
7977
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007978 // 'eval' is bound in the global context, but it may have been overwritten.
7979 // Compare it to the builtin 'GlobalEval' function to make sure.
7980 if (*callee != Top::global_context()->global_eval_fun() ||
7981 !args[1]->IsString()) {
7982 return MakePair(*callee, Top::context()->global()->global_receiver());
7983 }
7984
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007985 ASSERT(args[3]->IsSmi());
7986 return CompileGlobalEval(args.at<String>(1),
7987 args.at<Object>(2),
7988 static_cast<StrictModeFlag>(
7989 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007990}
7991
7992
7993static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007994 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007995
7996 HandleScope scope;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007997 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007998
7999 // 'eval' is bound in the global context, but it may have been overwritten.
8000 // Compare it to the builtin 'GlobalEval' function to make sure.
8001 if (*callee != Top::global_context()->global_eval_fun() ||
8002 !args[1]->IsString()) {
8003 return MakePair(*callee, Top::context()->global()->global_receiver());
8004 }
8005
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008006 ASSERT(args[3]->IsSmi());
8007 return CompileGlobalEval(args.at<String>(1),
8008 args.at<Object>(2),
8009 static_cast<StrictModeFlag>(
8010 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008011}
8012
8013
lrn@chromium.org303ada72010-10-27 09:33:13 +00008014static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008015 // This utility adjusts the property attributes for newly created Function
8016 // object ("new Function(...)") by changing the map.
8017 // All it does is changing the prototype property to enumerable
8018 // as specified in ECMA262, 15.3.5.2.
8019 HandleScope scope;
8020 ASSERT(args.length() == 1);
8021 CONVERT_ARG_CHECKED(JSFunction, func, 0);
8022 ASSERT(func->map()->instance_type() ==
8023 Top::function_instance_map()->instance_type());
8024 ASSERT(func->map()->instance_size() ==
8025 Top::function_instance_map()->instance_size());
8026 func->set_map(*Top::function_instance_map());
8027 return *func;
8028}
8029
8030
lrn@chromium.org303ada72010-10-27 09:33:13 +00008031static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008032 // Allocate a block of memory in NewSpace (filled with a filler).
8033 // Use as fallback for allocation in generated code when NewSpace
8034 // is full.
8035 ASSERT(args.length() == 1);
8036 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8037 int size = size_smi->value();
8038 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8039 RUNTIME_ASSERT(size > 0);
8040 static const int kMinFreeNewSpaceAfterGC =
8041 Heap::InitialSemiSpaceSize() * 3/4;
8042 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008043 Object* allocation;
8044 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
8045 if (maybe_allocation->ToObject(&allocation)) {
8046 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
8047 }
8048 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008049 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008050}
8051
8052
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008053// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008054// array. Returns true if the element was pushed on the stack and
8055// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008056static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008057 ASSERT(args.length() == 2);
8058 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008059 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008060 RUNTIME_ASSERT(array->HasFastElements());
8061 int length = Smi::cast(array->length())->value();
8062 FixedArray* elements = FixedArray::cast(array->elements());
8063 for (int i = 0; i < length; i++) {
8064 if (elements->get(i) == element) return Heap::false_value();
8065 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008066 Object* obj;
8067 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
8068 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8069 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008070 return Heap::true_value();
8071}
8072
8073
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008074/**
8075 * A simple visitor visits every element of Array's.
8076 * The backend storage can be a fixed array for fast elements case,
8077 * or a dictionary for sparse array. Since Dictionary is a subtype
8078 * of FixedArray, the class can be used by both fast and slow cases.
8079 * The second parameter of the constructor, fast_elements, specifies
8080 * whether the storage is a FixedArray or Dictionary.
8081 *
8082 * An index limit is used to deal with the situation that a result array
8083 * length overflows 32-bit non-negative integer.
8084 */
8085class ArrayConcatVisitor {
8086 public:
8087 ArrayConcatVisitor(Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008088 bool fast_elements) :
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008089 storage_(Handle<FixedArray>::cast(GlobalHandles::Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008090 index_offset_(0u),
8091 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008092
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008093 ~ArrayConcatVisitor() {
8094 clear_storage();
8095 }
8096
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008097 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008098 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008099 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008100
8101 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008102 if (index < static_cast<uint32_t>(storage_->length())) {
8103 storage_->set(index, *elm);
8104 return;
8105 }
8106 // Our initial estimate of length was foiled, possibly by
8107 // getters on the arrays increasing the length of later arrays
8108 // during iteration.
8109 // This shouldn't happen in anything but pathological cases.
8110 SetDictionaryMode(index);
8111 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008112 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008113 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008114 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008115 Handle<NumberDictionary> result =
8116 Factory::DictionaryAtNumberPut(dict, index, elm);
8117 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008118 // Dictionary needed to grow.
8119 clear_storage();
8120 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008121 }
8122}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008123
8124 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008125 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8126 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008127 } else {
8128 index_offset_ += delta;
8129 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008130 }
8131
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008132 Handle<JSArray> ToArray() {
8133 Handle<JSArray> array = Factory::NewJSArray(0);
8134 Handle<Object> length =
8135 Factory::NewNumber(static_cast<double>(index_offset_));
8136 Handle<Map> map;
8137 if (fast_elements_) {
8138 map = Factory::GetFastElementsMap(Handle<Map>(array->map()));
8139 } else {
8140 map = Factory::GetSlowElementsMap(Handle<Map>(array->map()));
8141 }
8142 array->set_map(*map);
8143 array->set_length(*length);
8144 array->set_elements(*storage_);
8145 return array;
8146 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008147
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008148 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008149 // Convert storage to dictionary mode.
8150 void SetDictionaryMode(uint32_t index) {
8151 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008152 Handle<FixedArray> current_storage(*storage_);
8153 Handle<NumberDictionary> slow_storage(
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008154 Factory::NewNumberDictionary(current_storage->length()));
8155 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8156 for (uint32_t i = 0; i < current_length; i++) {
8157 HandleScope loop_scope;
8158 Handle<Object> element(current_storage->get(i));
8159 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008160 Handle<NumberDictionary> new_storage =
8161 Factory::DictionaryAtNumberPut(slow_storage, i, element);
8162 if (!new_storage.is_identical_to(slow_storage)) {
8163 slow_storage = loop_scope.CloseAndEscape(new_storage);
8164 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008165 }
8166 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008167 clear_storage();
8168 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008169 fast_elements_ = false;
8170 }
8171
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008172 inline void clear_storage() {
8173 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
8174 }
8175
8176 inline void set_storage(FixedArray* storage) {
8177 storage_ = Handle<FixedArray>::cast(GlobalHandles::Create(storage));
8178 }
8179
8180 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008181 // Index after last seen index. Always less than or equal to
8182 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008183 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008184 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008185};
8186
8187
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008188static uint32_t EstimateElementCount(Handle<JSArray> array) {
8189 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8190 int element_count = 0;
8191 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008192 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008193 // Fast elements can't have lengths that are not representable by
8194 // a 32-bit signed integer.
8195 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8196 int fast_length = static_cast<int>(length);
8197 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8198 for (int i = 0; i < fast_length; i++) {
8199 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008200 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008201 break;
8202 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008203 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008204 Handle<NumberDictionary> dictionary(
8205 NumberDictionary::cast(array->elements()));
8206 int capacity = dictionary->Capacity();
8207 for (int i = 0; i < capacity; i++) {
8208 Handle<Object> key(dictionary->KeyAt(i));
8209 if (dictionary->IsKey(*key)) {
8210 element_count++;
8211 }
8212 }
8213 break;
8214 }
8215 default:
8216 // External arrays are always dense.
8217 return length;
8218 }
8219 // As an estimate, we assume that the prototype doesn't contain any
8220 // inherited elements.
8221 return element_count;
8222}
8223
8224
8225
8226template<class ExternalArrayClass, class ElementType>
8227static void IterateExternalArrayElements(Handle<JSObject> receiver,
8228 bool elements_are_ints,
8229 bool elements_are_guaranteed_smis,
8230 ArrayConcatVisitor* visitor) {
8231 Handle<ExternalArrayClass> array(
8232 ExternalArrayClass::cast(receiver->elements()));
8233 uint32_t len = static_cast<uint32_t>(array->length());
8234
8235 ASSERT(visitor != NULL);
8236 if (elements_are_ints) {
8237 if (elements_are_guaranteed_smis) {
8238 for (uint32_t j = 0; j < len; j++) {
8239 HandleScope loop_scope;
8240 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8241 visitor->visit(j, e);
8242 }
8243 } else {
8244 for (uint32_t j = 0; j < len; j++) {
8245 HandleScope loop_scope;
8246 int64_t val = static_cast<int64_t>(array->get(j));
8247 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8248 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8249 visitor->visit(j, e);
8250 } else {
8251 Handle<Object> e =
8252 Factory::NewNumber(static_cast<ElementType>(val));
8253 visitor->visit(j, e);
8254 }
8255 }
8256 }
8257 } else {
8258 for (uint32_t j = 0; j < len; j++) {
8259 HandleScope loop_scope;
8260 Handle<Object> e = Factory::NewNumber(array->get(j));
8261 visitor->visit(j, e);
8262 }
8263 }
8264}
8265
8266
8267// Used for sorting indices in a List<uint32_t>.
8268static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8269 uint32_t a = *ap;
8270 uint32_t b = *bp;
8271 return (a == b) ? 0 : (a < b) ? -1 : 1;
8272}
8273
8274
8275static void CollectElementIndices(Handle<JSObject> object,
8276 uint32_t range,
8277 List<uint32_t>* indices) {
8278 JSObject::ElementsKind kind = object->GetElementsKind();
8279 switch (kind) {
8280 case JSObject::FAST_ELEMENTS: {
8281 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8282 uint32_t length = static_cast<uint32_t>(elements->length());
8283 if (range < length) length = range;
8284 for (uint32_t i = 0; i < length; i++) {
8285 if (!elements->get(i)->IsTheHole()) {
8286 indices->Add(i);
8287 }
8288 }
8289 break;
8290 }
8291 case JSObject::DICTIONARY_ELEMENTS: {
8292 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008293 uint32_t capacity = dict->Capacity();
8294 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008295 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008296 Handle<Object> k(dict->KeyAt(j));
8297 if (dict->IsKey(*k)) {
8298 ASSERT(k->IsNumber());
8299 uint32_t index = static_cast<uint32_t>(k->Number());
8300 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008301 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008302 }
8303 }
8304 }
8305 break;
8306 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008307 default: {
8308 int dense_elements_length;
8309 switch (kind) {
8310 case JSObject::PIXEL_ELEMENTS: {
8311 dense_elements_length =
8312 PixelArray::cast(object->elements())->length();
8313 break;
8314 }
8315 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8316 dense_elements_length =
8317 ExternalByteArray::cast(object->elements())->length();
8318 break;
8319 }
8320 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8321 dense_elements_length =
8322 ExternalUnsignedByteArray::cast(object->elements())->length();
8323 break;
8324 }
8325 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8326 dense_elements_length =
8327 ExternalShortArray::cast(object->elements())->length();
8328 break;
8329 }
8330 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8331 dense_elements_length =
8332 ExternalUnsignedShortArray::cast(object->elements())->length();
8333 break;
8334 }
8335 case JSObject::EXTERNAL_INT_ELEMENTS: {
8336 dense_elements_length =
8337 ExternalIntArray::cast(object->elements())->length();
8338 break;
8339 }
8340 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8341 dense_elements_length =
8342 ExternalUnsignedIntArray::cast(object->elements())->length();
8343 break;
8344 }
8345 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8346 dense_elements_length =
8347 ExternalFloatArray::cast(object->elements())->length();
8348 break;
8349 }
8350 default:
8351 UNREACHABLE();
8352 dense_elements_length = 0;
8353 break;
8354 }
8355 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8356 if (range <= length) {
8357 length = range;
8358 // We will add all indices, so we might as well clear it first
8359 // and avoid duplicates.
8360 indices->Clear();
8361 }
8362 for (uint32_t i = 0; i < length; i++) {
8363 indices->Add(i);
8364 }
8365 if (length == range) return; // All indices accounted for already.
8366 break;
8367 }
8368 }
8369
8370 Handle<Object> prototype(object->GetPrototype());
8371 if (prototype->IsJSObject()) {
8372 // The prototype will usually have no inherited element indices,
8373 // but we have to check.
8374 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8375 }
8376}
8377
8378
8379/**
8380 * A helper function that visits elements of a JSArray in numerical
8381 * order.
8382 *
8383 * The visitor argument called for each existing element in the array
8384 * with the element index and the element's value.
8385 * Afterwards it increments the base-index of the visitor by the array
8386 * length.
8387 */
8388static void IterateElements(Handle<JSArray> receiver,
8389 ArrayConcatVisitor* visitor) {
8390 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8391 switch (receiver->GetElementsKind()) {
8392 case JSObject::FAST_ELEMENTS: {
8393 // Run through the elements FixedArray and use HasElement and GetElement
8394 // to check the prototype for missing elements.
8395 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8396 int fast_length = static_cast<int>(length);
8397 ASSERT(fast_length <= elements->length());
8398 for (int j = 0; j < fast_length; j++) {
8399 HandleScope loop_scope;
8400 Handle<Object> element_value(elements->get(j));
8401 if (!element_value->IsTheHole()) {
8402 visitor->visit(j, element_value);
8403 } else if (receiver->HasElement(j)) {
8404 // Call GetElement on receiver, not its prototype, or getters won't
8405 // have the correct receiver.
8406 element_value = GetElement(receiver, j);
8407 visitor->visit(j, element_value);
8408 }
8409 }
8410 break;
8411 }
8412 case JSObject::DICTIONARY_ELEMENTS: {
8413 Handle<NumberDictionary> dict(receiver->element_dictionary());
8414 List<uint32_t> indices(dict->Capacity() / 2);
8415 // Collect all indices in the object and the prototypes less
8416 // than length. This might introduce duplicates in the indices list.
8417 CollectElementIndices(receiver, length, &indices);
8418 indices.Sort(&compareUInt32);
8419 int j = 0;
8420 int n = indices.length();
8421 while (j < n) {
8422 HandleScope loop_scope;
8423 uint32_t index = indices[j];
8424 Handle<Object> element = GetElement(receiver, index);
8425 visitor->visit(index, element);
8426 // Skip to next different index (i.e., omit duplicates).
8427 do {
8428 j++;
8429 } while (j < n && indices[j] == index);
8430 }
8431 break;
8432 }
8433 case JSObject::PIXEL_ELEMENTS: {
8434 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
8435 for (uint32_t j = 0; j < length; j++) {
8436 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8437 visitor->visit(j, e);
8438 }
8439 break;
8440 }
8441 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8442 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8443 receiver, true, true, visitor);
8444 break;
8445 }
8446 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8447 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8448 receiver, true, true, visitor);
8449 break;
8450 }
8451 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8452 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8453 receiver, true, true, visitor);
8454 break;
8455 }
8456 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8457 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8458 receiver, true, true, visitor);
8459 break;
8460 }
8461 case JSObject::EXTERNAL_INT_ELEMENTS: {
8462 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8463 receiver, true, false, visitor);
8464 break;
8465 }
8466 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8467 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8468 receiver, true, false, visitor);
8469 break;
8470 }
8471 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8472 IterateExternalArrayElements<ExternalFloatArray, float>(
8473 receiver, false, false, visitor);
8474 break;
8475 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008476 default:
8477 UNREACHABLE();
8478 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008479 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008480 visitor->increase_index_offset(length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008481}
8482
8483
8484/**
8485 * Array::concat implementation.
8486 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008487 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008488 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008489 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008490static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008491 ASSERT(args.length() == 1);
8492 HandleScope handle_scope;
8493
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008494 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8495 int argument_count = static_cast<int>(arguments->length()->Number());
8496 RUNTIME_ASSERT(arguments->HasFastElements());
8497 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008498
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008499 // Pass 1: estimate the length and number of elements of the result.
8500 // The actual length can be larger if any of the arguments have getters
8501 // that mutate other arguments (but will otherwise be precise).
8502 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008503
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008504 uint32_t estimate_result_length = 0;
8505 uint32_t estimate_nof_elements = 0;
8506 {
8507 for (int i = 0; i < argument_count; i++) {
8508 HandleScope loop_scope;
8509 Handle<Object> obj(elements->get(i));
8510 uint32_t length_estimate;
8511 uint32_t element_estimate;
8512 if (obj->IsJSArray()) {
8513 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8514 length_estimate =
8515 static_cast<uint32_t>(array->length()->Number());
8516 element_estimate =
8517 EstimateElementCount(array);
8518 } else {
8519 length_estimate = 1;
8520 element_estimate = 1;
8521 }
8522 // Avoid overflows by capping at kMaxElementCount.
8523 if (JSObject::kMaxElementCount - estimate_result_length <
8524 length_estimate) {
8525 estimate_result_length = JSObject::kMaxElementCount;
8526 } else {
8527 estimate_result_length += length_estimate;
8528 }
8529 if (JSObject::kMaxElementCount - estimate_nof_elements <
8530 element_estimate) {
8531 estimate_nof_elements = JSObject::kMaxElementCount;
8532 } else {
8533 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008534 }
8535 }
8536 }
8537
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008538 // If estimated number of elements is more than half of length, a
8539 // fixed array (fast case) is more time and space-efficient than a
8540 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008541 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008542
8543 Handle<FixedArray> storage;
8544 if (fast_case) {
8545 // The backing storage array must have non-existing elements to
8546 // preserve holes across concat operations.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008547 storage = Factory::NewFixedArrayWithHoles(estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008548 } else {
8549 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8550 uint32_t at_least_space_for = estimate_nof_elements +
8551 (estimate_nof_elements >> 2);
8552 storage = Handle<FixedArray>::cast(
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008553 Factory::NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008554 }
8555
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008556 ArrayConcatVisitor visitor(storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008557
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008558 for (int i = 0; i < argument_count; i++) {
8559 Handle<Object> obj(elements->get(i));
8560 if (obj->IsJSArray()) {
8561 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8562 IterateElements(array, &visitor);
8563 } else {
8564 visitor.visit(0, obj);
8565 visitor.increase_index_offset(1);
8566 }
8567 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008568
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008569 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008570}
8571
8572
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008573// This will not allocate (flatten the string), but it may run
8574// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008575static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008576 NoHandleAllocation ha;
8577 ASSERT(args.length() == 1);
8578
8579 CONVERT_CHECKED(String, string, args[0]);
8580 StringInputBuffer buffer(string);
8581 while (buffer.has_more()) {
8582 uint16_t character = buffer.GetNext();
8583 PrintF("%c", character);
8584 }
8585 return string;
8586}
8587
ager@chromium.org5ec48922009-05-05 07:25:34 +00008588// Moves all own elements of an object, that are below a limit, to positions
8589// starting at zero. All undefined values are placed after non-undefined values,
8590// and are followed by non-existing element. Does not change the length
8591// property.
8592// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008593static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008594 ASSERT(args.length() == 2);
8595 CONVERT_CHECKED(JSObject, object, args[0]);
8596 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8597 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008598}
8599
8600
8601// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008602static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008603 ASSERT(args.length() == 2);
8604 CONVERT_CHECKED(JSArray, from, args[0]);
8605 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008606 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008607 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008608 if (new_elements->map() == Heap::fixed_array_map() ||
8609 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008610 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008611 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008612 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008613 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008614 Object* new_map;
8615 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008616 to->set_map(Map::cast(new_map));
8617 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008618 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008619 Object* obj;
8620 { MaybeObject* maybe_obj = from->ResetElements();
8621 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8622 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008623 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008624 return to;
8625}
8626
8627
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008628// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008629static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008630 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008631 CONVERT_CHECKED(JSObject, object, args[0]);
8632 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008633 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008634 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008635 } else if (object->IsJSArray()) {
8636 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008637 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008638 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008639 }
8640}
8641
8642
lrn@chromium.org303ada72010-10-27 09:33:13 +00008643static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008644 HandleScope handle_scope;
8645
8646 ASSERT_EQ(3, args.length());
8647
ager@chromium.orgac091b72010-05-05 07:34:42 +00008648 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008649 Handle<Object> key1 = args.at<Object>(1);
8650 Handle<Object> key2 = args.at<Object>(2);
8651
8652 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008653 if (!key1->ToArrayIndex(&index1)
8654 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008655 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008656 }
8657
ager@chromium.orgac091b72010-05-05 07:34:42 +00008658 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8659 Handle<Object> tmp1 = GetElement(jsobject, index1);
8660 Handle<Object> tmp2 = GetElement(jsobject, index2);
8661
8662 SetElement(jsobject, index1, tmp2);
8663 SetElement(jsobject, index2, tmp1);
8664
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008665 return Heap::undefined_value();
8666}
8667
8668
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008669// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008670// might have elements. Can either return keys (positive integers) or
8671// intervals (pair of a negative integer (-start-1) followed by a
8672// positive (length)) or undefined values.
8673// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008674static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008675 ASSERT(args.length() == 2);
8676 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008677 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008678 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008679 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008680 // Create an array and get all the keys into it, then remove all the
8681 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008682 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008683 int keys_length = keys->length();
8684 for (int i = 0; i < keys_length; i++) {
8685 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008686 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008687 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008688 // Zap invalid keys.
8689 keys->set_undefined(i);
8690 }
8691 }
8692 return *Factory::NewJSArrayWithElements(keys);
8693 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008694 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008695 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8696 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008697 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008698 uint32_t actual_length =
8699 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008700 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008701 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008702 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008703 single_interval->set(1, *length_object);
8704 return *Factory::NewJSArrayWithElements(single_interval);
8705 }
8706}
8707
8708
8709// DefineAccessor takes an optional final argument which is the
8710// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8711// to the way accessors are implemented, it is set for both the getter
8712// and setter on the first call to DefineAccessor and ignored on
8713// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008714static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008715 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8716 // Compute attributes.
8717 PropertyAttributes attributes = NONE;
8718 if (args.length() == 5) {
8719 CONVERT_CHECKED(Smi, attrs, args[4]);
8720 int value = attrs->value();
8721 // Only attribute bits should be set.
8722 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8723 attributes = static_cast<PropertyAttributes>(value);
8724 }
8725
8726 CONVERT_CHECKED(JSObject, obj, args[0]);
8727 CONVERT_CHECKED(String, name, args[1]);
8728 CONVERT_CHECKED(Smi, flag, args[2]);
8729 CONVERT_CHECKED(JSFunction, fun, args[3]);
8730 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8731}
8732
8733
lrn@chromium.org303ada72010-10-27 09:33:13 +00008734static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008735 ASSERT(args.length() == 3);
8736 CONVERT_CHECKED(JSObject, obj, args[0]);
8737 CONVERT_CHECKED(String, name, args[1]);
8738 CONVERT_CHECKED(Smi, flag, args[2]);
8739 return obj->LookupAccessor(name, flag->value() == 0);
8740}
8741
8742
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008743#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008744static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008745 ASSERT(args.length() == 0);
8746 return Execution::DebugBreakHelper();
8747}
8748
8749
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008750// Helper functions for wrapping and unwrapping stack frame ids.
8751static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008752 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008753 return Smi::FromInt(id >> 2);
8754}
8755
8756
8757static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8758 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8759}
8760
8761
8762// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008763// args[0]: debug event listener function to set or null or undefined for
8764// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008765// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008766static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008767 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008768 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8769 args[0]->IsUndefined() ||
8770 args[0]->IsNull());
8771 Handle<Object> callback = args.at<Object>(0);
8772 Handle<Object> data = args.at<Object>(1);
8773 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008774
8775 return Heap::undefined_value();
8776}
8777
8778
lrn@chromium.org303ada72010-10-27 09:33:13 +00008779static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008780 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008781 StackGuard::DebugBreak();
8782 return Heap::undefined_value();
8783}
8784
8785
lrn@chromium.org303ada72010-10-27 09:33:13 +00008786static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8787 LookupResult* result,
8788 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008789 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008790 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008791 case NORMAL:
8792 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008793 if (value->IsTheHole()) {
8794 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008795 }
8796 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008797 case FIELD:
8798 value =
8799 JSObject::cast(
8800 result->holder())->FastPropertyAt(result->GetFieldIndex());
8801 if (value->IsTheHole()) {
8802 return Heap::undefined_value();
8803 }
8804 return value;
8805 case CONSTANT_FUNCTION:
8806 return result->GetConstantFunction();
8807 case CALLBACKS: {
8808 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008809 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008810 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008811 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008812 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008813 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008814 ASSERT(maybe_value->IsException());
8815 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008816 Top::clear_pending_exception();
8817 if (caught_exception != NULL) {
8818 *caught_exception = true;
8819 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008820 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008821 }
8822 return value;
8823 } else {
8824 return Heap::undefined_value();
8825 }
8826 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008827 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008828 case MAP_TRANSITION:
8829 case CONSTANT_TRANSITION:
8830 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008831 return Heap::undefined_value();
8832 default:
8833 UNREACHABLE();
8834 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008835 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008836 return Heap::undefined_value();
8837}
8838
8839
ager@chromium.org32912102009-01-16 10:38:43 +00008840// Get debugger related details for an object property.
8841// args[0]: object holding property
8842// args[1]: name of the property
8843//
8844// The array returned contains the following information:
8845// 0: Property value
8846// 1: Property details
8847// 2: Property value is exception
8848// 3: Getter function if defined
8849// 4: Setter function if defined
8850// Items 2-4 are only filled if the property has either a getter or a setter
8851// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008852static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008853 HandleScope scope;
8854
8855 ASSERT(args.length() == 2);
8856
8857 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8858 CONVERT_ARG_CHECKED(String, name, 1);
8859
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008860 // Make sure to set the current context to the context before the debugger was
8861 // entered (if the debugger is entered). The reason for switching context here
8862 // is that for some property lookups (accessors and interceptors) callbacks
8863 // into the embedding application can occour, and the embedding application
8864 // could have the assumption that its own global context is the current
8865 // context and not some internal debugger context.
8866 SaveContext save;
8867 if (Debug::InDebugger()) {
8868 Top::set_context(*Debug::debugger_entry()->GetContext());
8869 }
8870
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008871 // Skip the global proxy as it has no properties and always delegates to the
8872 // real global object.
8873 if (obj->IsJSGlobalProxy()) {
8874 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8875 }
8876
8877
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008878 // Check if the name is trivially convertible to an index and get the element
8879 // if so.
8880 uint32_t index;
8881 if (name->AsArrayIndex(&index)) {
8882 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008883 Object* element_or_char;
8884 { MaybeObject* maybe_element_or_char =
8885 Runtime::GetElementOrCharAt(obj, index);
8886 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8887 return maybe_element_or_char;
8888 }
8889 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008890 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008891 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8892 return *Factory::NewJSArrayWithElements(details);
8893 }
8894
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008895 // Find the number of objects making up this.
8896 int length = LocalPrototypeChainLength(*obj);
8897
8898 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008899 Handle<JSObject> jsproto = obj;
8900 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008901 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008902 jsproto->LocalLookup(*name, &result);
8903 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008904 // LookupResult is not GC safe as it holds raw object pointers.
8905 // GC can happen later in this code so put the required fields into
8906 // local variables using handles when required for later use.
8907 PropertyType result_type = result.type();
8908 Handle<Object> result_callback_obj;
8909 if (result_type == CALLBACKS) {
8910 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8911 }
8912 Smi* property_details = result.GetPropertyDetails().AsSmi();
8913 // DebugLookupResultValue can cause GC so details from LookupResult needs
8914 // to be copied to handles before this.
8915 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008916 Object* raw_value;
8917 { MaybeObject* maybe_raw_value =
8918 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8919 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8920 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008921 Handle<Object> value(raw_value);
8922
8923 // If the callback object is a fixed array then it contains JavaScript
8924 // getter and/or setter.
8925 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8926 result_callback_obj->IsFixedArray();
8927 Handle<FixedArray> details =
8928 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8929 details->set(0, *value);
8930 details->set(1, property_details);
8931 if (hasJavaScriptAccessors) {
8932 details->set(2,
8933 caught_exception ? Heap::true_value()
8934 : Heap::false_value());
8935 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8936 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8937 }
8938
8939 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008940 }
8941 if (i < length - 1) {
8942 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8943 }
8944 }
8945
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008946 return Heap::undefined_value();
8947}
8948
8949
lrn@chromium.org303ada72010-10-27 09:33:13 +00008950static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008951 HandleScope scope;
8952
8953 ASSERT(args.length() == 2);
8954
8955 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8956 CONVERT_ARG_CHECKED(String, name, 1);
8957
8958 LookupResult result;
8959 obj->Lookup(*name, &result);
8960 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008961 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008962 }
8963 return Heap::undefined_value();
8964}
8965
8966
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008967// Return the property type calculated from the property details.
8968// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008969static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008970 ASSERT(args.length() == 1);
8971 CONVERT_CHECKED(Smi, details, args[0]);
8972 PropertyType type = PropertyDetails(details).type();
8973 return Smi::FromInt(static_cast<int>(type));
8974}
8975
8976
8977// Return the property attribute calculated from the property details.
8978// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008979static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008980 ASSERT(args.length() == 1);
8981 CONVERT_CHECKED(Smi, details, args[0]);
8982 PropertyAttributes attributes = PropertyDetails(details).attributes();
8983 return Smi::FromInt(static_cast<int>(attributes));
8984}
8985
8986
8987// Return the property insertion index calculated from the property details.
8988// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008989static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008990 ASSERT(args.length() == 1);
8991 CONVERT_CHECKED(Smi, details, args[0]);
8992 int index = PropertyDetails(details).index();
8993 return Smi::FromInt(index);
8994}
8995
8996
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008997// Return property value from named interceptor.
8998// args[0]: object
8999// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00009000static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001 HandleScope scope;
9002 ASSERT(args.length() == 2);
9003 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9004 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9005 CONVERT_ARG_CHECKED(String, name, 1);
9006
9007 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009008 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009009}
9010
9011
9012// Return element value from indexed interceptor.
9013// args[0]: object
9014// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00009015static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
9016 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009017 HandleScope scope;
9018 ASSERT(args.length() == 2);
9019 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9020 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9021 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9022
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009023 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009024}
9025
9026
lrn@chromium.org303ada72010-10-27 09:33:13 +00009027static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009028 ASSERT(args.length() >= 1);
9029 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009030 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009031 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009032 return Top::Throw(Heap::illegal_execution_state_symbol());
9033 }
9034
9035 return Heap::true_value();
9036}
9037
9038
lrn@chromium.org303ada72010-10-27 09:33:13 +00009039static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009040 HandleScope scope;
9041 ASSERT(args.length() == 1);
9042
9043 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009044 Object* result;
9045 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9046 if (!maybe_result->ToObject(&result)) return maybe_result;
9047 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009048
9049 // Count all frames which are relevant to debugging stack trace.
9050 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009051 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009052 if (id == StackFrame::NO_ID) {
9053 // If there is no JavaScript stack frame count is 0.
9054 return Smi::FromInt(0);
9055 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009056 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
9057 return Smi::FromInt(n);
9058}
9059
9060
9061static const int kFrameDetailsFrameIdIndex = 0;
9062static const int kFrameDetailsReceiverIndex = 1;
9063static const int kFrameDetailsFunctionIndex = 2;
9064static const int kFrameDetailsArgumentCountIndex = 3;
9065static const int kFrameDetailsLocalCountIndex = 4;
9066static const int kFrameDetailsSourcePositionIndex = 5;
9067static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009068static const int kFrameDetailsAtReturnIndex = 7;
9069static const int kFrameDetailsDebuggerFrameIndex = 8;
9070static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009071
9072// Return an array with frame details
9073// args[0]: number: break id
9074// args[1]: number: frame index
9075//
9076// The array returned contains the following information:
9077// 0: Frame id
9078// 1: Receiver
9079// 2: Function
9080// 3: Argument count
9081// 4: Local count
9082// 5: Source position
9083// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009084// 7: Is at return
9085// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009086// Arguments name, value
9087// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009088// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00009089static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009090 HandleScope scope;
9091 ASSERT(args.length() == 2);
9092
9093 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009094 Object* check;
9095 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9096 if (!maybe_check->ToObject(&check)) return maybe_check;
9097 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9099
9100 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009101 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009102 if (id == StackFrame::NO_ID) {
9103 // If there are no JavaScript stack frames return undefined.
9104 return Heap::undefined_value();
9105 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009106 int count = 0;
9107 JavaScriptFrameIterator it(id);
9108 for (; !it.done(); it.Advance()) {
9109 if (count == index) break;
9110 count++;
9111 }
9112 if (it.done()) return Heap::undefined_value();
9113
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009114 bool is_optimized_frame =
9115 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
9116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009117 // Traverse the saved contexts chain to find the active context for the
9118 // selected frame.
9119 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009120 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009121 save = save->prev();
9122 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009123 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009124
9125 // Get the frame id.
9126 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
9127
9128 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00009129 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009130
9131 // Check for constructor frame.
9132 bool constructor = it.frame()->IsConstructor();
9133
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009134 // Get scope info and read from it for local variable information.
9135 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009136 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009137 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009138
9139 // Get the context.
9140 Handle<Context> context(Context::cast(it.frame()->context()));
9141
9142 // Get the locals names and values into a temporary array.
9143 //
9144 // TODO(1240907): Hide compiler-introduced stack variables
9145 // (e.g. .result)? For users of the debugger, they will probably be
9146 // confusing.
9147 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009148
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009149 // Fill in the names of the locals.
9150 for (int i = 0; i < info.NumberOfLocals(); i++) {
9151 locals->set(i * 2, *info.LocalName(i));
9152 }
9153
9154 // Fill in the values of the locals.
9155 for (int i = 0; i < info.NumberOfLocals(); i++) {
9156 if (is_optimized_frame) {
9157 // If we are inspecting an optimized frame use undefined as the
9158 // value for all locals.
9159 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009160 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009161 // for locals in optimized frames.
9162 locals->set(i * 2 + 1, Heap::undefined_value());
9163 } else if (i < info.number_of_stack_slots()) {
9164 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009165 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9166 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009167 // Traverse the context chain to the function context as all local
9168 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009169 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009170 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171 context = Handle<Context>(context->previous());
9172 }
9173 ASSERT(context->is_function_context());
9174 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009175 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009176 }
9177 }
9178
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009179 // Check whether this frame is positioned at return. If not top
9180 // frame or if the frame is optimized it cannot be at a return.
9181 bool at_return = false;
9182 if (!is_optimized_frame && index == 0) {
9183 at_return = Debug::IsBreakAtReturn(it.frame());
9184 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009185
9186 // If positioned just before return find the value to be returned and add it
9187 // to the frame information.
9188 Handle<Object> return_value = Factory::undefined_value();
9189 if (at_return) {
9190 StackFrameIterator it2;
9191 Address internal_frame_sp = NULL;
9192 while (!it2.done()) {
9193 if (it2.frame()->is_internal()) {
9194 internal_frame_sp = it2.frame()->sp();
9195 } else {
9196 if (it2.frame()->is_java_script()) {
9197 if (it2.frame()->id() == it.frame()->id()) {
9198 // The internal frame just before the JavaScript frame contains the
9199 // value to return on top. A debug break at return will create an
9200 // internal frame to store the return value (eax/rax/r0) before
9201 // entering the debug break exit frame.
9202 if (internal_frame_sp != NULL) {
9203 return_value =
9204 Handle<Object>(Memory::Object_at(internal_frame_sp));
9205 break;
9206 }
9207 }
9208 }
9209
9210 // Indicate that the previous frame was not an internal frame.
9211 internal_frame_sp = NULL;
9212 }
9213 it2.Advance();
9214 }
9215 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009216
9217 // Now advance to the arguments adapter frame (if any). It contains all
9218 // the provided parameters whereas the function frame always have the number
9219 // of arguments matching the functions parameters. The rest of the
9220 // information (except for what is collected above) is the same.
9221 it.AdvanceToArgumentsFrame();
9222
9223 // Find the number of arguments to fill. At least fill the number of
9224 // parameters for the function and fill more if more parameters are provided.
9225 int argument_count = info.number_of_parameters();
9226 if (argument_count < it.frame()->GetProvidedParametersCount()) {
9227 argument_count = it.frame()->GetProvidedParametersCount();
9228 }
9229
9230 // Calculate the size of the result.
9231 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009232 2 * (argument_count + info.NumberOfLocals()) +
9233 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9235
9236 // Add the frame id.
9237 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9238
9239 // Add the function (same as in function frame).
9240 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9241
9242 // Add the arguments count.
9243 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9244
9245 // Add the locals count
9246 details->set(kFrameDetailsLocalCountIndex,
9247 Smi::FromInt(info.NumberOfLocals()));
9248
9249 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009250 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009251 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9252 } else {
9253 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
9254 }
9255
9256 // Add the constructor information.
9257 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
9258
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009259 // Add the at return information.
9260 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
9261
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009262 // Add information on whether this frame is invoked in the debugger context.
9263 details->set(kFrameDetailsDebuggerFrameIndex,
9264 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
9265
9266 // Fill the dynamic part.
9267 int details_index = kFrameDetailsFirstDynamicIndex;
9268
9269 // Add arguments name and value.
9270 for (int i = 0; i < argument_count; i++) {
9271 // Name of the argument.
9272 if (i < info.number_of_parameters()) {
9273 details->set(details_index++, *info.parameter_name(i));
9274 } else {
9275 details->set(details_index++, Heap::undefined_value());
9276 }
9277
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009278 // Parameter value. If we are inspecting an optimized frame, use
9279 // undefined as the value.
9280 //
9281 // TODO(3141533): We should be able to get the actual parameter
9282 // value for optimized frames.
9283 if (!is_optimized_frame &&
9284 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009285 details->set(details_index++, it.frame()->GetParameter(i));
9286 } else {
9287 details->set(details_index++, Heap::undefined_value());
9288 }
9289 }
9290
9291 // Add locals name and value from the temporary copy from the function frame.
9292 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9293 details->set(details_index++, locals->get(i));
9294 }
9295
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009296 // Add the value being returned.
9297 if (at_return) {
9298 details->set(details_index++, *return_value);
9299 }
9300
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009301 // Add the receiver (same as in function frame).
9302 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9303 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
9304 Handle<Object> receiver(it.frame()->receiver());
9305 if (!receiver->IsJSObject()) {
9306 // If the receiver is NOT a JSObject we have hit an optimization
9307 // where a value object is not converted into a wrapped JS objects.
9308 // To hide this optimization from the debugger, we wrap the receiver
9309 // by creating correct wrapper object based on the calling frame's
9310 // global context.
9311 it.Advance();
9312 Handle<Context> calling_frames_global_context(
9313 Context::cast(Context::cast(it.frame()->context())->global_context()));
9314 receiver = Factory::ToObject(receiver, calling_frames_global_context);
9315 }
9316 details->set(kFrameDetailsReceiverIndex, *receiver);
9317
9318 ASSERT_EQ(details_size, details_index);
9319 return *Factory::NewJSArrayWithElements(details);
9320}
9321
9322
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009323// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009324static bool CopyContextLocalsToScopeObject(
ager@chromium.orgb5737492010-07-15 09:29:43 +00009325 Handle<SerializedScopeInfo> serialized_scope_info,
9326 ScopeInfo<>& scope_info,
9327 Handle<Context> context,
9328 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009329 // Fill all context locals to the context extension.
9330 for (int i = Context::MIN_CONTEXT_SLOTS;
9331 i < scope_info.number_of_context_slots();
9332 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009333 int context_index = serialized_scope_info->ContextSlotIndex(
9334 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009335
9336 // Don't include the arguments shadow (.arguments) context variable.
9337 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009338 RETURN_IF_EMPTY_HANDLE_VALUE(
9339 SetProperty(scope_object,
9340 scope_info.context_slot_name(i),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009341 Handle<Object>(context->get(context_index)),
9342 NONE,
9343 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009344 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009345 }
9346 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009347
9348 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009349}
9350
9351
9352// Create a plain JSObject which materializes the local scope for the specified
9353// frame.
9354static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
9355 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009356 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009357 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9358 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009359
9360 // Allocate and initialize a JSObject with all the arguments, stack locals
9361 // heap locals and extension properties of the debugged function.
9362 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
9363
9364 // First fill all parameters.
9365 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009366 RETURN_IF_EMPTY_HANDLE_VALUE(
9367 SetProperty(local_scope,
9368 scope_info.parameter_name(i),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009369 Handle<Object>(frame->GetParameter(i)),
9370 NONE,
9371 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009372 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009373 }
9374
9375 // Second fill all stack locals.
9376 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009377 RETURN_IF_EMPTY_HANDLE_VALUE(
9378 SetProperty(local_scope,
9379 scope_info.stack_slot_name(i),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009380 Handle<Object>(frame->GetExpression(i)),
9381 NONE,
9382 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009383 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009384 }
9385
9386 // Third fill all context locals.
9387 Handle<Context> frame_context(Context::cast(frame->context()));
9388 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009389 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9390 function_context, local_scope)) {
9391 return Handle<JSObject>();
9392 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009393
9394 // Finally copy any properties from the function context extension. This will
9395 // be variables introduced by eval.
9396 if (function_context->closure() == *function) {
9397 if (function_context->has_extension() &&
9398 !function_context->IsGlobalContext()) {
9399 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009400 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009401 for (int i = 0; i < keys->length(); i++) {
9402 // Names of variables introduced by eval are strings.
9403 ASSERT(keys->get(i)->IsString());
9404 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009405 RETURN_IF_EMPTY_HANDLE_VALUE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009406 SetProperty(local_scope,
9407 key,
9408 GetProperty(ext, key),
9409 NONE,
9410 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009411 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009412 }
9413 }
9414 }
9415 return local_scope;
9416}
9417
9418
9419// Create a plain JSObject which materializes the closure content for the
9420// context.
9421static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
9422 ASSERT(context->is_function_context());
9423
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009424 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009425 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9426 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009427
9428 // Allocate and initialize a JSObject with all the content of theis function
9429 // closure.
9430 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
9431
9432 // Check whether the arguments shadow object exists.
9433 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00009434 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
9435 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009436 if (arguments_shadow_index >= 0) {
9437 // In this case all the arguments are available in the arguments shadow
9438 // object.
9439 Handle<JSObject> arguments_shadow(
9440 JSObject::cast(context->get(arguments_shadow_index)));
9441 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009442 // We don't expect exception-throwing getters on the arguments shadow.
9443 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009444 RETURN_IF_EMPTY_HANDLE_VALUE(
9445 SetProperty(closure_scope,
9446 scope_info.parameter_name(i),
9447 Handle<Object>(element),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009448 NONE,
9449 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009450 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009451 }
9452 }
9453
9454 // Fill all context locals to the context extension.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009455 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9456 context, closure_scope)) {
9457 return Handle<JSObject>();
9458 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009459
9460 // Finally copy any properties from the function context extension. This will
9461 // be variables introduced by eval.
9462 if (context->has_extension()) {
9463 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009464 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009465 for (int i = 0; i < keys->length(); i++) {
9466 // Names of variables introduced by eval are strings.
9467 ASSERT(keys->get(i)->IsString());
9468 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009469 RETURN_IF_EMPTY_HANDLE_VALUE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009470 SetProperty(closure_scope,
9471 key,
9472 GetProperty(ext, key),
9473 NONE,
9474 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009475 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009476 }
9477 }
9478
9479 return closure_scope;
9480}
9481
9482
9483// Iterate over the actual scopes visible from a stack frame. All scopes are
9484// backed by an actual context except the local scope, which is inserted
9485// "artifically" in the context chain.
9486class ScopeIterator {
9487 public:
9488 enum ScopeType {
9489 ScopeTypeGlobal = 0,
9490 ScopeTypeLocal,
9491 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009492 ScopeTypeClosure,
9493 // Every catch block contains an implicit with block (its parameter is
9494 // a JSContextExtensionObject) that extends current scope with a variable
9495 // holding exception object. Such with blocks are treated as scopes of their
9496 // own type.
9497 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009498 };
9499
9500 explicit ScopeIterator(JavaScriptFrame* frame)
9501 : frame_(frame),
9502 function_(JSFunction::cast(frame->function())),
9503 context_(Context::cast(frame->context())),
9504 local_done_(false),
9505 at_local_(false) {
9506
9507 // Check whether the first scope is actually a local scope.
9508 if (context_->IsGlobalContext()) {
9509 // If there is a stack slot for .result then this local scope has been
9510 // created for evaluating top level code and it is not a real local scope.
9511 // Checking for the existence of .result seems fragile, but the scope info
9512 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009513 int index = function_->shared()->scope_info()->
9514 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009515 at_local_ = index < 0;
9516 } else if (context_->is_function_context()) {
9517 at_local_ = true;
9518 }
9519 }
9520
9521 // More scopes?
9522 bool Done() { return context_.is_null(); }
9523
9524 // Move to the next scope.
9525 void Next() {
9526 // If at a local scope mark the local scope as passed.
9527 if (at_local_) {
9528 at_local_ = false;
9529 local_done_ = true;
9530
9531 // If the current context is not associated with the local scope the
9532 // current context is the next real scope, so don't move to the next
9533 // context in this case.
9534 if (context_->closure() != *function_) {
9535 return;
9536 }
9537 }
9538
9539 // The global scope is always the last in the chain.
9540 if (context_->IsGlobalContext()) {
9541 context_ = Handle<Context>();
9542 return;
9543 }
9544
9545 // Move to the next context.
9546 if (context_->is_function_context()) {
9547 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9548 } else {
9549 context_ = Handle<Context>(context_->previous());
9550 }
9551
9552 // If passing the local scope indicate that the current scope is now the
9553 // local scope.
9554 if (!local_done_ &&
9555 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9556 at_local_ = true;
9557 }
9558 }
9559
9560 // Return the type of the current scope.
9561 int Type() {
9562 if (at_local_) {
9563 return ScopeTypeLocal;
9564 }
9565 if (context_->IsGlobalContext()) {
9566 ASSERT(context_->global()->IsGlobalObject());
9567 return ScopeTypeGlobal;
9568 }
9569 if (context_->is_function_context()) {
9570 return ScopeTypeClosure;
9571 }
9572 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009573 // Current scope is either an explicit with statement or a with statement
9574 // implicitely generated for a catch block.
9575 // If the extension object here is a JSContextExtensionObject then
9576 // current with statement is one frome a catch block otherwise it's a
9577 // regular with statement.
9578 if (context_->extension()->IsJSContextExtensionObject()) {
9579 return ScopeTypeCatch;
9580 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009581 return ScopeTypeWith;
9582 }
9583
9584 // Return the JavaScript object with the content of the current scope.
9585 Handle<JSObject> ScopeObject() {
9586 switch (Type()) {
9587 case ScopeIterator::ScopeTypeGlobal:
9588 return Handle<JSObject>(CurrentContext()->global());
9589 break;
9590 case ScopeIterator::ScopeTypeLocal:
9591 // Materialize the content of the local scope into a JSObject.
9592 return MaterializeLocalScope(frame_);
9593 break;
9594 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009595 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009596 // Return the with object.
9597 return Handle<JSObject>(CurrentContext()->extension());
9598 break;
9599 case ScopeIterator::ScopeTypeClosure:
9600 // Materialize the content of the closure scope into a JSObject.
9601 return MaterializeClosure(CurrentContext());
9602 break;
9603 }
9604 UNREACHABLE();
9605 return Handle<JSObject>();
9606 }
9607
9608 // Return the context for this scope. For the local context there might not
9609 // be an actual context.
9610 Handle<Context> CurrentContext() {
9611 if (at_local_ && context_->closure() != *function_) {
9612 return Handle<Context>();
9613 }
9614 return context_;
9615 }
9616
9617#ifdef DEBUG
9618 // Debug print of the content of the current scope.
9619 void DebugPrint() {
9620 switch (Type()) {
9621 case ScopeIterator::ScopeTypeGlobal:
9622 PrintF("Global:\n");
9623 CurrentContext()->Print();
9624 break;
9625
9626 case ScopeIterator::ScopeTypeLocal: {
9627 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009628 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009629 scope_info.Print();
9630 if (!CurrentContext().is_null()) {
9631 CurrentContext()->Print();
9632 if (CurrentContext()->has_extension()) {
9633 Handle<JSObject> extension =
9634 Handle<JSObject>(CurrentContext()->extension());
9635 if (extension->IsJSContextExtensionObject()) {
9636 extension->Print();
9637 }
9638 }
9639 }
9640 break;
9641 }
9642
9643 case ScopeIterator::ScopeTypeWith: {
9644 PrintF("With:\n");
9645 Handle<JSObject> extension =
9646 Handle<JSObject>(CurrentContext()->extension());
9647 extension->Print();
9648 break;
9649 }
9650
ager@chromium.orga1645e22009-09-09 19:27:10 +00009651 case ScopeIterator::ScopeTypeCatch: {
9652 PrintF("Catch:\n");
9653 Handle<JSObject> extension =
9654 Handle<JSObject>(CurrentContext()->extension());
9655 extension->Print();
9656 break;
9657 }
9658
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009659 case ScopeIterator::ScopeTypeClosure: {
9660 PrintF("Closure:\n");
9661 CurrentContext()->Print();
9662 if (CurrentContext()->has_extension()) {
9663 Handle<JSObject> extension =
9664 Handle<JSObject>(CurrentContext()->extension());
9665 if (extension->IsJSContextExtensionObject()) {
9666 extension->Print();
9667 }
9668 }
9669 break;
9670 }
9671
9672 default:
9673 UNREACHABLE();
9674 }
9675 PrintF("\n");
9676 }
9677#endif
9678
9679 private:
9680 JavaScriptFrame* frame_;
9681 Handle<JSFunction> function_;
9682 Handle<Context> context_;
9683 bool local_done_;
9684 bool at_local_;
9685
9686 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9687};
9688
9689
lrn@chromium.org303ada72010-10-27 09:33:13 +00009690static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009691 HandleScope scope;
9692 ASSERT(args.length() == 2);
9693
9694 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009695 Object* check;
9696 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9697 if (!maybe_check->ToObject(&check)) return maybe_check;
9698 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009699 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9700
9701 // Get the frame where the debugging is performed.
9702 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9703 JavaScriptFrameIterator it(id);
9704 JavaScriptFrame* frame = it.frame();
9705
9706 // Count the visible scopes.
9707 int n = 0;
9708 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9709 n++;
9710 }
9711
9712 return Smi::FromInt(n);
9713}
9714
9715
9716static const int kScopeDetailsTypeIndex = 0;
9717static const int kScopeDetailsObjectIndex = 1;
9718static const int kScopeDetailsSize = 2;
9719
9720// Return an array with scope details
9721// args[0]: number: break id
9722// args[1]: number: frame index
9723// args[2]: number: scope index
9724//
9725// The array returned contains the following information:
9726// 0: Scope type
9727// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009728static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009729 HandleScope scope;
9730 ASSERT(args.length() == 3);
9731
9732 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009733 Object* check;
9734 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9735 if (!maybe_check->ToObject(&check)) return maybe_check;
9736 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009737 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9738 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9739
9740 // Get the frame where the debugging is performed.
9741 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9742 JavaScriptFrameIterator frame_it(id);
9743 JavaScriptFrame* frame = frame_it.frame();
9744
9745 // Find the requested scope.
9746 int n = 0;
9747 ScopeIterator it(frame);
9748 for (; !it.Done() && n < index; it.Next()) {
9749 n++;
9750 }
9751 if (it.Done()) {
9752 return Heap::undefined_value();
9753 }
9754
9755 // Calculate the size of the result.
9756 int details_size = kScopeDetailsSize;
9757 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9758
9759 // Fill in scope details.
9760 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009761 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009762 RETURN_IF_EMPTY_HANDLE(scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009763 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009764
9765 return *Factory::NewJSArrayWithElements(details);
9766}
9767
9768
lrn@chromium.org303ada72010-10-27 09:33:13 +00009769static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009770 HandleScope scope;
9771 ASSERT(args.length() == 0);
9772
9773#ifdef DEBUG
9774 // Print the scopes for the top frame.
9775 StackFrameLocator locator;
9776 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9777 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9778 it.DebugPrint();
9779 }
9780#endif
9781 return Heap::undefined_value();
9782}
9783
9784
lrn@chromium.org303ada72010-10-27 09:33:13 +00009785static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009786 HandleScope scope;
9787 ASSERT(args.length() == 1);
9788
9789 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009790 Object* result;
9791 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9792 if (!maybe_result->ToObject(&result)) return maybe_result;
9793 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009794
9795 // Count all archived V8 threads.
9796 int n = 0;
9797 for (ThreadState* thread = ThreadState::FirstInUse();
9798 thread != NULL;
9799 thread = thread->Next()) {
9800 n++;
9801 }
9802
9803 // Total number of threads is current thread and archived threads.
9804 return Smi::FromInt(n + 1);
9805}
9806
9807
9808static const int kThreadDetailsCurrentThreadIndex = 0;
9809static const int kThreadDetailsThreadIdIndex = 1;
9810static const int kThreadDetailsSize = 2;
9811
9812// Return an array with thread details
9813// args[0]: number: break id
9814// args[1]: number: thread index
9815//
9816// The array returned contains the following information:
9817// 0: Is current thread?
9818// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009819static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009820 HandleScope scope;
9821 ASSERT(args.length() == 2);
9822
9823 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009824 Object* check;
9825 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9826 if (!maybe_check->ToObject(&check)) return maybe_check;
9827 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009828 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9829
9830 // Allocate array for result.
9831 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9832
9833 // Thread index 0 is current thread.
9834 if (index == 0) {
9835 // Fill the details.
9836 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9837 details->set(kThreadDetailsThreadIdIndex,
9838 Smi::FromInt(ThreadManager::CurrentId()));
9839 } else {
9840 // Find the thread with the requested index.
9841 int n = 1;
9842 ThreadState* thread = ThreadState::FirstInUse();
9843 while (index != n && thread != NULL) {
9844 thread = thread->Next();
9845 n++;
9846 }
9847 if (thread == NULL) {
9848 return Heap::undefined_value();
9849 }
9850
9851 // Fill the details.
9852 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9853 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9854 }
9855
9856 // Convert to JS array and return.
9857 return *Factory::NewJSArrayWithElements(details);
9858}
9859
9860
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009861// Sets the disable break state
9862// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009863static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009864 HandleScope scope;
9865 ASSERT(args.length() == 1);
9866 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9867 Debug::set_disable_break(disable_break);
9868 return Heap::undefined_value();
9869}
9870
9871
lrn@chromium.org303ada72010-10-27 09:33:13 +00009872static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009873 HandleScope scope;
9874 ASSERT(args.length() == 1);
9875
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009876 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9877 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009878 // Find the number of break points
9879 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9880 if (break_locations->IsUndefined()) return Heap::undefined_value();
9881 // Return array as JS array
9882 return *Factory::NewJSArrayWithElements(
9883 Handle<FixedArray>::cast(break_locations));
9884}
9885
9886
9887// Set a break point in a function
9888// args[0]: function
9889// args[1]: number: break source position (within the function source)
9890// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009891static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009892 HandleScope scope;
9893 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009894 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9895 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009896 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9897 RUNTIME_ASSERT(source_position >= 0);
9898 Handle<Object> break_point_object_arg = args.at<Object>(2);
9899
9900 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009901 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009902
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009903 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009904}
9905
9906
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009907Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9908 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009909 // Iterate the heap looking for SharedFunctionInfo generated from the
9910 // script. The inner most SharedFunctionInfo containing the source position
9911 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009912 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009913 // which is found is not compiled it is compiled and the heap is iterated
9914 // again as the compilation might create inner functions from the newly
9915 // compiled function and the actual requested break point might be in one of
9916 // these functions.
9917 bool done = false;
9918 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009919 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009920 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009921 while (!done) {
9922 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009923 for (HeapObject* obj = iterator.next();
9924 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009925 if (obj->IsSharedFunctionInfo()) {
9926 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9927 if (shared->script() == *script) {
9928 // If the SharedFunctionInfo found has the requested script data and
9929 // contains the source position it is a candidate.
9930 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009931 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009932 start_position = shared->start_position();
9933 }
9934 if (start_position <= position &&
9935 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009936 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009937 // candidate this is the new candidate.
9938 if (target.is_null()) {
9939 target_start_position = start_position;
9940 target = shared;
9941 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009942 if (target_start_position == start_position &&
9943 shared->end_position() == target->end_position()) {
9944 // If a top-level function contain only one function
9945 // declartion the source for the top-level and the function is
9946 // the same. In that case prefer the non top-level function.
9947 if (!shared->is_toplevel()) {
9948 target_start_position = start_position;
9949 target = shared;
9950 }
9951 } else if (target_start_position <= start_position &&
9952 shared->end_position() <= target->end_position()) {
9953 // This containment check includes equality as a function inside
9954 // a top-level function can share either start or end position
9955 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009956 target_start_position = start_position;
9957 target = shared;
9958 }
9959 }
9960 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009961 }
9962 }
9963 }
9964
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009965 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009966 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009967 }
9968
9969 // If the candidate found is compiled we are done. NOTE: when lazy
9970 // compilation of inner functions is introduced some additional checking
9971 // needs to be done here to compile inner functions.
9972 done = target->is_compiled();
9973 if (!done) {
9974 // If the candidate is not compiled compile it to reveal any inner
9975 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009976 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009977 }
9978 }
9979
9980 return *target;
9981}
9982
9983
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009984// Changes the state of a break point in a script and returns source position
9985// where break point was set. NOTE: Regarding performance see the NOTE for
9986// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009987// args[0]: script to set break point in
9988// args[1]: number: break source position (within the script source)
9989// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009990static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009991 HandleScope scope;
9992 ASSERT(args.length() == 3);
9993 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9994 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9995 RUNTIME_ASSERT(source_position >= 0);
9996 Handle<Object> break_point_object_arg = args.at<Object>(2);
9997
9998 // Get the script from the script wrapper.
9999 RUNTIME_ASSERT(wrapper->value()->IsScript());
10000 Handle<Script> script(Script::cast(wrapper->value()));
10001
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010002 Object* result = Runtime::FindSharedFunctionInfoInScript(
10003 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010004 if (!result->IsUndefined()) {
10005 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10006 // Find position within function. The script position might be before the
10007 // source position of the first function.
10008 int position;
10009 if (shared->start_position() > source_position) {
10010 position = 0;
10011 } else {
10012 position = source_position - shared->start_position();
10013 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010014 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
10015 position += shared->start_position();
10016 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010017 }
10018 return Heap::undefined_value();
10019}
10020
10021
10022// Clear a break point
10023// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +000010024static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010025 HandleScope scope;
10026 ASSERT(args.length() == 1);
10027 Handle<Object> break_point_object_arg = args.at<Object>(0);
10028
10029 // Clear break point.
10030 Debug::ClearBreakPoint(break_point_object_arg);
10031
10032 return Heap::undefined_value();
10033}
10034
10035
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010036// Change the state of break on exceptions.
10037// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10038// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010039static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010040 HandleScope scope;
10041 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010042 RUNTIME_ASSERT(args[0]->IsNumber());
10043 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010044
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010045 // If the number doesn't match an enum value, the ChangeBreakOnException
10046 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010047 ExceptionBreakType type =
10048 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010049 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010050 Debug::ChangeBreakOnException(type, enable);
10051 return Heap::undefined_value();
10052}
10053
10054
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010055// Returns the state of break on exceptions
10056// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +000010057static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010058 HandleScope scope;
10059 ASSERT(args.length() == 1);
10060 RUNTIME_ASSERT(args[0]->IsNumber());
10061
10062 ExceptionBreakType type =
10063 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
10064 bool result = Debug::IsBreakOnException(type);
10065 return Smi::FromInt(result);
10066}
10067
10068
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010069// Prepare for stepping
10070// args[0]: break id for checking execution state
10071// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010072// args[2]: number of times to perform the step, for step out it is the number
10073// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010074static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010075 HandleScope scope;
10076 ASSERT(args.length() == 3);
10077 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010078 Object* check;
10079 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
10080 if (!maybe_check->ToObject(&check)) return maybe_check;
10081 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010082 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
10083 return Top::Throw(Heap::illegal_argument_symbol());
10084 }
10085
10086 // Get the step action and check validity.
10087 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10088 if (step_action != StepIn &&
10089 step_action != StepNext &&
10090 step_action != StepOut &&
10091 step_action != StepInMin &&
10092 step_action != StepMin) {
10093 return Top::Throw(Heap::illegal_argument_symbol());
10094 }
10095
10096 // Get the number of steps.
10097 int step_count = NumberToInt32(args[2]);
10098 if (step_count < 1) {
10099 return Top::Throw(Heap::illegal_argument_symbol());
10100 }
10101
ager@chromium.orga1645e22009-09-09 19:27:10 +000010102 // Clear all current stepping setup.
10103 Debug::ClearStepping();
10104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010105 // Prepare step.
10106 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
10107 return Heap::undefined_value();
10108}
10109
10110
10111// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010112static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010113 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010114 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115 Debug::ClearStepping();
10116 return Heap::undefined_value();
10117}
10118
10119
10120// Creates a copy of the with context chain. The copy of the context chain is
10121// is linked to the function context supplied.
10122static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10123 Handle<Context> function_context) {
10124 // At the bottom of the chain. Return the function context to link to.
10125 if (context_chain->is_function_context()) {
10126 return function_context;
10127 }
10128
10129 // Recursively copy the with contexts.
10130 Handle<Context> previous(context_chain->previous());
10131 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010132 Handle<Context> context = CopyWithContextChain(function_context, previous);
10133 return Factory::NewWithContext(context,
10134 extension,
10135 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010136}
10137
10138
10139// Helper function to find or create the arguments object for
10140// Runtime_DebugEvaluate.
10141static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
10142 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010143 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010144 const ScopeInfo<>* sinfo,
10145 Handle<Context> function_context) {
10146 // Try to find the value of 'arguments' to pass as parameter. If it is not
10147 // found (that is the debugged function does not reference 'arguments' and
10148 // does not support eval) then create an 'arguments' object.
10149 int index;
10150 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010151 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010152 if (index != -1) {
10153 return Handle<Object>(frame->GetExpression(index));
10154 }
10155 }
10156
10157 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010158 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010159 if (index != -1) {
10160 return Handle<Object>(function_context->get(index));
10161 }
10162 }
10163
10164 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010165 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
10166 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010167
10168 AssertNoAllocation no_gc;
10169 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010170 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010171 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010172 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010173 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010174 return arguments;
10175}
10176
10177
10178// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010179// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010180// extension part has all the parameters and locals of the function on the
10181// stack frame. A function which calls eval with the code to evaluate is then
10182// compiled in this context and called in this context. As this context
10183// replaces the context of the function on the stack frame a new (empty)
10184// function is created as well to be used as the closure for the context.
10185// This function and the context acts as replacements for the function on the
10186// stack frame presenting the same view of the values of parameters and
10187// local variables as if the piece of JavaScript was evaluated at the point
10188// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010189static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010190 HandleScope scope;
10191
10192 // Check the execution state and decode arguments frame and source to be
10193 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010194 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010195 Object* check_result;
10196 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10197 if (!maybe_check_result->ToObject(&check_result)) {
10198 return maybe_check_result;
10199 }
10200 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010201 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10202 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010203 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010204 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010205
10206 // Handle the processing of break.
10207 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010208
10209 // Get the frame where the debugging is performed.
10210 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10211 JavaScriptFrameIterator it(id);
10212 JavaScriptFrame* frame = it.frame();
10213 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010214 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010215 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010216
10217 // Traverse the saved contexts chain to find the active context for the
10218 // selected frame.
10219 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010220 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010221 save = save->prev();
10222 }
10223 ASSERT(save != NULL);
10224 SaveContext savex;
10225 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010226
10227 // Create the (empty) function replacing the function on the stack frame for
10228 // the purpose of evaluating in the context created below. It is important
10229 // that this function does not describe any parameters and local variables
10230 // in the context. If it does then this will cause problems with the lookup
10231 // in Context::Lookup, where context slots for parameters and local variables
10232 // are looked at before the extension object.
10233 Handle<JSFunction> go_between =
10234 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
10235 go_between->set_context(function->context());
10236#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010237 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010238 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10239 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10240#endif
10241
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010242 // Materialize the content of the local scope into a JSObject.
10243 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010244 RETURN_IF_EMPTY_HANDLE(local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245
10246 // Allocate a new context for the debug evaluation and set the extension
10247 // object build.
10248 Handle<Context> context =
10249 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010250 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010251 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010252 Handle<Context> frame_context(Context::cast(frame->context()));
10253 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254 context = CopyWithContextChain(frame_context, context);
10255
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010256 if (additional_context->IsJSObject()) {
10257 context = Factory::NewWithContext(context,
10258 Handle<JSObject>::cast(additional_context), false);
10259 }
10260
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010261 // Wrap the evaluation statement in a new function compiled in the newly
10262 // created context. The function has one parameter which has to be called
10263 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010264 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265 // function(arguments,__source__) {return eval(__source__);}
10266 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010267 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010268 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010269 Handle<String> function_source =
10270 Factory::NewStringFromAscii(Vector<const char>(source_str,
10271 source_str_length));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010272
10273 // Currently, the eval code will be executed in non-strict mode,
10274 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010275 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010276 Compiler::CompileEval(function_source,
10277 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010278 context->IsGlobalContext(),
10279 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010280 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010281 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010282 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010283
10284 // Invoke the result of the compilation to get the evaluation function.
10285 bool has_pending_exception;
10286 Handle<Object> receiver(frame->receiver());
10287 Handle<Object> evaluation_function =
10288 Execution::Call(compiled_function, receiver, 0, NULL,
10289 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010290 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010291
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010292 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
10293 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294
10295 // Invoke the evaluation function and return the result.
10296 const int argc = 2;
10297 Object** argv[argc] = { arguments.location(),
10298 Handle<Object>::cast(source).location() };
10299 Handle<Object> result =
10300 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10301 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010302 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010303
10304 // Skip the global proxy as it has no properties and always delegates to the
10305 // real global object.
10306 if (result->IsJSGlobalProxy()) {
10307 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10308 }
10309
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010310 return *result;
10311}
10312
10313
lrn@chromium.org303ada72010-10-27 09:33:13 +000010314static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315 HandleScope scope;
10316
10317 // Check the execution state and decode arguments frame and source to be
10318 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010319 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010320 Object* check_result;
10321 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10322 if (!maybe_check_result->ToObject(&check_result)) {
10323 return maybe_check_result;
10324 }
10325 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010326 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010327 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010328 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010329
10330 // Handle the processing of break.
10331 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010332
10333 // Enter the top context from before the debugger was invoked.
10334 SaveContext save;
10335 SaveContext* top = &save;
10336 while (top != NULL && *top->context() == *Debug::debug_context()) {
10337 top = top->prev();
10338 }
10339 if (top != NULL) {
10340 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010341 }
10342
10343 // Get the global context now set to the top context from before the
10344 // debugger was invoked.
10345 Handle<Context> context = Top::global_context();
10346
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010347 bool is_global = true;
10348
10349 if (additional_context->IsJSObject()) {
10350 // Create a function context first, than put 'with' context on top of it.
10351 Handle<JSFunction> go_between = Factory::NewFunction(
10352 Factory::empty_string(), Factory::undefined_value());
10353 go_between->set_context(*context);
10354 context =
10355 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
10356 context->set_extension(JSObject::cast(*additional_context));
10357 is_global = false;
10358 }
10359
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010360 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010361 // Currently, the eval code will be executed in non-strict mode,
10362 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010363 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010364 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010365 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010366 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010367 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
10368 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010369
10370 // Invoke the result of the compilation to get the evaluation function.
10371 bool has_pending_exception;
10372 Handle<Object> receiver = Top::global();
10373 Handle<Object> result =
10374 Execution::Call(compiled_function, receiver, 0, NULL,
10375 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010376 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010377 return *result;
10378}
10379
10380
lrn@chromium.org303ada72010-10-27 09:33:13 +000010381static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010382 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010383 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010385 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010386 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010387
10388 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010389 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010390 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10391 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10392 // because using
10393 // instances->set(i, *GetScriptWrapper(script))
10394 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10395 // already have deferenced the instances handle.
10396 Handle<JSValue> wrapper = GetScriptWrapper(script);
10397 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010398 }
10399
10400 // Return result as a JS array.
10401 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
10402 Handle<JSArray>::cast(result)->SetContent(*instances);
10403 return *result;
10404}
10405
10406
10407// Helper function used by Runtime_DebugReferencedBy below.
10408static int DebugReferencedBy(JSObject* target,
10409 Object* instance_filter, int max_references,
10410 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010411 JSFunction* arguments_function) {
10412 NoHandleAllocation ha;
10413 AssertNoAllocation no_alloc;
10414
10415 // Iterate the heap.
10416 int count = 0;
10417 JSObject* last = NULL;
10418 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010419 HeapObject* heap_obj = NULL;
10420 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010421 (max_references == 0 || count < max_references)) {
10422 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010423 if (heap_obj->IsJSObject()) {
10424 // Skip context extension objects and argument arrays as these are
10425 // checked in the context of functions using them.
10426 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010427 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010428 obj->map()->constructor() == arguments_function) {
10429 continue;
10430 }
10431
10432 // Check if the JS object has a reference to the object looked for.
10433 if (obj->ReferencesObject(target)) {
10434 // Check instance filter if supplied. This is normally used to avoid
10435 // references from mirror objects (see Runtime_IsInPrototypeChain).
10436 if (!instance_filter->IsUndefined()) {
10437 Object* V = obj;
10438 while (true) {
10439 Object* prototype = V->GetPrototype();
10440 if (prototype->IsNull()) {
10441 break;
10442 }
10443 if (instance_filter == prototype) {
10444 obj = NULL; // Don't add this object.
10445 break;
10446 }
10447 V = prototype;
10448 }
10449 }
10450
10451 if (obj != NULL) {
10452 // Valid reference found add to instance array if supplied an update
10453 // count.
10454 if (instances != NULL && count < instances_size) {
10455 instances->set(count, obj);
10456 }
10457 last = obj;
10458 count++;
10459 }
10460 }
10461 }
10462 }
10463
10464 // Check for circular reference only. This can happen when the object is only
10465 // referenced from mirrors and has a circular reference in which case the
10466 // object is not really alive and would have been garbage collected if not
10467 // referenced from the mirror.
10468 if (count == 1 && last == target) {
10469 count = 0;
10470 }
10471
10472 // Return the number of referencing objects found.
10473 return count;
10474}
10475
10476
10477// Scan the heap for objects with direct references to an object
10478// args[0]: the object to find references to
10479// args[1]: constructor function for instances to exclude (Mirror)
10480// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010481static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010482 ASSERT(args.length() == 3);
10483
10484 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010485 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010486
10487 // Check parameters.
10488 CONVERT_CHECKED(JSObject, target, args[0]);
10489 Object* instance_filter = args[1];
10490 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10491 instance_filter->IsJSObject());
10492 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10493 RUNTIME_ASSERT(max_references >= 0);
10494
10495 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010496 JSObject* arguments_boilerplate =
10497 Top::context()->global_context()->arguments_boilerplate();
10498 JSFunction* arguments_function =
10499 JSFunction::cast(arguments_boilerplate->map()->constructor());
10500
10501 // Get the number of referencing objects.
10502 int count;
10503 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010504 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010505
10506 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010507 Object* object;
10508 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10509 if (!maybe_object->ToObject(&object)) return maybe_object;
10510 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010511 FixedArray* instances = FixedArray::cast(object);
10512
10513 // Fill the referencing objects.
10514 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010515 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010516
10517 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010518 Object* result;
10519 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10520 Top::context()->global_context()->array_function());
10521 if (!maybe_result->ToObject(&result)) return maybe_result;
10522 }
10523 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010524 return result;
10525}
10526
10527
10528// Helper function used by Runtime_DebugConstructedBy below.
10529static int DebugConstructedBy(JSFunction* constructor, int max_references,
10530 FixedArray* instances, int instances_size) {
10531 AssertNoAllocation no_alloc;
10532
10533 // Iterate the heap.
10534 int count = 0;
10535 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010536 HeapObject* heap_obj = NULL;
10537 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010538 (max_references == 0 || count < max_references)) {
10539 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010540 if (heap_obj->IsJSObject()) {
10541 JSObject* obj = JSObject::cast(heap_obj);
10542 if (obj->map()->constructor() == constructor) {
10543 // Valid reference found add to instance array if supplied an update
10544 // count.
10545 if (instances != NULL && count < instances_size) {
10546 instances->set(count, obj);
10547 }
10548 count++;
10549 }
10550 }
10551 }
10552
10553 // Return the number of referencing objects found.
10554 return count;
10555}
10556
10557
10558// Scan the heap for objects constructed by a specific function.
10559// args[0]: the constructor to find instances of
10560// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010561static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010562 ASSERT(args.length() == 2);
10563
10564 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010565 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010566
10567 // Check parameters.
10568 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10569 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10570 RUNTIME_ASSERT(max_references >= 0);
10571
10572 // Get the number of referencing objects.
10573 int count;
10574 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10575
10576 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010577 Object* object;
10578 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10579 if (!maybe_object->ToObject(&object)) return maybe_object;
10580 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010581 FixedArray* instances = FixedArray::cast(object);
10582
10583 // Fill the referencing objects.
10584 count = DebugConstructedBy(constructor, max_references, instances, count);
10585
10586 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010587 Object* result;
10588 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10589 Top::context()->global_context()->array_function());
10590 if (!maybe_result->ToObject(&result)) return maybe_result;
10591 }
10592 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010593 return result;
10594}
10595
10596
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010597// Find the effective prototype object as returned by __proto__.
10598// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010599static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010600 ASSERT(args.length() == 1);
10601
10602 CONVERT_CHECKED(JSObject, obj, args[0]);
10603
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010604 // Use the __proto__ accessor.
10605 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010606}
10607
10608
lrn@chromium.org303ada72010-10-27 09:33:13 +000010609static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010610 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010611 CPU::DebugBreak();
10612 return Heap::undefined_value();
10613}
10614
10615
lrn@chromium.org303ada72010-10-27 09:33:13 +000010616static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010617#ifdef DEBUG
10618 HandleScope scope;
10619 ASSERT(args.length() == 1);
10620 // Get the function and make sure it is compiled.
10621 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010622 Handle<SharedFunctionInfo> shared(func->shared());
10623 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010624 return Failure::Exception();
10625 }
10626 func->code()->PrintLn();
10627#endif // DEBUG
10628 return Heap::undefined_value();
10629}
ager@chromium.org9085a012009-05-11 19:22:57 +000010630
10631
lrn@chromium.org303ada72010-10-27 09:33:13 +000010632static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010633#ifdef DEBUG
10634 HandleScope scope;
10635 ASSERT(args.length() == 1);
10636 // Get the function and make sure it is compiled.
10637 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010638 Handle<SharedFunctionInfo> shared(func->shared());
10639 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010640 return Failure::Exception();
10641 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010642 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010643#endif // DEBUG
10644 return Heap::undefined_value();
10645}
10646
10647
lrn@chromium.org303ada72010-10-27 09:33:13 +000010648static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010649 NoHandleAllocation ha;
10650 ASSERT(args.length() == 1);
10651
10652 CONVERT_CHECKED(JSFunction, f, args[0]);
10653 return f->shared()->inferred_name();
10654}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010655
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010656
10657static int FindSharedFunctionInfosForScript(Script* script,
10658 FixedArray* buffer) {
10659 AssertNoAllocation no_allocations;
10660
10661 int counter = 0;
10662 int buffer_size = buffer->length();
10663 HeapIterator iterator;
10664 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10665 ASSERT(obj != NULL);
10666 if (!obj->IsSharedFunctionInfo()) {
10667 continue;
10668 }
10669 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10670 if (shared->script() != script) {
10671 continue;
10672 }
10673 if (counter < buffer_size) {
10674 buffer->set(counter, shared);
10675 }
10676 counter++;
10677 }
10678 return counter;
10679}
10680
10681// For a script finds all SharedFunctionInfo's in the heap that points
10682// to this script. Returns JSArray of SharedFunctionInfo wrapped
10683// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010684static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010685 Arguments args) {
10686 ASSERT(args.length() == 1);
10687 HandleScope scope;
10688 CONVERT_CHECKED(JSValue, script_value, args[0]);
10689
10690 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10691
10692 const int kBufferSize = 32;
10693
10694 Handle<FixedArray> array;
10695 array = Factory::NewFixedArray(kBufferSize);
10696 int number = FindSharedFunctionInfosForScript(*script, *array);
10697 if (number > kBufferSize) {
10698 array = Factory::NewFixedArray(number);
10699 FindSharedFunctionInfosForScript(*script, *array);
10700 }
10701
10702 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10703 result->set_length(Smi::FromInt(number));
10704
10705 LiveEdit::WrapSharedFunctionInfos(result);
10706
10707 return *result;
10708}
10709
10710// For a script calculates compilation information about all its functions.
10711// The script source is explicitly specified by the second argument.
10712// The source of the actual script is not used, however it is important that
10713// all generated code keeps references to this particular instance of script.
10714// Returns a JSArray of compilation infos. The array is ordered so that
10715// each function with all its descendant is always stored in a continues range
10716// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010717static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010718 ASSERT(args.length() == 2);
10719 HandleScope scope;
10720 CONVERT_CHECKED(JSValue, script, args[0]);
10721 CONVERT_ARG_CHECKED(String, source, 1);
10722 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10723
10724 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10725
10726 if (Top::has_pending_exception()) {
10727 return Failure::Exception();
10728 }
10729
10730 return result;
10731}
10732
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010733// Changes the source of the script to a new_source.
10734// If old_script_name is provided (i.e. is a String), also creates a copy of
10735// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010736static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010737 ASSERT(args.length() == 3);
10738 HandleScope scope;
10739 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10740 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010741 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010742
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010743 CONVERT_CHECKED(Script, original_script_pointer,
10744 original_script_value->value());
10745 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010746
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010747 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10748 new_source,
10749 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010750
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010751 if (old_script->IsScript()) {
10752 Handle<Script> script_handle(Script::cast(old_script));
10753 return *(GetScriptWrapper(script_handle));
10754 } else {
10755 return Heap::null_value();
10756 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010757}
10758
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010759
10760static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10761 ASSERT(args.length() == 1);
10762 HandleScope scope;
10763 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10764 return LiveEdit::FunctionSourceUpdated(shared_info);
10765}
10766
10767
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010768// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010769static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010770 ASSERT(args.length() == 2);
10771 HandleScope scope;
10772 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10773 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10774
ager@chromium.orgac091b72010-05-05 07:34:42 +000010775 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010776}
10777
10778// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010779static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010780 ASSERT(args.length() == 2);
10781 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010782 Handle<Object> function_object(args[0]);
10783 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010784
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010785 if (function_object->IsJSValue()) {
10786 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10787 if (script_object->IsJSValue()) {
10788 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10789 script_object = Handle<Object>(script);
10790 }
10791
10792 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10793 } else {
10794 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10795 // and we check it in this function.
10796 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010797
10798 return Heap::undefined_value();
10799}
10800
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010801
10802// In a code of a parent function replaces original function as embedded object
10803// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010804static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010805 ASSERT(args.length() == 3);
10806 HandleScope scope;
10807
10808 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10809 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10810 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10811
10812 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10813 subst_wrapper);
10814
10815 return Heap::undefined_value();
10816}
10817
10818
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010819// Updates positions of a shared function info (first parameter) according
10820// to script source change. Text change is described in second parameter as
10821// array of groups of 3 numbers:
10822// (change_begin, change_end, change_end_new_position).
10823// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010824static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010825 ASSERT(args.length() == 2);
10826 HandleScope scope;
10827 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10828 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10829
ager@chromium.orgac091b72010-05-05 07:34:42 +000010830 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010831}
10832
10833
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010834// For array of SharedFunctionInfo's (each wrapped in JSValue)
10835// checks that none of them have activations on stacks (of any thread).
10836// Returns array of the same length with corresponding results of
10837// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010838static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010839 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010840 HandleScope scope;
10841 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010842 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010843
ager@chromium.org357bf652010-04-12 11:30:10 +000010844 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010845}
10846
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010847// Compares 2 strings line-by-line, then token-wise and returns diff in form
10848// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10849// of diff chunks.
10850static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010851 ASSERT(args.length() == 2);
10852 HandleScope scope;
10853 CONVERT_ARG_CHECKED(String, s1, 0);
10854 CONVERT_ARG_CHECKED(String, s2, 1);
10855
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010856 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010857}
10858
10859
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010860
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010861// A testing entry. Returns statement position which is the closest to
10862// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010863static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010864 ASSERT(args.length() == 2);
10865 HandleScope scope;
10866 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10867 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10868
10869 Handle<Code> code(function->code());
10870
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010871 if (code->kind() != Code::FUNCTION &&
10872 code->kind() != Code::OPTIMIZED_FUNCTION) {
10873 return Heap::undefined_value();
10874 }
10875
10876 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010877 int closest_pc = 0;
10878 int distance = kMaxInt;
10879 while (!it.done()) {
10880 int statement_position = static_cast<int>(it.rinfo()->data());
10881 // Check if this break point is closer that what was previously found.
10882 if (source_position <= statement_position &&
10883 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010884 closest_pc =
10885 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010886 distance = statement_position - source_position;
10887 // Check whether we can't get any closer.
10888 if (distance == 0) break;
10889 }
10890 it.next();
10891 }
10892
10893 return Smi::FromInt(closest_pc);
10894}
10895
10896
ager@chromium.org357bf652010-04-12 11:30:10 +000010897// Calls specified function with or without entering the debugger.
10898// This is used in unit tests to run code as if debugger is entered or simply
10899// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010900static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010901 ASSERT(args.length() == 2);
10902 HandleScope scope;
10903 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10904 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10905
10906 Handle<Object> result;
10907 bool pending_exception;
10908 {
10909 if (without_debugger) {
10910 result = Execution::Call(function, Top::global(), 0, NULL,
10911 &pending_exception);
10912 } else {
10913 EnterDebugger enter_debugger;
10914 result = Execution::Call(function, Top::global(), 0, NULL,
10915 &pending_exception);
10916 }
10917 }
10918 if (!pending_exception) {
10919 return *result;
10920 } else {
10921 return Failure::Exception();
10922 }
10923}
10924
10925
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010926// Sets a v8 flag.
10927static MaybeObject* Runtime_SetFlags(Arguments args) {
10928 CONVERT_CHECKED(String, arg, args[0]);
10929 SmartPointer<char> flags =
10930 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10931 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10932 return Heap::undefined_value();
10933}
10934
10935
10936// Performs a GC.
10937// Presently, it only does a full GC.
10938static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10939 Heap::CollectAllGarbage(true);
10940 return Heap::undefined_value();
10941}
10942
10943
10944// Gets the current heap usage.
10945static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10946 int usage = static_cast<int>(Heap::SizeOfObjects());
10947 if (!Smi::IsValid(usage)) {
10948 return *Factory::NewNumberFromInt(usage);
10949 }
10950 return Smi::FromInt(usage);
10951}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010952
10953
10954// Captures a live object list from the present heap.
10955static MaybeObject* Runtime_HasLOLEnabled(Arguments args) {
10956#ifdef LIVE_OBJECT_LIST
10957 return Heap::true_value();
10958#else
10959 return Heap::false_value();
10960#endif
10961}
10962
10963
10964// Captures a live object list from the present heap.
10965static MaybeObject* Runtime_CaptureLOL(Arguments args) {
10966#ifdef LIVE_OBJECT_LIST
10967 return LiveObjectList::Capture();
10968#else
10969 return Heap::undefined_value();
10970#endif
10971}
10972
10973
10974// Deletes the specified live object list.
10975static MaybeObject* Runtime_DeleteLOL(Arguments args) {
10976#ifdef LIVE_OBJECT_LIST
10977 CONVERT_SMI_CHECKED(id, args[0]);
10978 bool success = LiveObjectList::Delete(id);
10979 return success ? Heap::true_value() : Heap::false_value();
10980#else
10981 return Heap::undefined_value();
10982#endif
10983}
10984
10985
10986// Generates the response to a debugger request for a dump of the objects
10987// contained in the difference between the captured live object lists
10988// specified by id1 and id2.
10989// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
10990// dumped.
10991static MaybeObject* Runtime_DumpLOL(Arguments args) {
10992#ifdef LIVE_OBJECT_LIST
10993 HandleScope scope;
10994 CONVERT_SMI_CHECKED(id1, args[0]);
10995 CONVERT_SMI_CHECKED(id2, args[1]);
10996 CONVERT_SMI_CHECKED(start, args[2]);
10997 CONVERT_SMI_CHECKED(count, args[3]);
10998 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
10999 EnterDebugger enter_debugger;
11000 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11001#else
11002 return Heap::undefined_value();
11003#endif
11004}
11005
11006
11007// Gets the specified object as requested by the debugger.
11008// This is only used for obj ids shown in live object lists.
11009static MaybeObject* Runtime_GetLOLObj(Arguments args) {
11010#ifdef LIVE_OBJECT_LIST
11011 CONVERT_SMI_CHECKED(obj_id, args[0]);
11012 Object* result = LiveObjectList::GetObj(obj_id);
11013 return result;
11014#else
11015 return Heap::undefined_value();
11016#endif
11017}
11018
11019
11020// Gets the obj id for the specified address if valid.
11021// This is only used for obj ids shown in live object lists.
11022static MaybeObject* Runtime_GetLOLObjId(Arguments args) {
11023#ifdef LIVE_OBJECT_LIST
11024 HandleScope scope;
11025 CONVERT_ARG_CHECKED(String, address, 0);
11026 Object* result = LiveObjectList::GetObjId(address);
11027 return result;
11028#else
11029 return Heap::undefined_value();
11030#endif
11031}
11032
11033
11034// Gets the retainers that references the specified object alive.
11035static MaybeObject* Runtime_GetLOLObjRetainers(Arguments args) {
11036#ifdef LIVE_OBJECT_LIST
11037 HandleScope scope;
11038 CONVERT_SMI_CHECKED(obj_id, args[0]);
11039 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11040 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11041 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11042 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11043 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11044
11045 Handle<JSObject> instance_filter;
11046 if (args[1]->IsJSObject()) {
11047 instance_filter = args.at<JSObject>(1);
11048 }
11049 bool verbose = false;
11050 if (args[2]->IsBoolean()) {
11051 verbose = args[2]->IsTrue();
11052 }
11053 int start = 0;
11054 if (args[3]->IsSmi()) {
11055 start = Smi::cast(args[3])->value();
11056 }
11057 int limit = Smi::kMaxValue;
11058 if (args[4]->IsSmi()) {
11059 limit = Smi::cast(args[4])->value();
11060 }
11061
11062 return LiveObjectList::GetObjRetainers(obj_id,
11063 instance_filter,
11064 verbose,
11065 start,
11066 limit,
11067 filter_obj);
11068#else
11069 return Heap::undefined_value();
11070#endif
11071}
11072
11073
11074// Gets the reference path between 2 objects.
11075static MaybeObject* Runtime_GetLOLPath(Arguments args) {
11076#ifdef LIVE_OBJECT_LIST
11077 HandleScope scope;
11078 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11079 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11080 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11081
11082 Handle<JSObject> instance_filter;
11083 if (args[2]->IsJSObject()) {
11084 instance_filter = args.at<JSObject>(2);
11085 }
11086
11087 Object* result =
11088 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11089 return result;
11090#else
11091 return Heap::undefined_value();
11092#endif
11093}
11094
11095
11096// Generates the response to a debugger request for a list of all
11097// previously captured live object lists.
11098static MaybeObject* Runtime_InfoLOL(Arguments args) {
11099#ifdef LIVE_OBJECT_LIST
11100 CONVERT_SMI_CHECKED(start, args[0]);
11101 CONVERT_SMI_CHECKED(count, args[1]);
11102 return LiveObjectList::Info(start, count);
11103#else
11104 return Heap::undefined_value();
11105#endif
11106}
11107
11108
11109// Gets a dump of the specified object as requested by the debugger.
11110// This is only used for obj ids shown in live object lists.
11111static MaybeObject* Runtime_PrintLOLObj(Arguments args) {
11112#ifdef LIVE_OBJECT_LIST
11113 HandleScope scope;
11114 CONVERT_SMI_CHECKED(obj_id, args[0]);
11115 Object* result = LiveObjectList::PrintObj(obj_id);
11116 return result;
11117#else
11118 return Heap::undefined_value();
11119#endif
11120}
11121
11122
11123// Resets and releases all previously captured live object lists.
11124static MaybeObject* Runtime_ResetLOL(Arguments args) {
11125#ifdef LIVE_OBJECT_LIST
11126 LiveObjectList::Reset();
11127 return Heap::undefined_value();
11128#else
11129 return Heap::undefined_value();
11130#endif
11131}
11132
11133
11134// Generates the response to a debugger request for a summary of the types
11135// of objects in the difference between the captured live object lists
11136// specified by id1 and id2.
11137// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11138// summarized.
11139static MaybeObject* Runtime_SummarizeLOL(Arguments args) {
11140#ifdef LIVE_OBJECT_LIST
11141 HandleScope scope;
11142 CONVERT_SMI_CHECKED(id1, args[0]);
11143 CONVERT_SMI_CHECKED(id2, args[1]);
11144 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11145
11146 EnterDebugger enter_debugger;
11147 return LiveObjectList::Summarize(id1, id2, filter_obj);
11148#else
11149 return Heap::undefined_value();
11150#endif
11151}
11152
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011153#endif // ENABLE_DEBUGGER_SUPPORT
11154
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011155
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011156#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000011157static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011158 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011159 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011160
11161 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011162 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11163 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011164 return Heap::undefined_value();
11165}
11166
11167
lrn@chromium.org303ada72010-10-27 09:33:13 +000011168static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011169 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011170 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011171
11172 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011173 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11174 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011175 return Heap::undefined_value();
11176}
11177
11178#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011179
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011180// Finds the script object from the script data. NOTE: This operation uses
11181// heap traversal to find the function generated for the source position
11182// for the requested break point. For lazily compiled functions several heap
11183// traversals might be required rendering this operation as a rather slow
11184// operation. However for setting break points which is normally done through
11185// some kind of user interaction the performance is not crucial.
11186static Handle<Object> Runtime_GetScriptFromScriptName(
11187 Handle<String> script_name) {
11188 // Scan the heap for Script objects to find the script with the requested
11189 // script data.
11190 Handle<Script> script;
11191 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011192 HeapObject* obj = NULL;
11193 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011194 // If a script is found check if it has the script data requested.
11195 if (obj->IsScript()) {
11196 if (Script::cast(obj)->name()->IsString()) {
11197 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11198 script = Handle<Script>(Script::cast(obj));
11199 }
11200 }
11201 }
11202 }
11203
11204 // If no script with the requested script data is found return undefined.
11205 if (script.is_null()) return Factory::undefined_value();
11206
11207 // Return the script found.
11208 return GetScriptWrapper(script);
11209}
11210
11211
11212// Get the script object from script data. NOTE: Regarding performance
11213// see the NOTE for GetScriptFromScriptData.
11214// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000011215static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011216 HandleScope scope;
11217
11218 ASSERT(args.length() == 1);
11219
11220 CONVERT_CHECKED(String, script_name, args[0]);
11221
11222 // Find the requested script.
11223 Handle<Object> result =
11224 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11225 return *result;
11226}
11227
11228
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011229// Determines whether the given stack frame should be displayed in
11230// a stack trace. The caller is the error constructor that asked
11231// for the stack trace to be collected. The first time a construct
11232// call to this function is encountered it is skipped. The seen_caller
11233// in/out parameter is used to remember if the caller has been seen
11234// yet.
11235static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11236 bool* seen_caller) {
11237 // Only display JS frames.
11238 if (!raw_frame->is_java_script())
11239 return false;
11240 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11241 Object* raw_fun = frame->function();
11242 // Not sure when this can happen but skip it just in case.
11243 if (!raw_fun->IsJSFunction())
11244 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011245 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011246 *seen_caller = true;
11247 return false;
11248 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011249 // Skip all frames until we've seen the caller. Also, skip the most
11250 // obvious builtin calls. Some builtin calls (such as Number.ADD
11251 // which is invoked using 'call') are very difficult to recognize
11252 // so we're leaving them in for now.
11253 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011254}
11255
11256
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011257// Collect the raw data for a stack trace. Returns an array of 4
11258// element segments each containing a receiver, function, code and
11259// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011260static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011261 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011262 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011263 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11264
11265 HandleScope scope;
11266
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011267 limit = Max(limit, 0); // Ensure that limit is not negative.
11268 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011269 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011270
11271 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011272 // If the caller parameter is a function we skip frames until we're
11273 // under it before starting to collect.
11274 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011275 int cursor = 0;
11276 int frames_seen = 0;
11277 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011278 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011279 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011280 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011281 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011282 List<FrameSummary> frames(3); // Max 2 levels of inlining.
11283 frame->Summarize(&frames);
11284 for (int i = frames.length() - 1; i >= 0; i--) {
11285 Handle<Object> recv = frames[i].receiver();
11286 Handle<JSFunction> fun = frames[i].function();
11287 Handle<Code> code = frames[i].code();
11288 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
11289 FixedArray* elements = FixedArray::cast(result->elements());
11290 if (cursor + 3 < elements->length()) {
11291 elements->set(cursor++, *recv);
11292 elements->set(cursor++, *fun);
11293 elements->set(cursor++, *code);
11294 elements->set(cursor++, *offset);
11295 } else {
11296 SetElement(result, cursor++, recv);
11297 SetElement(result, cursor++, fun);
11298 SetElement(result, cursor++, code);
11299 SetElement(result, cursor++, offset);
11300 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011301 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011302 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011303 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011304 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011305
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011306 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011307 return *result;
11308}
11309
11310
ager@chromium.org3811b432009-10-28 14:53:37 +000011311// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011312static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011313 ASSERT_EQ(args.length(), 0);
11314
11315 NoHandleAllocation ha;
11316
11317 const char* version_string = v8::V8::GetVersion();
11318
11319 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
11320}
11321
11322
lrn@chromium.org303ada72010-10-27 09:33:13 +000011323static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011324 ASSERT(args.length() == 2);
11325 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11326 Smi::cast(args[1])->value());
11327 Top::PrintStack();
11328 OS::Abort();
11329 UNREACHABLE();
11330 return NULL;
11331}
11332
11333
lrn@chromium.org303ada72010-10-27 09:33:13 +000011334static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011335 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011336 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011337 Object* key = args[1];
11338
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011339 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011340 Object* o = cache->get(finger_index);
11341 if (o == key) {
11342 // The fastest case: hit the same place again.
11343 return cache->get(finger_index + 1);
11344 }
11345
11346 for (int i = finger_index - 2;
11347 i >= JSFunctionResultCache::kEntriesIndex;
11348 i -= 2) {
11349 o = cache->get(i);
11350 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011351 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011352 return cache->get(i + 1);
11353 }
11354 }
11355
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011356 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011357 ASSERT(size <= cache->length());
11358
11359 for (int i = size - 2; i > finger_index; i -= 2) {
11360 o = cache->get(i);
11361 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011362 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011363 return cache->get(i + 1);
11364 }
11365 }
11366
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011367 // There is no value in the cache. Invoke the function and cache result.
11368 HandleScope scope;
11369
11370 Handle<JSFunctionResultCache> cache_handle(cache);
11371 Handle<Object> key_handle(key);
11372 Handle<Object> value;
11373 {
11374 Handle<JSFunction> factory(JSFunction::cast(
11375 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11376 // TODO(antonm): consider passing a receiver when constructing a cache.
11377 Handle<Object> receiver(Top::global_context()->global());
11378 // This handle is nor shared, nor used later, so it's safe.
11379 Object** argv[] = { key_handle.location() };
11380 bool pending_exception = false;
11381 value = Execution::Call(factory,
11382 receiver,
11383 1,
11384 argv,
11385 &pending_exception);
11386 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011387 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011388
11389#ifdef DEBUG
11390 cache_handle->JSFunctionResultCacheVerify();
11391#endif
11392
11393 // Function invocation may have cleared the cache. Reread all the data.
11394 finger_index = cache_handle->finger_index();
11395 size = cache_handle->size();
11396
11397 // If we have spare room, put new data into it, otherwise evict post finger
11398 // entry which is likely to be the least recently used.
11399 int index = -1;
11400 if (size < cache_handle->length()) {
11401 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11402 index = size;
11403 } else {
11404 index = finger_index + JSFunctionResultCache::kEntrySize;
11405 if (index == cache_handle->length()) {
11406 index = JSFunctionResultCache::kEntriesIndex;
11407 }
11408 }
11409
11410 ASSERT(index % 2 == 0);
11411 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11412 ASSERT(index < cache_handle->length());
11413
11414 cache_handle->set(index, *key_handle);
11415 cache_handle->set(index + 1, *value);
11416 cache_handle->set_finger_index(index);
11417
11418#ifdef DEBUG
11419 cache_handle->JSFunctionResultCacheVerify();
11420#endif
11421
11422 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011423}
11424
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011425
11426static MaybeObject* Runtime_NewMessageObject(Arguments args) {
11427 HandleScope scope;
11428 CONVERT_ARG_CHECKED(String, type, 0);
11429 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
11430 return *Factory::NewJSMessageObject(type,
11431 arguments,
11432 0,
11433 0,
11434 Factory::undefined_value(),
11435 Factory::undefined_value(),
11436 Factory::undefined_value());
11437}
11438
11439
11440static MaybeObject* Runtime_MessageGetType(Arguments args) {
11441 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11442 return message->type();
11443}
11444
11445
11446static MaybeObject* Runtime_MessageGetArguments(Arguments args) {
11447 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11448 return message->arguments();
11449}
11450
11451
11452static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) {
11453 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11454 return Smi::FromInt(message->start_position());
11455}
11456
11457
11458static MaybeObject* Runtime_MessageGetScript(Arguments args) {
11459 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11460 return message->script();
11461}
11462
11463
kasper.lund44510672008-07-25 07:37:58 +000011464#ifdef DEBUG
11465// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11466// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011467static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000011468 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011469 HandleScope scope;
11470 Handle<JSArray> result = Factory::NewJSArray(0);
11471 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011472 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011473#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011474 { \
11475 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011476 Handle<String> name; \
11477 /* Inline runtime functions have an underscore in front of the name. */ \
11478 if (inline_runtime_functions) { \
11479 name = Factory::NewStringFromAscii( \
11480 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11481 } else { \
11482 name = Factory::NewStringFromAscii( \
11483 Vector<const char>(#Name, StrLength(#Name))); \
11484 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011485 Handle<JSArray> pair = Factory::NewJSArray(0); \
11486 SetElement(pair, 0, name); \
11487 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
11488 SetElement(result, index++, pair); \
11489 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011490 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011491 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011492 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011493 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011494 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011495#undef ADD_ENTRY
11496 return *result;
11497}
kasper.lund44510672008-07-25 07:37:58 +000011498#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011499
11500
lrn@chromium.org303ada72010-10-27 09:33:13 +000011501static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011502 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011503 CONVERT_CHECKED(String, format, args[0]);
11504 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011505 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011506 Logger::LogRuntime(chars, elms);
11507 return Heap::undefined_value();
11508}
11509
11510
lrn@chromium.org303ada72010-10-27 09:33:13 +000011511static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011512 UNREACHABLE(); // implemented as macro in the parser
11513 return NULL;
11514}
11515
11516
11517// ----------------------------------------------------------------------------
11518// Implementation of Runtime
11519
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011520#define F(name, number_of_args, result_size) \
11521 { Runtime::k##name, Runtime::RUNTIME, #name, \
11522 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011523
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011524
11525#define I(name, number_of_args, result_size) \
11526 { Runtime::kInline##name, Runtime::INLINE, \
11527 "_" #name, NULL, number_of_args, result_size },
11528
11529Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011530 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011531 INLINE_FUNCTION_LIST(I)
11532 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011533};
11534
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011535
lrn@chromium.org303ada72010-10-27 09:33:13 +000011536MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011537 ASSERT(dictionary != NULL);
11538 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11539 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011540 Object* name_symbol;
11541 { MaybeObject* maybe_name_symbol =
11542 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
11543 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11544 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011545 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011546 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11547 String::cast(name_symbol),
11548 Smi::FromInt(i),
11549 PropertyDetails(NONE, NORMAL));
11550 if (!maybe_dictionary->ToObject(&dictionary)) {
11551 // Non-recoverable failure. Calling code must restart heap
11552 // initialization.
11553 return maybe_dictionary;
11554 }
11555 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011556 }
11557 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011558}
11559
11560
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011561Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11562 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
11563 if (entry != kNotFound) {
11564 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
11565 int function_index = Smi::cast(smi_index)->value();
11566 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011567 }
11568 return NULL;
11569}
11570
11571
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011572Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
11573 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11574}
11575
11576
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011577void Runtime::PerformGC(Object* result) {
11578 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011579 if (failure->IsRetryAfterGC()) {
11580 // Try to do a garbage collection; ignore it if it fails. The C
11581 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000011582 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011583 } else {
11584 // Handle last resort GC and make sure to allow future allocations
11585 // to grow the heap without causing GCs (if possible).
11586 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000011587 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011588 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011589}
11590
11591
11592} } // namespace v8::internal