blob: b32ae8a1b4b81a85c4d8e0d1737eea1b367d61b3 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000049#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000050#include "runtime.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"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000053#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000054#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000055#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000056#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
kasperl@chromium.org71affb52009-05-26 05:44:31 +000058namespace v8 {
59namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
61
ager@chromium.org3e875802009-06-29 08:26:34 +000062#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000063 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65// Cast the given object to a value of the specified type and store
66// it in a variable with the given name. If the object is not of the
67// expected type call IllegalOperation and return.
68#define CONVERT_CHECKED(Type, name, obj) \
69 RUNTIME_ASSERT(obj->Is##Type()); \
70 Type* name = Type::cast(obj);
71
72#define CONVERT_ARG_CHECKED(Type, name, index) \
73 RUNTIME_ASSERT(args[index]->Is##Type()); \
74 Handle<Type> name = args.at<Type>(index);
75
kasper.lundbd3ec4e2008-07-09 11:06:54 +000076// Cast the given object to a boolean and store it in a variable with
77// the given name. If the object is not a boolean call IllegalOperation
78// and return.
79#define CONVERT_BOOLEAN_CHECKED(name, obj) \
80 RUNTIME_ASSERT(obj->IsBoolean()); \
81 bool name = (obj)->IsTrue();
82
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000083// Cast the given object to a Smi and store its value in an int variable
84// with the given name. If the object is not a Smi call IllegalOperation
85// and return.
86#define CONVERT_SMI_CHECKED(name, obj) \
87 RUNTIME_ASSERT(obj->IsSmi()); \
88 int name = Smi::cast(obj)->value();
89
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090// Cast the given object to a double and store it in a variable with
91// the given name. If the object is not a number (as opposed to
92// the number not-a-number) call IllegalOperation and return.
93#define CONVERT_DOUBLE_CHECKED(name, obj) \
94 RUNTIME_ASSERT(obj->IsNumber()); \
95 double name = (obj)->Number();
96
97// Call the specified converter on the object *comand store the result in
98// a variable of the specified type with the given name. If the
99// object is not a Number call IllegalOperation and return.
100#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
101 RUNTIME_ASSERT(obj->IsNumber()); \
102 type name = NumberTo##Type(obj);
103
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
106 JSObject* boilerplate) {
107 StackLimitCheck check(isolate);
108 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000110 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000111 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000113 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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000125 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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 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 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000161 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000162 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.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000175 ASSERT(!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());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000179 if (elements->map() == heap->fixed_cow_array_map()) {
180 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000181#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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000191 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
192 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000193 if (!maybe_result->ToObject(&result)) return maybe_result;
194 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000195 elements->set(i, result);
196 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000197 }
198 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000199 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000200 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 case JSObject::DICTIONARY_ELEMENTS: {
202 NumberDictionary* element_dictionary = copy->element_dictionary();
203 int capacity = element_dictionary->Capacity();
204 for (int i = 0; i < capacity; i++) {
205 Object* k = element_dictionary->KeyAt(i);
206 if (element_dictionary->IsKey(k)) {
207 Object* value = element_dictionary->ValueAt(i);
208 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000209 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000210 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
211 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000212 if (!maybe_result->ToObject(&result)) return maybe_result;
213 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000214 element_dictionary->ValueAtPut(i, result);
215 }
216 }
217 }
218 break;
219 }
220 default:
221 UNREACHABLE();
222 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000223 }
224 return copy;
225}
226
227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000228RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000229 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000230 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000231}
232
233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000234RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000236 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237}
238
239
ager@chromium.org236ad962008-09-25 09:45:57 +0000240static Handle<Map> ComputeObjectLiteralMap(
241 Handle<Context> context,
242 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000243 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000245 int properties_length = constant_properties->length();
246 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000247 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000248 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000249 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000250 for (int p = 0; p != properties_length; p += 2) {
251 Object* key = constant_properties->get(p);
252 uint32_t element_index = 0;
253 if (key->IsSymbol()) {
254 number_of_symbol_keys++;
255 } else if (key->ToArrayIndex(&element_index)) {
256 // An index key does not require space in the property backing store.
257 number_of_properties--;
258 } else {
259 // Bail out as a non-symbol non-index key makes caching impossible.
260 // ASSERT to make sure that the if condition after the loop is false.
261 ASSERT(number_of_symbol_keys != number_of_properties);
262 break;
263 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 // If we only have symbols and array indices among keys then we can
266 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000268 if ((number_of_symbol_keys == number_of_properties) &&
269 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000270 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000271 Handle<FixedArray> keys =
272 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000273 if (number_of_symbol_keys > 0) {
274 int index = 0;
275 for (int p = 0; p < properties_length; p += 2) {
276 Object* key = constant_properties->get(p);
277 if (key->IsSymbol()) {
278 keys->set(index++, key);
279 }
280 }
281 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000282 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000284 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000285 }
286 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000287 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000288 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000289 Handle<Map>(context->object_function()->initial_map()),
290 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000291}
292
293
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000294static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000295 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000296 Handle<FixedArray> literals,
297 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000298
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000299
300static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000302 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000303 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 bool should_have_fast_elements,
305 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000306 // Get the global context from the literals array. This is the
307 // context in which the function was created and we use the object
308 // function from this context to create the object literal. We do
309 // not use the object function from the current global context
310 // because this might be the object function from another context
311 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000312 Handle<Context> context =
313 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 // In case we have function literals, we want the object to be in
316 // slow properties mode for now. We don't go in the map cache because
317 // maps with constant functions can't be shared if the functions are
318 // not the same (which is the common case).
319 bool is_result_from_cache = false;
320 Handle<Map> map = has_function_literal
321 ? Handle<Map>(context->object_function()->initial_map())
322 : ComputeObjectLiteralMap(context,
323 constant_properties,
324 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000326 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000327
328 // Normalize the elements of the boilerplate to save space if needed.
329 if (!should_have_fast_elements) NormalizeElements(boilerplate);
330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 // Add the constant properties to the boilerplate.
332 int length = constant_properties->length();
333 bool should_transform =
334 !is_result_from_cache && boilerplate->HasFastProperties();
335 if (should_transform || has_function_literal) {
336 // Normalize the properties of object to avoid n^2 behavior
337 // when extending the object multiple properties. Indicate the number of
338 // properties to be added.
339 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
340 }
341
342 for (int index = 0; index < length; index +=2) {
343 Handle<Object> key(constant_properties->get(index+0), isolate);
344 Handle<Object> value(constant_properties->get(index+1), isolate);
345 if (value->IsFixedArray()) {
346 // The value contains the constant_properties of a
347 // simple object or array literal.
348 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
349 value = CreateLiteralBoilerplate(isolate, literals, array);
350 if (value.is_null()) return value;
351 }
352 Handle<Object> result;
353 uint32_t element_index = 0;
354 if (key->IsSymbol()) {
355 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
356 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000357 result = SetOwnElement(boilerplate,
358 element_index,
359 value,
360 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 Handle<String> name(String::cast(*key));
363 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000364 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
365 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000366 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 } else if (key->ToArrayIndex(&element_index)) {
368 // Array index (uint32).
369 result = SetOwnElement(boilerplate,
370 element_index,
371 value,
372 kNonStrictMode);
373 } else {
374 // Non-uint32 number.
375 ASSERT(key->IsNumber());
376 double num = key->Number();
377 char arr[100];
378 Vector<char> buffer(arr, ARRAY_SIZE(arr));
379 const char* str = DoubleToCString(num, buffer);
380 Handle<String> name =
381 isolate->factory()->NewStringFromAscii(CStrVector(str));
382 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
383 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000385 // If setting the property on the boilerplate throws an
386 // exception, the exception is converted to an empty handle in
387 // the handle based operations. In that case, we need to
388 // convert back to an exception.
389 if (result.is_null()) return result;
390 }
391
392 // Transform to fast properties if necessary. For object literals with
393 // containing function literals we defer this operation until after all
394 // computed properties have been assigned so that we can generate
395 // constant function properties.
396 if (should_transform && !has_function_literal) {
397 TransformToFastProperties(boilerplate,
398 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 }
400
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000401 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000402}
403
404
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000405static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000407 Handle<FixedArray> literals,
408 Handle<FixedArray> elements) {
409 // Create the JSArray.
410 Handle<JSFunction> constructor(
411 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000412 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 const bool is_cow =
415 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000416 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000418
419 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000420 if (is_cow) {
421#ifdef DEBUG
422 // Copy-on-write arrays must be shallow (and simple).
423 for (int i = 0; i < content->length(); i++) {
424 ASSERT(!content->get(i)->IsFixedArray());
425 }
426#endif
427 } else {
428 for (int i = 0; i < content->length(); i++) {
429 if (content->get(i)->IsFixedArray()) {
430 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000432 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
433 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000434 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435 if (result.is_null()) return result;
436 content->set(i, *result);
437 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438 }
439 }
440
441 // Set the elements.
442 Handle<JSArray>::cast(object)->SetContent(*content);
443 return object;
444}
445
446
447static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000449 Handle<FixedArray> literals,
450 Handle<FixedArray> array) {
451 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000452 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000453 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000454 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000455 return CreateObjectLiteralBoilerplate(isolate,
456 literals,
457 elements,
458 true,
459 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000460 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000461 return CreateObjectLiteralBoilerplate(isolate,
462 literals,
463 elements,
464 false,
465 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000466 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000467 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 default:
469 UNREACHABLE();
470 return Handle<Object>::null();
471 }
472}
473
474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000475RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000476 // Takes a FixedArray of elements containing the literal elements of
477 // the array literal and produces JSArray with those elements.
478 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000479 // which contains the context from which to get the Array function
480 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000482 ASSERT(args.length() == 3);
483 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
484 CONVERT_SMI_CHECKED(literals_index, args[1]);
485 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000487 Handle<Object> object =
488 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000489 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000490
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000491 // Update the functions literal and return the boilerplate.
492 literals->set(literals_index, *object);
493 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494}
495
496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000497RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000498 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000499 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000500 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
501 CONVERT_SMI_CHECKED(literals_index, args[1]);
502 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000503 CONVERT_SMI_CHECKED(flags, args[3]);
504 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
505 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000506
507 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000508 Handle<Object> boilerplate(literals->get(literals_index), isolate);
509 if (*boilerplate == isolate->heap()->undefined_value()) {
510 boilerplate = CreateObjectLiteralBoilerplate(isolate,
511 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000512 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000513 should_have_fast_elements,
514 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000515 if (boilerplate.is_null()) return Failure::Exception();
516 // Update the functions literal and return the boilerplate.
517 literals->set(literals_index, *boilerplate);
518 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000520}
521
522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000523RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000525 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000526 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
527 CONVERT_SMI_CHECKED(literals_index, args[1]);
528 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000529 CONVERT_SMI_CHECKED(flags, args[3]);
530 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
531 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000532
533 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 Handle<Object> boilerplate(literals->get(literals_index), isolate);
535 if (*boilerplate == isolate->heap()->undefined_value()) {
536 boilerplate = CreateObjectLiteralBoilerplate(isolate,
537 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000538 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 should_have_fast_elements,
540 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000541 if (boilerplate.is_null()) return Failure::Exception();
542 // Update the functions literal and return the boilerplate.
543 literals->set(literals_index, *boilerplate);
544 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000546}
547
548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000549RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000550 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000551 ASSERT(args.length() == 3);
552 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
553 CONVERT_SMI_CHECKED(literals_index, args[1]);
554 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
555
556 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000557 Handle<Object> boilerplate(literals->get(literals_index), isolate);
558 if (*boilerplate == isolate->heap()->undefined_value()) {
559 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560 if (boilerplate.is_null()) return Failure::Exception();
561 // Update the functions literal and return the boilerplate.
562 literals->set(literals_index, *boilerplate);
563 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565}
566
567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000568RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000570 ASSERT(args.length() == 3);
571 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
572 CONVERT_SMI_CHECKED(literals_index, args[1]);
573 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
574
575 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000576 Handle<Object> boilerplate(literals->get(literals_index), isolate);
577 if (*boilerplate == isolate->heap()->undefined_value()) {
578 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579 if (boilerplate.is_null()) return Failure::Exception();
580 // Update the functions literal and return the boilerplate.
581 literals->set(literals_index, *boilerplate);
582 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000583 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000585 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000586 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588}
589
590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000591RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000592 ASSERT(args.length() == 2);
593 CONVERT_CHECKED(String, key, args[0]);
594 Object* value = args[1];
595 // Create a catch context extension object.
596 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 isolate->context()->global_context()->
598 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000599 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000601 if (!maybe_object->ToObject(&object)) return maybe_object;
602 }
ager@chromium.org32912102009-01-16 10:38:43 +0000603 // Assign the exception value to the catch variable and make sure
604 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000605 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000606 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
607 JSObject::cast(object)->SetProperty(
608 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000609 if (!maybe_value->ToObject(&value)) return maybe_value;
610 }
ager@chromium.org32912102009-01-16 10:38:43 +0000611 return object;
612}
613
614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000615RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616 NoHandleAllocation ha;
617 ASSERT(args.length() == 1);
618 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 return JSObject::cast(obj)->class_name();
621}
622
ager@chromium.org7c537e22008-10-16 08:43:32 +0000623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000624RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000625 NoHandleAllocation ha;
626 ASSERT(args.length() == 2);
627 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
628 Object* O = args[0];
629 Object* V = args[1];
630 while (true) {
631 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 if (prototype->IsNull()) return isolate->heap()->false_value();
633 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 V = prototype;
635 }
636}
637
638
ager@chromium.org9085a012009-05-11 19:22:57 +0000639// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000640RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000641 NoHandleAllocation ha;
642 ASSERT(args.length() == 2);
643 CONVERT_CHECKED(JSObject, jsobject, args[0]);
644 CONVERT_CHECKED(JSObject, proto, args[1]);
645
646 // Sanity checks. The old prototype (that we are replacing) could
647 // theoretically be null, but if it is not null then check that we
648 // didn't already install a hidden prototype here.
649 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
650 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
651 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
652
653 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000654 Object* map_or_failure;
655 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
656 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
657 return maybe_map_or_failure;
658 }
659 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000660 Map* new_proto_map = Map::cast(map_or_failure);
661
lrn@chromium.org303ada72010-10-27 09:33:13 +0000662 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
663 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
664 return maybe_map_or_failure;
665 }
666 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000667 Map* new_map = Map::cast(map_or_failure);
668
669 // Set proto's prototype to be the old prototype of the object.
670 new_proto_map->set_prototype(jsobject->GetPrototype());
671 proto->set_map(new_proto_map);
672 new_proto_map->set_is_hidden_prototype();
673
674 // Set the object's prototype to proto.
675 new_map->set_prototype(proto);
676 jsobject->set_map(new_map);
677
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000678 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000679}
680
681
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000682RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000683 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000684 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000685 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000686 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000687}
688
689
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000690// Recursively traverses hidden prototypes if property is not found
691static void GetOwnPropertyImplementation(JSObject* obj,
692 String* name,
693 LookupResult* result) {
694 obj->LocalLookupRealNamedProperty(name, result);
695
696 if (!result->IsProperty()) {
697 Object* proto = obj->GetPrototype();
698 if (proto->IsJSObject() &&
699 JSObject::cast(proto)->map()->is_hidden_prototype())
700 GetOwnPropertyImplementation(JSObject::cast(proto),
701 name, result);
702 }
703}
704
705
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000706static bool CheckAccessException(LookupResult* result,
707 v8::AccessType access_type) {
708 if (result->type() == CALLBACKS) {
709 Object* callback = result->GetCallbackObject();
710 if (callback->IsAccessorInfo()) {
711 AccessorInfo* info = AccessorInfo::cast(callback);
712 bool can_access =
713 (access_type == v8::ACCESS_HAS &&
714 (info->all_can_read() || info->all_can_write())) ||
715 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
716 (access_type == v8::ACCESS_SET && info->all_can_write());
717 return can_access;
718 }
719 }
720
721 return false;
722}
723
724
725static bool CheckAccess(JSObject* obj,
726 String* name,
727 LookupResult* result,
728 v8::AccessType access_type) {
729 ASSERT(result->IsProperty());
730
731 JSObject* holder = result->holder();
732 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000733 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000734 while (true) {
735 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000736 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000737 // Access check callback denied the access, but some properties
738 // can have a special permissions which override callbacks descision
739 // (currently see v8::AccessControl).
740 break;
741 }
742
743 if (current == holder) {
744 return true;
745 }
746
747 current = JSObject::cast(current->GetPrototype());
748 }
749
750 // API callbacks can have per callback access exceptions.
751 switch (result->type()) {
752 case CALLBACKS: {
753 if (CheckAccessException(result, access_type)) {
754 return true;
755 }
756 break;
757 }
758 case INTERCEPTOR: {
759 // If the object has an interceptor, try real named properties.
760 // Overwrite the result to fetch the correct property later.
761 holder->LookupRealNamedProperty(name, result);
762 if (result->IsProperty()) {
763 if (CheckAccessException(result, access_type)) {
764 return true;
765 }
766 }
767 break;
768 }
769 default:
770 break;
771 }
772
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000773 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000774 return false;
775}
776
777
778// TODO(1095): we should traverse hidden prototype hierachy as well.
779static bool CheckElementAccess(JSObject* obj,
780 uint32_t index,
781 v8::AccessType access_type) {
782 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000783 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000784 return false;
785 }
786
787 return true;
788}
789
790
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000791// Enumerator used as indices into the array returned from GetOwnProperty
792enum PropertyDescriptorIndices {
793 IS_ACCESSOR_INDEX,
794 VALUE_INDEX,
795 GETTER_INDEX,
796 SETTER_INDEX,
797 WRITABLE_INDEX,
798 ENUMERABLE_INDEX,
799 CONFIGURABLE_INDEX,
800 DESCRIPTOR_SIZE
801};
802
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000803// Returns an array with the property description:
804// if args[1] is not a property on args[0]
805// returns undefined
806// if args[1] is a data property on args[0]
807// [false, value, Writeable, Enumerable, Configurable]
808// if args[1] is an accessor on args[0]
809// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000810RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000811 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000812 Heap* heap = isolate->heap();
813 HandleScope scope(isolate);
814 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
815 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000816 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000817 CONVERT_ARG_CHECKED(JSObject, obj, 0);
818 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000819
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000820 // This could be an element.
821 uint32_t index;
822 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000823 switch (obj->HasLocalElement(index)) {
824 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000825 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000826
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000827 case JSObject::STRING_CHARACTER_ELEMENT: {
828 // Special handling of string objects according to ECMAScript 5
829 // 15.5.5.2. Note that this might be a string object with elements
830 // other than the actual string value. This is covered by the
831 // subsequent cases.
832 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
833 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000834 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000836 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000837 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000838 elms->set(WRITABLE_INDEX, heap->false_value());
839 elms->set(ENUMERABLE_INDEX, heap->false_value());
840 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000841 return *desc;
842 }
843
844 case JSObject::INTERCEPTED_ELEMENT:
845 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000846 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000847 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000848 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000849 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000850 elms->set(WRITABLE_INDEX, heap->true_value());
851 elms->set(ENUMERABLE_INDEX, heap->true_value());
852 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000853 return *desc;
854 }
855
856 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000857 Handle<JSObject> holder = obj;
858 if (obj->IsJSGlobalProxy()) {
859 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000860 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000861 ASSERT(proto->IsJSGlobalObject());
862 holder = Handle<JSObject>(JSObject::cast(proto));
863 }
864 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000865 int entry = dictionary->FindEntry(index);
866 ASSERT(entry != NumberDictionary::kNotFound);
867 PropertyDetails details = dictionary->DetailsAt(entry);
868 switch (details.type()) {
869 case CALLBACKS: {
870 // This is an accessor property with getter and/or setter.
871 FixedArray* callbacks =
872 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000874 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
875 elms->set(GETTER_INDEX, callbacks->get(0));
876 }
877 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
878 elms->set(SETTER_INDEX, callbacks->get(1));
879 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000880 break;
881 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000882 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000883 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000884 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000885 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000886 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000887 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000888 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000889 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000890 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000891 default:
892 UNREACHABLE();
893 break;
894 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
896 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000897 return *desc;
898 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000899 }
900 }
901
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000902 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000903 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000904
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000905 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000907 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000908
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000909 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000910 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000911 }
912
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
914 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000915
916 bool is_js_accessor = (result.type() == CALLBACKS) &&
917 (result.GetCallbackObject()->IsFixedArray());
918
919 if (is_js_accessor) {
920 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000921 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000922
923 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
924 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
925 elms->set(GETTER_INDEX, structure->get(0));
926 }
927 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
928 elms->set(SETTER_INDEX, structure->get(1));
929 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000930 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
932 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000933
934 PropertyAttributes attrs;
935 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000936 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000937 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
938 if (!maybe_value->ToObject(&value)) return maybe_value;
939 }
940 elms->set(VALUE_INDEX, value);
941 }
942
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000943 return *desc;
944}
945
946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000947RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000948 ASSERT(args.length() == 1);
949 CONVERT_CHECKED(JSObject, obj, args[0]);
950 return obj->PreventExtensions();
951}
952
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000954RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000955 ASSERT(args.length() == 1);
956 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000957 if (obj->IsJSGlobalProxy()) {
958 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000959 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000960 ASSERT(proto->IsJSGlobalObject());
961 obj = JSObject::cast(proto);
962 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000963 return obj->map()->is_extensible() ? isolate->heap()->true_value()
964 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000965}
966
967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000968RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000971 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
972 CONVERT_ARG_CHECKED(String, pattern, 1);
973 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000974 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
975 if (result.is_null()) return Failure::Exception();
976 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000977}
978
979
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000980RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000981 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000983 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985}
986
987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000988RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989 ASSERT(args.length() == 1);
990 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000991 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000992 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000993}
994
995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000996RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 ASSERT(args.length() == 2);
998 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001000 int index = field->value();
1001 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1002 InstanceType type = templ->map()->instance_type();
1003 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1004 type == OBJECT_TEMPLATE_INFO_TYPE);
1005 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001006 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001007 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1008 } else {
1009 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1010 }
1011 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012}
1013
1014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001015RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001016 ASSERT(args.length() == 1);
1017 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001018 Map* old_map = object->map();
1019 bool needs_access_checks = old_map->is_access_check_needed();
1020 if (needs_access_checks) {
1021 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001022 Object* new_map;
1023 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1024 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1025 }
ager@chromium.org32912102009-01-16 10:38:43 +00001026
1027 Map::cast(new_map)->set_is_access_check_needed(false);
1028 object->set_map(Map::cast(new_map));
1029 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001030 return needs_access_checks ? isolate->heap()->true_value()
1031 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001032}
1033
1034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001035RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001036 ASSERT(args.length() == 1);
1037 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001038 Map* old_map = object->map();
1039 if (!old_map->is_access_check_needed()) {
1040 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001041 Object* new_map;
1042 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1043 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1044 }
ager@chromium.org32912102009-01-16 10:38:43 +00001045
1046 Map::cast(new_map)->set_is_access_check_needed(true);
1047 object->set_map(Map::cast(new_map));
1048 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001049 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001050}
1051
1052
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001053static Failure* ThrowRedeclarationError(Isolate* isolate,
1054 const char* type,
1055 Handle<String> name) {
1056 HandleScope scope(isolate);
1057 Handle<Object> type_handle =
1058 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059 Handle<Object> args[2] = { type_handle, name };
1060 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001061 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1062 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063}
1064
1065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001066RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001067 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068 HandleScope scope(isolate);
1069 Handle<GlobalObject> global = Handle<GlobalObject>(
1070 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071
ager@chromium.org3811b432009-10-28 14:53:37 +00001072 Handle<Context> context = args.at<Context>(0);
1073 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 StrictModeFlag strict_mode =
1076 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1077 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078
1079 // Compute the property attributes. According to ECMA-262, section
1080 // 13, page 71, the property must be read-only and
1081 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1082 // property as read-only, so we don't either.
1083 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1084
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085 // Traverse the name/value pairs and set the properties.
1086 int length = pairs->length();
1087 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001089 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001090 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091
1092 // We have to declare a global const property. To capture we only
1093 // assign to it when evaluating the assignment for "const x =
1094 // <expr>" the initial value is the hole.
1095 bool is_const_property = value->IsTheHole();
1096
1097 if (value->IsUndefined() || is_const_property) {
1098 // Lookup the property in the global object, and don't set the
1099 // value of the variable if the property is already there.
1100 LookupResult lookup;
1101 global->Lookup(*name, &lookup);
1102 if (lookup.IsProperty()) {
1103 // Determine if the property is local by comparing the holder
1104 // against the global object. The information will be used to
1105 // avoid throwing re-declaration errors when declaring
1106 // variables or constants that exist in the prototype chain.
1107 bool is_local = (*global == lookup.holder());
1108 // Get the property attributes and determine if the property is
1109 // read-only.
1110 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1111 bool is_read_only = (attributes & READ_ONLY) != 0;
1112 if (lookup.type() == INTERCEPTOR) {
1113 // If the interceptor says the property is there, we
1114 // just return undefined without overwriting the property.
1115 // Otherwise, we continue to setting the property.
1116 if (attributes != ABSENT) {
1117 // Check if the existing property conflicts with regards to const.
1118 if (is_local && (is_read_only || is_const_property)) {
1119 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001120 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001121 };
1122 // The property already exists without conflicting: Go to
1123 // the next declaration.
1124 continue;
1125 }
1126 // Fall-through and introduce the absent property by using
1127 // SetProperty.
1128 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001129 // For const properties, we treat a callback with this name
1130 // even in the prototype as a conflicting declaration.
1131 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001132 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001133 }
1134 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135 if (is_local && (is_read_only || is_const_property)) {
1136 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001137 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138 }
1139 // The property already exists without conflicting: Go to
1140 // the next declaration.
1141 continue;
1142 }
1143 }
1144 } else {
1145 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001146 Handle<SharedFunctionInfo> shared =
1147 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001149 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1150 context,
1151 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001152 value = function;
1153 }
1154
1155 LookupResult lookup;
1156 global->LocalLookup(*name, &lookup);
1157
1158 PropertyAttributes attributes = is_const_property
1159 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1160 : base;
1161
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001162 // There's a local property that we need to overwrite because
1163 // we're either declaring a function or there's an interceptor
1164 // that claims the property is absent.
1165 //
1166 // Check for conflicting re-declarations. We cannot have
1167 // conflicting types in case of intercepted properties because
1168 // they are absent.
1169 if (lookup.IsProperty() &&
1170 (lookup.type() != INTERCEPTOR) &&
1171 (lookup.IsReadOnly() || is_const_property)) {
1172 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001173 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001174 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001176 // Safari does not allow the invocation of callback setters for
1177 // function declarations. To mimic this behavior, we do not allow
1178 // the invocation of setters for function values. This makes a
1179 // difference for global functions with the same names as event
1180 // handlers such as "function onload() {}". Firefox does call the
1181 // onload setter in those case and Safari does not. We follow
1182 // Safari for compatibility.
1183 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001184 // Do not change DONT_DELETE to false from true.
1185 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1186 attributes = static_cast<PropertyAttributes>(
1187 attributes | (lookup.GetAttributes() & DONT_DELETE));
1188 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 RETURN_IF_EMPTY_HANDLE(isolate,
1190 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001191 name,
1192 value,
1193 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001194 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001195 RETURN_IF_EMPTY_HANDLE(isolate,
1196 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001197 name,
1198 value,
1199 attributes,
1200 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201 }
1202 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001204 ASSERT(!isolate->has_pending_exception());
1205 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206}
1207
1208
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001209RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001210 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001211 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212
ager@chromium.org7c537e22008-10-16 08:43:32 +00001213 CONVERT_ARG_CHECKED(Context, context, 0);
1214 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001216 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001217 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001218 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219
1220 // Declarations are always done in the function context.
1221 context = Handle<Context>(context->fcontext());
1222
1223 int index;
1224 PropertyAttributes attributes;
1225 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001226 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227 context->Lookup(name, flags, &index, &attributes);
1228
1229 if (attributes != ABSENT) {
1230 // The name was declared before; check for conflicting
1231 // re-declarations: This is similar to the code in parser.cc in
1232 // the AstBuildingParser::Declare function.
1233 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1234 // Functions are not read-only.
1235 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1236 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001237 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001238 }
1239
1240 // Initialize it if necessary.
1241 if (*initial_value != NULL) {
1242 if (index >= 0) {
1243 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001244 // the function context or the arguments object.
1245 if (holder->IsContext()) {
1246 ASSERT(holder.is_identical_to(context));
1247 if (((attributes & READ_ONLY) == 0) ||
1248 context->get(index)->IsTheHole()) {
1249 context->set(index, *initial_value);
1250 }
1251 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001252 // The holder is an arguments object.
1253 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001254 Handle<Object> result = SetElement(arguments, index, initial_value,
1255 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001256 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 }
1258 } else {
1259 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001260 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001261 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001262 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001263 SetProperty(context_ext, name, initial_value,
1264 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 }
1266 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001269 // The property is not in the function context. It needs to be
1270 // "declared" in the function context's extension context, or in the
1271 // global context.
1272 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001273 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001274 // The function context's extension context exists - use it.
1275 context_ext = Handle<JSObject>(context->extension());
1276 } else {
1277 // The function context's extension context does not exists - allocate
1278 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001279 context_ext = isolate->factory()->NewJSObject(
1280 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001281 // And store it in the extension slot.
1282 context->set_extension(*context_ext);
1283 }
1284 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285
ager@chromium.org7c537e22008-10-16 08:43:32 +00001286 // Declare the property by setting it to the initial value if provided,
1287 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1288 // constant declarations).
1289 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001290 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001291 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001292 // Declaring a const context slot is a conflicting declaration if
1293 // there is a callback with that name in a prototype. It is
1294 // allowed to introduce const variables in
1295 // JSContextExtensionObjects. They are treated specially in
1296 // SetProperty and no setters are invoked for those since they are
1297 // not real JSObjects.
1298 if (initial_value->IsTheHole() &&
1299 !context_ext->IsJSContextExtensionObject()) {
1300 LookupResult lookup;
1301 context_ext->Lookup(*name, &lookup);
1302 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001303 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001304 }
1305 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001306 RETURN_IF_EMPTY_HANDLE(isolate,
1307 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001308 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001309 }
1310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001311 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312}
1313
1314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001315RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001317 // args[0] == name
1318 // args[1] == strict_mode
1319 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320
1321 // Determine if we need to assign to the variable if it already
1322 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001323 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1324 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325
1326 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001327 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001328 RUNTIME_ASSERT(args[1]->IsSmi());
1329 StrictModeFlag strict_mode =
1330 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1331 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332
1333 // According to ECMA-262, section 12.2, page 62, the property must
1334 // not be deletable.
1335 PropertyAttributes attributes = DONT_DELETE;
1336
1337 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001338 // there, there is a property with this name in the prototype chain.
1339 // We follow Safari and Firefox behavior and only set the property
1340 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001341 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001342 // Note that objects can have hidden prototypes, so we need to traverse
1343 // the whole chain of hidden prototypes to do a 'local' lookup.
1344 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001346 while (true) {
1347 real_holder->LocalLookup(*name, &lookup);
1348 if (lookup.IsProperty()) {
1349 // Determine if this is a redeclaration of something read-only.
1350 if (lookup.IsReadOnly()) {
1351 // If we found readonly property on one of hidden prototypes,
1352 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001353 if (real_holder != isolate->context()->global()) break;
1354 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001355 }
1356
1357 // Determine if this is a redeclaration of an intercepted read-only
1358 // property and figure out if the property exists at all.
1359 bool found = true;
1360 PropertyType type = lookup.type();
1361 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001362 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001363 Handle<JSObject> holder(real_holder);
1364 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1365 real_holder = *holder;
1366 if (intercepted == ABSENT) {
1367 // The interceptor claims the property isn't there. We need to
1368 // make sure to introduce it.
1369 found = false;
1370 } else if ((intercepted & READ_ONLY) != 0) {
1371 // The property is present, but read-only. Since we're trying to
1372 // overwrite it with a variable declaration we must throw a
1373 // re-declaration error. However if we found readonly property
1374 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001375 if (real_holder != isolate->context()->global()) break;
1376 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001377 }
1378 }
1379
1380 if (found && !assign) {
1381 // The global property is there and we're not assigning any value
1382 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001383 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001384 }
1385
1386 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001387 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001388 return real_holder->SetProperty(
1389 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001390 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001391
1392 Object* proto = real_holder->GetPrototype();
1393 if (!proto->IsJSObject())
1394 break;
1395
1396 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1397 break;
1398
1399 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400 }
1401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001403 if (assign) {
1404 return global->SetProperty(*name, args[2], attributes, strict_mode);
1405 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001406 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407}
1408
1409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001410RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411 // All constants are declared with an initial value. The name
1412 // of the constant is the first argument and the initial value
1413 // is the second.
1414 RUNTIME_ASSERT(args.length() == 2);
1415 CONVERT_ARG_CHECKED(String, name, 0);
1416 Handle<Object> value = args.at<Object>(1);
1417
1418 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001419 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420
1421 // According to ECMA-262, section 12.2, page 62, the property must
1422 // not be deletable. Since it's a const, it must be READ_ONLY too.
1423 PropertyAttributes attributes =
1424 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1425
1426 // Lookup the property locally in the global object. If it isn't
1427 // there, we add the property and take special precautions to always
1428 // add it as a local property even in case of callbacks in the
1429 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001430 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431 LookupResult lookup;
1432 global->LocalLookup(*name, &lookup);
1433 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001434 return global->SetLocalPropertyIgnoreAttributes(*name,
1435 *value,
1436 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001437 }
1438
1439 // Determine if this is a redeclaration of something not
1440 // read-only. In case the result is hidden behind an interceptor we
1441 // need to ask it for the property attributes.
1442 if (!lookup.IsReadOnly()) {
1443 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001444 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445 }
1446
1447 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1448
1449 // Throw re-declaration error if the intercepted property is present
1450 // but not read-only.
1451 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001452 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001453 }
1454
1455 // Restore global object from context (in case of GC) and continue
1456 // with setting the value because the property is either absent or
1457 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458 HandleScope handle_scope(isolate);
1459 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001461 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001462 // property through an interceptor and only do it if it's
1463 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001464 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 RETURN_IF_EMPTY_HANDLE(isolate,
1466 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001467 name,
1468 value,
1469 attributes,
1470 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 return *value;
1472 }
1473
1474 // Set the value, but only we're assigning the initial value to a
1475 // constant. For now, we determine this by checking if the
1476 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001477 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001478 PropertyType type = lookup.type();
1479 if (type == FIELD) {
1480 FixedArray* properties = global->properties();
1481 int index = lookup.GetFieldIndex();
1482 if (properties->get(index)->IsTheHole()) {
1483 properties->set(index, *value);
1484 }
1485 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001486 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1487 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001488 }
1489 } else {
1490 // Ignore re-initialization of constants that have already been
1491 // assigned a function value.
1492 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1493 }
1494
1495 // Use the set value as the result of the operation.
1496 return *value;
1497}
1498
1499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001500RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001501 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 ASSERT(args.length() == 3);
1503
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001504 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001505 ASSERT(!value->IsTheHole());
1506 CONVERT_ARG_CHECKED(Context, context, 1);
1507 Handle<String> name(String::cast(args[2]));
1508
1509 // Initializations are always done in the function context.
1510 context = Handle<Context>(context->fcontext());
1511
1512 int index;
1513 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001514 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001515 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001516 context->Lookup(name, flags, &index, &attributes);
1517
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001518 // In most situations, the property introduced by the const
1519 // declaration should be present in the context extension object.
1520 // However, because declaration and initialization are separate, the
1521 // property might have been deleted (if it was introduced by eval)
1522 // before we reach the initialization point.
1523 //
1524 // Example:
1525 //
1526 // function f() { eval("delete x; const x;"); }
1527 //
1528 // In that case, the initialization behaves like a normal assignment
1529 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001530 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001531 // Property was found in a context.
1532 if (holder->IsContext()) {
1533 // The holder cannot be the function context. If it is, there
1534 // should have been a const redeclaration error when declaring
1535 // the const property.
1536 ASSERT(!holder.is_identical_to(context));
1537 if ((attributes & READ_ONLY) == 0) {
1538 Handle<Context>::cast(holder)->set(index, *value);
1539 }
1540 } else {
1541 // The holder is an arguments object.
1542 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001543 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001544 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001545 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001546 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547 }
1548 return *value;
1549 }
1550
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001551 // The property could not be found, we introduce it in the global
1552 // context.
1553 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001554 Handle<JSObject> global = Handle<JSObject>(
1555 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001556 // Strict mode not needed (const disallowed in strict mode).
1557 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001558 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001559 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001560 return *value;
1561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001563 // The property was present in a context extension object.
1564 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001566 if (*context_ext == context->extension()) {
1567 // This is the property that was introduced by the const
1568 // declaration. Set it if it hasn't been set before. NOTE: We
1569 // cannot use GetProperty() to get the current value as it
1570 // 'unholes' the value.
1571 LookupResult lookup;
1572 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1573 ASSERT(lookup.IsProperty()); // the property was declared
1574 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1575
1576 PropertyType type = lookup.type();
1577 if (type == FIELD) {
1578 FixedArray* properties = context_ext->properties();
1579 int index = lookup.GetFieldIndex();
1580 if (properties->get(index)->IsTheHole()) {
1581 properties->set(index, *value);
1582 }
1583 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001584 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1585 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001586 }
1587 } else {
1588 // We should not reach here. Any real, named property should be
1589 // either a field or a dictionary slot.
1590 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591 }
1592 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001593 // The property was found in a different context extension object.
1594 // Set it if it is not a read-only property.
1595 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001596 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001597 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001598 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001599 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001602
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 return *value;
1604}
1605
1606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001607RUNTIME_FUNCTION(MaybeObject*,
1608 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001609 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001610 ASSERT(args.length() == 2);
1611 CONVERT_ARG_CHECKED(JSObject, object, 0);
1612 CONVERT_SMI_CHECKED(properties, args[1]);
1613 if (object->HasFastProperties()) {
1614 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1615 }
1616 return *object;
1617}
1618
1619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001620RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001621 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001622 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001623 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1624 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001625 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001626 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001627 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001628 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001629 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001630 RUNTIME_ASSERT(index >= 0);
1631 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001632 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001633 Handle<Object> result = RegExpImpl::Exec(regexp,
1634 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001635 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001636 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001637 if (result.is_null()) return Failure::Exception();
1638 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639}
1640
1641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001642RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001643 ASSERT(args.length() == 3);
1644 CONVERT_SMI_CHECKED(elements_count, args[0]);
1645 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001646 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001647 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001648 Object* new_object;
1649 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001650 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001651 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1652 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001653 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001654 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1655 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001656 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1657 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001658 {
1659 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001660 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001661 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001662 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001663 }
1664 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001665 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001666 array->set_elements(elements);
1667 array->set_length(Smi::FromInt(elements_count));
1668 // Write in-object properties after the length of the array.
1669 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1670 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1671 return array;
1672}
1673
1674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001675RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001676 AssertNoAllocation no_alloc;
1677 ASSERT(args.length() == 5);
1678 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1679 CONVERT_CHECKED(String, source, args[1]);
1680
1681 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001682 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001683
1684 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001685 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001686
1687 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001689
1690 Map* map = regexp->map();
1691 Object* constructor = map->constructor();
1692 if (constructor->IsJSFunction() &&
1693 JSFunction::cast(constructor)->initial_map() == map) {
1694 // If we still have the original map, set in-object properties directly.
1695 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1696 // TODO(lrn): Consider skipping write barrier on booleans as well.
1697 // Both true and false should be in oldspace at all times.
1698 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1699 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1700 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1701 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1702 Smi::FromInt(0),
1703 SKIP_WRITE_BARRIER);
1704 return regexp;
1705 }
1706
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001707 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001708 PropertyAttributes final =
1709 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1710 PropertyAttributes writable =
1711 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001712 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001713 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001714 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001715 source,
1716 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001717 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001718 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001719 global,
1720 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001721 ASSERT(!result->IsFailure());
1722 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001723 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001724 ignoreCase,
1725 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001726 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001728 multiline,
1729 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730 ASSERT(!result->IsFailure());
1731 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001732 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001733 Smi::FromInt(0),
1734 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001735 ASSERT(!result->IsFailure());
1736 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001737 return regexp;
1738}
1739
1740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001741RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001742 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001743 ASSERT(args.length() == 1);
1744 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1745 // This is necessary to enable fast checks for absence of elements
1746 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001748 return Smi::FromInt(0);
1749}
1750
1751
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001752static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1753 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001754 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001755 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1757 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1758 Handle<JSFunction> optimized =
1759 isolate->factory()->NewFunction(key,
1760 JS_OBJECT_TYPE,
1761 JSObject::kHeaderSize,
1762 code,
1763 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001764 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001765 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001766 return optimized;
1767}
1768
1769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001770RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001771 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001772 ASSERT(args.length() == 1);
1773 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1774
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001775 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1776 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1777 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1778 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1779 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1780 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1781 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001782
1783 return *holder;
1784}
1785
1786
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001787RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001788 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 Context* global_context =
1790 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001791 return global_context->global()->global_receiver();
1792}
1793
1794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001795RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001796 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797 ASSERT(args.length() == 4);
1798 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1799 int index = Smi::cast(args[1])->value();
1800 Handle<String> pattern = args.at<String>(2);
1801 Handle<String> flags = args.at<String>(3);
1802
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001803 // Get the RegExp function from the context in the literals array.
1804 // This is the RegExp function from the context in which the
1805 // function was created. We do not use the RegExp function from the
1806 // current global context because this might be the RegExp function
1807 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001808 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001809 Handle<JSFunction>(
1810 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001811 // Compute the regular expression literal.
1812 bool has_pending_exception;
1813 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001814 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1815 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001818 return Failure::Exception();
1819 }
1820 literals->set(index, *regexp);
1821 return *regexp;
1822}
1823
1824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001825RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001826 NoHandleAllocation ha;
1827 ASSERT(args.length() == 1);
1828
1829 CONVERT_CHECKED(JSFunction, f, args[0]);
1830 return f->shared()->name();
1831}
1832
1833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001834RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001835 NoHandleAllocation ha;
1836 ASSERT(args.length() == 2);
1837
1838 CONVERT_CHECKED(JSFunction, f, args[0]);
1839 CONVERT_CHECKED(String, name, args[1]);
1840 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001841 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001842}
1843
1844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001845RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001846 NoHandleAllocation ha;
1847 ASSERT(args.length() == 1);
1848
1849 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001850 Object* obj = f->RemovePrototype();
1851 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001853 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001854}
1855
1856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001857RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001858 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001859 ASSERT(args.length() == 1);
1860
1861 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1863 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001864
1865 return *GetScriptWrapper(Handle<Script>::cast(script));
1866}
1867
1868
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001869RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001870 NoHandleAllocation ha;
1871 ASSERT(args.length() == 1);
1872
1873 CONVERT_CHECKED(JSFunction, f, args[0]);
1874 return f->shared()->GetSourceCode();
1875}
1876
1877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001878RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001879 NoHandleAllocation ha;
1880 ASSERT(args.length() == 1);
1881
1882 CONVERT_CHECKED(JSFunction, fun, args[0]);
1883 int pos = fun->shared()->start_position();
1884 return Smi::FromInt(pos);
1885}
1886
1887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001888RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001889 ASSERT(args.length() == 2);
1890
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001891 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001892 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1893
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001894 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1895
1896 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001897 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001898}
1899
1900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001901RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001902 NoHandleAllocation ha;
1903 ASSERT(args.length() == 2);
1904
1905 CONVERT_CHECKED(JSFunction, fun, args[0]);
1906 CONVERT_CHECKED(String, name, args[1]);
1907 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001908 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001909}
1910
1911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001912RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001913 NoHandleAllocation ha;
1914 ASSERT(args.length() == 2);
1915
1916 CONVERT_CHECKED(JSFunction, fun, args[0]);
1917 CONVERT_CHECKED(Smi, length, args[1]);
1918 fun->shared()->set_length(length->value());
1919 return length;
1920}
1921
1922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001923RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001924 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 ASSERT(args.length() == 2);
1926
1927 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001928 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001929 Object* obj;
1930 { MaybeObject* maybe_obj =
1931 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1932 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1933 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934 return args[0]; // return TOS
1935}
1936
1937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001938RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001939 NoHandleAllocation ha;
1940 ASSERT(args.length() == 1);
1941
1942 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001943 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1944 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001945}
1946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951
1952 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001953 return f->IsBuiltin() ? isolate->heap()->true_value() :
1954 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001955}
1956
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001957
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001958RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001959 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960 ASSERT(args.length() == 2);
1961
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001962 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001963 Handle<Object> code = args.at<Object>(1);
1964
1965 Handle<Context> context(target->context());
1966
1967 if (!code->IsNull()) {
1968 RUNTIME_ASSERT(code->IsJSFunction());
1969 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001970 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001971
1972 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001973 return Failure::Exception();
1974 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001975 // Since we don't store the source for this we should never
1976 // optimize this.
1977 shared->code()->set_optimizable(false);
1978
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001979 // Set the code, scope info, formal parameter count,
1980 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001981 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001982 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001983 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001984 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001986 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001987 // Set the source code of the target function to undefined.
1988 // SetCode is only used for built-in constructors like String,
1989 // Array, and Object, and some web code
1990 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001991 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001992 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001993 // Clear the optimization hints related to the compiled code as these are no
1994 // longer valid when the code is overwritten.
1995 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001996 context = Handle<Context>(fun->context());
1997
1998 // Make sure we get a fresh copy of the literal vector to avoid
1999 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002000 int number_of_literals = fun->NumberOfLiterals();
2001 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002002 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002003 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002004 // Insert the object, regexp and array functions in the literals
2005 // array prefix. These are the functions that will be used when
2006 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002007 literals->set(JSFunction::kLiteralGlobalContextIndex,
2008 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002010 // It's okay to skip the write barrier here because the literals
2011 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002012 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002013 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014 }
2015
2016 target->set_context(*context);
2017 return *target;
2018}
2019
2020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002021RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002022 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002023 ASSERT(args.length() == 2);
2024 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2025 CONVERT_SMI_CHECKED(num, args[1]);
2026 RUNTIME_ASSERT(num >= 0);
2027 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002028 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002029}
2030
2031
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002032MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2033 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002034 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002035 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002036 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002037 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002038 }
2039 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002040 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002041}
2042
2043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002044RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002045 NoHandleAllocation ha;
2046 ASSERT(args.length() == 2);
2047
2048 CONVERT_CHECKED(String, subject, args[0]);
2049 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002050 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002052 uint32_t i = 0;
2053 if (index->IsSmi()) {
2054 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002055 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002056 i = value;
2057 } else {
2058 ASSERT(index->IsHeapNumber());
2059 double value = HeapNumber::cast(index)->value();
2060 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002061 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002062
2063 // Flatten the string. If someone wants to get a char at an index
2064 // in a cons string, it is likely that more indices will be
2065 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002066 Object* flat;
2067 { MaybeObject* maybe_flat = subject->TryFlatten();
2068 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2069 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002070 subject = String::cast(flat);
2071
2072 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002073 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002074 }
2075
2076 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002077}
2078
2079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002080RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002081 NoHandleAllocation ha;
2082 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002083 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002084}
2085
lrn@chromium.org25156de2010-04-06 13:10:27 +00002086
2087class FixedArrayBuilder {
2088 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002089 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2090 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002091 length_(0) {
2092 // Require a non-zero initial size. Ensures that doubling the size to
2093 // extend the array will work.
2094 ASSERT(initial_capacity > 0);
2095 }
2096
2097 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2098 : array_(backing_store),
2099 length_(0) {
2100 // Require a non-zero initial size. Ensures that doubling the size to
2101 // extend the array will work.
2102 ASSERT(backing_store->length() > 0);
2103 }
2104
2105 bool HasCapacity(int elements) {
2106 int length = array_->length();
2107 int required_length = length_ + elements;
2108 return (length >= required_length);
2109 }
2110
2111 void EnsureCapacity(int elements) {
2112 int length = array_->length();
2113 int required_length = length_ + elements;
2114 if (length < required_length) {
2115 int new_length = length;
2116 do {
2117 new_length *= 2;
2118 } while (new_length < required_length);
2119 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002120 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002121 array_->CopyTo(0, *extended_array, 0, length_);
2122 array_ = extended_array;
2123 }
2124 }
2125
2126 void Add(Object* value) {
2127 ASSERT(length_ < capacity());
2128 array_->set(length_, value);
2129 length_++;
2130 }
2131
2132 void Add(Smi* value) {
2133 ASSERT(length_ < capacity());
2134 array_->set(length_, value);
2135 length_++;
2136 }
2137
2138 Handle<FixedArray> array() {
2139 return array_;
2140 }
2141
2142 int length() {
2143 return length_;
2144 }
2145
2146 int capacity() {
2147 return array_->length();
2148 }
2149
2150 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002151 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002152 result_array->set_length(Smi::FromInt(length_));
2153 return result_array;
2154 }
2155
2156 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2157 target_array->set_elements(*array_);
2158 target_array->set_length(Smi::FromInt(length_));
2159 return target_array;
2160 }
2161
2162 private:
2163 Handle<FixedArray> array_;
2164 int length_;
2165};
2166
2167
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002168// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002169const int kStringBuilderConcatHelperLengthBits = 11;
2170const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002171
2172template <typename schar>
2173static inline void StringBuilderConcatHelper(String*,
2174 schar*,
2175 FixedArray*,
2176 int);
2177
lrn@chromium.org25156de2010-04-06 13:10:27 +00002178typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2179 StringBuilderSubstringLength;
2180typedef BitField<int,
2181 kStringBuilderConcatHelperLengthBits,
2182 kStringBuilderConcatHelperPositionBits>
2183 StringBuilderSubstringPosition;
2184
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002185
2186class ReplacementStringBuilder {
2187 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002188 ReplacementStringBuilder(Heap* heap,
2189 Handle<String> subject,
2190 int estimated_part_count)
2191 : heap_(heap),
2192 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002193 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002194 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002195 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002196 // Require a non-zero initial size. Ensures that doubling the size to
2197 // extend the array will work.
2198 ASSERT(estimated_part_count > 0);
2199 }
2200
lrn@chromium.org25156de2010-04-06 13:10:27 +00002201 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2202 int from,
2203 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002204 ASSERT(from >= 0);
2205 int length = to - from;
2206 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002207 if (StringBuilderSubstringLength::is_valid(length) &&
2208 StringBuilderSubstringPosition::is_valid(from)) {
2209 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2210 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002211 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002212 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002213 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002214 builder->Add(Smi::FromInt(-length));
2215 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002216 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002217 }
2218
2219
2220 void EnsureCapacity(int elements) {
2221 array_builder_.EnsureCapacity(elements);
2222 }
2223
2224
2225 void AddSubjectSlice(int from, int to) {
2226 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002227 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002228 }
2229
2230
2231 void AddString(Handle<String> string) {
2232 int length = string->length();
2233 ASSERT(length > 0);
2234 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002235 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002236 is_ascii_ = false;
2237 }
2238 IncrementCharacterCount(length);
2239 }
2240
2241
2242 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002243 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002244 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002245 }
2246
2247 Handle<String> joined_string;
2248 if (is_ascii_) {
2249 joined_string = NewRawAsciiString(character_count_);
2250 AssertNoAllocation no_alloc;
2251 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2252 char* char_buffer = seq->GetChars();
2253 StringBuilderConcatHelper(*subject_,
2254 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002255 *array_builder_.array(),
2256 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002257 } else {
2258 // Non-ASCII.
2259 joined_string = NewRawTwoByteString(character_count_);
2260 AssertNoAllocation no_alloc;
2261 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2262 uc16* char_buffer = seq->GetChars();
2263 StringBuilderConcatHelper(*subject_,
2264 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002265 *array_builder_.array(),
2266 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002267 }
2268 return joined_string;
2269 }
2270
2271
2272 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002273 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002274 V8::FatalProcessOutOfMemory("String.replace result too large.");
2275 }
2276 character_count_ += by;
2277 }
2278
lrn@chromium.org25156de2010-04-06 13:10:27 +00002279 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002280 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002281 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002282
lrn@chromium.org25156de2010-04-06 13:10:27 +00002283 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002284 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002285 CALL_HEAP_FUNCTION(heap_->isolate(),
2286 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002287 }
2288
2289
2290 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002291 CALL_HEAP_FUNCTION(heap_->isolate(),
2292 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002293 }
2294
2295
2296 void AddElement(Object* element) {
2297 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002298 ASSERT(array_builder_.capacity() > array_builder_.length());
2299 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002300 }
2301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002302 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002303 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002304 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002305 int character_count_;
2306 bool is_ascii_;
2307};
2308
2309
2310class CompiledReplacement {
2311 public:
2312 CompiledReplacement()
2313 : parts_(1), replacement_substrings_(0) {}
2314
2315 void Compile(Handle<String> replacement,
2316 int capture_count,
2317 int subject_length);
2318
2319 void Apply(ReplacementStringBuilder* builder,
2320 int match_from,
2321 int match_to,
2322 Handle<JSArray> last_match_info);
2323
2324 // Number of distinct parts of the replacement pattern.
2325 int parts() {
2326 return parts_.length();
2327 }
2328 private:
2329 enum PartType {
2330 SUBJECT_PREFIX = 1,
2331 SUBJECT_SUFFIX,
2332 SUBJECT_CAPTURE,
2333 REPLACEMENT_SUBSTRING,
2334 REPLACEMENT_STRING,
2335
2336 NUMBER_OF_PART_TYPES
2337 };
2338
2339 struct ReplacementPart {
2340 static inline ReplacementPart SubjectMatch() {
2341 return ReplacementPart(SUBJECT_CAPTURE, 0);
2342 }
2343 static inline ReplacementPart SubjectCapture(int capture_index) {
2344 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2345 }
2346 static inline ReplacementPart SubjectPrefix() {
2347 return ReplacementPart(SUBJECT_PREFIX, 0);
2348 }
2349 static inline ReplacementPart SubjectSuffix(int subject_length) {
2350 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2351 }
2352 static inline ReplacementPart ReplacementString() {
2353 return ReplacementPart(REPLACEMENT_STRING, 0);
2354 }
2355 static inline ReplacementPart ReplacementSubString(int from, int to) {
2356 ASSERT(from >= 0);
2357 ASSERT(to > from);
2358 return ReplacementPart(-from, to);
2359 }
2360
2361 // If tag <= 0 then it is the negation of a start index of a substring of
2362 // the replacement pattern, otherwise it's a value from PartType.
2363 ReplacementPart(int tag, int data)
2364 : tag(tag), data(data) {
2365 // Must be non-positive or a PartType value.
2366 ASSERT(tag < NUMBER_OF_PART_TYPES);
2367 }
2368 // Either a value of PartType or a non-positive number that is
2369 // the negation of an index into the replacement string.
2370 int tag;
2371 // The data value's interpretation depends on the value of tag:
2372 // tag == SUBJECT_PREFIX ||
2373 // tag == SUBJECT_SUFFIX: data is unused.
2374 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2375 // tag == REPLACEMENT_SUBSTRING ||
2376 // tag == REPLACEMENT_STRING: data is index into array of substrings
2377 // of the replacement string.
2378 // tag <= 0: Temporary representation of the substring of the replacement
2379 // string ranging over -tag .. data.
2380 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2381 // substring objects.
2382 int data;
2383 };
2384
2385 template<typename Char>
2386 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2387 Vector<Char> characters,
2388 int capture_count,
2389 int subject_length) {
2390 int length = characters.length();
2391 int last = 0;
2392 for (int i = 0; i < length; i++) {
2393 Char c = characters[i];
2394 if (c == '$') {
2395 int next_index = i + 1;
2396 if (next_index == length) { // No next character!
2397 break;
2398 }
2399 Char c2 = characters[next_index];
2400 switch (c2) {
2401 case '$':
2402 if (i > last) {
2403 // There is a substring before. Include the first "$".
2404 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2405 last = next_index + 1; // Continue after the second "$".
2406 } else {
2407 // Let the next substring start with the second "$".
2408 last = next_index;
2409 }
2410 i = next_index;
2411 break;
2412 case '`':
2413 if (i > last) {
2414 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2415 }
2416 parts->Add(ReplacementPart::SubjectPrefix());
2417 i = next_index;
2418 last = i + 1;
2419 break;
2420 case '\'':
2421 if (i > last) {
2422 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2423 }
2424 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2425 i = next_index;
2426 last = i + 1;
2427 break;
2428 case '&':
2429 if (i > last) {
2430 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2431 }
2432 parts->Add(ReplacementPart::SubjectMatch());
2433 i = next_index;
2434 last = i + 1;
2435 break;
2436 case '0':
2437 case '1':
2438 case '2':
2439 case '3':
2440 case '4':
2441 case '5':
2442 case '6':
2443 case '7':
2444 case '8':
2445 case '9': {
2446 int capture_ref = c2 - '0';
2447 if (capture_ref > capture_count) {
2448 i = next_index;
2449 continue;
2450 }
2451 int second_digit_index = next_index + 1;
2452 if (second_digit_index < length) {
2453 // Peek ahead to see if we have two digits.
2454 Char c3 = characters[second_digit_index];
2455 if ('0' <= c3 && c3 <= '9') { // Double digits.
2456 int double_digit_ref = capture_ref * 10 + c3 - '0';
2457 if (double_digit_ref <= capture_count) {
2458 next_index = second_digit_index;
2459 capture_ref = double_digit_ref;
2460 }
2461 }
2462 }
2463 if (capture_ref > 0) {
2464 if (i > last) {
2465 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2466 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002467 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2469 last = next_index + 1;
2470 }
2471 i = next_index;
2472 break;
2473 }
2474 default:
2475 i = next_index;
2476 break;
2477 }
2478 }
2479 }
2480 if (length > last) {
2481 if (last == 0) {
2482 parts->Add(ReplacementPart::ReplacementString());
2483 } else {
2484 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2485 }
2486 }
2487 }
2488
2489 ZoneList<ReplacementPart> parts_;
2490 ZoneList<Handle<String> > replacement_substrings_;
2491};
2492
2493
2494void CompiledReplacement::Compile(Handle<String> replacement,
2495 int capture_count,
2496 int subject_length) {
2497 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002498 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002499 AssertNoAllocation no_alloc;
2500 ParseReplacementPattern(&parts_,
2501 replacement->ToAsciiVector(),
2502 capture_count,
2503 subject_length);
2504 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002505 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002506 AssertNoAllocation no_alloc;
2507
2508 ParseReplacementPattern(&parts_,
2509 replacement->ToUC16Vector(),
2510 capture_count,
2511 subject_length);
2512 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002513 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002514 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002515 int substring_index = 0;
2516 for (int i = 0, n = parts_.length(); i < n; i++) {
2517 int tag = parts_[i].tag;
2518 if (tag <= 0) { // A replacement string slice.
2519 int from = -tag;
2520 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002521 replacement_substrings_.Add(
2522 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002523 parts_[i].tag = REPLACEMENT_SUBSTRING;
2524 parts_[i].data = substring_index;
2525 substring_index++;
2526 } else if (tag == REPLACEMENT_STRING) {
2527 replacement_substrings_.Add(replacement);
2528 parts_[i].data = substring_index;
2529 substring_index++;
2530 }
2531 }
2532}
2533
2534
2535void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2536 int match_from,
2537 int match_to,
2538 Handle<JSArray> last_match_info) {
2539 for (int i = 0, n = parts_.length(); i < n; i++) {
2540 ReplacementPart part = parts_[i];
2541 switch (part.tag) {
2542 case SUBJECT_PREFIX:
2543 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2544 break;
2545 case SUBJECT_SUFFIX: {
2546 int subject_length = part.data;
2547 if (match_to < subject_length) {
2548 builder->AddSubjectSlice(match_to, subject_length);
2549 }
2550 break;
2551 }
2552 case SUBJECT_CAPTURE: {
2553 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002554 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002555 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2556 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2557 if (from >= 0 && to > from) {
2558 builder->AddSubjectSlice(from, to);
2559 }
2560 break;
2561 }
2562 case REPLACEMENT_SUBSTRING:
2563 case REPLACEMENT_STRING:
2564 builder->AddString(replacement_substrings_[part.data]);
2565 break;
2566 default:
2567 UNREACHABLE();
2568 }
2569 }
2570}
2571
2572
2573
lrn@chromium.org303ada72010-10-27 09:33:13 +00002574MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002575 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002576 String* subject,
2577 JSRegExp* regexp,
2578 String* replacement,
2579 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002580 ASSERT(subject->IsFlat());
2581 ASSERT(replacement->IsFlat());
2582
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002583 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002584
2585 int length = subject->length();
2586 Handle<String> subject_handle(subject);
2587 Handle<JSRegExp> regexp_handle(regexp);
2588 Handle<String> replacement_handle(replacement);
2589 Handle<JSArray> last_match_info_handle(last_match_info);
2590 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2591 subject_handle,
2592 0,
2593 last_match_info_handle);
2594 if (match.is_null()) {
2595 return Failure::Exception();
2596 }
2597 if (match->IsNull()) {
2598 return *subject_handle;
2599 }
2600
2601 int capture_count = regexp_handle->CaptureCount();
2602
2603 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002604 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002605 CompiledReplacement compiled_replacement;
2606 compiled_replacement.Compile(replacement_handle,
2607 capture_count,
2608 length);
2609
2610 bool is_global = regexp_handle->GetFlags().is_global();
2611
2612 // Guessing the number of parts that the final result string is built
2613 // from. Global regexps can match any number of times, so we guess
2614 // conservatively.
2615 int expected_parts =
2616 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002617 ReplacementStringBuilder builder(isolate->heap(),
2618 subject_handle,
2619 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002620
2621 // Index of end of last match.
2622 int prev = 0;
2623
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002624 // Number of parts added by compiled replacement plus preceeding
2625 // string and possibly suffix after last match. It is possible for
2626 // all components to use two elements when encoded as two smis.
2627 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002628 bool matched = true;
2629 do {
2630 ASSERT(last_match_info_handle->HasFastElements());
2631 // Increase the capacity of the builder before entering local handle-scope,
2632 // so its internal buffer can safely allocate a new handle if it grows.
2633 builder.EnsureCapacity(parts_added_per_loop);
2634
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002635 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002636 int start, end;
2637 {
2638 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002639 FixedArray* match_info_array =
2640 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002641
2642 ASSERT_EQ(capture_count * 2 + 2,
2643 RegExpImpl::GetLastCaptureCount(match_info_array));
2644 start = RegExpImpl::GetCapture(match_info_array, 0);
2645 end = RegExpImpl::GetCapture(match_info_array, 1);
2646 }
2647
2648 if (prev < start) {
2649 builder.AddSubjectSlice(prev, start);
2650 }
2651 compiled_replacement.Apply(&builder,
2652 start,
2653 end,
2654 last_match_info_handle);
2655 prev = end;
2656
2657 // Only continue checking for global regexps.
2658 if (!is_global) break;
2659
2660 // Continue from where the match ended, unless it was an empty match.
2661 int next = end;
2662 if (start == end) {
2663 next = end + 1;
2664 if (next > length) break;
2665 }
2666
2667 match = RegExpImpl::Exec(regexp_handle,
2668 subject_handle,
2669 next,
2670 last_match_info_handle);
2671 if (match.is_null()) {
2672 return Failure::Exception();
2673 }
2674 matched = !match->IsNull();
2675 } while (matched);
2676
2677 if (prev < length) {
2678 builder.AddSubjectSlice(prev, length);
2679 }
2680
2681 return *(builder.ToString());
2682}
2683
2684
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002685template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002686MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002687 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002688 String* subject,
2689 JSRegExp* regexp,
2690 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002691 ASSERT(subject->IsFlat());
2692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002693 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002694
2695 Handle<String> subject_handle(subject);
2696 Handle<JSRegExp> regexp_handle(regexp);
2697 Handle<JSArray> last_match_info_handle(last_match_info);
2698 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2699 subject_handle,
2700 0,
2701 last_match_info_handle);
2702 if (match.is_null()) return Failure::Exception();
2703 if (match->IsNull()) return *subject_handle;
2704
2705 ASSERT(last_match_info_handle->HasFastElements());
2706
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002707 int start, end;
2708 {
2709 AssertNoAllocation match_info_array_is_not_in_a_handle;
2710 FixedArray* match_info_array =
2711 FixedArray::cast(last_match_info_handle->elements());
2712
2713 start = RegExpImpl::GetCapture(match_info_array, 0);
2714 end = RegExpImpl::GetCapture(match_info_array, 1);
2715 }
2716
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002717 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002718 int new_length = length - (end - start);
2719 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002720 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002721 }
2722 Handle<ResultSeqString> answer;
2723 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002724 answer = Handle<ResultSeqString>::cast(
2725 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002726 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002727 answer = Handle<ResultSeqString>::cast(
2728 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002729 }
2730
2731 // If the regexp isn't global, only match once.
2732 if (!regexp_handle->GetFlags().is_global()) {
2733 if (start > 0) {
2734 String::WriteToFlat(*subject_handle,
2735 answer->GetChars(),
2736 0,
2737 start);
2738 }
2739 if (end < length) {
2740 String::WriteToFlat(*subject_handle,
2741 answer->GetChars() + start,
2742 end,
2743 length);
2744 }
2745 return *answer;
2746 }
2747
2748 int prev = 0; // Index of end of last match.
2749 int next = 0; // Start of next search (prev unless last match was empty).
2750 int position = 0;
2751
2752 do {
2753 if (prev < start) {
2754 // Add substring subject[prev;start] to answer string.
2755 String::WriteToFlat(*subject_handle,
2756 answer->GetChars() + position,
2757 prev,
2758 start);
2759 position += start - prev;
2760 }
2761 prev = end;
2762 next = end;
2763 // Continue from where the match ended, unless it was an empty match.
2764 if (start == end) {
2765 next++;
2766 if (next > length) break;
2767 }
2768 match = RegExpImpl::Exec(regexp_handle,
2769 subject_handle,
2770 next,
2771 last_match_info_handle);
2772 if (match.is_null()) return Failure::Exception();
2773 if (match->IsNull()) break;
2774
2775 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002776 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002777 {
2778 AssertNoAllocation match_info_array_is_not_in_a_handle;
2779 FixedArray* match_info_array =
2780 FixedArray::cast(last_match_info_handle->elements());
2781 start = RegExpImpl::GetCapture(match_info_array, 0);
2782 end = RegExpImpl::GetCapture(match_info_array, 1);
2783 }
2784 } while (true);
2785
2786 if (prev < length) {
2787 // Add substring subject[prev;length] to answer string.
2788 String::WriteToFlat(*subject_handle,
2789 answer->GetChars() + position,
2790 prev,
2791 length);
2792 position += length - prev;
2793 }
2794
2795 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002796 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002797 }
2798
2799 // Shorten string and fill
2800 int string_size = ResultSeqString::SizeFor(position);
2801 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2802 int delta = allocated_string_size - string_size;
2803
2804 answer->set_length(position);
2805 if (delta == 0) return *answer;
2806
2807 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002808 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002809
2810 return *answer;
2811}
2812
2813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002814RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002815 ASSERT(args.length() == 4);
2816
2817 CONVERT_CHECKED(String, subject, args[0]);
2818 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002819 Object* flat_subject;
2820 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2821 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2822 return maybe_flat_subject;
2823 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002824 }
2825 subject = String::cast(flat_subject);
2826 }
2827
2828 CONVERT_CHECKED(String, replacement, args[2]);
2829 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002830 Object* flat_replacement;
2831 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2832 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2833 return maybe_flat_replacement;
2834 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002835 }
2836 replacement = String::cast(flat_replacement);
2837 }
2838
2839 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2840 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2841
2842 ASSERT(last_match_info->HasFastElements());
2843
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002844 if (replacement->length() == 0) {
2845 if (subject->HasOnlyAsciiChars()) {
2846 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002847 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002848 } else {
2849 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002850 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002851 }
2852 }
2853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002854 return StringReplaceRegExpWithString(isolate,
2855 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002856 regexp,
2857 replacement,
2858 last_match_info);
2859}
2860
2861
ager@chromium.org7c537e22008-10-16 08:43:32 +00002862// Perform string match of pattern on subject, starting at start index.
2863// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002864// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002865int Runtime::StringMatch(Isolate* isolate,
2866 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002867 Handle<String> pat,
2868 int start_index) {
2869 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002870 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002871
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002872 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002873 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002874
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002875 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002876 if (start_index + pattern_length > subject_length) return -1;
2877
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002878 if (!sub->IsFlat()) FlattenString(sub);
2879 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002880
ager@chromium.org7c537e22008-10-16 08:43:32 +00002881 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002882 // Extract flattened substrings of cons strings before determining asciiness.
2883 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002884 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002885 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002886 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002887
ager@chromium.org7c537e22008-10-16 08:43:32 +00002888 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002889 if (seq_pat->IsAsciiRepresentation()) {
2890 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2891 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002892 return SearchString(isolate,
2893 seq_sub->ToAsciiVector(),
2894 pat_vector,
2895 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002896 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002897 return SearchString(isolate,
2898 seq_sub->ToUC16Vector(),
2899 pat_vector,
2900 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002901 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002902 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2903 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002904 return SearchString(isolate,
2905 seq_sub->ToAsciiVector(),
2906 pat_vector,
2907 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002908 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002909 return SearchString(isolate,
2910 seq_sub->ToUC16Vector(),
2911 pat_vector,
2912 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002913}
2914
2915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002916RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002917 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002918 ASSERT(args.length() == 3);
2919
ager@chromium.org7c537e22008-10-16 08:43:32 +00002920 CONVERT_ARG_CHECKED(String, sub, 0);
2921 CONVERT_ARG_CHECKED(String, pat, 1);
2922
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002923 Object* index = args[2];
2924 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002925 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002926
ager@chromium.org870a0b62008-11-04 11:43:05 +00002927 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002928 int position =
2929 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002930 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002931}
2932
2933
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002934template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002935static int StringMatchBackwards(Vector<const schar> subject,
2936 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002937 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002938 int pattern_length = pattern.length();
2939 ASSERT(pattern_length >= 1);
2940 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002941
2942 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002943 for (int i = 0; i < pattern_length; i++) {
2944 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002945 if (c > String::kMaxAsciiCharCode) {
2946 return -1;
2947 }
2948 }
2949 }
2950
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002951 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002952 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002953 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002954 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002955 while (j < pattern_length) {
2956 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002957 break;
2958 }
2959 j++;
2960 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002961 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002962 return i;
2963 }
2964 }
2965 return -1;
2966}
2967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002968RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002969 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002970 ASSERT(args.length() == 3);
2971
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002972 CONVERT_ARG_CHECKED(String, sub, 0);
2973 CONVERT_ARG_CHECKED(String, pat, 1);
2974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002975 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002976 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002977 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002978
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002979 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002980 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002981
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002982 if (start_index + pat_length > sub_length) {
2983 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002984 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002985
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002986 if (pat_length == 0) {
2987 return Smi::FromInt(start_index);
2988 }
2989
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002990 if (!sub->IsFlat()) FlattenString(sub);
2991 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002992
2993 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2994
2995 int position = -1;
2996
2997 if (pat->IsAsciiRepresentation()) {
2998 Vector<const char> pat_vector = pat->ToAsciiVector();
2999 if (sub->IsAsciiRepresentation()) {
3000 position = StringMatchBackwards(sub->ToAsciiVector(),
3001 pat_vector,
3002 start_index);
3003 } else {
3004 position = StringMatchBackwards(sub->ToUC16Vector(),
3005 pat_vector,
3006 start_index);
3007 }
3008 } else {
3009 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3010 if (sub->IsAsciiRepresentation()) {
3011 position = StringMatchBackwards(sub->ToAsciiVector(),
3012 pat_vector,
3013 start_index);
3014 } else {
3015 position = StringMatchBackwards(sub->ToUC16Vector(),
3016 pat_vector,
3017 start_index);
3018 }
3019 }
3020
3021 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003022}
3023
3024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003025RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003026 NoHandleAllocation ha;
3027 ASSERT(args.length() == 2);
3028
3029 CONVERT_CHECKED(String, str1, args[0]);
3030 CONVERT_CHECKED(String, str2, args[1]);
3031
3032 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003033 int str1_length = str1->length();
3034 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003035
3036 // Decide trivial cases without flattening.
3037 if (str1_length == 0) {
3038 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3039 return Smi::FromInt(-str2_length);
3040 } else {
3041 if (str2_length == 0) return Smi::FromInt(str1_length);
3042 }
3043
3044 int end = str1_length < str2_length ? str1_length : str2_length;
3045
3046 // No need to flatten if we are going to find the answer on the first
3047 // character. At this point we know there is at least one character
3048 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003049 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003050 if (d != 0) return Smi::FromInt(d);
3051
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003052 str1->TryFlatten();
3053 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003055 StringInputBuffer& buf1 =
3056 *isolate->runtime_state()->string_locale_compare_buf1();
3057 StringInputBuffer& buf2 =
3058 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003059
3060 buf1.Reset(str1);
3061 buf2.Reset(str2);
3062
3063 for (int i = 0; i < end; i++) {
3064 uint16_t char1 = buf1.GetNext();
3065 uint16_t char2 = buf2.GetNext();
3066 if (char1 != char2) return Smi::FromInt(char1 - char2);
3067 }
3068
3069 return Smi::FromInt(str1_length - str2_length);
3070}
3071
3072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003073RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003074 NoHandleAllocation ha;
3075 ASSERT(args.length() == 3);
3076
3077 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003078 Object* from = args[1];
3079 Object* to = args[2];
3080 int start, end;
3081 // We have a fast integer-only case here to avoid a conversion to double in
3082 // the common case where from and to are Smis.
3083 if (from->IsSmi() && to->IsSmi()) {
3084 start = Smi::cast(from)->value();
3085 end = Smi::cast(to)->value();
3086 } else {
3087 CONVERT_DOUBLE_CHECKED(from_number, from);
3088 CONVERT_DOUBLE_CHECKED(to_number, to);
3089 start = FastD2I(from_number);
3090 end = FastD2I(to_number);
3091 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003092 RUNTIME_ASSERT(end >= start);
3093 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003094 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003095 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003096 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003097}
3098
3099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003100RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003101 ASSERT_EQ(3, args.length());
3102
3103 CONVERT_ARG_CHECKED(String, subject, 0);
3104 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3105 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3106 HandleScope handles;
3107
3108 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3109
3110 if (match.is_null()) {
3111 return Failure::Exception();
3112 }
3113 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003114 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003115 }
3116 int length = subject->length();
3117
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003118 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003119 ZoneList<int> offsets(8);
3120 do {
3121 int start;
3122 int end;
3123 {
3124 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003125 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003126 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3127 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3128 }
3129 offsets.Add(start);
3130 offsets.Add(end);
3131 int index = start < end ? end : end + 1;
3132 if (index > length) break;
3133 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3134 if (match.is_null()) {
3135 return Failure::Exception();
3136 }
3137 } while (!match->IsNull());
3138 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003139 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003140 for (int i = 0; i < matches ; i++) {
3141 int from = offsets.at(i * 2);
3142 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003143 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003144 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003145 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003146 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003147 result->set_length(Smi::FromInt(matches));
3148 return *result;
3149}
3150
3151
lrn@chromium.org25156de2010-04-06 13:10:27 +00003152// Two smis before and after the match, for very long strings.
3153const int kMaxBuilderEntriesPerRegExpMatch = 5;
3154
3155
3156static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3157 Handle<JSArray> last_match_info,
3158 int match_start,
3159 int match_end) {
3160 // Fill last_match_info with a single capture.
3161 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3162 AssertNoAllocation no_gc;
3163 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3164 RegExpImpl::SetLastCaptureCount(elements, 2);
3165 RegExpImpl::SetLastInput(elements, *subject);
3166 RegExpImpl::SetLastSubject(elements, *subject);
3167 RegExpImpl::SetCapture(elements, 0, match_start);
3168 RegExpImpl::SetCapture(elements, 1, match_end);
3169}
3170
3171
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003172template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003173static bool SearchStringMultiple(Isolate* isolate,
3174 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003175 Vector<const PatternChar> pattern,
3176 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003177 FixedArrayBuilder* builder,
3178 int* match_pos) {
3179 int pos = *match_pos;
3180 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003181 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003182 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003183 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003184 while (pos <= max_search_start) {
3185 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3186 *match_pos = pos;
3187 return false;
3188 }
3189 // Position of end of previous match.
3190 int match_end = pos + pattern_length;
3191 int new_pos = search.Search(subject, match_end);
3192 if (new_pos >= 0) {
3193 // A match.
3194 if (new_pos > match_end) {
3195 ReplacementStringBuilder::AddSubjectSlice(builder,
3196 match_end,
3197 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003198 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003199 pos = new_pos;
3200 builder->Add(pattern_string);
3201 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003202 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003203 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003204 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003205
lrn@chromium.org25156de2010-04-06 13:10:27 +00003206 if (pos < max_search_start) {
3207 ReplacementStringBuilder::AddSubjectSlice(builder,
3208 pos + pattern_length,
3209 subject_length);
3210 }
3211 *match_pos = pos;
3212 return true;
3213}
3214
3215
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003216static bool SearchStringMultiple(Isolate* isolate,
3217 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003218 Handle<String> pattern,
3219 Handle<JSArray> last_match_info,
3220 FixedArrayBuilder* builder) {
3221 ASSERT(subject->IsFlat());
3222 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003223
3224 // Treating as if a previous match was before first character.
3225 int match_pos = -pattern->length();
3226
3227 for (;;) { // Break when search complete.
3228 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3229 AssertNoAllocation no_gc;
3230 if (subject->IsAsciiRepresentation()) {
3231 Vector<const char> subject_vector = subject->ToAsciiVector();
3232 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003233 if (SearchStringMultiple(isolate,
3234 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003235 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003236 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003237 builder,
3238 &match_pos)) break;
3239 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003240 if (SearchStringMultiple(isolate,
3241 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003242 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003243 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003244 builder,
3245 &match_pos)) break;
3246 }
3247 } else {
3248 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3249 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003250 if (SearchStringMultiple(isolate,
3251 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003252 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003253 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003254 builder,
3255 &match_pos)) break;
3256 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003257 if (SearchStringMultiple(isolate,
3258 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003259 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003260 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003261 builder,
3262 &match_pos)) break;
3263 }
3264 }
3265 }
3266
3267 if (match_pos >= 0) {
3268 SetLastMatchInfoNoCaptures(subject,
3269 last_match_info,
3270 match_pos,
3271 match_pos + pattern->length());
3272 return true;
3273 }
3274 return false; // No matches at all.
3275}
3276
3277
3278static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003279 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003280 Handle<String> subject,
3281 Handle<JSRegExp> regexp,
3282 Handle<JSArray> last_match_array,
3283 FixedArrayBuilder* builder) {
3284 ASSERT(subject->IsFlat());
3285 int match_start = -1;
3286 int match_end = 0;
3287 int pos = 0;
3288 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3289 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3290
3291 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003292 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003293 int subject_length = subject->length();
3294
3295 for (;;) { // Break on failure, return on exception.
3296 RegExpImpl::IrregexpResult result =
3297 RegExpImpl::IrregexpExecOnce(regexp,
3298 subject,
3299 pos,
3300 register_vector);
3301 if (result == RegExpImpl::RE_SUCCESS) {
3302 match_start = register_vector[0];
3303 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3304 if (match_end < match_start) {
3305 ReplacementStringBuilder::AddSubjectSlice(builder,
3306 match_end,
3307 match_start);
3308 }
3309 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003310 HandleScope loop_scope(isolate);
3311 builder->Add(*isolate->factory()->NewSubString(subject,
3312 match_start,
3313 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003314 if (match_start != match_end) {
3315 pos = match_end;
3316 } else {
3317 pos = match_end + 1;
3318 if (pos > subject_length) break;
3319 }
3320 } else if (result == RegExpImpl::RE_FAILURE) {
3321 break;
3322 } else {
3323 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3324 return result;
3325 }
3326 }
3327
3328 if (match_start >= 0) {
3329 if (match_end < subject_length) {
3330 ReplacementStringBuilder::AddSubjectSlice(builder,
3331 match_end,
3332 subject_length);
3333 }
3334 SetLastMatchInfoNoCaptures(subject,
3335 last_match_array,
3336 match_start,
3337 match_end);
3338 return RegExpImpl::RE_SUCCESS;
3339 } else {
3340 return RegExpImpl::RE_FAILURE; // No matches at all.
3341 }
3342}
3343
3344
3345static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003346 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003347 Handle<String> subject,
3348 Handle<JSRegExp> regexp,
3349 Handle<JSArray> last_match_array,
3350 FixedArrayBuilder* builder) {
3351
3352 ASSERT(subject->IsFlat());
3353 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3354 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3355
3356 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003357 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003358
3359 RegExpImpl::IrregexpResult result =
3360 RegExpImpl::IrregexpExecOnce(regexp,
3361 subject,
3362 0,
3363 register_vector);
3364
3365 int capture_count = regexp->CaptureCount();
3366 int subject_length = subject->length();
3367
3368 // Position to search from.
3369 int pos = 0;
3370 // End of previous match. Differs from pos if match was empty.
3371 int match_end = 0;
3372 if (result == RegExpImpl::RE_SUCCESS) {
3373 // Need to keep a copy of the previous match for creating last_match_info
3374 // at the end, so we have two vectors that we swap between.
3375 OffsetsVector registers2(required_registers);
3376 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3377
3378 do {
3379 int match_start = register_vector[0];
3380 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3381 if (match_end < match_start) {
3382 ReplacementStringBuilder::AddSubjectSlice(builder,
3383 match_end,
3384 match_start);
3385 }
3386 match_end = register_vector[1];
3387
3388 {
3389 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003390 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003391 // Arguments array to replace function is match, captures, index and
3392 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003393 Handle<FixedArray> elements =
3394 isolate->factory()->NewFixedArray(3 + capture_count);
3395 Handle<String> match = isolate->factory()->NewSubString(subject,
3396 match_start,
3397 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003398 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003399 for (int i = 1; i <= capture_count; i++) {
3400 int start = register_vector[i * 2];
3401 if (start >= 0) {
3402 int end = register_vector[i * 2 + 1];
3403 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003404 Handle<String> substring = isolate->factory()->NewSubString(subject,
3405 start,
3406 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003407 elements->set(i, *substring);
3408 } else {
3409 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003410 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003411 }
3412 }
3413 elements->set(capture_count + 1, Smi::FromInt(match_start));
3414 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003415 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003416 }
3417 // Swap register vectors, so the last successful match is in
3418 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003419 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003420 prev_register_vector = register_vector;
3421 register_vector = tmp;
3422
3423 if (match_end > match_start) {
3424 pos = match_end;
3425 } else {
3426 pos = match_end + 1;
3427 if (pos > subject_length) {
3428 break;
3429 }
3430 }
3431
3432 result = RegExpImpl::IrregexpExecOnce(regexp,
3433 subject,
3434 pos,
3435 register_vector);
3436 } while (result == RegExpImpl::RE_SUCCESS);
3437
3438 if (result != RegExpImpl::RE_EXCEPTION) {
3439 // Finished matching, with at least one match.
3440 if (match_end < subject_length) {
3441 ReplacementStringBuilder::AddSubjectSlice(builder,
3442 match_end,
3443 subject_length);
3444 }
3445
3446 int last_match_capture_count = (capture_count + 1) * 2;
3447 int last_match_array_size =
3448 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3449 last_match_array->EnsureSize(last_match_array_size);
3450 AssertNoAllocation no_gc;
3451 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3452 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3453 RegExpImpl::SetLastSubject(elements, *subject);
3454 RegExpImpl::SetLastInput(elements, *subject);
3455 for (int i = 0; i < last_match_capture_count; i++) {
3456 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3457 }
3458 return RegExpImpl::RE_SUCCESS;
3459 }
3460 }
3461 // No matches at all, return failure or exception result directly.
3462 return result;
3463}
3464
3465
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003466RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003467 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003468 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003469
3470 CONVERT_ARG_CHECKED(String, subject, 1);
3471 if (!subject->IsFlat()) { FlattenString(subject); }
3472 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3473 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3474 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3475
3476 ASSERT(last_match_info->HasFastElements());
3477 ASSERT(regexp->GetFlags().is_global());
3478 Handle<FixedArray> result_elements;
3479 if (result_array->HasFastElements()) {
3480 result_elements =
3481 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3482 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003483 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003484 }
3485 FixedArrayBuilder builder(result_elements);
3486
3487 if (regexp->TypeTag() == JSRegExp::ATOM) {
3488 Handle<String> pattern(
3489 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003490 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003491 if (SearchStringMultiple(isolate, subject, pattern,
3492 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003493 return *builder.ToJSArray(result_array);
3494 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003495 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003496 }
3497
3498 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3499
3500 RegExpImpl::IrregexpResult result;
3501 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003502 result = SearchRegExpNoCaptureMultiple(isolate,
3503 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003504 regexp,
3505 last_match_info,
3506 &builder);
3507 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003508 result = SearchRegExpMultiple(isolate,
3509 subject,
3510 regexp,
3511 last_match_info,
3512 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003513 }
3514 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003515 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003516 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3517 return Failure::Exception();
3518}
3519
3520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003521RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003522 NoHandleAllocation ha;
3523 ASSERT(args.length() == 2);
3524
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003525 // Fast case where the result is a one character string.
3526 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3527 int value = Smi::cast(args[0])->value();
3528 int radix = Smi::cast(args[1])->value();
3529 if (value >= 0 && value < radix) {
3530 RUNTIME_ASSERT(radix <= 36);
3531 // Character array used for conversion.
3532 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003533 return isolate->heap()->
3534 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003535 }
3536 }
3537
3538 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003539 CONVERT_DOUBLE_CHECKED(value, args[0]);
3540 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003541 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003542 }
3543 if (isinf(value)) {
3544 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003545 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003547 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003548 }
3549 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3550 int radix = FastD2I(radix_number);
3551 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3552 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003553 MaybeObject* result =
3554 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003555 DeleteArray(str);
3556 return result;
3557}
3558
3559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003560RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003561 NoHandleAllocation ha;
3562 ASSERT(args.length() == 2);
3563
3564 CONVERT_DOUBLE_CHECKED(value, args[0]);
3565 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003566 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003567 }
3568 if (isinf(value)) {
3569 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003570 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003572 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003573 }
3574 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3575 int f = FastD2I(f_number);
3576 RUNTIME_ASSERT(f >= 0);
3577 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003578 MaybeObject* res =
3579 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003581 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003582}
3583
3584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003585RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003586 NoHandleAllocation ha;
3587 ASSERT(args.length() == 2);
3588
3589 CONVERT_DOUBLE_CHECKED(value, args[0]);
3590 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003591 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 }
3593 if (isinf(value)) {
3594 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003595 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003597 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 }
3599 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3600 int f = FastD2I(f_number);
3601 RUNTIME_ASSERT(f >= -1 && f <= 20);
3602 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003603 MaybeObject* res =
3604 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003606 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003607}
3608
3609
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003610RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 NoHandleAllocation ha;
3612 ASSERT(args.length() == 2);
3613
3614 CONVERT_DOUBLE_CHECKED(value, args[0]);
3615 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003617 }
3618 if (isinf(value)) {
3619 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003620 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003621 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003622 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003623 }
3624 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3625 int f = FastD2I(f_number);
3626 RUNTIME_ASSERT(f >= 1 && f <= 21);
3627 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003628 MaybeObject* res =
3629 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003630 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003631 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003632}
3633
3634
3635// Returns a single character string where first character equals
3636// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003637static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003638 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003639 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003640 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003641 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003643 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644}
3645
3646
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003647MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3648 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003649 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003650 // Handle [] indexing on Strings
3651 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003652 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3653 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003654 }
3655
3656 // Handle [] indexing on String objects
3657 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003658 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3659 Handle<Object> result =
3660 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3661 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003662 }
3663
3664 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003665 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003666 return prototype->GetElement(index);
3667 }
3668
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003669 return GetElement(object, index);
3670}
3671
3672
lrn@chromium.org303ada72010-10-27 09:33:13 +00003673MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003674 return object->GetElement(index);
3675}
3676
3677
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003678MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3679 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003680 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003681 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003683 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003684 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003685 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003686 isolate->factory()->NewTypeError("non_object_property_load",
3687 HandleVector(args, 2));
3688 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003689 }
3690
3691 // Check if the given key is an array index.
3692 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003693 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003694 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003695 }
3696
3697 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003698 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003699 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003700 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003702 bool has_pending_exception = false;
3703 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003704 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003705 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003706 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003707 }
3708
ager@chromium.org32912102009-01-16 10:38:43 +00003709 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003710 // the element if so.
3711 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003712 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003713 } else {
3714 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003715 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003716 }
3717}
3718
3719
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003720RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003721 NoHandleAllocation ha;
3722 ASSERT(args.length() == 2);
3723
3724 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003725 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003727 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728}
3729
3730
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003731// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003732RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003733 NoHandleAllocation ha;
3734 ASSERT(args.length() == 2);
3735
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003736 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003737 // itself.
3738 //
3739 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003740 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003741 // global proxy object never has properties. This is the case
3742 // because the global proxy object forwards everything to its hidden
3743 // prototype including local lookups.
3744 //
3745 // Additionally, we need to make sure that we do not cache results
3746 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003747 if (args[0]->IsJSObject() &&
3748 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003749 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003750 args[1]->IsString()) {
3751 JSObject* receiver = JSObject::cast(args[0]);
3752 String* key = String::cast(args[1]);
3753 if (receiver->HasFastProperties()) {
3754 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003755 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003756 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3757 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003758 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003759 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003760 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003761 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003762 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003763 LookupResult result;
3764 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003765 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003766 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003767 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003768 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003769 }
3770 } else {
3771 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003772 StringDictionary* dictionary = receiver->property_dictionary();
3773 int entry = dictionary->FindEntry(key);
3774 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003775 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003776 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003777 if (!receiver->IsGlobalObject()) return value;
3778 value = JSGlobalPropertyCell::cast(value)->value();
3779 if (!value->IsTheHole()) return value;
3780 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003781 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003782 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003783 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3784 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003785 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003786 Handle<String> str = args.at<String>(0);
3787 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003788 if (index >= 0 && index < str->length()) {
3789 Handle<Object> result = GetCharAt(str, index);
3790 return *result;
3791 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003792 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003793
3794 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003795 return Runtime::GetObjectProperty(isolate,
3796 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003797 args.at<Object>(1));
3798}
3799
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003800// Implements part of 8.12.9 DefineOwnProperty.
3801// There are 3 cases that lead here:
3802// Step 4b - define a new accessor property.
3803// Steps 9c & 12 - replace an existing data property with an accessor property.
3804// Step 12 - update an existing accessor property with an accessor or generic
3805// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003806RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003807 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003808 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003809 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3810 CONVERT_CHECKED(String, name, args[1]);
3811 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003812 Object* fun = args[3];
3813 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003814 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3815 int unchecked = flag_attr->value();
3816 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3817 RUNTIME_ASSERT(!obj->IsNull());
3818 LookupResult result;
3819 obj->LocalLookupRealNamedProperty(name, &result);
3820
3821 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3822 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3823 // delete it to avoid running into trouble in DefineAccessor, which
3824 // handles this incorrectly if the property is readonly (does nothing)
3825 if (result.IsProperty() &&
3826 (result.type() == FIELD || result.type() == NORMAL
3827 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003828 Object* ok;
3829 { MaybeObject* maybe_ok =
3830 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3831 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3832 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003833 }
3834 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3835}
3836
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003837// Implements part of 8.12.9 DefineOwnProperty.
3838// There are 3 cases that lead here:
3839// Step 4a - define a new data property.
3840// Steps 9b & 12 - replace an existing accessor property with a data property.
3841// Step 12 - update an existing data property with a data or generic
3842// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003843RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003844 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003845 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003846 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3847 CONVERT_ARG_CHECKED(String, name, 1);
3848 Handle<Object> obj_value = args.at<Object>(2);
3849
3850 CONVERT_CHECKED(Smi, flag, args[3]);
3851 int unchecked = flag->value();
3852 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3853
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003854 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3855
3856 // Check if this is an element.
3857 uint32_t index;
3858 bool is_element = name->AsArrayIndex(&index);
3859
3860 // Special case for elements if any of the flags are true.
3861 // If elements are in fast case we always implicitly assume that:
3862 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3863 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3864 is_element) {
3865 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003866 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003867 // We do not need to do access checks here since these has already
3868 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003869 Handle<Object> proto(js_object->GetPrototype());
3870 // If proxy is detached, ignore the assignment. Alternatively,
3871 // we could throw an exception.
3872 if (proto->IsNull()) return *obj_value;
3873 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003874 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003875 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003876 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003877 // Make sure that we never go back to fast case.
3878 dictionary->set_requires_slow_elements();
3879 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003880 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003881 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003882 }
3883
ager@chromium.org5c838252010-02-19 08:53:10 +00003884 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003885 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003886
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003887 // To be compatible with safari we do not change the value on API objects
3888 // in defineProperty. Firefox disagrees here, and actually changes the value.
3889 if (result.IsProperty() &&
3890 (result.type() == CALLBACKS) &&
3891 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003892 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003893 }
3894
ager@chromium.org5c838252010-02-19 08:53:10 +00003895 // Take special care when attributes are different and there is already
3896 // a property. For simplicity we normalize the property which enables us
3897 // to not worry about changing the instance_descriptor and creating a new
3898 // map. The current version of SetObjectProperty does not handle attributes
3899 // correctly in the case where a property is a field and is reset with
3900 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003901 if (result.IsProperty() &&
3902 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003903 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003904 if (js_object->IsJSGlobalProxy()) {
3905 // Since the result is a property, the prototype will exist so
3906 // we don't have to check for null.
3907 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003908 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003909 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003910 // Use IgnoreAttributes version since a readonly property may be
3911 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003912 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3913 *obj_value,
3914 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003915 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003917 return Runtime::ForceSetObjectProperty(isolate,
3918 js_object,
3919 name,
3920 obj_value,
3921 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003922}
3923
3924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003925MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3926 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003927 Handle<Object> key,
3928 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003929 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003930 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003931 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003934 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003935 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003936 isolate->factory()->NewTypeError("non_object_property_store",
3937 HandleVector(args, 2));
3938 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003939 }
3940
3941 // If the object isn't a JavaScript object, we ignore the store.
3942 if (!object->IsJSObject()) return *value;
3943
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003944 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3945
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 // Check if the given key is an array index.
3947 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003948 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3950 // of a string using [] notation. We need to support this too in
3951 // JavaScript.
3952 // In the case of a String object we just need to redirect the assignment to
3953 // the underlying string if the index is in range. Since the underlying
3954 // string does nothing with the assignment then we can ignore such
3955 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003956 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003957 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003958 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003960 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003961 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003962 return *value;
3963 }
3964
3965 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003966 Handle<Object> result;
3967 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003968 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003970 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003971 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003972 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003974 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003975 return *value;
3976 }
3977
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979 bool has_pending_exception = false;
3980 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3981 if (has_pending_exception) return Failure::Exception();
3982 Handle<String> name = Handle<String>::cast(converted);
3983
3984 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003985 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003987 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988 }
3989}
3990
3991
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003992MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
3993 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003994 Handle<Object> key,
3995 Handle<Object> value,
3996 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003997 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003998
3999 // Check if the given key is an array index.
4000 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004001 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004002 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4003 // of a string using [] notation. We need to support this too in
4004 // JavaScript.
4005 // In the case of a String object we just need to redirect the assignment to
4006 // the underlying string if the index is in range. Since the underlying
4007 // string does nothing with the assignment then we can ignore such
4008 // assignments.
4009 if (js_object->IsStringObjectWithCharacterAt(index)) {
4010 return *value;
4011 }
4012
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004013 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004014 }
4015
4016 if (key->IsString()) {
4017 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004018 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004019 } else {
4020 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004021 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004022 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4023 *value,
4024 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004025 }
4026 }
4027
4028 // Call-back into JavaScript to convert the key to a string.
4029 bool has_pending_exception = false;
4030 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4031 if (has_pending_exception) return Failure::Exception();
4032 Handle<String> name = Handle<String>::cast(converted);
4033
4034 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004035 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004036 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004037 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004038 }
4039}
4040
4041
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004042MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4043 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004044 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004045 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004046
4047 // Check if the given key is an array index.
4048 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004049 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004050 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4051 // characters of a string using [] notation. In the case of a
4052 // String object we just need to redirect the deletion to the
4053 // underlying string if the index is in range. Since the
4054 // underlying string does nothing with the deletion, we can ignore
4055 // such deletions.
4056 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004057 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004058 }
4059
4060 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4061 }
4062
4063 Handle<String> key_string;
4064 if (key->IsString()) {
4065 key_string = Handle<String>::cast(key);
4066 } else {
4067 // Call-back into JavaScript to convert the key to a string.
4068 bool has_pending_exception = false;
4069 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4070 if (has_pending_exception) return Failure::Exception();
4071 key_string = Handle<String>::cast(converted);
4072 }
4073
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004074 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004075 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4076}
4077
4078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004079RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004080 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004081 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082
4083 Handle<Object> object = args.at<Object>(0);
4084 Handle<Object> key = args.at<Object>(1);
4085 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004086 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4087 RUNTIME_ASSERT(
4088 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004089 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004090 PropertyAttributes attributes =
4091 static_cast<PropertyAttributes>(unchecked_attributes);
4092
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004093 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004094 if (args.length() == 5) {
4095 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4096 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4097 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004098 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004101 return Runtime::SetObjectProperty(isolate,
4102 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004103 key,
4104 value,
4105 attributes,
4106 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107}
4108
4109
4110// Set a local property, even if it is READ_ONLY. If the property does not
4111// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004112RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004114 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004115 CONVERT_CHECKED(JSObject, object, args[0]);
4116 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004117 // Compute attributes.
4118 PropertyAttributes attributes = NONE;
4119 if (args.length() == 4) {
4120 CONVERT_CHECKED(Smi, value_obj, args[3]);
4121 int unchecked_value = value_obj->value();
4122 // Only attribute bits should be set.
4123 RUNTIME_ASSERT(
4124 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4125 attributes = static_cast<PropertyAttributes>(unchecked_value);
4126 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004128 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004129 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004130}
4131
4132
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004133RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004135 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136
4137 CONVERT_CHECKED(JSObject, object, args[0]);
4138 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004139 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004140 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004141 ? JSObject::STRICT_DELETION
4142 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143}
4144
4145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004146static Object* HasLocalPropertyImplementation(Isolate* isolate,
4147 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004148 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004149 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004150 // Handle hidden prototypes. If there's a hidden prototype above this thing
4151 // then we have to check it for properties, because they are supposed to
4152 // look like they are on this object.
4153 Handle<Object> proto(object->GetPrototype());
4154 if (proto->IsJSObject() &&
4155 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004156 return HasLocalPropertyImplementation(isolate,
4157 Handle<JSObject>::cast(proto),
4158 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004159 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004160 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004161}
4162
4163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004164RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004165 NoHandleAllocation ha;
4166 ASSERT(args.length() == 2);
4167 CONVERT_CHECKED(String, key, args[1]);
4168
ager@chromium.org9085a012009-05-11 19:22:57 +00004169 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004170 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004171 if (obj->IsJSObject()) {
4172 JSObject* object = JSObject::cast(obj);
4173 // Fast case - no interceptors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004174 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004175 // Slow case. Either it's not there or we have an interceptor. We should
4176 // have handles for this kind of deal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177 HandleScope scope(isolate);
4178 return HasLocalPropertyImplementation(isolate,
4179 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004180 Handle<String>(key));
4181 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004182 // Well, there is one exception: Handle [] on strings.
4183 uint32_t index;
4184 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004185 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004186 if (index < static_cast<uint32_t>(string->length()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004187 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 }
4189 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004190 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191}
4192
4193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004194RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 NoHandleAllocation na;
4196 ASSERT(args.length() == 2);
4197
4198 // Only JS objects can have properties.
4199 if (args[0]->IsJSObject()) {
4200 JSObject* object = JSObject::cast(args[0]);
4201 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004202 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004204 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004205}
4206
4207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004208RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 NoHandleAllocation na;
4210 ASSERT(args.length() == 2);
4211
4212 // Only JS objects can have elements.
4213 if (args[0]->IsJSObject()) {
4214 JSObject* object = JSObject::cast(args[0]);
4215 CONVERT_CHECKED(Smi, index_obj, args[1]);
4216 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004217 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004219 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004220}
4221
4222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004223RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004224 NoHandleAllocation ha;
4225 ASSERT(args.length() == 2);
4226
4227 CONVERT_CHECKED(JSObject, object, args[0]);
4228 CONVERT_CHECKED(String, key, args[1]);
4229
4230 uint32_t index;
4231 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004232 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004233 }
4234
ager@chromium.org870a0b62008-11-04 11:43:05 +00004235 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004236 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004237}
4238
4239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004240RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004241 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004242 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004243 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004244 return *GetKeysFor(object);
4245}
4246
4247
4248// Returns either a FixedArray as Runtime_GetPropertyNames,
4249// or, if the given object has an enum cache that contains
4250// all enumerable properties of the object and its prototypes
4251// have none, the map of the object. This is used to speed up
4252// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004253RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004254 ASSERT(args.length() == 1);
4255
4256 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4257
4258 if (raw_object->IsSimpleEnum()) return raw_object->map();
4259
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004260 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004261 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004262 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4263 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004264
4265 // Test again, since cache may have been built by preceding call.
4266 if (object->IsSimpleEnum()) return object->map();
4267
4268 return *content;
4269}
4270
4271
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004272// Find the length of the prototype chain that is to to handled as one. If a
4273// prototype object is hidden it is to be viewed as part of the the object it
4274// is prototype for.
4275static int LocalPrototypeChainLength(JSObject* obj) {
4276 int count = 1;
4277 Object* proto = obj->GetPrototype();
4278 while (proto->IsJSObject() &&
4279 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4280 count++;
4281 proto = JSObject::cast(proto)->GetPrototype();
4282 }
4283 return count;
4284}
4285
4286
4287// Return the names of the local named properties.
4288// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004289RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004290 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004291 ASSERT(args.length() == 1);
4292 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004293 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004294 }
4295 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4296
4297 // Skip the global proxy as it has no properties and always delegates to the
4298 // real global object.
4299 if (obj->IsJSGlobalProxy()) {
4300 // Only collect names if access is permitted.
4301 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004302 !isolate->MayNamedAccess(*obj,
4303 isolate->heap()->undefined_value(),
4304 v8::ACCESS_KEYS)) {
4305 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4306 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004307 }
4308 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4309 }
4310
4311 // Find the number of objects making up this.
4312 int length = LocalPrototypeChainLength(*obj);
4313
4314 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004315 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004316 int total_property_count = 0;
4317 Handle<JSObject> jsproto = obj;
4318 for (int i = 0; i < length; i++) {
4319 // Only collect names if access is permitted.
4320 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004321 !isolate->MayNamedAccess(*jsproto,
4322 isolate->heap()->undefined_value(),
4323 v8::ACCESS_KEYS)) {
4324 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4325 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004326 }
4327 int n;
4328 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4329 local_property_count[i] = n;
4330 total_property_count += n;
4331 if (i < length - 1) {
4332 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4333 }
4334 }
4335
4336 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 Handle<FixedArray> names =
4338 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004339
4340 // Get the property names.
4341 jsproto = obj;
4342 int proto_with_hidden_properties = 0;
4343 for (int i = 0; i < length; i++) {
4344 jsproto->GetLocalPropertyNames(*names,
4345 i == 0 ? 0 : local_property_count[i - 1]);
4346 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4347 proto_with_hidden_properties++;
4348 }
4349 if (i < length - 1) {
4350 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4351 }
4352 }
4353
4354 // Filter out name of hidden propeties object.
4355 if (proto_with_hidden_properties > 0) {
4356 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004357 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004358 names->length() - proto_with_hidden_properties);
4359 int dest_pos = 0;
4360 for (int i = 0; i < total_property_count; i++) {
4361 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004362 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004363 continue;
4364 }
4365 names->set(dest_pos++, name);
4366 }
4367 }
4368
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004369 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004370}
4371
4372
4373// Return the names of the local indexed properties.
4374// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004375RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004376 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004377 ASSERT(args.length() == 1);
4378 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004379 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004380 }
4381 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4382
4383 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004384 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004385 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004386 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004387}
4388
4389
4390// Return information on whether an object has a named or indexed interceptor.
4391// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004392RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004393 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004394 ASSERT(args.length() == 1);
4395 if (!args[0]->IsJSObject()) {
4396 return Smi::FromInt(0);
4397 }
4398 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4399
4400 int result = 0;
4401 if (obj->HasNamedInterceptor()) result |= 2;
4402 if (obj->HasIndexedInterceptor()) result |= 1;
4403
4404 return Smi::FromInt(result);
4405}
4406
4407
4408// Return property names from named interceptor.
4409// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004410RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004411 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004412 ASSERT(args.length() == 1);
4413 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4414
4415 if (obj->HasNamedInterceptor()) {
4416 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4417 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4418 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004419 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004420}
4421
4422
4423// Return element names from indexed interceptor.
4424// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004425RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004426 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004427 ASSERT(args.length() == 1);
4428 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4429
4430 if (obj->HasIndexedInterceptor()) {
4431 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4432 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4433 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004434 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004435}
4436
4437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004438RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004439 ASSERT_EQ(args.length(), 1);
4440 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004441 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004442 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004443
4444 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004445 // Do access checks before going to the global object.
4446 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004447 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004448 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004449 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4450 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004451 }
4452
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004453 Handle<Object> proto(object->GetPrototype());
4454 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004455 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004456 object = Handle<JSObject>::cast(proto);
4457 }
4458
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004459 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4460 LOCAL_ONLY);
4461 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4462 // property array and since the result is mutable we have to create
4463 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004464 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004465 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004466 for (int i = 0; i < length; i++) {
4467 Object* entry = contents->get(i);
4468 if (entry->IsString()) {
4469 copy->set(i, entry);
4470 } else {
4471 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004472 HandleScope scope(isolate);
4473 Handle<Object> entry_handle(entry, isolate);
4474 Handle<Object> entry_str =
4475 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004476 copy->set(i, *entry_str);
4477 }
4478 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004479 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004480}
4481
4482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004483RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004484 NoHandleAllocation ha;
4485 ASSERT(args.length() == 1);
4486
4487 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004488 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 it.AdvanceToArgumentsFrame();
4490 JavaScriptFrame* frame = it.frame();
4491
4492 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004493 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004494
4495 // Try to convert the key to an index. If successful and within
4496 // index return the the argument from the frame.
4497 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004498 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499 return frame->GetParameter(index);
4500 }
4501
4502 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004503 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004504 bool exception = false;
4505 Handle<Object> converted =
4506 Execution::ToString(args.at<Object>(0), &exception);
4507 if (exception) return Failure::Exception();
4508 Handle<String> key = Handle<String>::cast(converted);
4509
4510 // Try to convert the string key into an array index.
4511 if (key->AsArrayIndex(&index)) {
4512 if (index < n) {
4513 return frame->GetParameter(index);
4514 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004515 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004516 }
4517 }
4518
4519 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004520 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4521 if (key->Equals(isolate->heap()->callee_symbol())) {
4522 Object* function = frame->function();
4523 if (function->IsJSFunction() &&
4524 JSFunction::cast(function)->shared()->strict_mode()) {
4525 return isolate->Throw(*isolate->factory()->NewTypeError(
4526 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4527 }
4528 return function;
4529 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004530
4531 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004532 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533}
4534
4535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004536RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004537 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004538
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004539 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004540 Handle<Object> object = args.at<Object>(0);
4541 if (object->IsJSObject()) {
4542 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004543 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004544 MaybeObject* ok = js_object->TransformToFastProperties(0);
4545 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004546 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004547 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004548 return *object;
4549}
4550
4551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004552RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004553 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004554
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004555 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004556 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004557 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004558 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004559 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004560 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004561 return *object;
4562}
4563
4564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004565RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004566 NoHandleAllocation ha;
4567 ASSERT(args.length() == 1);
4568
4569 return args[0]->ToBoolean();
4570}
4571
4572
4573// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4574// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004575RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004576 NoHandleAllocation ha;
4577
4578 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004579 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004580 HeapObject* heap_obj = HeapObject::cast(obj);
4581
4582 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004583 if (heap_obj->map()->is_undetectable()) {
4584 return isolate->heap()->undefined_symbol();
4585 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586
4587 InstanceType instance_type = heap_obj->map()->instance_type();
4588 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004589 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004590 }
4591
4592 switch (instance_type) {
4593 case ODDBALL_TYPE:
4594 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004595 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004596 }
4597 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004598 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004599 }
4600 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004601 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004602 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004603 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004604 default:
4605 // For any kind of object not handled above, the spec rule for
4606 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004607 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004608 }
4609}
4610
4611
lrn@chromium.org25156de2010-04-06 13:10:27 +00004612static bool AreDigits(const char*s, int from, int to) {
4613 for (int i = from; i < to; i++) {
4614 if (s[i] < '0' || s[i] > '9') return false;
4615 }
4616
4617 return true;
4618}
4619
4620
4621static int ParseDecimalInteger(const char*s, int from, int to) {
4622 ASSERT(to - from < 10); // Overflow is not possible.
4623 ASSERT(from < to);
4624 int d = s[from] - '0';
4625
4626 for (int i = from + 1; i < to; i++) {
4627 d = 10 * d + (s[i] - '0');
4628 }
4629
4630 return d;
4631}
4632
4633
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004634RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004635 NoHandleAllocation ha;
4636 ASSERT(args.length() == 1);
4637 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004638 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004639
4640 // Fast case: short integer or some sorts of junk values.
4641 int len = subject->length();
4642 if (subject->IsSeqAsciiString()) {
4643 if (len == 0) return Smi::FromInt(0);
4644
4645 char const* data = SeqAsciiString::cast(subject)->GetChars();
4646 bool minus = (data[0] == '-');
4647 int start_pos = (minus ? 1 : 0);
4648
4649 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004650 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004651 } else if (data[start_pos] > '9') {
4652 // Fast check for a junk value. A valid string may start from a
4653 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4654 // the 'I' character ('Infinity'). All of that have codes not greater than
4655 // '9' except 'I'.
4656 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004657 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004658 }
4659 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4660 // The maximal/minimal smi has 10 digits. If the string has less digits we
4661 // know it will fit into the smi-data type.
4662 int d = ParseDecimalInteger(data, start_pos, len);
4663 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004664 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004665 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004666 } else if (!subject->HasHashCode() &&
4667 len <= String::kMaxArrayIndexSize &&
4668 (len == 1 || data[0] != '0')) {
4669 // String hash is not calculated yet but all the data are present.
4670 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004671 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004672#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004673 subject->Hash(); // Force hash calculation.
4674 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4675 static_cast<int>(hash));
4676#endif
4677 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004678 }
4679 return Smi::FromInt(d);
4680 }
4681 }
4682
4683 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004684 return isolate->heap()->NumberFromDouble(
4685 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004686}
4687
4688
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004689RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004690 NoHandleAllocation ha;
4691 ASSERT(args.length() == 1);
4692
4693 CONVERT_CHECKED(JSArray, codes, args[0]);
4694 int length = Smi::cast(codes->length())->value();
4695
4696 // Check if the string can be ASCII.
4697 int i;
4698 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004699 Object* element;
4700 { MaybeObject* maybe_element = codes->GetElement(i);
4701 // We probably can't get an exception here, but just in order to enforce
4702 // the checking of inputs in the runtime calls we check here.
4703 if (!maybe_element->ToObject(&element)) return maybe_element;
4704 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004705 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4706 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4707 break;
4708 }
4709
lrn@chromium.org303ada72010-10-27 09:33:13 +00004710 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004712 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004713 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004714 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004715 }
4716
lrn@chromium.org303ada72010-10-27 09:33:13 +00004717 Object* object = NULL;
4718 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004719 String* result = String::cast(object);
4720 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004721 Object* element;
4722 { MaybeObject* maybe_element = codes->GetElement(i);
4723 if (!maybe_element->ToObject(&element)) return maybe_element;
4724 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004726 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004727 }
4728 return result;
4729}
4730
4731
4732// kNotEscaped is generated by the following:
4733//
4734// #!/bin/perl
4735// for (my $i = 0; $i < 256; $i++) {
4736// print "\n" if $i % 16 == 0;
4737// my $c = chr($i);
4738// my $escaped = 1;
4739// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4740// print $escaped ? "0, " : "1, ";
4741// }
4742
4743
4744static bool IsNotEscaped(uint16_t character) {
4745 // Only for 8 bit characters, the rest are always escaped (in a different way)
4746 ASSERT(character < 256);
4747 static const char kNotEscaped[256] = {
4748 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4749 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4750 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4751 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4752 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4753 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4754 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4755 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4756 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4757 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4758 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4759 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4760 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4761 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4762 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4763 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4764 };
4765 return kNotEscaped[character] != 0;
4766}
4767
4768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004769RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004770 const char hex_chars[] = "0123456789ABCDEF";
4771 NoHandleAllocation ha;
4772 ASSERT(args.length() == 1);
4773 CONVERT_CHECKED(String, source, args[0]);
4774
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004775 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004776
4777 int escaped_length = 0;
4778 int length = source->length();
4779 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004780 Access<StringInputBuffer> buffer(
4781 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004782 buffer->Reset(source);
4783 while (buffer->has_more()) {
4784 uint16_t character = buffer->GetNext();
4785 if (character >= 256) {
4786 escaped_length += 6;
4787 } else if (IsNotEscaped(character)) {
4788 escaped_length++;
4789 } else {
4790 escaped_length += 3;
4791 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004792 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004793 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004794 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004795 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004796 return Failure::OutOfMemoryException();
4797 }
4798 }
4799 }
4800 // No length change implies no change. Return original string if no change.
4801 if (escaped_length == length) {
4802 return source;
4803 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004804 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004805 { MaybeObject* maybe_o =
4806 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004807 if (!maybe_o->ToObject(&o)) return maybe_o;
4808 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004809 String* destination = String::cast(o);
4810 int dest_position = 0;
4811
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004812 Access<StringInputBuffer> buffer(
4813 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814 buffer->Rewind();
4815 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004816 uint16_t chr = buffer->GetNext();
4817 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004818 destination->Set(dest_position, '%');
4819 destination->Set(dest_position+1, 'u');
4820 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4821 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4822 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4823 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004825 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004826 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827 dest_position++;
4828 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004829 destination->Set(dest_position, '%');
4830 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4831 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004832 dest_position += 3;
4833 }
4834 }
4835 return destination;
4836}
4837
4838
4839static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4840 static const signed char kHexValue['g'] = {
4841 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4842 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4843 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4844 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4845 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4846 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4847 -1, 10, 11, 12, 13, 14, 15 };
4848
4849 if (character1 > 'f') return -1;
4850 int hi = kHexValue[character1];
4851 if (hi == -1) return -1;
4852 if (character2 > 'f') return -1;
4853 int lo = kHexValue[character2];
4854 if (lo == -1) return -1;
4855 return (hi << 4) + lo;
4856}
4857
4858
ager@chromium.org870a0b62008-11-04 11:43:05 +00004859static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004860 int i,
4861 int length,
4862 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004863 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004864 int32_t hi = 0;
4865 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866 if (character == '%' &&
4867 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004868 source->Get(i + 1) == 'u' &&
4869 (hi = TwoDigitHex(source->Get(i + 2),
4870 source->Get(i + 3))) != -1 &&
4871 (lo = TwoDigitHex(source->Get(i + 4),
4872 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004873 *step = 6;
4874 return (hi << 8) + lo;
4875 } else if (character == '%' &&
4876 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004877 (lo = TwoDigitHex(source->Get(i + 1),
4878 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004879 *step = 3;
4880 return lo;
4881 } else {
4882 *step = 1;
4883 return character;
4884 }
4885}
4886
4887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004888RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004889 NoHandleAllocation ha;
4890 ASSERT(args.length() == 1);
4891 CONVERT_CHECKED(String, source, args[0]);
4892
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004893 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004894
4895 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004896 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004897
4898 int unescaped_length = 0;
4899 for (int i = 0; i < length; unescaped_length++) {
4900 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004901 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004902 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004903 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004904 i += step;
4905 }
4906
4907 // No length change implies no change. Return original string if no change.
4908 if (unescaped_length == length)
4909 return source;
4910
lrn@chromium.org303ada72010-10-27 09:33:13 +00004911 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004912 { MaybeObject* maybe_o =
4913 ascii ?
4914 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4915 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004916 if (!maybe_o->ToObject(&o)) return maybe_o;
4917 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004918 String* destination = String::cast(o);
4919
4920 int dest_position = 0;
4921 for (int i = 0; i < length; dest_position++) {
4922 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004923 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004924 i += step;
4925 }
4926 return destination;
4927}
4928
4929
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004930static const unsigned int kQuoteTableLength = 128u;
4931
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004932static const int kJsonQuotesCharactersPerEntry = 8;
4933static const char* const JsonQuotes =
4934 "\\u0000 \\u0001 \\u0002 \\u0003 "
4935 "\\u0004 \\u0005 \\u0006 \\u0007 "
4936 "\\b \\t \\n \\u000b "
4937 "\\f \\r \\u000e \\u000f "
4938 "\\u0010 \\u0011 \\u0012 \\u0013 "
4939 "\\u0014 \\u0015 \\u0016 \\u0017 "
4940 "\\u0018 \\u0019 \\u001a \\u001b "
4941 "\\u001c \\u001d \\u001e \\u001f "
4942 " ! \\\" # "
4943 "$ % & ' "
4944 "( ) * + "
4945 ", - . / "
4946 "0 1 2 3 "
4947 "4 5 6 7 "
4948 "8 9 : ; "
4949 "< = > ? "
4950 "@ A B C "
4951 "D E F G "
4952 "H I J K "
4953 "L M N O "
4954 "P Q R S "
4955 "T U V W "
4956 "X Y Z [ "
4957 "\\\\ ] ^ _ "
4958 "` a b c "
4959 "d e f g "
4960 "h i j k "
4961 "l m n o "
4962 "p q r s "
4963 "t u v w "
4964 "x y z { "
4965 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004966
4967
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004968// For a string that is less than 32k characters it should always be
4969// possible to allocate it in new space.
4970static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4971
4972
4973// Doing JSON quoting cannot make the string more than this many times larger.
4974static const int kJsonQuoteWorstCaseBlowup = 6;
4975
4976
4977// Covers the entire ASCII range (all other characters are unchanged by JSON
4978// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004979static const byte JsonQuoteLengths[kQuoteTableLength] = {
4980 6, 6, 6, 6, 6, 6, 6, 6,
4981 2, 2, 2, 6, 2, 2, 6, 6,
4982 6, 6, 6, 6, 6, 6, 6, 6,
4983 6, 6, 6, 6, 6, 6, 6, 6,
4984 1, 1, 2, 1, 1, 1, 1, 1,
4985 1, 1, 1, 1, 1, 1, 1, 1,
4986 1, 1, 1, 1, 1, 1, 1, 1,
4987 1, 1, 1, 1, 1, 1, 1, 1,
4988 1, 1, 1, 1, 1, 1, 1, 1,
4989 1, 1, 1, 1, 1, 1, 1, 1,
4990 1, 1, 1, 1, 1, 1, 1, 1,
4991 1, 1, 1, 1, 2, 1, 1, 1,
4992 1, 1, 1, 1, 1, 1, 1, 1,
4993 1, 1, 1, 1, 1, 1, 1, 1,
4994 1, 1, 1, 1, 1, 1, 1, 1,
4995 1, 1, 1, 1, 1, 1, 1, 1,
4996};
4997
4998
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004999template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005000MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005001
5002
5003template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005004MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5005 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005006}
5007
5008
5009template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005010MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5011 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005012}
5013
5014
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005015template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005016static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5017 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005018 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005019 const Char* read_cursor = characters.start();
5020 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005021 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005022 int quoted_length = kSpaceForQuotes;
5023 while (read_cursor < end) {
5024 Char c = *(read_cursor++);
5025 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5026 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005027 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005028 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005029 }
5030 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005031 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5032 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005033 Object* new_object;
5034 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005035 return new_alloc;
5036 }
5037 StringType* new_string = StringType::cast(new_object);
5038
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005039 Char* write_cursor = reinterpret_cast<Char*>(
5040 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005041 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005042 *(write_cursor++) = '"';
5043
5044 read_cursor = characters.start();
5045 while (read_cursor < end) {
5046 Char c = *(read_cursor++);
5047 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5048 *(write_cursor++) = c;
5049 } else {
5050 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5051 const char* replacement = JsonQuotes +
5052 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5053 for (int i = 0; i < len; i++) {
5054 *write_cursor++ = *replacement++;
5055 }
5056 }
5057 }
5058 *(write_cursor++) = '"';
5059 return new_string;
5060}
5061
5062
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005063template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005064static MaybeObject* QuoteJsonString(Isolate* isolate,
5065 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005066 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005067 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005068 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005069 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5070 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005071 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005072 }
5073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005074 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5075 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005076 Object* new_object;
5077 if (!new_alloc->ToObject(&new_object)) {
5078 return new_alloc;
5079 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005080 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005081 // Even if our string is small enough to fit in new space we still have to
5082 // handle it being allocated in old space as may happen in the third
5083 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5084 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005085 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005086 }
5087 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005088 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005089
5090 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5091 Char* write_cursor = reinterpret_cast<Char*>(
5092 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005093 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005094 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005095
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005096 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005097 const Char* end = read_cursor + length;
5098 while (read_cursor < end) {
5099 Char c = *(read_cursor++);
5100 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5101 *(write_cursor++) = c;
5102 } else {
5103 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5104 const char* replacement = JsonQuotes +
5105 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5106 write_cursor[0] = replacement[0];
5107 if (len > 1) {
5108 write_cursor[1] = replacement[1];
5109 if (len > 2) {
5110 ASSERT(len == 6);
5111 write_cursor[2] = replacement[2];
5112 write_cursor[3] = replacement[3];
5113 write_cursor[4] = replacement[4];
5114 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005115 }
5116 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005117 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005118 }
5119 }
5120 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005121
5122 int final_length = static_cast<int>(
5123 write_cursor - reinterpret_cast<Char*>(
5124 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005125 isolate->heap()->new_space()->
5126 template ShrinkStringAtAllocationBoundary<StringType>(
5127 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005128 return new_string;
5129}
5130
5131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005132RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005133 NoHandleAllocation ha;
5134 CONVERT_CHECKED(String, str, args[0]);
5135 if (!str->IsFlat()) {
5136 MaybeObject* try_flatten = str->TryFlatten();
5137 Object* flat;
5138 if (!try_flatten->ToObject(&flat)) {
5139 return try_flatten;
5140 }
5141 str = String::cast(flat);
5142 ASSERT(str->IsFlat());
5143 }
5144 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005145 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5146 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005147 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005148 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5149 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005150 }
5151}
5152
5153
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005154RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005155 NoHandleAllocation ha;
5156 CONVERT_CHECKED(String, str, args[0]);
5157 if (!str->IsFlat()) {
5158 MaybeObject* try_flatten = str->TryFlatten();
5159 Object* flat;
5160 if (!try_flatten->ToObject(&flat)) {
5161 return try_flatten;
5162 }
5163 str = String::cast(flat);
5164 ASSERT(str->IsFlat());
5165 }
5166 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005167 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5168 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005169 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005170 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5171 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005172 }
5173}
5174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005175RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005176 NoHandleAllocation ha;
5177
5178 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005179 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005180
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005181 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005182
lrn@chromium.org25156de2010-04-06 13:10:27 +00005183 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005184 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005185 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005186}
5187
5188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005189RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005190 NoHandleAllocation ha;
5191 CONVERT_CHECKED(String, str, args[0]);
5192
5193 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005194 double value = StringToDouble(isolate->unicode_cache(),
5195 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196
5197 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005198 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005199}
5200
5201
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005202template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005203MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005204 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005205 String* s,
5206 int length,
5207 int input_string_length,
5208 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005209 // We try this twice, once with the assumption that the result is no longer
5210 // than the input and, if that assumption breaks, again with the exact
5211 // length. This may not be pretty, but it is nicer than what was here before
5212 // and I hereby claim my vaffel-is.
5213 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005214 // Allocate the resulting string.
5215 //
5216 // NOTE: This assumes that the upper/lower case of an ascii
5217 // character is also ascii. This is currently the case, but it
5218 // might break in the future if we implement more context and locale
5219 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005220 Object* o;
5221 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005222 ? isolate->heap()->AllocateRawAsciiString(length)
5223 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005224 if (!maybe_o->ToObject(&o)) return maybe_o;
5225 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226 String* result = String::cast(o);
5227 bool has_changed_character = false;
5228
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005229 // Convert all characters to upper case, assuming that they will fit
5230 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005231 Access<StringInputBuffer> buffer(
5232 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005233 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005234 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005235 // We can assume that the string is not empty
5236 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005237 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005238 bool has_next = buffer->has_more();
5239 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005240 int char_length = mapping->get(current, next, chars);
5241 if (char_length == 0) {
5242 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005243 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005244 i++;
5245 } else if (char_length == 1) {
5246 // Common case: converting the letter resulted in one character.
5247 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005248 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005249 has_changed_character = true;
5250 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005251 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005252 // We've assumed that the result would be as long as the
5253 // input but here is a character that converts to several
5254 // characters. No matter, we calculate the exact length
5255 // of the result and try the whole thing again.
5256 //
5257 // Note that this leaves room for optimization. We could just
5258 // memcpy what we already have to the result string. Also,
5259 // the result string is the last object allocated we could
5260 // "realloc" it and probably, in the vast majority of cases,
5261 // extend the existing string to be able to hold the full
5262 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005263 int next_length = 0;
5264 if (has_next) {
5265 next_length = mapping->get(next, 0, chars);
5266 if (next_length == 0) next_length = 1;
5267 }
5268 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005269 while (buffer->has_more()) {
5270 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005271 // NOTE: we use 0 as the next character here because, while
5272 // the next character may affect what a character converts to,
5273 // it does not in any case affect the length of what it convert
5274 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005275 int char_length = mapping->get(current, 0, chars);
5276 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005277 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005278 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005279 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005280 return Failure::OutOfMemoryException();
5281 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005282 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005283 // Try again with the real length.
5284 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005285 } else {
5286 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005287 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005288 i++;
5289 }
5290 has_changed_character = true;
5291 }
5292 current = next;
5293 }
5294 if (has_changed_character) {
5295 return result;
5296 } else {
5297 // If we didn't actually change anything in doing the conversion
5298 // we simple return the result and let the converted string
5299 // become garbage; there is no reason to keep two identical strings
5300 // alive.
5301 return s;
5302 }
5303}
5304
5305
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005306namespace {
5307
lrn@chromium.org303ada72010-10-27 09:33:13 +00005308static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5309
5310
5311// Given a word and two range boundaries returns a word with high bit
5312// set in every byte iff the corresponding input byte was strictly in
5313// the range (m, n). All the other bits in the result are cleared.
5314// This function is only useful when it can be inlined and the
5315// boundaries are statically known.
5316// Requires: all bytes in the input word and the boundaries must be
5317// ascii (less than 0x7F).
5318static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5319 // Every byte in an ascii string is less than or equal to 0x7F.
5320 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5321 // Use strict inequalities since in edge cases the function could be
5322 // further simplified.
5323 ASSERT(0 < m && m < n && n < 0x7F);
5324 // Has high bit set in every w byte less than n.
5325 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5326 // Has high bit set in every w byte greater than m.
5327 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5328 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5329}
5330
5331
5332enum AsciiCaseConversion {
5333 ASCII_TO_LOWER,
5334 ASCII_TO_UPPER
5335};
5336
5337
5338template <AsciiCaseConversion dir>
5339struct FastAsciiConverter {
5340 static bool Convert(char* dst, char* src, int length) {
5341#ifdef DEBUG
5342 char* saved_dst = dst;
5343 char* saved_src = src;
5344#endif
5345 // We rely on the distance between upper and lower case letters
5346 // being a known power of 2.
5347 ASSERT('a' - 'A' == (1 << 5));
5348 // Boundaries for the range of input characters than require conversion.
5349 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5350 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5351 bool changed = false;
5352 char* const limit = src + length;
5353#ifdef V8_HOST_CAN_READ_UNALIGNED
5354 // Process the prefix of the input that requires no conversion one
5355 // (machine) word at a time.
5356 while (src <= limit - sizeof(uintptr_t)) {
5357 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5358 if (AsciiRangeMask(w, lo, hi) != 0) {
5359 changed = true;
5360 break;
5361 }
5362 *reinterpret_cast<uintptr_t*>(dst) = w;
5363 src += sizeof(uintptr_t);
5364 dst += sizeof(uintptr_t);
5365 }
5366 // Process the remainder of the input performing conversion when
5367 // required one word at a time.
5368 while (src <= limit - sizeof(uintptr_t)) {
5369 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5370 uintptr_t m = AsciiRangeMask(w, lo, hi);
5371 // The mask has high (7th) bit set in every byte that needs
5372 // conversion and we know that the distance between cases is
5373 // 1 << 5.
5374 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5375 src += sizeof(uintptr_t);
5376 dst += sizeof(uintptr_t);
5377 }
5378#endif
5379 // Process the last few bytes of the input (or the whole input if
5380 // unaligned access is not supported).
5381 while (src < limit) {
5382 char c = *src;
5383 if (lo < c && c < hi) {
5384 c ^= (1 << 5);
5385 changed = true;
5386 }
5387 *dst = c;
5388 ++src;
5389 ++dst;
5390 }
5391#ifdef DEBUG
5392 CheckConvert(saved_dst, saved_src, length, changed);
5393#endif
5394 return changed;
5395 }
5396
5397#ifdef DEBUG
5398 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5399 bool expected_changed = false;
5400 for (int i = 0; i < length; i++) {
5401 if (dst[i] == src[i]) continue;
5402 expected_changed = true;
5403 if (dir == ASCII_TO_LOWER) {
5404 ASSERT('A' <= src[i] && src[i] <= 'Z');
5405 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5406 } else {
5407 ASSERT(dir == ASCII_TO_UPPER);
5408 ASSERT('a' <= src[i] && src[i] <= 'z');
5409 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5410 }
5411 }
5412 ASSERT(expected_changed == changed);
5413 }
5414#endif
5415};
5416
5417
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005418struct ToLowerTraits {
5419 typedef unibrow::ToLowercase UnibrowConverter;
5420
lrn@chromium.org303ada72010-10-27 09:33:13 +00005421 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005422};
5423
5424
5425struct ToUpperTraits {
5426 typedef unibrow::ToUppercase UnibrowConverter;
5427
lrn@chromium.org303ada72010-10-27 09:33:13 +00005428 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005429};
5430
5431} // namespace
5432
5433
5434template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005435MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005436 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005437 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005438 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005439 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005440 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005441 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005442
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005443 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005444 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005445 if (length == 0) return s;
5446
5447 // Simpler handling of ascii strings.
5448 //
5449 // NOTE: This assumes that the upper/lower case of an ascii
5450 // character is also ascii. This is currently the case, but it
5451 // might break in the future if we implement more context and locale
5452 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005453 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005454 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005455 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005456 if (!maybe_o->ToObject(&o)) return maybe_o;
5457 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005458 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005459 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005460 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005461 return has_changed_character ? result : s;
5462 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005463
lrn@chromium.org303ada72010-10-27 09:33:13 +00005464 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005465 { MaybeObject* maybe_answer =
5466 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005467 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5468 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005469 if (answer->IsSmi()) {
5470 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005471 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005472 ConvertCaseHelper(isolate,
5473 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005474 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5475 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005476 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005477 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005478}
5479
5480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005481RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005482 return ConvertCase<ToLowerTraits>(
5483 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005484}
5485
5486
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005487RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005488 return ConvertCase<ToUpperTraits>(
5489 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005490}
5491
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005492
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005493static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5494 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5495}
5496
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005498RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005499 NoHandleAllocation ha;
5500 ASSERT(args.length() == 3);
5501
5502 CONVERT_CHECKED(String, s, args[0]);
5503 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5504 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5505
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005506 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005507 int length = s->length();
5508
5509 int left = 0;
5510 if (trimLeft) {
5511 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5512 left++;
5513 }
5514 }
5515
5516 int right = length;
5517 if (trimRight) {
5518 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5519 right--;
5520 }
5521 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005522 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005523}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005524
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005525
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005526template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005527void FindStringIndices(Isolate* isolate,
5528 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005529 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005530 ZoneList<int>* indices,
5531 unsigned int limit) {
5532 ASSERT(limit > 0);
5533 // Collect indices of pattern in subject, and the end-of-string index.
5534 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005535 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005536 int pattern_length = pattern.length();
5537 int index = 0;
5538 while (limit > 0) {
5539 index = search.Search(subject, index);
5540 if (index < 0) return;
5541 indices->Add(index);
5542 index += pattern_length;
5543 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005544 }
5545}
5546
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005548RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005549 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005550 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005551 CONVERT_ARG_CHECKED(String, subject, 0);
5552 CONVERT_ARG_CHECKED(String, pattern, 1);
5553 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5554
5555 int subject_length = subject->length();
5556 int pattern_length = pattern->length();
5557 RUNTIME_ASSERT(pattern_length > 0);
5558
5559 // The limit can be very large (0xffffffffu), but since the pattern
5560 // isn't empty, we can never create more parts than ~half the length
5561 // of the subject.
5562
5563 if (!subject->IsFlat()) FlattenString(subject);
5564
5565 static const int kMaxInitialListCapacity = 16;
5566
5567 ZoneScope scope(DELETE_ON_EXIT);
5568
5569 // Find (up to limit) indices of separator and end-of-string in subject
5570 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5571 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005572 if (!pattern->IsFlat()) FlattenString(pattern);
5573
5574 // No allocation block.
5575 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005576 AssertNoAllocation nogc;
5577 if (subject->IsAsciiRepresentation()) {
5578 Vector<const char> subject_vector = subject->ToAsciiVector();
5579 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005580 FindStringIndices(isolate,
5581 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005582 pattern->ToAsciiVector(),
5583 &indices,
5584 limit);
5585 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005586 FindStringIndices(isolate,
5587 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005588 pattern->ToUC16Vector(),
5589 &indices,
5590 limit);
5591 }
5592 } else {
5593 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5594 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005595 FindStringIndices(isolate,
5596 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005597 pattern->ToAsciiVector(),
5598 &indices,
5599 limit);
5600 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005601 FindStringIndices(isolate,
5602 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005603 pattern->ToUC16Vector(),
5604 &indices,
5605 limit);
5606 }
5607 }
5608 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005609
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005610 if (static_cast<uint32_t>(indices.length()) < limit) {
5611 indices.Add(subject_length);
5612 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005613
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005614 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005615
5616 // Create JSArray of substrings separated by separator.
5617 int part_count = indices.length();
5618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005619 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005620 result->set_length(Smi::FromInt(part_count));
5621
5622 ASSERT(result->HasFastElements());
5623
5624 if (part_count == 1 && indices.at(0) == subject_length) {
5625 FixedArray::cast(result->elements())->set(0, *subject);
5626 return *result;
5627 }
5628
5629 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5630 int part_start = 0;
5631 for (int i = 0; i < part_count; i++) {
5632 HandleScope local_loop_handle;
5633 int part_end = indices.at(i);
5634 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005635 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005636 elements->set(i, *substring);
5637 part_start = part_end + pattern_length;
5638 }
5639
5640 return *result;
5641}
5642
5643
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005644// Copies ascii characters to the given fixed array looking up
5645// one-char strings in the cache. Gives up on the first char that is
5646// not in the cache and fills the remainder with smi zeros. Returns
5647// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005648static int CopyCachedAsciiCharsToArray(Heap* heap,
5649 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005650 FixedArray* elements,
5651 int length) {
5652 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005653 FixedArray* ascii_cache = heap->single_character_string_cache();
5654 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005655 int i;
5656 for (i = 0; i < length; ++i) {
5657 Object* value = ascii_cache->get(chars[i]);
5658 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005659 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005660 elements->set(i, value, SKIP_WRITE_BARRIER);
5661 }
5662 if (i < length) {
5663 ASSERT(Smi::FromInt(0) == 0);
5664 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5665 }
5666#ifdef DEBUG
5667 for (int j = 0; j < length; ++j) {
5668 Object* element = elements->get(j);
5669 ASSERT(element == Smi::FromInt(0) ||
5670 (element->IsString() && String::cast(element)->LooksValid()));
5671 }
5672#endif
5673 return i;
5674}
5675
5676
5677// Converts a String to JSArray.
5678// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005679RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005680 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005681 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005682 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005683 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005684
5685 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005686 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005687
5688 Handle<FixedArray> elements;
5689 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005690 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005691 { MaybeObject* maybe_obj =
5692 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005693 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5694 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005695 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005696
5697 Vector<const char> chars = s->ToAsciiVector();
5698 // Note, this will initialize all elements (not only the prefix)
5699 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005700 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5701 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005702 *elements,
5703 length);
5704
5705 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005706 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5707 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005708 }
5709 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005710 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005711 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005712 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5713 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005714 }
5715 }
5716
5717#ifdef DEBUG
5718 for (int i = 0; i < length; ++i) {
5719 ASSERT(String::cast(elements->get(i))->length() == 1);
5720 }
5721#endif
5722
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005723 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005724}
5725
5726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005727RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005728 NoHandleAllocation ha;
5729 ASSERT(args.length() == 1);
5730 CONVERT_CHECKED(String, value, args[0]);
5731 return value->ToObject();
5732}
5733
5734
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005735bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005736 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005737 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005738 return char_length == 0;
5739}
5740
5741
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005742RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005743 NoHandleAllocation ha;
5744 ASSERT(args.length() == 1);
5745
5746 Object* number = args[0];
5747 RUNTIME_ASSERT(number->IsNumber());
5748
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005749 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005750}
5751
5752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005753RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005754 NoHandleAllocation ha;
5755 ASSERT(args.length() == 1);
5756
5757 Object* number = args[0];
5758 RUNTIME_ASSERT(number->IsNumber());
5759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005760 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005761}
5762
5763
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005764RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005765 NoHandleAllocation ha;
5766 ASSERT(args.length() == 1);
5767
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005768 CONVERT_DOUBLE_CHECKED(number, args[0]);
5769
5770 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5771 if (number > 0 && number <= Smi::kMaxValue) {
5772 return Smi::FromInt(static_cast<int>(number));
5773 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005774 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005775}
5776
5777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005778RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005779 NoHandleAllocation ha;
5780 ASSERT(args.length() == 1);
5781
5782 CONVERT_DOUBLE_CHECKED(number, args[0]);
5783
5784 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5785 if (number > 0 && number <= Smi::kMaxValue) {
5786 return Smi::FromInt(static_cast<int>(number));
5787 }
5788
5789 double double_value = DoubleToInteger(number);
5790 // Map both -0 and +0 to +0.
5791 if (double_value == 0) double_value = 0;
5792
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005794}
5795
5796
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005797RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005798 NoHandleAllocation ha;
5799 ASSERT(args.length() == 1);
5800
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005801 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005802 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005803}
5804
5805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005806RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005807 NoHandleAllocation ha;
5808 ASSERT(args.length() == 1);
5809
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005810 CONVERT_DOUBLE_CHECKED(number, args[0]);
5811
5812 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5813 if (number > 0 && number <= Smi::kMaxValue) {
5814 return Smi::FromInt(static_cast<int>(number));
5815 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005816 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005817}
5818
5819
ager@chromium.org870a0b62008-11-04 11:43:05 +00005820// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5821// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005822RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005823 NoHandleAllocation ha;
5824 ASSERT(args.length() == 1);
5825
5826 Object* obj = args[0];
5827 if (obj->IsSmi()) {
5828 return obj;
5829 }
5830 if (obj->IsHeapNumber()) {
5831 double value = HeapNumber::cast(obj)->value();
5832 int int_value = FastD2I(value);
5833 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5834 return Smi::FromInt(int_value);
5835 }
5836 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005837 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005838}
5839
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005841RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005842 NoHandleAllocation ha;
5843 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005844 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005845}
5846
5847
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005848RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005849 NoHandleAllocation ha;
5850 ASSERT(args.length() == 2);
5851
5852 CONVERT_DOUBLE_CHECKED(x, args[0]);
5853 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005854 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005855}
5856
5857
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005858RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005859 NoHandleAllocation ha;
5860 ASSERT(args.length() == 2);
5861
5862 CONVERT_DOUBLE_CHECKED(x, args[0]);
5863 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005864 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005865}
5866
5867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005868RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005869 NoHandleAllocation ha;
5870 ASSERT(args.length() == 2);
5871
5872 CONVERT_DOUBLE_CHECKED(x, args[0]);
5873 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005874 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005875}
5876
5877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005878RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005879 NoHandleAllocation ha;
5880 ASSERT(args.length() == 1);
5881
5882 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005883 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005884}
5885
5886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005887RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005888 NoHandleAllocation ha;
5889 ASSERT(args.length() == 0);
5890
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005891 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005892}
5893
5894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005895RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005896 NoHandleAllocation ha;
5897 ASSERT(args.length() == 2);
5898
5899 CONVERT_DOUBLE_CHECKED(x, args[0]);
5900 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005901 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005902}
5903
5904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005905RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005906 NoHandleAllocation ha;
5907 ASSERT(args.length() == 2);
5908
5909 CONVERT_DOUBLE_CHECKED(x, args[0]);
5910 CONVERT_DOUBLE_CHECKED(y, args[1]);
5911
ager@chromium.org3811b432009-10-28 14:53:37 +00005912 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005913 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005914 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005915}
5916
5917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005918RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005919 NoHandleAllocation ha;
5920 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921 CONVERT_CHECKED(String, str1, args[0]);
5922 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005923 isolate->counters()->string_add_runtime()->Increment();
5924 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005925}
5926
5927
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005928template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005929static inline void StringBuilderConcatHelper(String* special,
5930 sinkchar* sink,
5931 FixedArray* fixed_array,
5932 int array_length) {
5933 int position = 0;
5934 for (int i = 0; i < array_length; i++) {
5935 Object* element = fixed_array->get(i);
5936 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005937 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005938 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005939 int pos;
5940 int len;
5941 if (encoded_slice > 0) {
5942 // Position and length encoded in one smi.
5943 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5944 len = StringBuilderSubstringLength::decode(encoded_slice);
5945 } else {
5946 // Position and length encoded in two smis.
5947 Object* obj = fixed_array->get(++i);
5948 ASSERT(obj->IsSmi());
5949 pos = Smi::cast(obj)->value();
5950 len = -encoded_slice;
5951 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005952 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005953 sink + position,
5954 pos,
5955 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005956 position += len;
5957 } else {
5958 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005959 int element_length = string->length();
5960 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005961 position += element_length;
5962 }
5963 }
5964}
5965
5966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005968 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005969 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005970 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005971 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005972 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005973 return Failure::OutOfMemoryException();
5974 }
5975 int array_length = Smi::cast(args[1])->value();
5976 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005977
5978 // This assumption is used by the slice encoding in one or two smis.
5979 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5980
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005981 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005983 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005984 }
5985 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005986 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005987 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005988 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989
5990 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005991 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992 } else if (array_length == 1) {
5993 Object* first = fixed_array->get(0);
5994 if (first->IsString()) return first;
5995 }
5996
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005997 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 int position = 0;
5999 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006000 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001 Object* elt = fixed_array->get(i);
6002 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006003 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006004 int smi_value = Smi::cast(elt)->value();
6005 int pos;
6006 int len;
6007 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006008 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006009 pos = StringBuilderSubstringPosition::decode(smi_value);
6010 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006011 } else {
6012 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006013 len = -smi_value;
6014 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006015 i++;
6016 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006017 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006018 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006019 Object* next_smi = fixed_array->get(i);
6020 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006021 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006022 }
6023 pos = Smi::cast(next_smi)->value();
6024 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006025 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006026 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006028 ASSERT(pos >= 0);
6029 ASSERT(len >= 0);
6030 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006031 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006032 }
6033 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006034 } else if (elt->IsString()) {
6035 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006036 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006037 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006038 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006039 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006040 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006041 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006042 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006043 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006044 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006045 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006046 return Failure::OutOfMemoryException();
6047 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006048 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006049 }
6050
6051 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006052 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006053
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006054 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006055 { MaybeObject* maybe_object =
6056 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006057 if (!maybe_object->ToObject(&object)) return maybe_object;
6058 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006059 SeqAsciiString* answer = SeqAsciiString::cast(object);
6060 StringBuilderConcatHelper(special,
6061 answer->GetChars(),
6062 fixed_array,
6063 array_length);
6064 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006065 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006066 { MaybeObject* maybe_object =
6067 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006068 if (!maybe_object->ToObject(&object)) return maybe_object;
6069 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006070 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6071 StringBuilderConcatHelper(special,
6072 answer->GetChars(),
6073 fixed_array,
6074 array_length);
6075 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006077}
6078
6079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006080RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006081 NoHandleAllocation ha;
6082 ASSERT(args.length() == 3);
6083 CONVERT_CHECKED(JSArray, array, args[0]);
6084 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006085 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006086 return Failure::OutOfMemoryException();
6087 }
6088 int array_length = Smi::cast(args[1])->value();
6089 CONVERT_CHECKED(String, separator, args[2]);
6090
6091 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006092 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006093 }
6094 FixedArray* fixed_array = FixedArray::cast(array->elements());
6095 if (fixed_array->length() < array_length) {
6096 array_length = fixed_array->length();
6097 }
6098
6099 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006100 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006101 } else if (array_length == 1) {
6102 Object* first = fixed_array->get(0);
6103 if (first->IsString()) return first;
6104 }
6105
6106 int separator_length = separator->length();
6107 int max_nof_separators =
6108 (String::kMaxLength + separator_length - 1) / separator_length;
6109 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006110 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006111 return Failure::OutOfMemoryException();
6112 }
6113 int length = (array_length - 1) * separator_length;
6114 for (int i = 0; i < array_length; i++) {
6115 Object* element_obj = fixed_array->get(i);
6116 if (!element_obj->IsString()) {
6117 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006118 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006119 }
6120 String* element = String::cast(element_obj);
6121 int increment = element->length();
6122 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006123 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006124 return Failure::OutOfMemoryException();
6125 }
6126 length += increment;
6127 }
6128
6129 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006130 { MaybeObject* maybe_object =
6131 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006132 if (!maybe_object->ToObject(&object)) return maybe_object;
6133 }
6134 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6135
6136 uc16* sink = answer->GetChars();
6137#ifdef DEBUG
6138 uc16* end = sink + length;
6139#endif
6140
6141 String* first = String::cast(fixed_array->get(0));
6142 int first_length = first->length();
6143 String::WriteToFlat(first, sink, 0, first_length);
6144 sink += first_length;
6145
6146 for (int i = 1; i < array_length; i++) {
6147 ASSERT(sink + separator_length <= end);
6148 String::WriteToFlat(separator, sink, 0, separator_length);
6149 sink += separator_length;
6150
6151 String* element = String::cast(fixed_array->get(i));
6152 int element_length = element->length();
6153 ASSERT(sink + element_length <= end);
6154 String::WriteToFlat(element, sink, 0, element_length);
6155 sink += element_length;
6156 }
6157 ASSERT(sink == end);
6158
6159 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6160 return answer;
6161}
6162
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006163template <typename Char>
6164static void JoinSparseArrayWithSeparator(FixedArray* elements,
6165 int elements_length,
6166 uint32_t array_length,
6167 String* separator,
6168 Vector<Char> buffer) {
6169 int previous_separator_position = 0;
6170 int separator_length = separator->length();
6171 int cursor = 0;
6172 for (int i = 0; i < elements_length; i += 2) {
6173 int position = NumberToInt32(elements->get(i));
6174 String* string = String::cast(elements->get(i + 1));
6175 int string_length = string->length();
6176 if (string->length() > 0) {
6177 while (previous_separator_position < position) {
6178 String::WriteToFlat<Char>(separator, &buffer[cursor],
6179 0, separator_length);
6180 cursor += separator_length;
6181 previous_separator_position++;
6182 }
6183 String::WriteToFlat<Char>(string, &buffer[cursor],
6184 0, string_length);
6185 cursor += string->length();
6186 }
6187 }
6188 if (separator_length > 0) {
6189 // Array length must be representable as a signed 32-bit number,
6190 // otherwise the total string length would have been too large.
6191 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6192 int last_array_index = static_cast<int>(array_length - 1);
6193 while (previous_separator_position < last_array_index) {
6194 String::WriteToFlat<Char>(separator, &buffer[cursor],
6195 0, separator_length);
6196 cursor += separator_length;
6197 previous_separator_position++;
6198 }
6199 }
6200 ASSERT(cursor <= buffer.length());
6201}
6202
6203
6204RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6205 NoHandleAllocation ha;
6206 ASSERT(args.length() == 3);
6207 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6208 RUNTIME_ASSERT(elements_array->HasFastElements());
6209 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6210 CONVERT_CHECKED(String, separator, args[2]);
6211 // elements_array is fast-mode JSarray of alternating positions
6212 // (increasing order) and strings.
6213 // array_length is length of original array (used to add separators);
6214 // separator is string to put between elements. Assumed to be non-empty.
6215
6216 // Find total length of join result.
6217 int string_length = 0;
6218 bool is_ascii = true;
6219 int max_string_length = SeqAsciiString::kMaxLength;
6220 bool overflow = false;
6221 CONVERT_NUMBER_CHECKED(int, elements_length,
6222 Int32, elements_array->length());
6223 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6224 FixedArray* elements = FixedArray::cast(elements_array->elements());
6225 for (int i = 0; i < elements_length; i += 2) {
6226 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6227 CONVERT_CHECKED(String, string, elements->get(i + 1));
6228 int length = string->length();
6229 if (is_ascii && !string->IsAsciiRepresentation()) {
6230 is_ascii = false;
6231 max_string_length = SeqTwoByteString::kMaxLength;
6232 }
6233 if (length > max_string_length ||
6234 max_string_length - length < string_length) {
6235 overflow = true;
6236 break;
6237 }
6238 string_length += length;
6239 }
6240 int separator_length = separator->length();
6241 if (!overflow && separator_length > 0) {
6242 if (array_length <= 0x7fffffffu) {
6243 int separator_count = static_cast<int>(array_length) - 1;
6244 int remaining_length = max_string_length - string_length;
6245 if ((remaining_length / separator_length) >= separator_count) {
6246 string_length += separator_length * (array_length - 1);
6247 } else {
6248 // Not room for the separators within the maximal string length.
6249 overflow = true;
6250 }
6251 } else {
6252 // Nonempty separator and at least 2^31-1 separators necessary
6253 // means that the string is too large to create.
6254 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6255 overflow = true;
6256 }
6257 }
6258 if (overflow) {
6259 // Throw OutOfMemory exception for creating too large a string.
6260 V8::FatalProcessOutOfMemory("Array join result too large.");
6261 }
6262
6263 if (is_ascii) {
6264 MaybeObject* result_allocation =
6265 isolate->heap()->AllocateRawAsciiString(string_length);
6266 if (result_allocation->IsFailure()) return result_allocation;
6267 SeqAsciiString* result_string =
6268 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6269 JoinSparseArrayWithSeparator<char>(elements,
6270 elements_length,
6271 array_length,
6272 separator,
6273 Vector<char>(result_string->GetChars(),
6274 string_length));
6275 return result_string;
6276 } else {
6277 MaybeObject* result_allocation =
6278 isolate->heap()->AllocateRawTwoByteString(string_length);
6279 if (result_allocation->IsFailure()) return result_allocation;
6280 SeqTwoByteString* result_string =
6281 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6282 JoinSparseArrayWithSeparator<uc16>(elements,
6283 elements_length,
6284 array_length,
6285 separator,
6286 Vector<uc16>(result_string->GetChars(),
6287 string_length));
6288 return result_string;
6289 }
6290}
6291
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006293RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006294 NoHandleAllocation ha;
6295 ASSERT(args.length() == 2);
6296
6297 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6298 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006299 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006300}
6301
6302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006303RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006304 NoHandleAllocation ha;
6305 ASSERT(args.length() == 2);
6306
6307 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6308 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006309 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006310}
6311
6312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006313RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006314 NoHandleAllocation ha;
6315 ASSERT(args.length() == 2);
6316
6317 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6318 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006319 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320}
6321
6322
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006323RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006324 NoHandleAllocation ha;
6325 ASSERT(args.length() == 1);
6326
6327 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006328 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006329}
6330
6331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006332RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006333 NoHandleAllocation ha;
6334 ASSERT(args.length() == 2);
6335
6336 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6337 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006338 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006339}
6340
6341
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006342RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006343 NoHandleAllocation ha;
6344 ASSERT(args.length() == 2);
6345
6346 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6347 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006348 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006349}
6350
6351
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006352RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006353 NoHandleAllocation ha;
6354 ASSERT(args.length() == 2);
6355
6356 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6357 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006358 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006359}
6360
6361
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006362RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006363 NoHandleAllocation ha;
6364 ASSERT(args.length() == 2);
6365
6366 CONVERT_DOUBLE_CHECKED(x, args[0]);
6367 CONVERT_DOUBLE_CHECKED(y, args[1]);
6368 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6369 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6370 if (x == y) return Smi::FromInt(EQUAL);
6371 Object* result;
6372 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6373 result = Smi::FromInt(EQUAL);
6374 } else {
6375 result = Smi::FromInt(NOT_EQUAL);
6376 }
6377 return result;
6378}
6379
6380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006381RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006382 NoHandleAllocation ha;
6383 ASSERT(args.length() == 2);
6384
6385 CONVERT_CHECKED(String, x, args[0]);
6386 CONVERT_CHECKED(String, y, args[1]);
6387
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006388 bool not_equal = !x->Equals(y);
6389 // This is slightly convoluted because the value that signifies
6390 // equality is 0 and inequality is 1 so we have to negate the result
6391 // from String::Equals.
6392 ASSERT(not_equal == 0 || not_equal == 1);
6393 STATIC_CHECK(EQUAL == 0);
6394 STATIC_CHECK(NOT_EQUAL == 1);
6395 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006396}
6397
6398
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006399RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006400 NoHandleAllocation ha;
6401 ASSERT(args.length() == 3);
6402
6403 CONVERT_DOUBLE_CHECKED(x, args[0]);
6404 CONVERT_DOUBLE_CHECKED(y, args[1]);
6405 if (isnan(x) || isnan(y)) return args[2];
6406 if (x == y) return Smi::FromInt(EQUAL);
6407 if (isless(x, y)) return Smi::FromInt(LESS);
6408 return Smi::FromInt(GREATER);
6409}
6410
6411
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006412// Compare two Smis as if they were converted to strings and then
6413// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006414RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006415 NoHandleAllocation ha;
6416 ASSERT(args.length() == 2);
6417
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006418 // Extract the integer values from the Smis.
6419 CONVERT_CHECKED(Smi, x, args[0]);
6420 CONVERT_CHECKED(Smi, y, args[1]);
6421 int x_value = x->value();
6422 int y_value = y->value();
6423
6424 // If the integers are equal so are the string representations.
6425 if (x_value == y_value) return Smi::FromInt(EQUAL);
6426
6427 // If one of the integers are zero the normal integer order is the
6428 // same as the lexicographic order of the string representations.
6429 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6430
ager@chromium.org32912102009-01-16 10:38:43 +00006431 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006432 // smallest because the char code of '-' is less than the char code
6433 // of any digit. Otherwise, we make both values positive.
6434 if (x_value < 0 || y_value < 0) {
6435 if (y_value >= 0) return Smi::FromInt(LESS);
6436 if (x_value >= 0) return Smi::FromInt(GREATER);
6437 x_value = -x_value;
6438 y_value = -y_value;
6439 }
6440
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006441 // Arrays for the individual characters of the two Smis. Smis are
6442 // 31 bit integers and 10 decimal digits are therefore enough.
6443 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6444 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6445 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6446
6447
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006448 // Convert the integers to arrays of their decimal digits.
6449 int x_index = 0;
6450 int y_index = 0;
6451 while (x_value > 0) {
6452 x_elms[x_index++] = x_value % 10;
6453 x_value /= 10;
6454 }
6455 while (y_value > 0) {
6456 y_elms[y_index++] = y_value % 10;
6457 y_value /= 10;
6458 }
6459
6460 // Loop through the arrays of decimal digits finding the first place
6461 // where they differ.
6462 while (--x_index >= 0 && --y_index >= 0) {
6463 int diff = x_elms[x_index] - y_elms[y_index];
6464 if (diff != 0) return Smi::FromInt(diff);
6465 }
6466
6467 // If one array is a suffix of the other array, the longest array is
6468 // the representation of the largest of the Smis in the
6469 // lexicographic ordering.
6470 return Smi::FromInt(x_index - y_index);
6471}
6472
6473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006474static Object* StringInputBufferCompare(RuntimeState* state,
6475 String* x,
6476 String* y) {
6477 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6478 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006479 bufx.Reset(x);
6480 bufy.Reset(y);
6481 while (bufx.has_more() && bufy.has_more()) {
6482 int d = bufx.GetNext() - bufy.GetNext();
6483 if (d < 0) return Smi::FromInt(LESS);
6484 else if (d > 0) return Smi::FromInt(GREATER);
6485 }
6486
6487 // x is (non-trivial) prefix of y:
6488 if (bufy.has_more()) return Smi::FromInt(LESS);
6489 // y is prefix of x:
6490 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6491}
6492
6493
6494static Object* FlatStringCompare(String* x, String* y) {
6495 ASSERT(x->IsFlat());
6496 ASSERT(y->IsFlat());
6497 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6498 int prefix_length = x->length();
6499 if (y->length() < prefix_length) {
6500 prefix_length = y->length();
6501 equal_prefix_result = Smi::FromInt(GREATER);
6502 } else if (y->length() > prefix_length) {
6503 equal_prefix_result = Smi::FromInt(LESS);
6504 }
6505 int r;
6506 if (x->IsAsciiRepresentation()) {
6507 Vector<const char> x_chars = x->ToAsciiVector();
6508 if (y->IsAsciiRepresentation()) {
6509 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006510 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006511 } else {
6512 Vector<const uc16> y_chars = y->ToUC16Vector();
6513 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6514 }
6515 } else {
6516 Vector<const uc16> x_chars = x->ToUC16Vector();
6517 if (y->IsAsciiRepresentation()) {
6518 Vector<const char> y_chars = y->ToAsciiVector();
6519 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6520 } else {
6521 Vector<const uc16> y_chars = y->ToUC16Vector();
6522 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6523 }
6524 }
6525 Object* result;
6526 if (r == 0) {
6527 result = equal_prefix_result;
6528 } else {
6529 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6530 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006531 ASSERT(result ==
6532 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006533 return result;
6534}
6535
6536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006537RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006538 NoHandleAllocation ha;
6539 ASSERT(args.length() == 2);
6540
6541 CONVERT_CHECKED(String, x, args[0]);
6542 CONVERT_CHECKED(String, y, args[1]);
6543
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006544 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006545
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006546 // A few fast case tests before we flatten.
6547 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006548 if (y->length() == 0) {
6549 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006551 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006552 return Smi::FromInt(LESS);
6553 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006554
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006555 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006556 if (d < 0) return Smi::FromInt(LESS);
6557 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006558
lrn@chromium.org303ada72010-10-27 09:33:13 +00006559 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006560 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006561 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6562 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006563 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006564 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6565 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006567 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006568 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569}
6570
6571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006572RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573 NoHandleAllocation ha;
6574 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006575 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006576
6577 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006578 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006579}
6580
6581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006582RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583 NoHandleAllocation ha;
6584 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006585 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006586
6587 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006588 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589}
6590
6591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006592RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593 NoHandleAllocation ha;
6594 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006595 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006596
6597 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006598 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006599}
6600
6601
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006602static const double kPiDividedBy4 = 0.78539816339744830962;
6603
6604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006605RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006606 NoHandleAllocation ha;
6607 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006608 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609
6610 CONVERT_DOUBLE_CHECKED(x, args[0]);
6611 CONVERT_DOUBLE_CHECKED(y, args[1]);
6612 double result;
6613 if (isinf(x) && isinf(y)) {
6614 // Make sure that the result in case of two infinite arguments
6615 // is a multiple of Pi / 4. The sign of the result is determined
6616 // by the first argument (x) and the sign of the second argument
6617 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618 int multiplier = (x < 0) ? -1 : 1;
6619 if (y < 0) multiplier *= 3;
6620 result = multiplier * kPiDividedBy4;
6621 } else {
6622 result = atan2(x, y);
6623 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625}
6626
6627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006628RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 NoHandleAllocation ha;
6630 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006631 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006632
6633 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006634 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006635}
6636
6637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006638RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006639 NoHandleAllocation ha;
6640 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006641 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642
6643 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006644 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006645}
6646
6647
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006648RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006649 NoHandleAllocation ha;
6650 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006651 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652
6653 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006654 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655}
6656
6657
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006658RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006659 NoHandleAllocation ha;
6660 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006661 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006662
6663 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006664 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006665}
6666
6667
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006668RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669 NoHandleAllocation ha;
6670 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006671 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006672
6673 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006674 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006675}
6676
6677
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006678RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679 NoHandleAllocation ha;
6680 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006681 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006682
6683 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006684
6685 // If the second argument is a smi, it is much faster to call the
6686 // custom powi() function than the generic pow().
6687 if (args[1]->IsSmi()) {
6688 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006689 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006690 }
6691
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006692 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006693 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006694}
6695
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006696// Fast version of Math.pow if we know that y is not an integer and
6697// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006698RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006699 NoHandleAllocation ha;
6700 ASSERT(args.length() == 2);
6701 CONVERT_DOUBLE_CHECKED(x, args[0]);
6702 CONVERT_DOUBLE_CHECKED(y, args[1]);
6703 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006704 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006705 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006706 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006707 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006708 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006709 }
6710}
6711
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006712
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006713RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006714 NoHandleAllocation ha;
6715 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006716 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006717
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006718 if (!args[0]->IsHeapNumber()) {
6719 // Must be smi. Return the argument unchanged for all the other types
6720 // to make fuzz-natives test happy.
6721 return args[0];
6722 }
6723
6724 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6725
6726 double value = number->value();
6727 int exponent = number->get_exponent();
6728 int sign = number->get_sign();
6729
danno@chromium.org160a7b02011-04-18 15:51:38 +00006730 if (exponent < -1) {
6731 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6732 if (sign) return isolate->heap()->minus_zero_value();
6733 return Smi::FromInt(0);
6734 }
6735
6736 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6737 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6738 // agument holds for 32-bit smis).
6739 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006740 return Smi::FromInt(static_cast<int>(value + 0.5));
6741 }
6742
6743 // If the magnitude is big enough, there's no place for fraction part. If we
6744 // try to add 0.5 to this number, 1.0 will be added instead.
6745 if (exponent >= 52) {
6746 return number;
6747 }
6748
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006749 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006750
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006751 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753}
6754
6755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006756RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006757 NoHandleAllocation ha;
6758 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006759 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760
6761 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006762 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763}
6764
6765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006766RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767 NoHandleAllocation ha;
6768 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006769 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770
6771 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006772 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006773}
6774
6775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006776RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006777 NoHandleAllocation ha;
6778 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006779 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006780
6781 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006782 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006783}
6784
6785
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006786static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006787 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6788 181, 212, 243, 273, 304, 334};
6789 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6790 182, 213, 244, 274, 305, 335};
6791
6792 year += month / 12;
6793 month %= 12;
6794 if (month < 0) {
6795 year--;
6796 month += 12;
6797 }
6798
6799 ASSERT(month >= 0);
6800 ASSERT(month < 12);
6801
6802 // year_delta is an arbitrary number such that:
6803 // a) year_delta = -1 (mod 400)
6804 // b) year + year_delta > 0 for years in the range defined by
6805 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6806 // Jan 1 1970. This is required so that we don't run into integer
6807 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006808 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006809 // operations.
6810 static const int year_delta = 399999;
6811 static const int base_day = 365 * (1970 + year_delta) +
6812 (1970 + year_delta) / 4 -
6813 (1970 + year_delta) / 100 +
6814 (1970 + year_delta) / 400;
6815
6816 int year1 = year + year_delta;
6817 int day_from_year = 365 * year1 +
6818 year1 / 4 -
6819 year1 / 100 +
6820 year1 / 400 -
6821 base_day;
6822
6823 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006824 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006825 }
6826
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006827 return day_from_year + day_from_month_leap[month] + day - 1;
6828}
6829
6830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006831RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006832 NoHandleAllocation ha;
6833 ASSERT(args.length() == 3);
6834
6835 CONVERT_SMI_CHECKED(year, args[0]);
6836 CONVERT_SMI_CHECKED(month, args[1]);
6837 CONVERT_SMI_CHECKED(date, args[2]);
6838
6839 return Smi::FromInt(MakeDay(year, month, date));
6840}
6841
6842
6843static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6844static const int kDaysIn4Years = 4 * 365 + 1;
6845static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6846static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6847static const int kDays1970to2000 = 30 * 365 + 7;
6848static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6849 kDays1970to2000;
6850static const int kYearsOffset = 400000;
6851
6852static const char kDayInYear[] = {
6853 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6854 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6855 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6856 22, 23, 24, 25, 26, 27, 28,
6857 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6858 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6859 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6860 22, 23, 24, 25, 26, 27, 28, 29, 30,
6861 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6862 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6863 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6864 22, 23, 24, 25, 26, 27, 28, 29, 30,
6865 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6866 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6867 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6868 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6869 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6870 22, 23, 24, 25, 26, 27, 28, 29, 30,
6871 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6872 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6873 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6874 22, 23, 24, 25, 26, 27, 28, 29, 30,
6875 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6876 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6877
6878 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6879 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6880 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6881 22, 23, 24, 25, 26, 27, 28,
6882 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6883 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6884 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6885 22, 23, 24, 25, 26, 27, 28, 29, 30,
6886 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6887 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6888 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6889 22, 23, 24, 25, 26, 27, 28, 29, 30,
6890 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6891 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6892 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6893 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6894 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6895 22, 23, 24, 25, 26, 27, 28, 29, 30,
6896 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6897 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6898 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6899 22, 23, 24, 25, 26, 27, 28, 29, 30,
6900 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6901 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6902
6903 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6904 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6905 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6906 22, 23, 24, 25, 26, 27, 28, 29,
6907 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6908 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6909 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6910 22, 23, 24, 25, 26, 27, 28, 29, 30,
6911 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6912 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6913 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6914 22, 23, 24, 25, 26, 27, 28, 29, 30,
6915 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6916 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6917 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6918 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6919 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6920 22, 23, 24, 25, 26, 27, 28, 29, 30,
6921 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6922 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6923 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6924 22, 23, 24, 25, 26, 27, 28, 29, 30,
6925 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6926 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6927
6928 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6929 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6930 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6931 22, 23, 24, 25, 26, 27, 28,
6932 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6933 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6934 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6935 22, 23, 24, 25, 26, 27, 28, 29, 30,
6936 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6937 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6938 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6939 22, 23, 24, 25, 26, 27, 28, 29, 30,
6940 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6941 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6942 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6943 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6944 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6945 22, 23, 24, 25, 26, 27, 28, 29, 30,
6946 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6947 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6948 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6949 22, 23, 24, 25, 26, 27, 28, 29, 30,
6950 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6951 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6952
6953static const char kMonthInYear[] = {
6954 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,
6955 0, 0, 0, 0, 0, 0,
6956 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,
6957 1, 1, 1,
6958 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,
6959 2, 2, 2, 2, 2, 2,
6960 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,
6961 3, 3, 3, 3, 3,
6962 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,
6963 4, 4, 4, 4, 4, 4,
6964 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,
6965 5, 5, 5, 5, 5,
6966 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,
6967 6, 6, 6, 6, 6, 6,
6968 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,
6969 7, 7, 7, 7, 7, 7,
6970 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,
6971 8, 8, 8, 8, 8,
6972 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,
6973 9, 9, 9, 9, 9, 9,
6974 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6975 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6976 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6977 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6978
6979 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,
6980 0, 0, 0, 0, 0, 0,
6981 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,
6982 1, 1, 1,
6983 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,
6984 2, 2, 2, 2, 2, 2,
6985 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,
6986 3, 3, 3, 3, 3,
6987 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,
6988 4, 4, 4, 4, 4, 4,
6989 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,
6990 5, 5, 5, 5, 5,
6991 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,
6992 6, 6, 6, 6, 6, 6,
6993 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,
6994 7, 7, 7, 7, 7, 7,
6995 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,
6996 8, 8, 8, 8, 8,
6997 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,
6998 9, 9, 9, 9, 9, 9,
6999 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7000 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7001 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7002 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7003
7004 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,
7005 0, 0, 0, 0, 0, 0,
7006 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,
7007 1, 1, 1, 1,
7008 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,
7009 2, 2, 2, 2, 2, 2,
7010 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,
7011 3, 3, 3, 3, 3,
7012 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,
7013 4, 4, 4, 4, 4, 4,
7014 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,
7015 5, 5, 5, 5, 5,
7016 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,
7017 6, 6, 6, 6, 6, 6,
7018 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,
7019 7, 7, 7, 7, 7, 7,
7020 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,
7021 8, 8, 8, 8, 8,
7022 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,
7023 9, 9, 9, 9, 9, 9,
7024 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7025 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7026 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7027 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7028
7029 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,
7030 0, 0, 0, 0, 0, 0,
7031 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,
7032 1, 1, 1,
7033 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,
7034 2, 2, 2, 2, 2, 2,
7035 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,
7036 3, 3, 3, 3, 3,
7037 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,
7038 4, 4, 4, 4, 4, 4,
7039 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,
7040 5, 5, 5, 5, 5,
7041 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,
7042 6, 6, 6, 6, 6, 6,
7043 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,
7044 7, 7, 7, 7, 7, 7,
7045 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,
7046 8, 8, 8, 8, 8,
7047 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,
7048 9, 9, 9, 9, 9, 9,
7049 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7050 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7051 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7052 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7053
7054
7055// This function works for dates from 1970 to 2099.
7056static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007057 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007058#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007059 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007060#endif
7061
7062 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7063 date %= kDaysIn4Years;
7064
7065 month = kMonthInYear[date];
7066 day = kDayInYear[date];
7067
7068 ASSERT(MakeDay(year, month, day) == save_date);
7069}
7070
7071
7072static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007073 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007074#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007075 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007076#endif
7077
7078 date += kDaysOffset;
7079 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7080 date %= kDaysIn400Years;
7081
7082 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7083
7084 date--;
7085 int yd1 = date / kDaysIn100Years;
7086 date %= kDaysIn100Years;
7087 year += 100 * yd1;
7088
7089 date++;
7090 int yd2 = date / kDaysIn4Years;
7091 date %= kDaysIn4Years;
7092 year += 4 * yd2;
7093
7094 date--;
7095 int yd3 = date / 365;
7096 date %= 365;
7097 year += yd3;
7098
7099 bool is_leap = (!yd1 || yd2) && !yd3;
7100
7101 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007102 ASSERT(is_leap || (date >= 0));
7103 ASSERT((date < 365) || (is_leap && (date < 366)));
7104 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7105 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7106 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007107
7108 if (is_leap) {
7109 day = kDayInYear[2*365 + 1 + date];
7110 month = kMonthInYear[2*365 + 1 + date];
7111 } else {
7112 day = kDayInYear[date];
7113 month = kMonthInYear[date];
7114 }
7115
7116 ASSERT(MakeDay(year, month, day) == save_date);
7117}
7118
7119
7120static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007121 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007122 if (date >= 0 && date < 32 * kDaysIn4Years) {
7123 DateYMDFromTimeAfter1970(date, year, month, day);
7124 } else {
7125 DateYMDFromTimeSlow(date, year, month, day);
7126 }
7127}
7128
7129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007130RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007131 NoHandleAllocation ha;
7132 ASSERT(args.length() == 2);
7133
7134 CONVERT_DOUBLE_CHECKED(t, args[0]);
7135 CONVERT_CHECKED(JSArray, res_array, args[1]);
7136
7137 int year, month, day;
7138 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7139
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007140 RUNTIME_ASSERT(res_array->elements()->map() ==
7141 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007142 FixedArray* elms = FixedArray::cast(res_array->elements());
7143 RUNTIME_ASSERT(elms->length() == 3);
7144
7145 elms->set(0, Smi::FromInt(year));
7146 elms->set(1, Smi::FromInt(month));
7147 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007149 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007150}
7151
7152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007153RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007154 NoHandleAllocation ha;
7155 ASSERT(args.length() == 3);
7156
7157 JSFunction* callee = JSFunction::cast(args[0]);
7158 Object** parameters = reinterpret_cast<Object**>(args[1]);
7159 const int length = Smi::cast(args[2])->value();
7160
lrn@chromium.org303ada72010-10-27 09:33:13 +00007161 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007162 { MaybeObject* maybe_result =
7163 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007164 if (!maybe_result->ToObject(&result)) return maybe_result;
7165 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007166 // Allocate the elements if needed.
7167 if (length > 0) {
7168 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007169 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007170 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007171 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7172 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007173
7174 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007175 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007176 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007177 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007178
7179 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007180 for (int i = 0; i < length; i++) {
7181 array->set(i, *--parameters, mode);
7182 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007183 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007184 }
7185 return result;
7186}
7187
7188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007189RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007190 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007191 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007192 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007193 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007194 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007195
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007196 // Allocate global closures in old space and allocate local closures
7197 // in new space. Additionally pretenure closures that are assigned
7198 // directly to properties.
7199 pretenure = pretenure || (context->global_context() == *context);
7200 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007201 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007202 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7203 context,
7204 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007205 return *result;
7206}
7207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007208
7209static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7210 int* total_argc) {
7211 // Find frame containing arguments passed to the caller.
7212 JavaScriptFrameIterator it;
7213 JavaScriptFrame* frame = it.frame();
7214 List<JSFunction*> functions(2);
7215 frame->GetFunctions(&functions);
7216 if (functions.length() > 1) {
7217 int inlined_frame_index = functions.length() - 1;
7218 JSFunction* inlined_function = functions[inlined_frame_index];
7219 int args_count = inlined_function->shared()->formal_parameter_count();
7220 ScopedVector<SlotRef> args_slots(args_count);
7221 SlotRef::ComputeSlotMappingForArguments(frame,
7222 inlined_frame_index,
7223 &args_slots);
7224
7225 *total_argc = bound_argc + args_count;
7226 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7227 for (int i = 0; i < args_count; i++) {
7228 Handle<Object> val = args_slots[i].GetValue();
7229 param_data[bound_argc + i] = val.location();
7230 }
7231 return param_data;
7232 } else {
7233 it.AdvanceToArgumentsFrame();
7234 frame = it.frame();
7235 int args_count = frame->ComputeParametersCount();
7236
7237 *total_argc = bound_argc + args_count;
7238 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7239 for (int i = 0; i < args_count; i++) {
7240 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7241 param_data[bound_argc + i] = val.location();
7242 }
7243 return param_data;
7244 }
7245}
7246
7247
7248RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007249 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007250 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007251 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007252 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007253
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007254 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007255 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007256 int bound_argc = 0;
7257 if (!args[1]->IsNull()) {
7258 CONVERT_ARG_CHECKED(JSArray, params, 1);
7259 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007260 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007261 bound_argc = Smi::cast(params->length())->value();
7262 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007264 int total_argc = 0;
7265 SmartPointer<Object**> param_data =
7266 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007267 for (int i = 0; i < bound_argc; i++) {
7268 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007269 param_data[i] = val.location();
7270 }
7271
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007272 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007273 Handle<Object> result =
7274 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007275 if (exception) {
7276 return Failure::Exception();
7277 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007278
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007279 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007280 return *result;
7281}
7282
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007284static void TrySettingInlineConstructStub(Isolate* isolate,
7285 Handle<JSFunction> function) {
7286 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007287 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007288 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007289 }
7290 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007291 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007292 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007293 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007294 function->shared()->set_construct_stub(
7295 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007296 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007297 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007298}
7299
7300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007301RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007302 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007303 ASSERT(args.length() == 1);
7304
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007305 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007306
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007307 // If the constructor isn't a proper function we throw a type error.
7308 if (!constructor->IsJSFunction()) {
7309 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7310 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007311 isolate->factory()->NewTypeError("not_constructor", arguments);
7312 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007313 }
7314
7315 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007316
7317 // If function should not have prototype, construction is not allowed. In this
7318 // case generated code bailouts here, since function has no initial_map.
7319 if (!function->should_have_prototype()) {
7320 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7321 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007322 isolate->factory()->NewTypeError("not_constructor", arguments);
7323 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007324 }
7325
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007326#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007327 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007328 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007329 if (debug->StepInActive()) {
7330 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007331 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007332#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007333
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007334 if (function->has_initial_map()) {
7335 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007336 // The 'Function' function ignores the receiver object when
7337 // called using 'new' and creates a new JSFunction object that
7338 // is returned. The receiver object is only used for error
7339 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007341 // allocate JSFunctions since it does not properly initialize
7342 // the shared part of the function. Since the receiver is
7343 // ignored anyway, we use the global object as the receiver
7344 // instead of a new JSFunction object. This way, errors are
7345 // reported the same way whether or not 'Function' is called
7346 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007347 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007349 }
7350
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007351 // The function should be compiled for the optimization hints to be
7352 // available. We cannot use EnsureCompiled because that forces a
7353 // compilation through the shared function info which makes it
7354 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007355 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007356 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007357
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007358 if (!function->has_initial_map() &&
7359 shared->IsInobjectSlackTrackingInProgress()) {
7360 // The tracking is already in progress for another function. We can only
7361 // track one initial_map at a time, so we force the completion before the
7362 // function is called as a constructor for the first time.
7363 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007364 }
7365
7366 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007367 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7368 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007369 // Delay setting the stub if inobject slack tracking is in progress.
7370 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007371 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007372 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007373
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007374 isolate->counters()->constructed_objects()->Increment();
7375 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007376
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007377 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007378}
7379
7380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007381RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007382 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007383 ASSERT(args.length() == 1);
7384
7385 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7386 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007387 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007388
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007389 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007390}
7391
7392
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007393RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395 ASSERT(args.length() == 1);
7396
7397 Handle<JSFunction> function = args.at<JSFunction>(0);
7398#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007399 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007401 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007402 PrintF("]\n");
7403 }
7404#endif
7405
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007406 // Compile the target function. Here we compile using CompileLazyInLoop in
7407 // order to get the optimized version. This helps code like delta-blue
7408 // that calls performance-critical routines through constructors. A
7409 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7410 // direct call. Since the in-loop tracking takes place through CallICs
7411 // this means that things called through constructors are never known to
7412 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007414 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007415 return Failure::Exception();
7416 }
7417
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007418 // All done. Return the compiled code.
7419 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420 return function->code();
7421}
7422
7423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007424RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007425 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007426 ASSERT(args.length() == 1);
7427 Handle<JSFunction> function = args.at<JSFunction>(0);
7428 // If the function is not optimizable or debugger is active continue using the
7429 // code from the full compiler.
7430 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007431 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007432 if (FLAG_trace_opt) {
7433 PrintF("[failed to optimize ");
7434 function->PrintName();
7435 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7436 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007437 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007438 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007439 function->ReplaceCode(function->shared()->code());
7440 return function->code();
7441 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007442 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007443 return function->code();
7444 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007445 if (FLAG_trace_opt) {
7446 PrintF("[failed to optimize ");
7447 function->PrintName();
7448 PrintF(": optimized compilation failed]\n");
7449 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007450 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007451 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007452}
7453
7454
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007455RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007456 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007457 ASSERT(args.length() == 1);
7458 RUNTIME_ASSERT(args[0]->IsSmi());
7459 Deoptimizer::BailoutType type =
7460 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007461 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7462 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007463 int frames = deoptimizer->output_count();
7464
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007465 deoptimizer->MaterializeHeapNumbers();
7466 delete deoptimizer;
7467
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007468 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007469 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007470 for (int i = 0; i < frames - 1; i++) it.Advance();
7471 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007472
7473 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007474 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007475 Handle<Object> arguments;
7476 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007477 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007478 if (arguments.is_null()) {
7479 // FunctionGetArguments can't throw an exception, so cast away the
7480 // doubt with an assert.
7481 arguments = Handle<Object>(
7482 Accessors::FunctionGetArguments(*function,
7483 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007484 ASSERT(*arguments != isolate->heap()->null_value());
7485 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007486 }
7487 frame->SetExpression(i, *arguments);
7488 }
7489 }
7490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007491 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007492 if (type == Deoptimizer::EAGER) {
7493 RUNTIME_ASSERT(function->IsOptimized());
7494 } else {
7495 RUNTIME_ASSERT(!function->IsOptimized());
7496 }
7497
7498 // Avoid doing too much work when running with --always-opt and keep
7499 // the optimized code around.
7500 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007501 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007502 }
7503
7504 // Count the number of optimized activations of the function.
7505 int activations = 0;
7506 while (!it.done()) {
7507 JavaScriptFrame* frame = it.frame();
7508 if (frame->is_optimized() && frame->function() == *function) {
7509 activations++;
7510 }
7511 it.Advance();
7512 }
7513
7514 // TODO(kasperl): For now, we cannot support removing the optimized
7515 // code when we have recursive invocations of the same function.
7516 if (activations == 0) {
7517 if (FLAG_trace_deopt) {
7518 PrintF("[removing optimized code for: ");
7519 function->PrintName();
7520 PrintF("]\n");
7521 }
7522 function->ReplaceCode(function->shared()->code());
7523 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007524 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007525}
7526
7527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007528RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007529 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007530 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007531 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007532}
7533
7534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007535RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007536 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007537 ASSERT(args.length() == 1);
7538 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007539 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007540
7541 Deoptimizer::DeoptimizeFunction(*function);
7542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007543 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007544}
7545
7546
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007547RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7548 HandleScope scope(isolate);
7549 ASSERT(args.length() == 1);
7550 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7551 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7552 function->MarkForLazyRecompilation();
7553 return isolate->heap()->undefined_value();
7554}
7555
7556
lrn@chromium.org1c092762011-05-09 09:42:16 +00007557RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7558 HandleScope scope(isolate);
7559 ASSERT(args.length() == 1);
7560 if (!V8::UseCrankshaft()) {
7561 return Smi::FromInt(4); // 4 == "never".
7562 }
7563 if (FLAG_always_opt) {
7564 return Smi::FromInt(3); // 3 == "always".
7565 }
7566 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7567 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7568 : Smi::FromInt(2); // 2 == "no".
7569}
7570
7571
7572RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7573 HandleScope scope(isolate);
7574 ASSERT(args.length() == 1);
7575 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7576 return Smi::FromInt(function->shared()->opt_count());
7577}
7578
7579
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007580RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007581 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007582 ASSERT(args.length() == 1);
7583 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7584
7585 // We're not prepared to handle a function with arguments object.
7586 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7587
7588 // We have hit a back edge in an unoptimized frame for a function that was
7589 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007590 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007591 // Keep track of whether we've succeeded in optimizing.
7592 bool succeeded = unoptimized->optimizable();
7593 if (succeeded) {
7594 // If we are trying to do OSR when there are already optimized
7595 // activations of the function, it means (a) the function is directly or
7596 // indirectly recursive and (b) an optimized invocation has been
7597 // deoptimized so that we are currently in an unoptimized activation.
7598 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007599 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007600 while (succeeded && !it.done()) {
7601 JavaScriptFrame* frame = it.frame();
7602 succeeded = !frame->is_optimized() || frame->function() != *function;
7603 it.Advance();
7604 }
7605 }
7606
7607 int ast_id = AstNode::kNoNumber;
7608 if (succeeded) {
7609 // The top JS function is this one, the PC is somewhere in the
7610 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007611 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007612 JavaScriptFrame* frame = it.frame();
7613 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007614 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007615 ASSERT(unoptimized->contains(frame->pc()));
7616
7617 // Use linear search of the unoptimized code's stack check table to find
7618 // the AST id matching the PC.
7619 Address start = unoptimized->instruction_start();
7620 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007621 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007622 uint32_t table_length = Memory::uint32_at(table_cursor);
7623 table_cursor += kIntSize;
7624 for (unsigned i = 0; i < table_length; ++i) {
7625 // Table entries are (AST id, pc offset) pairs.
7626 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7627 if (pc_offset == target_pc_offset) {
7628 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7629 break;
7630 }
7631 table_cursor += 2 * kIntSize;
7632 }
7633 ASSERT(ast_id != AstNode::kNoNumber);
7634 if (FLAG_trace_osr) {
7635 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7636 function->PrintName();
7637 PrintF("]\n");
7638 }
7639
7640 // Try to compile the optimized code. A true return value from
7641 // CompileOptimized means that compilation succeeded, not necessarily
7642 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007643 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7644 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007645 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7646 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007647 if (data->OsrPcOffset()->value() >= 0) {
7648 if (FLAG_trace_osr) {
7649 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007650 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007651 }
7652 ASSERT(data->OsrAstId()->value() == ast_id);
7653 } else {
7654 // We may never generate the desired OSR entry if we emit an
7655 // early deoptimize.
7656 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007657 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007658 } else {
7659 succeeded = false;
7660 }
7661 }
7662
7663 // Revert to the original stack checks in the original unoptimized code.
7664 if (FLAG_trace_osr) {
7665 PrintF("[restoring original stack checks in ");
7666 function->PrintName();
7667 PrintF("]\n");
7668 }
7669 StackCheckStub check_stub;
7670 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007671 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007672 Deoptimizer::RevertStackCheckCode(*unoptimized,
7673 *check_code,
7674 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007675
7676 // Allow OSR only at nesting level zero again.
7677 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7678
7679 // If the optimization attempt succeeded, return the AST id tagged as a
7680 // smi. This tells the builtin that we need to translate the unoptimized
7681 // frame to an optimized one.
7682 if (succeeded) {
7683 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7684 return Smi::FromInt(ast_id);
7685 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007686 if (function->IsMarkedForLazyRecompilation()) {
7687 function->ReplaceCode(function->shared()->code());
7688 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007689 return Smi::FromInt(-1);
7690 }
7691}
7692
7693
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007694RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007695 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007696 ASSERT(args.length() == 1);
7697 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7698 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7699}
7700
7701
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007702RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007703 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007704 ASSERT(args.length() == 1);
7705 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7706 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7707}
7708
7709
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007710RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007711 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007712 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007713
kasper.lund7276f142008-07-30 08:49:36 +00007714 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007715 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007716 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007717 { MaybeObject* maybe_result =
7718 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007719 if (!maybe_result->ToObject(&result)) return maybe_result;
7720 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007721
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007722 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007723
kasper.lund7276f142008-07-30 08:49:36 +00007724 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007725}
7726
lrn@chromium.org303ada72010-10-27 09:33:13 +00007727
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007728MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7729 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007730 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007732 Object* js_object = object;
7733 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007734 MaybeObject* maybe_js_object = js_object->ToObject();
7735 if (!maybe_js_object->ToObject(&js_object)) {
7736 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7737 return maybe_js_object;
7738 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007739 HandleScope scope(isolate);
7740 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007741 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007742 isolate->factory()->NewTypeError("with_expression",
7743 HandleVector(&handle, 1));
7744 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007745 }
7746 }
7747
lrn@chromium.org303ada72010-10-27 09:33:13 +00007748 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007749 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7750 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007751 if (!maybe_result->ToObject(&result)) return maybe_result;
7752 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007753
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007754 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007755 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007756
kasper.lund7276f142008-07-30 08:49:36 +00007757 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007758}
7759
7760
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007761RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007762 NoHandleAllocation ha;
7763 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007764 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007765}
7766
7767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007768RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007769 NoHandleAllocation ha;
7770 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007771 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007772}
7773
7774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007775RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007776 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007777 ASSERT(args.length() == 2);
7778
7779 CONVERT_ARG_CHECKED(Context, context, 0);
7780 CONVERT_ARG_CHECKED(String, name, 1);
7781
7782 int index;
7783 PropertyAttributes attributes;
7784 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007785 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007786
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007787 // If the slot was not found the result is true.
7788 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007789 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007790 }
7791
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007792 // If the slot was found in a context, it should be DONT_DELETE.
7793 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007794 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007795 }
7796
7797 // The slot was found in a JSObject, either a context extension object,
7798 // the global object, or an arguments object. Try to delete it
7799 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7800 // which allows deleting all parameters in functions that mention
7801 // 'arguments', we do this even for the case of slots found on an
7802 // arguments object. The slot was found on an arguments object if the
7803 // index is non-negative.
7804 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7805 if (index >= 0) {
7806 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7807 } else {
7808 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7809 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007810}
7811
7812
ager@chromium.orga1645e22009-09-09 19:27:10 +00007813// A mechanism to return a pair of Object pointers in registers (if possible).
7814// How this is achieved is calling convention-dependent.
7815// All currently supported x86 compiles uses calling conventions that are cdecl
7816// variants where a 64-bit value is returned in two 32-bit registers
7817// (edx:eax on ia32, r1:r0 on ARM).
7818// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7819// In Win64 calling convention, a struct of two pointers is returned in memory,
7820// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007821#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007822struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007823 MaybeObject* x;
7824 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007825};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007826
lrn@chromium.org303ada72010-10-27 09:33:13 +00007827static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007828 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007829 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7830 // In Win64 they are assigned to a hidden first argument.
7831 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007832}
7833#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007834typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007835static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007836 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007837 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007838}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007839#endif
7840
7841
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007842static inline MaybeObject* Unhole(Heap* heap,
7843 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007844 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007845 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7846 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007847 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007848}
7849
7850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007851static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7852 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007853 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007854 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007855 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007856 JSFunction* context_extension_function =
7857 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007858 // If the holder isn't a context extension object, we just return it
7859 // as the receiver. This allows arguments objects to be used as
7860 // receivers, but only if they are put in the context scope chain
7861 // explicitly via a with-statement.
7862 Object* constructor = holder->map()->constructor();
7863 if (constructor != context_extension_function) return holder;
7864 // Fall back to using the global object as the receiver if the
7865 // property turns out to be a local variable allocated in a context
7866 // extension object - introduced via eval.
7867 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007868}
7869
7870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007871static ObjectPair LoadContextSlotHelper(Arguments args,
7872 Isolate* isolate,
7873 bool throw_error) {
7874 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007875 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007876
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007877 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007878 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007879 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007880 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007881 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007882
7883 int index;
7884 PropertyAttributes attributes;
7885 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007886 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007887
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007888 // If the index is non-negative, the slot has been found in a local
7889 // variable or a parameter. Read it from the context object or the
7890 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007891 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007892 // If the "property" we were looking for is a local variable or an
7893 // argument in a context, the receiver is the global object; see
7894 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007895 JSObject* receiver =
7896 isolate->context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007897 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007898 ? Context::cast(*holder)->get(index)
7899 : JSObject::cast(*holder)->GetElement(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007900 return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007901 }
7902
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007903 // If the holder is found, we read the property from it.
7904 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007905 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007906 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007907 JSObject* receiver;
7908 if (object->IsGlobalObject()) {
7909 receiver = GlobalObject::cast(object)->global_receiver();
7910 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007911 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007912 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007913 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007914 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007915 // No need to unhole the value here. This is taken care of by the
7916 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007917 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007918 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007919 }
7920
7921 if (throw_error) {
7922 // The property doesn't exist - throw exception.
7923 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007924 isolate->factory()->NewReferenceError("not_defined",
7925 HandleVector(&name, 1));
7926 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007927 } else {
7928 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007929 return MakePair(isolate->heap()->undefined_value(),
7930 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007931 }
7932}
7933
7934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007935RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007936 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007937}
7938
7939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007940RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007941 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007942}
7943
7944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007945RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007946 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007947 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007949 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007950 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007951 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007952 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7953 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7954 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007955 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007956
7957 int index;
7958 PropertyAttributes attributes;
7959 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007960 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007961
7962 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007963 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007964 // Ignore if read_only variable.
7965 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007966 // Context is a fixed array and set cannot fail.
7967 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007968 } else if (strict_mode == kStrictMode) {
7969 // Setting read only property in strict mode.
7970 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007971 isolate->factory()->NewTypeError("strict_cannot_assign",
7972 HandleVector(&name, 1));
7973 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007974 }
7975 } else {
7976 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007977 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007978 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007979 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007980 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007981 return Failure::Exception();
7982 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007983 }
7984 return *value;
7985 }
7986
7987 // Slow case: The property is not in a FixedArray context.
7988 // It is either in an JSObject extension context or it was not found.
7989 Handle<JSObject> context_ext;
7990
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007991 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007992 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007993 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007994 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007995 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007996 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007997
7998 if (strict_mode == kStrictMode) {
7999 // Throw in strict mode (assignment to undefined variable).
8000 Handle<Object> error =
8001 isolate->factory()->NewReferenceError(
8002 "not_defined", HandleVector(&name, 1));
8003 return isolate->Throw(*error);
8004 }
8005 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008006 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008007 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008008 }
8009
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008010 // Set the property, but ignore if read_only variable on the context
8011 // extension object itself.
8012 if ((attributes & READ_ONLY) == 0 ||
8013 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008014 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008015 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008016 SetProperty(context_ext, name, value, NONE, strict_mode));
8017 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008018 // Setting read only property in strict mode.
8019 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008020 isolate->factory()->NewTypeError(
8021 "strict_cannot_assign", HandleVector(&name, 1));
8022 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008023 }
8024 return *value;
8025}
8026
8027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008028RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008029 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008030 ASSERT(args.length() == 1);
8031
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008032 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008033}
8034
8035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008036RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008037 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008038 ASSERT(args.length() == 1);
8039
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008040 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008041}
8042
8043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008044RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008045 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008046 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008047}
8048
8049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008050RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008051 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008052 ASSERT(args.length() == 1);
8053
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008054 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008055 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008056 isolate->factory()->NewReferenceError("not_defined",
8057 HandleVector(&name, 1));
8058 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008059}
8060
8061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008062RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008063 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008064
8065 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008066 if (isolate->stack_guard()->IsStackOverflow()) {
8067 NoHandleAllocation na;
8068 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008069 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008070
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008071 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072}
8073
8074
8075// NOTE: These PrintXXX functions are defined for all builds (not just
8076// DEBUG builds) because we may want to be able to trace function
8077// calls in all modes.
8078static void PrintString(String* str) {
8079 // not uncommon to have empty strings
8080 if (str->length() > 0) {
8081 SmartPointer<char> s =
8082 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8083 PrintF("%s", *s);
8084 }
8085}
8086
8087
8088static void PrintObject(Object* obj) {
8089 if (obj->IsSmi()) {
8090 PrintF("%d", Smi::cast(obj)->value());
8091 } else if (obj->IsString() || obj->IsSymbol()) {
8092 PrintString(String::cast(obj));
8093 } else if (obj->IsNumber()) {
8094 PrintF("%g", obj->Number());
8095 } else if (obj->IsFailure()) {
8096 PrintF("<failure>");
8097 } else if (obj->IsUndefined()) {
8098 PrintF("<undefined>");
8099 } else if (obj->IsNull()) {
8100 PrintF("<null>");
8101 } else if (obj->IsTrue()) {
8102 PrintF("<true>");
8103 } else if (obj->IsFalse()) {
8104 PrintF("<false>");
8105 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008106 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008107 }
8108}
8109
8110
8111static int StackSize() {
8112 int n = 0;
8113 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8114 return n;
8115}
8116
8117
8118static void PrintTransition(Object* result) {
8119 // indentation
8120 { const int nmax = 80;
8121 int n = StackSize();
8122 if (n <= nmax)
8123 PrintF("%4d:%*s", n, n, "");
8124 else
8125 PrintF("%4d:%*s", n, nmax, "...");
8126 }
8127
8128 if (result == NULL) {
8129 // constructor calls
8130 JavaScriptFrameIterator it;
8131 JavaScriptFrame* frame = it.frame();
8132 if (frame->IsConstructor()) PrintF("new ");
8133 // function name
8134 Object* fun = frame->function();
8135 if (fun->IsJSFunction()) {
8136 PrintObject(JSFunction::cast(fun)->shared()->name());
8137 } else {
8138 PrintObject(fun);
8139 }
8140 // function arguments
8141 // (we are intentionally only printing the actually
8142 // supplied parameters, not all parameters required)
8143 PrintF("(this=");
8144 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008145 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008146 for (int i = 0; i < length; i++) {
8147 PrintF(", ");
8148 PrintObject(frame->GetParameter(i));
8149 }
8150 PrintF(") {\n");
8151
8152 } else {
8153 // function result
8154 PrintF("} -> ");
8155 PrintObject(result);
8156 PrintF("\n");
8157 }
8158}
8159
8160
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008161RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008162 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008163 NoHandleAllocation ha;
8164 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008165 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008166}
8167
8168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008169RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008170 NoHandleAllocation ha;
8171 PrintTransition(args[0]);
8172 return args[0]; // return TOS
8173}
8174
8175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008176RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008177 NoHandleAllocation ha;
8178 ASSERT(args.length() == 1);
8179
8180#ifdef DEBUG
8181 if (args[0]->IsString()) {
8182 // If we have a string, assume it's a code "marker"
8183 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008184 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008185 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008186 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8187 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008188 } else {
8189 PrintF("DebugPrint: ");
8190 }
8191 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008192 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008193 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008194 HeapObject::cast(args[0])->map()->Print();
8195 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008196#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008197 // ShortPrint is available in release mode. Print is not.
8198 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008199#endif
8200 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008201 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008202
8203 return args[0]; // return TOS
8204}
8205
8206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008207RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008208 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008209 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008210 isolate->PrintStack();
8211 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008212}
8213
8214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008215RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008216 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008217 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008218
8219 // According to ECMA-262, section 15.9.1, page 117, the precision of
8220 // the number in a Date object representing a particular instant in
8221 // time is milliseconds. Therefore, we floor the result of getting
8222 // the OS time.
8223 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008224 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008225}
8226
8227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008228RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008229 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008230 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008231
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008232 CONVERT_ARG_CHECKED(String, str, 0);
8233 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008234
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008235 CONVERT_ARG_CHECKED(JSArray, output, 1);
8236 RUNTIME_ASSERT(output->HasFastElements());
8237
8238 AssertNoAllocation no_allocation;
8239
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008240 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008241 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8242 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008243 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008244 result = DateParser::Parse(str->ToAsciiVector(),
8245 output_array,
8246 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008247 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008248 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008249 result = DateParser::Parse(str->ToUC16Vector(),
8250 output_array,
8251 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008252 }
8253
8254 if (result) {
8255 return *output;
8256 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008257 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008258 }
8259}
8260
8261
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008262RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008263 NoHandleAllocation ha;
8264 ASSERT(args.length() == 1);
8265
8266 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008267 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008268 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008269}
8270
8271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008272RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008274 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008275
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008276 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008277}
8278
8279
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008280RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008281 NoHandleAllocation ha;
8282 ASSERT(args.length() == 1);
8283
8284 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008285 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008286}
8287
8288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008289RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008290 ASSERT(args.length() == 1);
8291 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008292 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008293 return JSGlobalObject::cast(global)->global_receiver();
8294}
8295
8296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008297RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008298 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008299 ASSERT_EQ(1, args.length());
8300 CONVERT_ARG_CHECKED(String, source, 0);
8301
8302 Handle<Object> result = JsonParser::Parse(source);
8303 if (result.is_null()) {
8304 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008305 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008306 return Failure::Exception();
8307 }
8308 return *result;
8309}
8310
8311
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008312bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8313 Handle<Context> context) {
8314 if (context->allow_code_gen_from_strings()->IsFalse()) {
8315 // Check with callback if set.
8316 AllowCodeGenerationFromStringsCallback callback =
8317 isolate->allow_code_gen_callback();
8318 if (callback == NULL) {
8319 // No callback set and code generation disallowed.
8320 return false;
8321 } else {
8322 // Callback set. Let it decide if code generation is allowed.
8323 VMState state(isolate, EXTERNAL);
8324 return callback(v8::Utils::ToLocal(context));
8325 }
8326 }
8327 return true;
8328}
8329
8330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008331RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008332 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008333 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008334 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008335
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008336 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008337 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008338
8339 // Check if global context allows code generation from
8340 // strings. Throw an exception if it doesn't.
8341 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8342 return isolate->Throw(*isolate->factory()->NewError(
8343 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8344 }
8345
8346 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008347 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8348 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008349 true,
8350 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008351 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008352 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008353 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8354 context,
8355 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008356 return *fun;
8357}
8358
8359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008360static ObjectPair CompileGlobalEval(Isolate* isolate,
8361 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008362 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008363 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008364 Handle<Context> context = Handle<Context>(isolate->context());
8365 Handle<Context> global_context = Handle<Context>(context->global_context());
8366
8367 // Check if global context allows code generation from
8368 // strings. Throw an exception if it doesn't.
8369 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8370 isolate->Throw(*isolate->factory()->NewError(
8371 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8372 return MakePair(Failure::Exception(), NULL);
8373 }
8374
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008375 // Deal with a normal eval call with a string argument. Compile it
8376 // and return the compiled function bound in the local context.
8377 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8378 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008379 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008380 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008381 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008382 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008383 Handle<JSFunction> compiled =
8384 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008385 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008386 return MakePair(*compiled, *receiver);
8387}
8388
8389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008390RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008391 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008392
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008393 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008394 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008395 Handle<Object> receiver; // Will be overwritten.
8396
8397 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008398 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008399#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008400 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008401 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008402 StackFrameLocator locator;
8403 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008404 ASSERT(Context::cast(frame->context()) == *context);
8405#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008406
8407 // Find where the 'eval' symbol is bound. It is unaliased only if
8408 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008409 int index = -1;
8410 PropertyAttributes attributes = ABSENT;
8411 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008412 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8413 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008414 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008415 // Stop search when eval is found or when the global context is
8416 // reached.
8417 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008418 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008419 context = Handle<Context>(Context::cast(context->closure()->context()),
8420 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008421 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008422 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008423 }
8424 }
8425
iposva@chromium.org245aa852009-02-10 00:49:54 +00008426 // If eval could not be resolved, it has been deleted and we need to
8427 // throw a reference error.
8428 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008429 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008430 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008431 isolate->factory()->NewReferenceError("not_defined",
8432 HandleVector(&name, 1));
8433 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008434 }
8435
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008436 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008437 // 'eval' is not bound in the global context. Just call the function
8438 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008439 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008440 receiver = Handle<JSObject>(
8441 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008442 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008443 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008444 }
8445
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008446 // 'eval' is bound in the global context, but it may have been overwritten.
8447 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008448 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008449 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008450 return MakePair(*callee,
8451 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008452 }
8453
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008454 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008455 return CompileGlobalEval(isolate,
8456 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008457 args.at<Object>(2),
8458 static_cast<StrictModeFlag>(
8459 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008460}
8461
8462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008463RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008464 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008465
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008466 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008467 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008468
8469 // 'eval' is bound in the global context, but it may have been overwritten.
8470 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008471 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008472 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008473 return MakePair(*callee,
8474 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008475 }
8476
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008477 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008478 return CompileGlobalEval(isolate,
8479 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008480 args.at<Object>(2),
8481 static_cast<StrictModeFlag>(
8482 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008483}
8484
8485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008486RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008487 // This utility adjusts the property attributes for newly created Function
8488 // object ("new Function(...)") by changing the map.
8489 // All it does is changing the prototype property to enumerable
8490 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008491 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008492 ASSERT(args.length() == 1);
8493 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008494
8495 Handle<Map> map = func->shared()->strict_mode()
8496 ? isolate->strict_mode_function_instance_map()
8497 : isolate->function_instance_map();
8498
8499 ASSERT(func->map()->instance_type() == map->instance_type());
8500 ASSERT(func->map()->instance_size() == map->instance_size());
8501 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008502 return *func;
8503}
8504
8505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008506RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008507 // Allocate a block of memory in NewSpace (filled with a filler).
8508 // Use as fallback for allocation in generated code when NewSpace
8509 // is full.
8510 ASSERT(args.length() == 1);
8511 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8512 int size = size_smi->value();
8513 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8514 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008515 Heap* heap = isolate->heap();
8516 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008517 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008518 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008519 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008520 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008521 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008522 }
8523 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008524 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008525}
8526
8527
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008528// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008529// array. Returns true if the element was pushed on the stack and
8530// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008531RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008532 ASSERT(args.length() == 2);
8533 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008534 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008535 RUNTIME_ASSERT(array->HasFastElements());
8536 int length = Smi::cast(array->length())->value();
8537 FixedArray* elements = FixedArray::cast(array->elements());
8538 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008539 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008540 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008541 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008542 // Strict not needed. Used for cycle detection in Array join implementation.
8543 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8544 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008545 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008547 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008548}
8549
8550
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008551/**
8552 * A simple visitor visits every element of Array's.
8553 * The backend storage can be a fixed array for fast elements case,
8554 * or a dictionary for sparse array. Since Dictionary is a subtype
8555 * of FixedArray, the class can be used by both fast and slow cases.
8556 * The second parameter of the constructor, fast_elements, specifies
8557 * whether the storage is a FixedArray or Dictionary.
8558 *
8559 * An index limit is used to deal with the situation that a result array
8560 * length overflows 32-bit non-negative integer.
8561 */
8562class ArrayConcatVisitor {
8563 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008564 ArrayConcatVisitor(Isolate* isolate,
8565 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008566 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008567 isolate_(isolate),
8568 storage_(Handle<FixedArray>::cast(
8569 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008570 index_offset_(0u),
8571 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008572
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008573 ~ArrayConcatVisitor() {
8574 clear_storage();
8575 }
8576
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008577 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008578 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008579 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008580
8581 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008582 if (index < static_cast<uint32_t>(storage_->length())) {
8583 storage_->set(index, *elm);
8584 return;
8585 }
8586 // Our initial estimate of length was foiled, possibly by
8587 // getters on the arrays increasing the length of later arrays
8588 // during iteration.
8589 // This shouldn't happen in anything but pathological cases.
8590 SetDictionaryMode(index);
8591 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008592 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008593 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008594 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008595 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008596 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008597 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008598 // Dictionary needed to grow.
8599 clear_storage();
8600 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008601 }
8602}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008603
8604 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008605 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8606 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008607 } else {
8608 index_offset_ += delta;
8609 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008610 }
8611
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008612 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008613 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008614 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008615 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008616 Handle<Map> map;
8617 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008618 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008619 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008620 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008621 }
8622 array->set_map(*map);
8623 array->set_length(*length);
8624 array->set_elements(*storage_);
8625 return array;
8626 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008627
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008628 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008629 // Convert storage to dictionary mode.
8630 void SetDictionaryMode(uint32_t index) {
8631 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008632 Handle<FixedArray> current_storage(*storage_);
8633 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008634 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008635 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8636 for (uint32_t i = 0; i < current_length; i++) {
8637 HandleScope loop_scope;
8638 Handle<Object> element(current_storage->get(i));
8639 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008640 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008641 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008642 if (!new_storage.is_identical_to(slow_storage)) {
8643 slow_storage = loop_scope.CloseAndEscape(new_storage);
8644 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008645 }
8646 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008647 clear_storage();
8648 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008649 fast_elements_ = false;
8650 }
8651
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008652 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008653 isolate_->global_handles()->Destroy(
8654 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008655 }
8656
8657 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008658 storage_ = Handle<FixedArray>::cast(
8659 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008660 }
8661
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008662 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008663 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008664 // Index after last seen index. Always less than or equal to
8665 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008666 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008667 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008668};
8669
8670
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008671static uint32_t EstimateElementCount(Handle<JSArray> array) {
8672 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8673 int element_count = 0;
8674 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008675 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008676 // Fast elements can't have lengths that are not representable by
8677 // a 32-bit signed integer.
8678 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8679 int fast_length = static_cast<int>(length);
8680 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8681 for (int i = 0; i < fast_length; i++) {
8682 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008683 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008684 break;
8685 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008686 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008687 Handle<NumberDictionary> dictionary(
8688 NumberDictionary::cast(array->elements()));
8689 int capacity = dictionary->Capacity();
8690 for (int i = 0; i < capacity; i++) {
8691 Handle<Object> key(dictionary->KeyAt(i));
8692 if (dictionary->IsKey(*key)) {
8693 element_count++;
8694 }
8695 }
8696 break;
8697 }
8698 default:
8699 // External arrays are always dense.
8700 return length;
8701 }
8702 // As an estimate, we assume that the prototype doesn't contain any
8703 // inherited elements.
8704 return element_count;
8705}
8706
8707
8708
8709template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008710static void IterateExternalArrayElements(Isolate* isolate,
8711 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008712 bool elements_are_ints,
8713 bool elements_are_guaranteed_smis,
8714 ArrayConcatVisitor* visitor) {
8715 Handle<ExternalArrayClass> array(
8716 ExternalArrayClass::cast(receiver->elements()));
8717 uint32_t len = static_cast<uint32_t>(array->length());
8718
8719 ASSERT(visitor != NULL);
8720 if (elements_are_ints) {
8721 if (elements_are_guaranteed_smis) {
8722 for (uint32_t j = 0; j < len; j++) {
8723 HandleScope loop_scope;
8724 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8725 visitor->visit(j, e);
8726 }
8727 } else {
8728 for (uint32_t j = 0; j < len; j++) {
8729 HandleScope loop_scope;
8730 int64_t val = static_cast<int64_t>(array->get(j));
8731 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8732 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8733 visitor->visit(j, e);
8734 } else {
8735 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008736 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008737 visitor->visit(j, e);
8738 }
8739 }
8740 }
8741 } else {
8742 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008743 HandleScope loop_scope(isolate);
8744 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008745 visitor->visit(j, e);
8746 }
8747 }
8748}
8749
8750
8751// Used for sorting indices in a List<uint32_t>.
8752static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8753 uint32_t a = *ap;
8754 uint32_t b = *bp;
8755 return (a == b) ? 0 : (a < b) ? -1 : 1;
8756}
8757
8758
8759static void CollectElementIndices(Handle<JSObject> object,
8760 uint32_t range,
8761 List<uint32_t>* indices) {
8762 JSObject::ElementsKind kind = object->GetElementsKind();
8763 switch (kind) {
8764 case JSObject::FAST_ELEMENTS: {
8765 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8766 uint32_t length = static_cast<uint32_t>(elements->length());
8767 if (range < length) length = range;
8768 for (uint32_t i = 0; i < length; i++) {
8769 if (!elements->get(i)->IsTheHole()) {
8770 indices->Add(i);
8771 }
8772 }
8773 break;
8774 }
8775 case JSObject::DICTIONARY_ELEMENTS: {
8776 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008777 uint32_t capacity = dict->Capacity();
8778 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008779 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008780 Handle<Object> k(dict->KeyAt(j));
8781 if (dict->IsKey(*k)) {
8782 ASSERT(k->IsNumber());
8783 uint32_t index = static_cast<uint32_t>(k->Number());
8784 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008785 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008786 }
8787 }
8788 }
8789 break;
8790 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008791 default: {
8792 int dense_elements_length;
8793 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008794 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008795 dense_elements_length =
8796 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008797 break;
8798 }
8799 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008800 dense_elements_length =
8801 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008802 break;
8803 }
8804 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008805 dense_elements_length =
8806 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008807 break;
8808 }
8809 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008810 dense_elements_length =
8811 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008812 break;
8813 }
8814 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008815 dense_elements_length =
8816 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008817 break;
8818 }
8819 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008820 dense_elements_length =
8821 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008822 break;
8823 }
8824 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008825 dense_elements_length =
8826 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008827 break;
8828 }
8829 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008830 dense_elements_length =
8831 ExternalFloatArray::cast(object->elements())->length();
8832 break;
8833 }
8834 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8835 dense_elements_length =
8836 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008837 break;
8838 }
8839 default:
8840 UNREACHABLE();
8841 dense_elements_length = 0;
8842 break;
8843 }
8844 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8845 if (range <= length) {
8846 length = range;
8847 // We will add all indices, so we might as well clear it first
8848 // and avoid duplicates.
8849 indices->Clear();
8850 }
8851 for (uint32_t i = 0; i < length; i++) {
8852 indices->Add(i);
8853 }
8854 if (length == range) return; // All indices accounted for already.
8855 break;
8856 }
8857 }
8858
8859 Handle<Object> prototype(object->GetPrototype());
8860 if (prototype->IsJSObject()) {
8861 // The prototype will usually have no inherited element indices,
8862 // but we have to check.
8863 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8864 }
8865}
8866
8867
8868/**
8869 * A helper function that visits elements of a JSArray in numerical
8870 * order.
8871 *
8872 * The visitor argument called for each existing element in the array
8873 * with the element index and the element's value.
8874 * Afterwards it increments the base-index of the visitor by the array
8875 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008876 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008877 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008878static bool IterateElements(Isolate* isolate,
8879 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008880 ArrayConcatVisitor* visitor) {
8881 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8882 switch (receiver->GetElementsKind()) {
8883 case JSObject::FAST_ELEMENTS: {
8884 // Run through the elements FixedArray and use HasElement and GetElement
8885 // to check the prototype for missing elements.
8886 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8887 int fast_length = static_cast<int>(length);
8888 ASSERT(fast_length <= elements->length());
8889 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008890 HandleScope loop_scope(isolate);
8891 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008892 if (!element_value->IsTheHole()) {
8893 visitor->visit(j, element_value);
8894 } else if (receiver->HasElement(j)) {
8895 // Call GetElement on receiver, not its prototype, or getters won't
8896 // have the correct receiver.
8897 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008898 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008899 visitor->visit(j, element_value);
8900 }
8901 }
8902 break;
8903 }
8904 case JSObject::DICTIONARY_ELEMENTS: {
8905 Handle<NumberDictionary> dict(receiver->element_dictionary());
8906 List<uint32_t> indices(dict->Capacity() / 2);
8907 // Collect all indices in the object and the prototypes less
8908 // than length. This might introduce duplicates in the indices list.
8909 CollectElementIndices(receiver, length, &indices);
8910 indices.Sort(&compareUInt32);
8911 int j = 0;
8912 int n = indices.length();
8913 while (j < n) {
8914 HandleScope loop_scope;
8915 uint32_t index = indices[j];
8916 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008917 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008918 visitor->visit(index, element);
8919 // Skip to next different index (i.e., omit duplicates).
8920 do {
8921 j++;
8922 } while (j < n && indices[j] == index);
8923 }
8924 break;
8925 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008926 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8927 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8928 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008929 for (uint32_t j = 0; j < length; j++) {
8930 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8931 visitor->visit(j, e);
8932 }
8933 break;
8934 }
8935 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8936 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008937 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008938 break;
8939 }
8940 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8941 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008942 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008943 break;
8944 }
8945 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8946 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008947 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008948 break;
8949 }
8950 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8951 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008952 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008953 break;
8954 }
8955 case JSObject::EXTERNAL_INT_ELEMENTS: {
8956 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008957 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008958 break;
8959 }
8960 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8961 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008962 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008963 break;
8964 }
8965 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8966 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008967 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008968 break;
8969 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008970 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8971 IterateExternalArrayElements<ExternalDoubleArray, double>(
8972 isolate, receiver, false, false, visitor);
8973 break;
8974 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008975 default:
8976 UNREACHABLE();
8977 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008978 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008979 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008980 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008981}
8982
8983
8984/**
8985 * Array::concat implementation.
8986 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008987 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008988 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008989 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008990RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008991 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008992 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008993
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008994 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8995 int argument_count = static_cast<int>(arguments->length()->Number());
8996 RUNTIME_ASSERT(arguments->HasFastElements());
8997 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008998
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008999 // Pass 1: estimate the length and number of elements of the result.
9000 // The actual length can be larger if any of the arguments have getters
9001 // that mutate other arguments (but will otherwise be precise).
9002 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009003
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009004 uint32_t estimate_result_length = 0;
9005 uint32_t estimate_nof_elements = 0;
9006 {
9007 for (int i = 0; i < argument_count; i++) {
9008 HandleScope loop_scope;
9009 Handle<Object> obj(elements->get(i));
9010 uint32_t length_estimate;
9011 uint32_t element_estimate;
9012 if (obj->IsJSArray()) {
9013 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9014 length_estimate =
9015 static_cast<uint32_t>(array->length()->Number());
9016 element_estimate =
9017 EstimateElementCount(array);
9018 } else {
9019 length_estimate = 1;
9020 element_estimate = 1;
9021 }
9022 // Avoid overflows by capping at kMaxElementCount.
9023 if (JSObject::kMaxElementCount - estimate_result_length <
9024 length_estimate) {
9025 estimate_result_length = JSObject::kMaxElementCount;
9026 } else {
9027 estimate_result_length += length_estimate;
9028 }
9029 if (JSObject::kMaxElementCount - estimate_nof_elements <
9030 element_estimate) {
9031 estimate_nof_elements = JSObject::kMaxElementCount;
9032 } else {
9033 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009034 }
9035 }
9036 }
9037
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009038 // If estimated number of elements is more than half of length, a
9039 // fixed array (fast case) is more time and space-efficient than a
9040 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009041 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009042
9043 Handle<FixedArray> storage;
9044 if (fast_case) {
9045 // The backing storage array must have non-existing elements to
9046 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009047 storage = isolate->factory()->NewFixedArrayWithHoles(
9048 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009049 } else {
9050 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9051 uint32_t at_least_space_for = estimate_nof_elements +
9052 (estimate_nof_elements >> 2);
9053 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009054 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009055 }
9056
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009057 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009058
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009059 for (int i = 0; i < argument_count; i++) {
9060 Handle<Object> obj(elements->get(i));
9061 if (obj->IsJSArray()) {
9062 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009063 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009064 return Failure::Exception();
9065 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009066 } else {
9067 visitor.visit(0, obj);
9068 visitor.increase_index_offset(1);
9069 }
9070 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009071
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009072 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009073}
9074
9075
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009076// This will not allocate (flatten the string), but it may run
9077// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009078RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009079 NoHandleAllocation ha;
9080 ASSERT(args.length() == 1);
9081
9082 CONVERT_CHECKED(String, string, args[0]);
9083 StringInputBuffer buffer(string);
9084 while (buffer.has_more()) {
9085 uint16_t character = buffer.GetNext();
9086 PrintF("%c", character);
9087 }
9088 return string;
9089}
9090
ager@chromium.org5ec48922009-05-05 07:25:34 +00009091// Moves all own elements of an object, that are below a limit, to positions
9092// starting at zero. All undefined values are placed after non-undefined values,
9093// and are followed by non-existing element. Does not change the length
9094// property.
9095// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009096RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009097 ASSERT(args.length() == 2);
9098 CONVERT_CHECKED(JSObject, object, args[0]);
9099 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9100 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009101}
9102
9103
9104// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009105RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009106 ASSERT(args.length() == 2);
9107 CONVERT_CHECKED(JSArray, from, args[0]);
9108 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009109 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009110 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009111 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9112 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009113 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009114 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009115 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009116 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009117 Object* new_map;
9118 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009119 to->set_map(Map::cast(new_map));
9120 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009121 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009122 Object* obj;
9123 { MaybeObject* maybe_obj = from->ResetElements();
9124 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9125 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009126 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009127 return to;
9128}
9129
9130
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009131// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009132RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009133 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009134 CONVERT_CHECKED(JSObject, object, args[0]);
9135 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009136 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009137 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009138 } else if (object->IsJSArray()) {
9139 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009140 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009141 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142 }
9143}
9144
9145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009146RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009147 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009148
9149 ASSERT_EQ(3, args.length());
9150
ager@chromium.orgac091b72010-05-05 07:34:42 +00009151 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009152 Handle<Object> key1 = args.at<Object>(1);
9153 Handle<Object> key2 = args.at<Object>(2);
9154
9155 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009156 if (!key1->ToArrayIndex(&index1)
9157 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009158 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009159 }
9160
ager@chromium.orgac091b72010-05-05 07:34:42 +00009161 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9162 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009163 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009164 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009165 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009166
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009167 RETURN_IF_EMPTY_HANDLE(isolate,
9168 SetElement(jsobject, index1, tmp2, kStrictMode));
9169 RETURN_IF_EMPTY_HANDLE(isolate,
9170 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009171
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009172 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009173}
9174
9175
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009176// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009177// might have elements. Can either return keys (positive integers) or
9178// intervals (pair of a negative integer (-start-1) followed by a
9179// positive (length)) or undefined values.
9180// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009181RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009182 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009183 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009184 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009185 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009186 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009187 // Create an array and get all the keys into it, then remove all the
9188 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009189 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009190 int keys_length = keys->length();
9191 for (int i = 0; i < keys_length; i++) {
9192 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009193 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009194 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009195 // Zap invalid keys.
9196 keys->set_undefined(i);
9197 }
9198 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009199 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009200 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009201 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009202 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009203 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009204 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009205 uint32_t actual_length =
9206 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009207 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009208 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009209 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009210 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009211 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009212 }
9213}
9214
9215
9216// DefineAccessor takes an optional final argument which is the
9217// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9218// to the way accessors are implemented, it is set for both the getter
9219// and setter on the first call to DefineAccessor and ignored on
9220// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009221RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009222 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9223 // Compute attributes.
9224 PropertyAttributes attributes = NONE;
9225 if (args.length() == 5) {
9226 CONVERT_CHECKED(Smi, attrs, args[4]);
9227 int value = attrs->value();
9228 // Only attribute bits should be set.
9229 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9230 attributes = static_cast<PropertyAttributes>(value);
9231 }
9232
9233 CONVERT_CHECKED(JSObject, obj, args[0]);
9234 CONVERT_CHECKED(String, name, args[1]);
9235 CONVERT_CHECKED(Smi, flag, args[2]);
9236 CONVERT_CHECKED(JSFunction, fun, args[3]);
9237 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9238}
9239
9240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009241RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009242 ASSERT(args.length() == 3);
9243 CONVERT_CHECKED(JSObject, obj, args[0]);
9244 CONVERT_CHECKED(String, name, args[1]);
9245 CONVERT_CHECKED(Smi, flag, args[2]);
9246 return obj->LookupAccessor(name, flag->value() == 0);
9247}
9248
9249
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009250#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009251RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009252 ASSERT(args.length() == 0);
9253 return Execution::DebugBreakHelper();
9254}
9255
9256
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009257// Helper functions for wrapping and unwrapping stack frame ids.
9258static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009259 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009260 return Smi::FromInt(id >> 2);
9261}
9262
9263
9264static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9265 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9266}
9267
9268
9269// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009270// args[0]: debug event listener function to set or null or undefined for
9271// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009272// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009273RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009274 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009275 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9276 args[0]->IsUndefined() ||
9277 args[0]->IsNull());
9278 Handle<Object> callback = args.at<Object>(0);
9279 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009280 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009281
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009282 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009283}
9284
9285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009286RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009287 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009288 isolate->stack_guard()->DebugBreak();
9289 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009290}
9291
9292
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009293static MaybeObject* DebugLookupResultValue(Heap* heap,
9294 Object* receiver,
9295 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009296 LookupResult* result,
9297 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009298 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009299 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009300 case NORMAL:
9301 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009302 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009303 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009304 }
9305 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009306 case FIELD:
9307 value =
9308 JSObject::cast(
9309 result->holder())->FastPropertyAt(result->GetFieldIndex());
9310 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009311 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009312 }
9313 return value;
9314 case CONSTANT_FUNCTION:
9315 return result->GetConstantFunction();
9316 case CALLBACKS: {
9317 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009318 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009319 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009320 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009321 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009322 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009323 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009324 maybe_value = heap->isolate()->pending_exception();
9325 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009326 if (caught_exception != NULL) {
9327 *caught_exception = true;
9328 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009329 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009330 }
9331 return value;
9332 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009333 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009334 }
9335 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009336 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009337 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009338 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009339 case CONSTANT_TRANSITION:
9340 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009341 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009342 default:
9343 UNREACHABLE();
9344 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009345 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009346 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009347}
9348
9349
ager@chromium.org32912102009-01-16 10:38:43 +00009350// Get debugger related details for an object property.
9351// args[0]: object holding property
9352// args[1]: name of the property
9353//
9354// The array returned contains the following information:
9355// 0: Property value
9356// 1: Property details
9357// 2: Property value is exception
9358// 3: Getter function if defined
9359// 4: Setter function if defined
9360// Items 2-4 are only filled if the property has either a getter or a setter
9361// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009362RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009363 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009364
9365 ASSERT(args.length() == 2);
9366
9367 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9368 CONVERT_ARG_CHECKED(String, name, 1);
9369
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009370 // Make sure to set the current context to the context before the debugger was
9371 // entered (if the debugger is entered). The reason for switching context here
9372 // is that for some property lookups (accessors and interceptors) callbacks
9373 // into the embedding application can occour, and the embedding application
9374 // could have the assumption that its own global context is the current
9375 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009376 SaveContext save(isolate);
9377 if (isolate->debug()->InDebugger()) {
9378 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009379 }
9380
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009381 // Skip the global proxy as it has no properties and always delegates to the
9382 // real global object.
9383 if (obj->IsJSGlobalProxy()) {
9384 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9385 }
9386
9387
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009388 // Check if the name is trivially convertible to an index and get the element
9389 // if so.
9390 uint32_t index;
9391 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009392 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009393 Object* element_or_char;
9394 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009395 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009396 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9397 return maybe_element_or_char;
9398 }
9399 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009400 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009401 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009402 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009403 }
9404
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009405 // Find the number of objects making up this.
9406 int length = LocalPrototypeChainLength(*obj);
9407
9408 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009409 Handle<JSObject> jsproto = obj;
9410 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009411 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009412 jsproto->LocalLookup(*name, &result);
9413 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009414 // LookupResult is not GC safe as it holds raw object pointers.
9415 // GC can happen later in this code so put the required fields into
9416 // local variables using handles when required for later use.
9417 PropertyType result_type = result.type();
9418 Handle<Object> result_callback_obj;
9419 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009420 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9421 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009422 }
9423 Smi* property_details = result.GetPropertyDetails().AsSmi();
9424 // DebugLookupResultValue can cause GC so details from LookupResult needs
9425 // to be copied to handles before this.
9426 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009427 Object* raw_value;
9428 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009429 DebugLookupResultValue(isolate->heap(), *obj, *name,
9430 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009431 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9432 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009433 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009434
9435 // If the callback object is a fixed array then it contains JavaScript
9436 // getter and/or setter.
9437 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9438 result_callback_obj->IsFixedArray();
9439 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009440 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009441 details->set(0, *value);
9442 details->set(1, property_details);
9443 if (hasJavaScriptAccessors) {
9444 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009445 caught_exception ? isolate->heap()->true_value()
9446 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009447 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9448 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9449 }
9450
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009451 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009452 }
9453 if (i < length - 1) {
9454 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9455 }
9456 }
9457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009458 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009459}
9460
9461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009462RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009463 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009464
9465 ASSERT(args.length() == 2);
9466
9467 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9468 CONVERT_ARG_CHECKED(String, name, 1);
9469
9470 LookupResult result;
9471 obj->Lookup(*name, &result);
9472 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009473 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009474 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009475 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009476}
9477
9478
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009479// Return the property type calculated from the property details.
9480// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009481RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009482 ASSERT(args.length() == 1);
9483 CONVERT_CHECKED(Smi, details, args[0]);
9484 PropertyType type = PropertyDetails(details).type();
9485 return Smi::FromInt(static_cast<int>(type));
9486}
9487
9488
9489// Return the property attribute calculated from the property details.
9490// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009491RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009492 ASSERT(args.length() == 1);
9493 CONVERT_CHECKED(Smi, details, args[0]);
9494 PropertyAttributes attributes = PropertyDetails(details).attributes();
9495 return Smi::FromInt(static_cast<int>(attributes));
9496}
9497
9498
9499// Return the property insertion index calculated from the property details.
9500// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009501RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009502 ASSERT(args.length() == 1);
9503 CONVERT_CHECKED(Smi, details, args[0]);
9504 int index = PropertyDetails(details).index();
9505 return Smi::FromInt(index);
9506}
9507
9508
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009509// Return property value from named interceptor.
9510// args[0]: object
9511// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009512RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009513 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009514 ASSERT(args.length() == 2);
9515 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9516 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9517 CONVERT_ARG_CHECKED(String, name, 1);
9518
9519 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009520 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009521}
9522
9523
9524// Return element value from indexed interceptor.
9525// args[0]: object
9526// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009527RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009528 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009529 ASSERT(args.length() == 2);
9530 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9531 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9532 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9533
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009534 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009535}
9536
9537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009538RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009539 ASSERT(args.length() >= 1);
9540 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009541 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 if (isolate->debug()->break_id() == 0 ||
9543 break_id != isolate->debug()->break_id()) {
9544 return isolate->Throw(
9545 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009546 }
9547
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009548 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009549}
9550
9551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009552RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009553 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009554 ASSERT(args.length() == 1);
9555
9556 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009557 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009558 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9559 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009560 if (!maybe_result->ToObject(&result)) return maybe_result;
9561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009562
9563 // Count all frames which are relevant to debugging stack trace.
9564 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009565 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009566 if (id == StackFrame::NO_ID) {
9567 // If there is no JavaScript stack frame count is 0.
9568 return Smi::FromInt(0);
9569 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009570 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009571 return Smi::FromInt(n);
9572}
9573
9574
9575static const int kFrameDetailsFrameIdIndex = 0;
9576static const int kFrameDetailsReceiverIndex = 1;
9577static const int kFrameDetailsFunctionIndex = 2;
9578static const int kFrameDetailsArgumentCountIndex = 3;
9579static const int kFrameDetailsLocalCountIndex = 4;
9580static const int kFrameDetailsSourcePositionIndex = 5;
9581static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009582static const int kFrameDetailsAtReturnIndex = 7;
9583static const int kFrameDetailsDebuggerFrameIndex = 8;
9584static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009585
9586// Return an array with frame details
9587// args[0]: number: break id
9588// args[1]: number: frame index
9589//
9590// The array returned contains the following information:
9591// 0: Frame id
9592// 1: Receiver
9593// 2: Function
9594// 3: Argument count
9595// 4: Local count
9596// 5: Source position
9597// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009598// 7: Is at return
9599// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009600// Arguments name, value
9601// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009602// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009603RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009604 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009605 ASSERT(args.length() == 2);
9606
9607 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009608 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009609 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9610 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009611 if (!maybe_check->ToObject(&check)) return maybe_check;
9612 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009613 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009614 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009615
9616 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009617 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009618 if (id == StackFrame::NO_ID) {
9619 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009620 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009621 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009622 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009623 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009624 for (; !it.done(); it.Advance()) {
9625 if (count == index) break;
9626 count++;
9627 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009628 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009629
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009630 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009631 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009632
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009633 // Traverse the saved contexts chain to find the active context for the
9634 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009635 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009636 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009637 save = save->prev();
9638 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009639 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009640
9641 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009642 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009643
9644 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009645 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009646 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009647
9648 // Check for constructor frame.
9649 bool constructor = it.frame()->IsConstructor();
9650
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009651 // Get scope info and read from it for local variable information.
9652 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009653 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009654 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009655
9656 // Get the context.
9657 Handle<Context> context(Context::cast(it.frame()->context()));
9658
9659 // Get the locals names and values into a temporary array.
9660 //
9661 // TODO(1240907): Hide compiler-introduced stack variables
9662 // (e.g. .result)? For users of the debugger, they will probably be
9663 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009664 Handle<FixedArray> locals =
9665 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009666
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009667 // Fill in the names of the locals.
9668 for (int i = 0; i < info.NumberOfLocals(); i++) {
9669 locals->set(i * 2, *info.LocalName(i));
9670 }
9671
9672 // Fill in the values of the locals.
9673 for (int i = 0; i < info.NumberOfLocals(); i++) {
9674 if (is_optimized_frame) {
9675 // If we are inspecting an optimized frame use undefined as the
9676 // value for all locals.
9677 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009678 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009679 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009680 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009681 } else if (i < info.number_of_stack_slots()) {
9682 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009683 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9684 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009685 // Traverse the context chain to the function context as all local
9686 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009687 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009688 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009689 context = Handle<Context>(context->previous());
9690 }
9691 ASSERT(context->is_function_context());
9692 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009693 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009694 }
9695 }
9696
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009697 // Check whether this frame is positioned at return. If not top
9698 // frame or if the frame is optimized it cannot be at a return.
9699 bool at_return = false;
9700 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009701 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009702 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009703
9704 // If positioned just before return find the value to be returned and add it
9705 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009706 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009707 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009708 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009709 Address internal_frame_sp = NULL;
9710 while (!it2.done()) {
9711 if (it2.frame()->is_internal()) {
9712 internal_frame_sp = it2.frame()->sp();
9713 } else {
9714 if (it2.frame()->is_java_script()) {
9715 if (it2.frame()->id() == it.frame()->id()) {
9716 // The internal frame just before the JavaScript frame contains the
9717 // value to return on top. A debug break at return will create an
9718 // internal frame to store the return value (eax/rax/r0) before
9719 // entering the debug break exit frame.
9720 if (internal_frame_sp != NULL) {
9721 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009722 Handle<Object>(Memory::Object_at(internal_frame_sp),
9723 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009724 break;
9725 }
9726 }
9727 }
9728
9729 // Indicate that the previous frame was not an internal frame.
9730 internal_frame_sp = NULL;
9731 }
9732 it2.Advance();
9733 }
9734 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009735
9736 // Now advance to the arguments adapter frame (if any). It contains all
9737 // the provided parameters whereas the function frame always have the number
9738 // of arguments matching the functions parameters. The rest of the
9739 // information (except for what is collected above) is the same.
9740 it.AdvanceToArgumentsFrame();
9741
9742 // Find the number of arguments to fill. At least fill the number of
9743 // parameters for the function and fill more if more parameters are provided.
9744 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009745 if (argument_count < it.frame()->ComputeParametersCount()) {
9746 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009747 }
9748
9749 // Calculate the size of the result.
9750 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009751 2 * (argument_count + info.NumberOfLocals()) +
9752 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009753 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009754
9755 // Add the frame id.
9756 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9757
9758 // Add the function (same as in function frame).
9759 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9760
9761 // Add the arguments count.
9762 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9763
9764 // Add the locals count
9765 details->set(kFrameDetailsLocalCountIndex,
9766 Smi::FromInt(info.NumberOfLocals()));
9767
9768 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009769 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009770 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9771 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009772 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009773 }
9774
9775 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009776 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009777
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009778 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009779 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009780
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009781 // Add information on whether this frame is invoked in the debugger context.
9782 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009783 heap->ToBoolean(*save->context() ==
9784 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009785
9786 // Fill the dynamic part.
9787 int details_index = kFrameDetailsFirstDynamicIndex;
9788
9789 // Add arguments name and value.
9790 for (int i = 0; i < argument_count; i++) {
9791 // Name of the argument.
9792 if (i < info.number_of_parameters()) {
9793 details->set(details_index++, *info.parameter_name(i));
9794 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009795 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009796 }
9797
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009798 // Parameter value. If we are inspecting an optimized frame, use
9799 // undefined as the value.
9800 //
9801 // TODO(3141533): We should be able to get the actual parameter
9802 // value for optimized frames.
9803 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009804 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009805 details->set(details_index++, it.frame()->GetParameter(i));
9806 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009807 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009808 }
9809 }
9810
9811 // Add locals name and value from the temporary copy from the function frame.
9812 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9813 details->set(details_index++, locals->get(i));
9814 }
9815
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009816 // Add the value being returned.
9817 if (at_return) {
9818 details->set(details_index++, *return_value);
9819 }
9820
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009821 // Add the receiver (same as in function frame).
9822 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9823 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009824 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009825 if (!receiver->IsJSObject()) {
9826 // If the receiver is NOT a JSObject we have hit an optimization
9827 // where a value object is not converted into a wrapped JS objects.
9828 // To hide this optimization from the debugger, we wrap the receiver
9829 // by creating correct wrapper object based on the calling frame's
9830 // global context.
9831 it.Advance();
9832 Handle<Context> calling_frames_global_context(
9833 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009834 receiver =
9835 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009836 }
9837 details->set(kFrameDetailsReceiverIndex, *receiver);
9838
9839 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009840 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009841}
9842
9843
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009844// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009845static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009846 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009847 Handle<SerializedScopeInfo> serialized_scope_info,
9848 ScopeInfo<>& scope_info,
9849 Handle<Context> context,
9850 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009851 // Fill all context locals to the context extension.
9852 for (int i = Context::MIN_CONTEXT_SLOTS;
9853 i < scope_info.number_of_context_slots();
9854 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009855 int context_index = serialized_scope_info->ContextSlotIndex(
9856 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009857
9858 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009859 if (*scope_info.context_slot_name(i) !=
9860 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009861 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009862 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009863 SetProperty(scope_object,
9864 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009865 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009866 NONE,
9867 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009868 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009869 }
9870 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009871
9872 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009873}
9874
9875
9876// Create a plain JSObject which materializes the local scope for the specified
9877// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009878static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9879 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009880 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009881 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009882 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9883 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009884
9885 // Allocate and initialize a JSObject with all the arguments, stack locals
9886 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009887 Handle<JSObject> local_scope =
9888 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009889
9890 // First fill all parameters.
9891 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009892 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009893 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009894 SetProperty(local_scope,
9895 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009896 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009897 NONE,
9898 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009899 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009900 }
9901
9902 // Second fill all stack locals.
9903 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009904 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009905 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009906 SetProperty(local_scope,
9907 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009908 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009909 NONE,
9910 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009911 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009912 }
9913
9914 // Third fill all context locals.
9915 Handle<Context> frame_context(Context::cast(frame->context()));
9916 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009917 if (!CopyContextLocalsToScopeObject(isolate,
9918 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009919 function_context, local_scope)) {
9920 return Handle<JSObject>();
9921 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009922
9923 // Finally copy any properties from the function context extension. This will
9924 // be variables introduced by eval.
9925 if (function_context->closure() == *function) {
9926 if (function_context->has_extension() &&
9927 !function_context->IsGlobalContext()) {
9928 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009929 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009930 for (int i = 0; i < keys->length(); i++) {
9931 // Names of variables introduced by eval are strings.
9932 ASSERT(keys->get(i)->IsString());
9933 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009934 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009935 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009936 SetProperty(local_scope,
9937 key,
9938 GetProperty(ext, key),
9939 NONE,
9940 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009941 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009942 }
9943 }
9944 }
9945 return local_scope;
9946}
9947
9948
9949// Create a plain JSObject which materializes the closure content for the
9950// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009951static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9952 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009953 ASSERT(context->is_function_context());
9954
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009955 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009956 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9957 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009958
9959 // Allocate and initialize a JSObject with all the content of theis function
9960 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009961 Handle<JSObject> closure_scope =
9962 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009963
9964 // Check whether the arguments shadow object exists.
9965 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009966 shared->scope_info()->ContextSlotIndex(
9967 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009968 if (arguments_shadow_index >= 0) {
9969 // In this case all the arguments are available in the arguments shadow
9970 // object.
9971 Handle<JSObject> arguments_shadow(
9972 JSObject::cast(context->get(arguments_shadow_index)));
9973 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009974 // We don't expect exception-throwing getters on the arguments shadow.
9975 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009976 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009977 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009978 SetProperty(closure_scope,
9979 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009980 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009981 NONE,
9982 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009983 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009984 }
9985 }
9986
9987 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009988 if (!CopyContextLocalsToScopeObject(isolate,
9989 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009990 context, closure_scope)) {
9991 return Handle<JSObject>();
9992 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009993
9994 // Finally copy any properties from the function context extension. This will
9995 // be variables introduced by eval.
9996 if (context->has_extension()) {
9997 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009998 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009999 for (int i = 0; i < keys->length(); i++) {
10000 // Names of variables introduced by eval are strings.
10001 ASSERT(keys->get(i)->IsString());
10002 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010003 RETURN_IF_EMPTY_HANDLE_VALUE(
10004 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010005 SetProperty(closure_scope,
10006 key,
10007 GetProperty(ext, key),
10008 NONE,
10009 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010010 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010011 }
10012 }
10013
10014 return closure_scope;
10015}
10016
10017
10018// Iterate over the actual scopes visible from a stack frame. All scopes are
10019// backed by an actual context except the local scope, which is inserted
10020// "artifically" in the context chain.
10021class ScopeIterator {
10022 public:
10023 enum ScopeType {
10024 ScopeTypeGlobal = 0,
10025 ScopeTypeLocal,
10026 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010027 ScopeTypeClosure,
10028 // Every catch block contains an implicit with block (its parameter is
10029 // a JSContextExtensionObject) that extends current scope with a variable
10030 // holding exception object. Such with blocks are treated as scopes of their
10031 // own type.
10032 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010033 };
10034
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010035 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10036 : isolate_(isolate),
10037 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010038 function_(JSFunction::cast(frame->function())),
10039 context_(Context::cast(frame->context())),
10040 local_done_(false),
10041 at_local_(false) {
10042
10043 // Check whether the first scope is actually a local scope.
10044 if (context_->IsGlobalContext()) {
10045 // If there is a stack slot for .result then this local scope has been
10046 // created for evaluating top level code and it is not a real local scope.
10047 // Checking for the existence of .result seems fragile, but the scope info
10048 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010049 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010050 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010051 at_local_ = index < 0;
10052 } else if (context_->is_function_context()) {
10053 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010054 } else if (context_->closure() != *function_) {
10055 // The context_ is a with block from the outer function.
10056 ASSERT(context_->has_extension());
10057 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010058 }
10059 }
10060
10061 // More scopes?
10062 bool Done() { return context_.is_null(); }
10063
10064 // Move to the next scope.
10065 void Next() {
10066 // If at a local scope mark the local scope as passed.
10067 if (at_local_) {
10068 at_local_ = false;
10069 local_done_ = true;
10070
10071 // If the current context is not associated with the local scope the
10072 // current context is the next real scope, so don't move to the next
10073 // context in this case.
10074 if (context_->closure() != *function_) {
10075 return;
10076 }
10077 }
10078
10079 // The global scope is always the last in the chain.
10080 if (context_->IsGlobalContext()) {
10081 context_ = Handle<Context>();
10082 return;
10083 }
10084
10085 // Move to the next context.
10086 if (context_->is_function_context()) {
10087 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10088 } else {
10089 context_ = Handle<Context>(context_->previous());
10090 }
10091
10092 // If passing the local scope indicate that the current scope is now the
10093 // local scope.
10094 if (!local_done_ &&
10095 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10096 at_local_ = true;
10097 }
10098 }
10099
10100 // Return the type of the current scope.
10101 int Type() {
10102 if (at_local_) {
10103 return ScopeTypeLocal;
10104 }
10105 if (context_->IsGlobalContext()) {
10106 ASSERT(context_->global()->IsGlobalObject());
10107 return ScopeTypeGlobal;
10108 }
10109 if (context_->is_function_context()) {
10110 return ScopeTypeClosure;
10111 }
10112 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010113 // Current scope is either an explicit with statement or a with statement
10114 // implicitely generated for a catch block.
10115 // If the extension object here is a JSContextExtensionObject then
10116 // current with statement is one frome a catch block otherwise it's a
10117 // regular with statement.
10118 if (context_->extension()->IsJSContextExtensionObject()) {
10119 return ScopeTypeCatch;
10120 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010121 return ScopeTypeWith;
10122 }
10123
10124 // Return the JavaScript object with the content of the current scope.
10125 Handle<JSObject> ScopeObject() {
10126 switch (Type()) {
10127 case ScopeIterator::ScopeTypeGlobal:
10128 return Handle<JSObject>(CurrentContext()->global());
10129 break;
10130 case ScopeIterator::ScopeTypeLocal:
10131 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010132 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010133 break;
10134 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010135 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010136 // Return the with object.
10137 return Handle<JSObject>(CurrentContext()->extension());
10138 break;
10139 case ScopeIterator::ScopeTypeClosure:
10140 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010141 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010142 break;
10143 }
10144 UNREACHABLE();
10145 return Handle<JSObject>();
10146 }
10147
10148 // Return the context for this scope. For the local context there might not
10149 // be an actual context.
10150 Handle<Context> CurrentContext() {
10151 if (at_local_ && context_->closure() != *function_) {
10152 return Handle<Context>();
10153 }
10154 return context_;
10155 }
10156
10157#ifdef DEBUG
10158 // Debug print of the content of the current scope.
10159 void DebugPrint() {
10160 switch (Type()) {
10161 case ScopeIterator::ScopeTypeGlobal:
10162 PrintF("Global:\n");
10163 CurrentContext()->Print();
10164 break;
10165
10166 case ScopeIterator::ScopeTypeLocal: {
10167 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010168 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010169 scope_info.Print();
10170 if (!CurrentContext().is_null()) {
10171 CurrentContext()->Print();
10172 if (CurrentContext()->has_extension()) {
10173 Handle<JSObject> extension =
10174 Handle<JSObject>(CurrentContext()->extension());
10175 if (extension->IsJSContextExtensionObject()) {
10176 extension->Print();
10177 }
10178 }
10179 }
10180 break;
10181 }
10182
10183 case ScopeIterator::ScopeTypeWith: {
10184 PrintF("With:\n");
10185 Handle<JSObject> extension =
10186 Handle<JSObject>(CurrentContext()->extension());
10187 extension->Print();
10188 break;
10189 }
10190
ager@chromium.orga1645e22009-09-09 19:27:10 +000010191 case ScopeIterator::ScopeTypeCatch: {
10192 PrintF("Catch:\n");
10193 Handle<JSObject> extension =
10194 Handle<JSObject>(CurrentContext()->extension());
10195 extension->Print();
10196 break;
10197 }
10198
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010199 case ScopeIterator::ScopeTypeClosure: {
10200 PrintF("Closure:\n");
10201 CurrentContext()->Print();
10202 if (CurrentContext()->has_extension()) {
10203 Handle<JSObject> extension =
10204 Handle<JSObject>(CurrentContext()->extension());
10205 if (extension->IsJSContextExtensionObject()) {
10206 extension->Print();
10207 }
10208 }
10209 break;
10210 }
10211
10212 default:
10213 UNREACHABLE();
10214 }
10215 PrintF("\n");
10216 }
10217#endif
10218
10219 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010220 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010221 JavaScriptFrame* frame_;
10222 Handle<JSFunction> function_;
10223 Handle<Context> context_;
10224 bool local_done_;
10225 bool at_local_;
10226
10227 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10228};
10229
10230
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010231RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010232 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010233 ASSERT(args.length() == 2);
10234
10235 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010236 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010237 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10238 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010239 if (!maybe_check->ToObject(&check)) return maybe_check;
10240 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010241 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10242
10243 // Get the frame where the debugging is performed.
10244 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010245 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010246 JavaScriptFrame* frame = it.frame();
10247
10248 // Count the visible scopes.
10249 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010250 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010251 n++;
10252 }
10253
10254 return Smi::FromInt(n);
10255}
10256
10257
10258static const int kScopeDetailsTypeIndex = 0;
10259static const int kScopeDetailsObjectIndex = 1;
10260static const int kScopeDetailsSize = 2;
10261
10262// Return an array with scope details
10263// args[0]: number: break id
10264// args[1]: number: frame index
10265// args[2]: number: scope index
10266//
10267// The array returned contains the following information:
10268// 0: Scope type
10269// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010270RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010271 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010272 ASSERT(args.length() == 3);
10273
10274 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010275 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010276 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10277 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010278 if (!maybe_check->ToObject(&check)) return maybe_check;
10279 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010280 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10281 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10282
10283 // Get the frame where the debugging is performed.
10284 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010285 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010286 JavaScriptFrame* frame = frame_it.frame();
10287
10288 // Find the requested scope.
10289 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010290 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010291 for (; !it.Done() && n < index; it.Next()) {
10292 n++;
10293 }
10294 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010295 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010296 }
10297
10298 // Calculate the size of the result.
10299 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010300 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010301
10302 // Fill in scope details.
10303 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010304 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010305 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010306 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010307
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010308 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010309}
10310
10311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010312RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010313 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010314 ASSERT(args.length() == 0);
10315
10316#ifdef DEBUG
10317 // Print the scopes for the top frame.
10318 StackFrameLocator locator;
10319 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010320 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010321 it.DebugPrint();
10322 }
10323#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010324 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010325}
10326
10327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010328RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010329 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010330 ASSERT(args.length() == 1);
10331
10332 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010333 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010334 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10335 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010336 if (!maybe_result->ToObject(&result)) return maybe_result;
10337 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010338
10339 // Count all archived V8 threads.
10340 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010341 for (ThreadState* thread =
10342 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010343 thread != NULL;
10344 thread = thread->Next()) {
10345 n++;
10346 }
10347
10348 // Total number of threads is current thread and archived threads.
10349 return Smi::FromInt(n + 1);
10350}
10351
10352
10353static const int kThreadDetailsCurrentThreadIndex = 0;
10354static const int kThreadDetailsThreadIdIndex = 1;
10355static const int kThreadDetailsSize = 2;
10356
10357// Return an array with thread details
10358// args[0]: number: break id
10359// args[1]: number: thread index
10360//
10361// The array returned contains the following information:
10362// 0: Is current thread?
10363// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010364RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010365 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010366 ASSERT(args.length() == 2);
10367
10368 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010369 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010370 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10371 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010372 if (!maybe_check->ToObject(&check)) return maybe_check;
10373 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010374 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10375
10376 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010377 Handle<FixedArray> details =
10378 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010379
10380 // Thread index 0 is current thread.
10381 if (index == 0) {
10382 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010383 details->set(kThreadDetailsCurrentThreadIndex,
10384 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010385 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010386 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010387 } else {
10388 // Find the thread with the requested index.
10389 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010390 ThreadState* thread =
10391 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010392 while (index != n && thread != NULL) {
10393 thread = thread->Next();
10394 n++;
10395 }
10396 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010397 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010398 }
10399
10400 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010401 details->set(kThreadDetailsCurrentThreadIndex,
10402 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010403 details->set(kThreadDetailsThreadIdIndex,
10404 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010405 }
10406
10407 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010408 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010409}
10410
10411
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010412// Sets the disable break state
10413// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010414RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010415 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010416 ASSERT(args.length() == 1);
10417 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010418 isolate->debug()->set_disable_break(disable_break);
10419 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010420}
10421
10422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010423RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010424 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010425 ASSERT(args.length() == 1);
10426
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010427 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10428 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010429 // Find the number of break points
10430 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010431 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010432 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010433 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010434 Handle<FixedArray>::cast(break_locations));
10435}
10436
10437
10438// Set a break point in a function
10439// args[0]: function
10440// args[1]: number: break source position (within the function source)
10441// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010442RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010443 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010444 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010445 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10446 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010447 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10448 RUNTIME_ASSERT(source_position >= 0);
10449 Handle<Object> break_point_object_arg = args.at<Object>(2);
10450
10451 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010452 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10453 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010454
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010455 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010456}
10457
10458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010459Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10460 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010461 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010462 // Iterate the heap looking for SharedFunctionInfo generated from the
10463 // script. The inner most SharedFunctionInfo containing the source position
10464 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010465 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010466 // which is found is not compiled it is compiled and the heap is iterated
10467 // again as the compilation might create inner functions from the newly
10468 // compiled function and the actual requested break point might be in one of
10469 // these functions.
10470 bool done = false;
10471 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010472 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010473 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010474 while (!done) {
10475 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010476 for (HeapObject* obj = iterator.next();
10477 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010478 if (obj->IsSharedFunctionInfo()) {
10479 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10480 if (shared->script() == *script) {
10481 // If the SharedFunctionInfo found has the requested script data and
10482 // contains the source position it is a candidate.
10483 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010484 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010485 start_position = shared->start_position();
10486 }
10487 if (start_position <= position &&
10488 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010489 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010490 // candidate this is the new candidate.
10491 if (target.is_null()) {
10492 target_start_position = start_position;
10493 target = shared;
10494 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010495 if (target_start_position == start_position &&
10496 shared->end_position() == target->end_position()) {
10497 // If a top-level function contain only one function
10498 // declartion the source for the top-level and the function is
10499 // the same. In that case prefer the non top-level function.
10500 if (!shared->is_toplevel()) {
10501 target_start_position = start_position;
10502 target = shared;
10503 }
10504 } else if (target_start_position <= start_position &&
10505 shared->end_position() <= target->end_position()) {
10506 // This containment check includes equality as a function inside
10507 // a top-level function can share either start or end position
10508 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010509 target_start_position = start_position;
10510 target = shared;
10511 }
10512 }
10513 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010514 }
10515 }
10516 }
10517
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010519 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010520 }
10521
10522 // If the candidate found is compiled we are done. NOTE: when lazy
10523 // compilation of inner functions is introduced some additional checking
10524 // needs to be done here to compile inner functions.
10525 done = target->is_compiled();
10526 if (!done) {
10527 // If the candidate is not compiled compile it to reveal any inner
10528 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010529 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010530 }
10531 }
10532
10533 return *target;
10534}
10535
10536
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010537// Changes the state of a break point in a script and returns source position
10538// where break point was set. NOTE: Regarding performance see the NOTE for
10539// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010540// args[0]: script to set break point in
10541// args[1]: number: break source position (within the script source)
10542// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010543RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010544 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010545 ASSERT(args.length() == 3);
10546 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10547 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10548 RUNTIME_ASSERT(source_position >= 0);
10549 Handle<Object> break_point_object_arg = args.at<Object>(2);
10550
10551 // Get the script from the script wrapper.
10552 RUNTIME_ASSERT(wrapper->value()->IsScript());
10553 Handle<Script> script(Script::cast(wrapper->value()));
10554
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010555 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010556 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010557 if (!result->IsUndefined()) {
10558 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10559 // Find position within function. The script position might be before the
10560 // source position of the first function.
10561 int position;
10562 if (shared->start_position() > source_position) {
10563 position = 0;
10564 } else {
10565 position = source_position - shared->start_position();
10566 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010567 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010568 position += shared->start_position();
10569 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010571 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010572}
10573
10574
10575// Clear a break point
10576// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010577RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010578 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010579 ASSERT(args.length() == 1);
10580 Handle<Object> break_point_object_arg = args.at<Object>(0);
10581
10582 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010583 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010585 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010586}
10587
10588
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010589// Change the state of break on exceptions.
10590// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10591// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010592RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010593 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010595 RUNTIME_ASSERT(args[0]->IsNumber());
10596 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010597
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010598 // If the number doesn't match an enum value, the ChangeBreakOnException
10599 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010600 ExceptionBreakType type =
10601 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010602 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010603 isolate->debug()->ChangeBreakOnException(type, enable);
10604 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010605}
10606
10607
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010608// Returns the state of break on exceptions
10609// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010610RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010611 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010612 ASSERT(args.length() == 1);
10613 RUNTIME_ASSERT(args[0]->IsNumber());
10614
10615 ExceptionBreakType type =
10616 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010617 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010618 return Smi::FromInt(result);
10619}
10620
10621
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010622// Prepare for stepping
10623// args[0]: break id for checking execution state
10624// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010625// args[2]: number of times to perform the step, for step out it is the number
10626// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010627RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010628 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010629 ASSERT(args.length() == 3);
10630 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010631 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010632 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10633 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010634 if (!maybe_check->ToObject(&check)) return maybe_check;
10635 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010636 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010637 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010638 }
10639
10640 // Get the step action and check validity.
10641 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10642 if (step_action != StepIn &&
10643 step_action != StepNext &&
10644 step_action != StepOut &&
10645 step_action != StepInMin &&
10646 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010647 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010648 }
10649
10650 // Get the number of steps.
10651 int step_count = NumberToInt32(args[2]);
10652 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010653 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010654 }
10655
ager@chromium.orga1645e22009-09-09 19:27:10 +000010656 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010657 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010658
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010659 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010660 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10661 step_count);
10662 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010663}
10664
10665
10666// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010667RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010668 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010669 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010670 isolate->debug()->ClearStepping();
10671 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010672}
10673
10674
10675// Creates a copy of the with context chain. The copy of the context chain is
10676// is linked to the function context supplied.
10677static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10678 Handle<Context> function_context) {
10679 // At the bottom of the chain. Return the function context to link to.
10680 if (context_chain->is_function_context()) {
10681 return function_context;
10682 }
10683
10684 // Recursively copy the with contexts.
10685 Handle<Context> previous(context_chain->previous());
10686 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010687 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010688 return context->GetIsolate()->factory()->NewWithContext(
10689 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690}
10691
10692
10693// Helper function to find or create the arguments object for
10694// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010695static Handle<Object> GetArgumentsObject(Isolate* isolate,
10696 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010697 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010698 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010699 const ScopeInfo<>* sinfo,
10700 Handle<Context> function_context) {
10701 // Try to find the value of 'arguments' to pass as parameter. If it is not
10702 // found (that is the debugged function does not reference 'arguments' and
10703 // does not support eval) then create an 'arguments' object.
10704 int index;
10705 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010706 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010707 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010708 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010709 }
10710 }
10711
10712 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010713 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10714 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010715 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010716 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010717 }
10718 }
10719
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010720 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010721 Handle<JSObject> arguments =
10722 isolate->factory()->NewArgumentsObject(function, length);
10723 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010724
10725 AssertNoAllocation no_gc;
10726 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010727 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010728 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010729 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010730 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010731 return arguments;
10732}
10733
10734
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010735static const char kSourceStr[] =
10736 "(function(arguments,__source__){return eval(__source__);})";
10737
10738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010739// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010740// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010741// extension part has all the parameters and locals of the function on the
10742// stack frame. A function which calls eval with the code to evaluate is then
10743// compiled in this context and called in this context. As this context
10744// replaces the context of the function on the stack frame a new (empty)
10745// function is created as well to be used as the closure for the context.
10746// This function and the context acts as replacements for the function on the
10747// stack frame presenting the same view of the values of parameters and
10748// local variables as if the piece of JavaScript was evaluated at the point
10749// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010750RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010751 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010752
10753 // Check the execution state and decode arguments frame and source to be
10754 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010755 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010756 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010757 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10758 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010759 if (!maybe_check_result->ToObject(&check_result)) {
10760 return maybe_check_result;
10761 }
10762 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010763 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10764 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010765 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010766 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010767
10768 // Handle the processing of break.
10769 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010770
10771 // Get the frame where the debugging is performed.
10772 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010773 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010774 JavaScriptFrame* frame = it.frame();
10775 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010776 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010777 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010778
10779 // Traverse the saved contexts chain to find the active context for the
10780 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010781 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010782 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010783 save = save->prev();
10784 }
10785 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010786 SaveContext savex(isolate);
10787 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010788
10789 // Create the (empty) function replacing the function on the stack frame for
10790 // the purpose of evaluating in the context created below. It is important
10791 // that this function does not describe any parameters and local variables
10792 // in the context. If it does then this will cause problems with the lookup
10793 // in Context::Lookup, where context slots for parameters and local variables
10794 // are looked at before the extension object.
10795 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010796 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10797 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010798 go_between->set_context(function->context());
10799#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010800 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010801 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10802 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10803#endif
10804
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010805 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010806 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10807 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010808
10809 // Allocate a new context for the debug evaluation and set the extension
10810 // object build.
10811 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010812 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10813 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010814 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010815 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010816 Handle<Context> frame_context(Context::cast(frame->context()));
10817 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010818 context = CopyWithContextChain(frame_context, context);
10819
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010820 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010821 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010822 Handle<JSObject>::cast(additional_context), false);
10823 }
10824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010825 // Wrap the evaluation statement in a new function compiled in the newly
10826 // created context. The function has one parameter which has to be called
10827 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010828 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010829 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010830
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010831 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010832 isolate->factory()->NewStringFromAscii(
10833 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010834
10835 // Currently, the eval code will be executed in non-strict mode,
10836 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010837 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010838 Compiler::CompileEval(function_source,
10839 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010840 context->IsGlobalContext(),
10841 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010842 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010843 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010844 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010845
10846 // Invoke the result of the compilation to get the evaluation function.
10847 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010848 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010849 Handle<Object> evaluation_function =
10850 Execution::Call(compiled_function, receiver, 0, NULL,
10851 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010852 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010854 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10855 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010856 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010857
10858 // Invoke the evaluation function and return the result.
10859 const int argc = 2;
10860 Object** argv[argc] = { arguments.location(),
10861 Handle<Object>::cast(source).location() };
10862 Handle<Object> result =
10863 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10864 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010865 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010866
10867 // Skip the global proxy as it has no properties and always delegates to the
10868 // real global object.
10869 if (result->IsJSGlobalProxy()) {
10870 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10871 }
10872
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873 return *result;
10874}
10875
10876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010877RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010878 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010879
10880 // Check the execution state and decode arguments frame and source to be
10881 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010882 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010883 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010884 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10885 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010886 if (!maybe_check_result->ToObject(&check_result)) {
10887 return maybe_check_result;
10888 }
10889 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010891 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010892 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010893
10894 // Handle the processing of break.
10895 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010896
10897 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010898 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010899 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010900 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010901 top = top->prev();
10902 }
10903 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010904 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010905 }
10906
10907 // Get the global context now set to the top context from before the
10908 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010909 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010910
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010911 bool is_global = true;
10912
10913 if (additional_context->IsJSObject()) {
10914 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010915 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10916 isolate->factory()->empty_string(),
10917 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010918 go_between->set_context(*context);
10919 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010920 isolate->factory()->NewFunctionContext(
10921 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010922 context->set_extension(JSObject::cast(*additional_context));
10923 is_global = false;
10924 }
10925
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010926 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010927 // Currently, the eval code will be executed in non-strict mode,
10928 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010929 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010930 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010931 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010932 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010933 Handle<JSFunction>(
10934 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10935 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010936
10937 // Invoke the result of the compilation to get the evaluation function.
10938 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010939 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010940 Handle<Object> result =
10941 Execution::Call(compiled_function, receiver, 0, NULL,
10942 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010943 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010944 return *result;
10945}
10946
10947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010948RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010949 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010950 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010951
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010952 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010953 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010954
10955 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010956 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010957 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10958 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10959 // because using
10960 // instances->set(i, *GetScriptWrapper(script))
10961 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10962 // already have deferenced the instances handle.
10963 Handle<JSValue> wrapper = GetScriptWrapper(script);
10964 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010965 }
10966
10967 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010968 Handle<JSObject> result =
10969 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010970 Handle<JSArray>::cast(result)->SetContent(*instances);
10971 return *result;
10972}
10973
10974
10975// Helper function used by Runtime_DebugReferencedBy below.
10976static int DebugReferencedBy(JSObject* target,
10977 Object* instance_filter, int max_references,
10978 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979 JSFunction* arguments_function) {
10980 NoHandleAllocation ha;
10981 AssertNoAllocation no_alloc;
10982
10983 // Iterate the heap.
10984 int count = 0;
10985 JSObject* last = NULL;
10986 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010987 HeapObject* heap_obj = NULL;
10988 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010989 (max_references == 0 || count < max_references)) {
10990 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010991 if (heap_obj->IsJSObject()) {
10992 // Skip context extension objects and argument arrays as these are
10993 // checked in the context of functions using them.
10994 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010995 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010996 obj->map()->constructor() == arguments_function) {
10997 continue;
10998 }
10999
11000 // Check if the JS object has a reference to the object looked for.
11001 if (obj->ReferencesObject(target)) {
11002 // Check instance filter if supplied. This is normally used to avoid
11003 // references from mirror objects (see Runtime_IsInPrototypeChain).
11004 if (!instance_filter->IsUndefined()) {
11005 Object* V = obj;
11006 while (true) {
11007 Object* prototype = V->GetPrototype();
11008 if (prototype->IsNull()) {
11009 break;
11010 }
11011 if (instance_filter == prototype) {
11012 obj = NULL; // Don't add this object.
11013 break;
11014 }
11015 V = prototype;
11016 }
11017 }
11018
11019 if (obj != NULL) {
11020 // Valid reference found add to instance array if supplied an update
11021 // count.
11022 if (instances != NULL && count < instances_size) {
11023 instances->set(count, obj);
11024 }
11025 last = obj;
11026 count++;
11027 }
11028 }
11029 }
11030 }
11031
11032 // Check for circular reference only. This can happen when the object is only
11033 // referenced from mirrors and has a circular reference in which case the
11034 // object is not really alive and would have been garbage collected if not
11035 // referenced from the mirror.
11036 if (count == 1 && last == target) {
11037 count = 0;
11038 }
11039
11040 // Return the number of referencing objects found.
11041 return count;
11042}
11043
11044
11045// Scan the heap for objects with direct references to an object
11046// args[0]: the object to find references to
11047// args[1]: constructor function for instances to exclude (Mirror)
11048// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011049RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011050 ASSERT(args.length() == 3);
11051
11052 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011053 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011054
11055 // Check parameters.
11056 CONVERT_CHECKED(JSObject, target, args[0]);
11057 Object* instance_filter = args[1];
11058 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11059 instance_filter->IsJSObject());
11060 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11061 RUNTIME_ASSERT(max_references >= 0);
11062
11063 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011064 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011065 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011066 JSFunction* arguments_function =
11067 JSFunction::cast(arguments_boilerplate->map()->constructor());
11068
11069 // Get the number of referencing objects.
11070 int count;
11071 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011072 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011073
11074 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011075 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011076 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011077 if (!maybe_object->ToObject(&object)) return maybe_object;
11078 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011079 FixedArray* instances = FixedArray::cast(object);
11080
11081 // Fill the referencing objects.
11082 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011083 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011084
11085 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011086 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011087 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11088 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011089 if (!maybe_result->ToObject(&result)) return maybe_result;
11090 }
11091 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011092 return result;
11093}
11094
11095
11096// Helper function used by Runtime_DebugConstructedBy below.
11097static int DebugConstructedBy(JSFunction* constructor, int max_references,
11098 FixedArray* instances, int instances_size) {
11099 AssertNoAllocation no_alloc;
11100
11101 // Iterate the heap.
11102 int count = 0;
11103 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011104 HeapObject* heap_obj = NULL;
11105 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011106 (max_references == 0 || count < max_references)) {
11107 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011108 if (heap_obj->IsJSObject()) {
11109 JSObject* obj = JSObject::cast(heap_obj);
11110 if (obj->map()->constructor() == constructor) {
11111 // Valid reference found add to instance array if supplied an update
11112 // count.
11113 if (instances != NULL && count < instances_size) {
11114 instances->set(count, obj);
11115 }
11116 count++;
11117 }
11118 }
11119 }
11120
11121 // Return the number of referencing objects found.
11122 return count;
11123}
11124
11125
11126// Scan the heap for objects constructed by a specific function.
11127// args[0]: the constructor to find instances of
11128// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011129RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011130 ASSERT(args.length() == 2);
11131
11132 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011133 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011134
11135 // Check parameters.
11136 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11137 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11138 RUNTIME_ASSERT(max_references >= 0);
11139
11140 // Get the number of referencing objects.
11141 int count;
11142 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11143
11144 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011145 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011146 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011147 if (!maybe_object->ToObject(&object)) return maybe_object;
11148 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011149 FixedArray* instances = FixedArray::cast(object);
11150
11151 // Fill the referencing objects.
11152 count = DebugConstructedBy(constructor, max_references, instances, count);
11153
11154 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011155 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011156 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11157 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011158 if (!maybe_result->ToObject(&result)) return maybe_result;
11159 }
11160 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011161 return result;
11162}
11163
11164
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011165// Find the effective prototype object as returned by __proto__.
11166// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011167RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011168 ASSERT(args.length() == 1);
11169
11170 CONVERT_CHECKED(JSObject, obj, args[0]);
11171
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011172 // Use the __proto__ accessor.
11173 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011174}
11175
11176
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011177RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011178 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011179 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011180 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011181}
11182
11183
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011184RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011185#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011186 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011187 ASSERT(args.length() == 1);
11188 // Get the function and make sure it is compiled.
11189 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011190 Handle<SharedFunctionInfo> shared(func->shared());
11191 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011192 return Failure::Exception();
11193 }
11194 func->code()->PrintLn();
11195#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011196 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011197}
ager@chromium.org9085a012009-05-11 19:22:57 +000011198
11199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011200RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011201#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011202 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011203 ASSERT(args.length() == 1);
11204 // Get the function and make sure it is compiled.
11205 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011206 Handle<SharedFunctionInfo> shared(func->shared());
11207 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011208 return Failure::Exception();
11209 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011210 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011211#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011212 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011213}
11214
11215
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011216RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011217 NoHandleAllocation ha;
11218 ASSERT(args.length() == 1);
11219
11220 CONVERT_CHECKED(JSFunction, f, args[0]);
11221 return f->shared()->inferred_name();
11222}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011223
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011224
11225static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011226 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011227 AssertNoAllocation no_allocations;
11228
11229 int counter = 0;
11230 int buffer_size = buffer->length();
11231 HeapIterator iterator;
11232 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11233 ASSERT(obj != NULL);
11234 if (!obj->IsSharedFunctionInfo()) {
11235 continue;
11236 }
11237 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11238 if (shared->script() != script) {
11239 continue;
11240 }
11241 if (counter < buffer_size) {
11242 buffer->set(counter, shared);
11243 }
11244 counter++;
11245 }
11246 return counter;
11247}
11248
11249// For a script finds all SharedFunctionInfo's in the heap that points
11250// to this script. Returns JSArray of SharedFunctionInfo wrapped
11251// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011252RUNTIME_FUNCTION(MaybeObject*,
11253 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011254 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011255 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011256 CONVERT_CHECKED(JSValue, script_value, args[0]);
11257
11258 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11259
11260 const int kBufferSize = 32;
11261
11262 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011263 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011264 int number = FindSharedFunctionInfosForScript(*script, *array);
11265 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011266 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011267 FindSharedFunctionInfosForScript(*script, *array);
11268 }
11269
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011270 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011271 result->set_length(Smi::FromInt(number));
11272
11273 LiveEdit::WrapSharedFunctionInfos(result);
11274
11275 return *result;
11276}
11277
11278// For a script calculates compilation information about all its functions.
11279// The script source is explicitly specified by the second argument.
11280// The source of the actual script is not used, however it is important that
11281// all generated code keeps references to this particular instance of script.
11282// Returns a JSArray of compilation infos. The array is ordered so that
11283// each function with all its descendant is always stored in a continues range
11284// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011285RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011286 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011287 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011288 CONVERT_CHECKED(JSValue, script, args[0]);
11289 CONVERT_ARG_CHECKED(String, source, 1);
11290 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11291
11292 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11293
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011294 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011295 return Failure::Exception();
11296 }
11297
11298 return result;
11299}
11300
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011301// Changes the source of the script to a new_source.
11302// If old_script_name is provided (i.e. is a String), also creates a copy of
11303// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011304RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011305 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011306 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011307 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11308 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011309 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011310
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011311 CONVERT_CHECKED(Script, original_script_pointer,
11312 original_script_value->value());
11313 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011314
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011315 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11316 new_source,
11317 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011318
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011319 if (old_script->IsScript()) {
11320 Handle<Script> script_handle(Script::cast(old_script));
11321 return *(GetScriptWrapper(script_handle));
11322 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011323 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011324 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011325}
11326
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011328RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011329 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011330 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011331 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11332 return LiveEdit::FunctionSourceUpdated(shared_info);
11333}
11334
11335
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011336// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011337RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011338 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011339 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011340 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11341 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11342
ager@chromium.orgac091b72010-05-05 07:34:42 +000011343 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011344}
11345
11346// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011347RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011348 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011349 HandleScope scope(isolate);
11350 Handle<Object> function_object(args[0], isolate);
11351 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011352
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011353 if (function_object->IsJSValue()) {
11354 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11355 if (script_object->IsJSValue()) {
11356 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011357 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011358 }
11359
11360 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11361 } else {
11362 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11363 // and we check it in this function.
11364 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011365
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011366 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011367}
11368
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011369
11370// In a code of a parent function replaces original function as embedded object
11371// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011372RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011373 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011374 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011375
11376 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11377 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11378 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11379
11380 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11381 subst_wrapper);
11382
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011383 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011384}
11385
11386
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011387// Updates positions of a shared function info (first parameter) according
11388// to script source change. Text change is described in second parameter as
11389// array of groups of 3 numbers:
11390// (change_begin, change_end, change_end_new_position).
11391// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011392RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011393 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011394 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011395 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11396 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11397
ager@chromium.orgac091b72010-05-05 07:34:42 +000011398 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011399}
11400
11401
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011402// For array of SharedFunctionInfo's (each wrapped in JSValue)
11403// checks that none of them have activations on stacks (of any thread).
11404// Returns array of the same length with corresponding results of
11405// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011406RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011407 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011408 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011409 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011410 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011411
ager@chromium.org357bf652010-04-12 11:30:10 +000011412 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011413}
11414
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011415// Compares 2 strings line-by-line, then token-wise and returns diff in form
11416// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11417// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011418RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011419 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011420 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011421 CONVERT_ARG_CHECKED(String, s1, 0);
11422 CONVERT_ARG_CHECKED(String, s2, 1);
11423
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011424 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011425}
11426
11427
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011428// A testing entry. Returns statement position which is the closest to
11429// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011430RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011431 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011432 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011433 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11434 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11435
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011436 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011437
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011438 if (code->kind() != Code::FUNCTION &&
11439 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011440 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011441 }
11442
11443 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011444 int closest_pc = 0;
11445 int distance = kMaxInt;
11446 while (!it.done()) {
11447 int statement_position = static_cast<int>(it.rinfo()->data());
11448 // Check if this break point is closer that what was previously found.
11449 if (source_position <= statement_position &&
11450 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011451 closest_pc =
11452 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011453 distance = statement_position - source_position;
11454 // Check whether we can't get any closer.
11455 if (distance == 0) break;
11456 }
11457 it.next();
11458 }
11459
11460 return Smi::FromInt(closest_pc);
11461}
11462
11463
ager@chromium.org357bf652010-04-12 11:30:10 +000011464// Calls specified function with or without entering the debugger.
11465// This is used in unit tests to run code as if debugger is entered or simply
11466// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011467RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011468 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011469 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011470 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11471 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11472
11473 Handle<Object> result;
11474 bool pending_exception;
11475 {
11476 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011477 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011478 &pending_exception);
11479 } else {
11480 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011481 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011482 &pending_exception);
11483 }
11484 }
11485 if (!pending_exception) {
11486 return *result;
11487 } else {
11488 return Failure::Exception();
11489 }
11490}
11491
11492
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011493// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011494RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011495 CONVERT_CHECKED(String, arg, args[0]);
11496 SmartPointer<char> flags =
11497 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11498 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011499 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011500}
11501
11502
11503// Performs a GC.
11504// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011505RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011506 isolate->heap()->CollectAllGarbage(true);
11507 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011508}
11509
11510
11511// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011512RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011513 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011514 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011515 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011516 }
11517 return Smi::FromInt(usage);
11518}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011519
11520
11521// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011522RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011523#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011524 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011525#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011526 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011527#endif
11528}
11529
11530
11531// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011532RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011533#ifdef LIVE_OBJECT_LIST
11534 return LiveObjectList::Capture();
11535#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011536 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011537#endif
11538}
11539
11540
11541// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011542RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011543#ifdef LIVE_OBJECT_LIST
11544 CONVERT_SMI_CHECKED(id, args[0]);
11545 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011546 return success ? isolate->heap()->true_value() :
11547 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011548#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011549 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011550#endif
11551}
11552
11553
11554// Generates the response to a debugger request for a dump of the objects
11555// contained in the difference between the captured live object lists
11556// specified by id1 and id2.
11557// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11558// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011559RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011560#ifdef LIVE_OBJECT_LIST
11561 HandleScope scope;
11562 CONVERT_SMI_CHECKED(id1, args[0]);
11563 CONVERT_SMI_CHECKED(id2, args[1]);
11564 CONVERT_SMI_CHECKED(start, args[2]);
11565 CONVERT_SMI_CHECKED(count, args[3]);
11566 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11567 EnterDebugger enter_debugger;
11568 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11569#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011570 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011571#endif
11572}
11573
11574
11575// Gets the specified object as requested by the debugger.
11576// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011577RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011578#ifdef LIVE_OBJECT_LIST
11579 CONVERT_SMI_CHECKED(obj_id, args[0]);
11580 Object* result = LiveObjectList::GetObj(obj_id);
11581 return result;
11582#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011583 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011584#endif
11585}
11586
11587
11588// Gets the obj id for the specified address if valid.
11589// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011590RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011591#ifdef LIVE_OBJECT_LIST
11592 HandleScope scope;
11593 CONVERT_ARG_CHECKED(String, address, 0);
11594 Object* result = LiveObjectList::GetObjId(address);
11595 return result;
11596#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011597 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011598#endif
11599}
11600
11601
11602// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011603RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011604#ifdef LIVE_OBJECT_LIST
11605 HandleScope scope;
11606 CONVERT_SMI_CHECKED(obj_id, args[0]);
11607 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11608 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11609 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11610 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11611 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11612
11613 Handle<JSObject> instance_filter;
11614 if (args[1]->IsJSObject()) {
11615 instance_filter = args.at<JSObject>(1);
11616 }
11617 bool verbose = false;
11618 if (args[2]->IsBoolean()) {
11619 verbose = args[2]->IsTrue();
11620 }
11621 int start = 0;
11622 if (args[3]->IsSmi()) {
11623 start = Smi::cast(args[3])->value();
11624 }
11625 int limit = Smi::kMaxValue;
11626 if (args[4]->IsSmi()) {
11627 limit = Smi::cast(args[4])->value();
11628 }
11629
11630 return LiveObjectList::GetObjRetainers(obj_id,
11631 instance_filter,
11632 verbose,
11633 start,
11634 limit,
11635 filter_obj);
11636#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011637 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011638#endif
11639}
11640
11641
11642// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011643RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011644#ifdef LIVE_OBJECT_LIST
11645 HandleScope scope;
11646 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11647 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11648 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11649
11650 Handle<JSObject> instance_filter;
11651 if (args[2]->IsJSObject()) {
11652 instance_filter = args.at<JSObject>(2);
11653 }
11654
11655 Object* result =
11656 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11657 return result;
11658#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011659 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011660#endif
11661}
11662
11663
11664// Generates the response to a debugger request for a list of all
11665// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011666RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011667#ifdef LIVE_OBJECT_LIST
11668 CONVERT_SMI_CHECKED(start, args[0]);
11669 CONVERT_SMI_CHECKED(count, args[1]);
11670 return LiveObjectList::Info(start, count);
11671#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011672 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011673#endif
11674}
11675
11676
11677// Gets a dump of the specified object as requested by the debugger.
11678// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011679RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011680#ifdef LIVE_OBJECT_LIST
11681 HandleScope scope;
11682 CONVERT_SMI_CHECKED(obj_id, args[0]);
11683 Object* result = LiveObjectList::PrintObj(obj_id);
11684 return result;
11685#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011686 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011687#endif
11688}
11689
11690
11691// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011692RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011693#ifdef LIVE_OBJECT_LIST
11694 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011695 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011696#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011697 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011698#endif
11699}
11700
11701
11702// Generates the response to a debugger request for a summary of the types
11703// of objects in the difference between the captured live object lists
11704// specified by id1 and id2.
11705// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11706// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011707RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011708#ifdef LIVE_OBJECT_LIST
11709 HandleScope scope;
11710 CONVERT_SMI_CHECKED(id1, args[0]);
11711 CONVERT_SMI_CHECKED(id2, args[1]);
11712 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11713
11714 EnterDebugger enter_debugger;
11715 return LiveObjectList::Summarize(id1, id2, filter_obj);
11716#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011717 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011718#endif
11719}
11720
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011721#endif // ENABLE_DEBUGGER_SUPPORT
11722
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011723
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011724#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011725RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011726 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011727 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011728
11729 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011730 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11731 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011732 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011733}
11734
11735
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011736RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011737 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011738 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011739
11740 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011741 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11742 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011743 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011744}
11745
11746#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011747
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011748// Finds the script object from the script data. NOTE: This operation uses
11749// heap traversal to find the function generated for the source position
11750// for the requested break point. For lazily compiled functions several heap
11751// traversals might be required rendering this operation as a rather slow
11752// operation. However for setting break points which is normally done through
11753// some kind of user interaction the performance is not crucial.
11754static Handle<Object> Runtime_GetScriptFromScriptName(
11755 Handle<String> script_name) {
11756 // Scan the heap for Script objects to find the script with the requested
11757 // script data.
11758 Handle<Script> script;
11759 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011760 HeapObject* obj = NULL;
11761 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011762 // If a script is found check if it has the script data requested.
11763 if (obj->IsScript()) {
11764 if (Script::cast(obj)->name()->IsString()) {
11765 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11766 script = Handle<Script>(Script::cast(obj));
11767 }
11768 }
11769 }
11770 }
11771
11772 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011773 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774
11775 // Return the script found.
11776 return GetScriptWrapper(script);
11777}
11778
11779
11780// Get the script object from script data. NOTE: Regarding performance
11781// see the NOTE for GetScriptFromScriptData.
11782// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011783RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011784 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011785
11786 ASSERT(args.length() == 1);
11787
11788 CONVERT_CHECKED(String, script_name, args[0]);
11789
11790 // Find the requested script.
11791 Handle<Object> result =
11792 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11793 return *result;
11794}
11795
11796
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011797// Determines whether the given stack frame should be displayed in
11798// a stack trace. The caller is the error constructor that asked
11799// for the stack trace to be collected. The first time a construct
11800// call to this function is encountered it is skipped. The seen_caller
11801// in/out parameter is used to remember if the caller has been seen
11802// yet.
11803static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11804 bool* seen_caller) {
11805 // Only display JS frames.
11806 if (!raw_frame->is_java_script())
11807 return false;
11808 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11809 Object* raw_fun = frame->function();
11810 // Not sure when this can happen but skip it just in case.
11811 if (!raw_fun->IsJSFunction())
11812 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011813 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011814 *seen_caller = true;
11815 return false;
11816 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011817 // Skip all frames until we've seen the caller. Also, skip the most
11818 // obvious builtin calls. Some builtin calls (such as Number.ADD
11819 // which is invoked using 'call') are very difficult to recognize
11820 // so we're leaving them in for now.
11821 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011822}
11823
11824
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011825// Collect the raw data for a stack trace. Returns an array of 4
11826// element segments each containing a receiver, function, code and
11827// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011828RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011829 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011830 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011831 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11832
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011833 HandleScope scope(isolate);
11834 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011835
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011836 limit = Max(limit, 0); // Ensure that limit is not negative.
11837 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011838 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011839 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011840
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011841 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011842 // If the caller parameter is a function we skip frames until we're
11843 // under it before starting to collect.
11844 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011845 int cursor = 0;
11846 int frames_seen = 0;
11847 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011848 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011849 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011850 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011851 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011852 // Set initial size to the maximum inlining level + 1 for the outermost
11853 // function.
11854 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011855 frame->Summarize(&frames);
11856 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011857 if (cursor + 4 > elements->length()) {
11858 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11859 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011860 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011861 for (int i = 0; i < cursor; i++) {
11862 new_elements->set(i, elements->get(i));
11863 }
11864 elements = new_elements;
11865 }
11866 ASSERT(cursor + 4 <= elements->length());
11867
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011868 Handle<Object> recv = frames[i].receiver();
11869 Handle<JSFunction> fun = frames[i].function();
11870 Handle<Code> code = frames[i].code();
11871 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011872 elements->set(cursor++, *recv);
11873 elements->set(cursor++, *fun);
11874 elements->set(cursor++, *code);
11875 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011876 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011877 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011878 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011879 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011880 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011881 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011882 return *result;
11883}
11884
11885
ager@chromium.org3811b432009-10-28 14:53:37 +000011886// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011887RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011888 ASSERT_EQ(args.length(), 0);
11889
11890 NoHandleAllocation ha;
11891
11892 const char* version_string = v8::V8::GetVersion();
11893
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011894 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11895 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011896}
11897
11898
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011899RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011900 ASSERT(args.length() == 2);
11901 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11902 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011903 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011904 OS::Abort();
11905 UNREACHABLE();
11906 return NULL;
11907}
11908
11909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011910RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011911 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011912 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011913 Object* key = args[1];
11914
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011915 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011916 Object* o = cache->get(finger_index);
11917 if (o == key) {
11918 // The fastest case: hit the same place again.
11919 return cache->get(finger_index + 1);
11920 }
11921
11922 for (int i = finger_index - 2;
11923 i >= JSFunctionResultCache::kEntriesIndex;
11924 i -= 2) {
11925 o = cache->get(i);
11926 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011927 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011928 return cache->get(i + 1);
11929 }
11930 }
11931
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011932 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011933 ASSERT(size <= cache->length());
11934
11935 for (int i = size - 2; i > finger_index; i -= 2) {
11936 o = cache->get(i);
11937 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011938 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011939 return cache->get(i + 1);
11940 }
11941 }
11942
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011943 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011944 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011945
11946 Handle<JSFunctionResultCache> cache_handle(cache);
11947 Handle<Object> key_handle(key);
11948 Handle<Object> value;
11949 {
11950 Handle<JSFunction> factory(JSFunction::cast(
11951 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11952 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011953 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011954 // This handle is nor shared, nor used later, so it's safe.
11955 Object** argv[] = { key_handle.location() };
11956 bool pending_exception = false;
11957 value = Execution::Call(factory,
11958 receiver,
11959 1,
11960 argv,
11961 &pending_exception);
11962 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011963 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011964
11965#ifdef DEBUG
11966 cache_handle->JSFunctionResultCacheVerify();
11967#endif
11968
11969 // Function invocation may have cleared the cache. Reread all the data.
11970 finger_index = cache_handle->finger_index();
11971 size = cache_handle->size();
11972
11973 // If we have spare room, put new data into it, otherwise evict post finger
11974 // entry which is likely to be the least recently used.
11975 int index = -1;
11976 if (size < cache_handle->length()) {
11977 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11978 index = size;
11979 } else {
11980 index = finger_index + JSFunctionResultCache::kEntrySize;
11981 if (index == cache_handle->length()) {
11982 index = JSFunctionResultCache::kEntriesIndex;
11983 }
11984 }
11985
11986 ASSERT(index % 2 == 0);
11987 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11988 ASSERT(index < cache_handle->length());
11989
11990 cache_handle->set(index, *key_handle);
11991 cache_handle->set(index + 1, *value);
11992 cache_handle->set_finger_index(index);
11993
11994#ifdef DEBUG
11995 cache_handle->JSFunctionResultCacheVerify();
11996#endif
11997
11998 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011999}
12000
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012001
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012002RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012003 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012004 CONVERT_ARG_CHECKED(String, type, 0);
12005 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012006 return *isolate->factory()->NewJSMessageObject(
12007 type,
12008 arguments,
12009 0,
12010 0,
12011 isolate->factory()->undefined_value(),
12012 isolate->factory()->undefined_value(),
12013 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012014}
12015
12016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012017RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012018 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12019 return message->type();
12020}
12021
12022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012023RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012024 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12025 return message->arguments();
12026}
12027
12028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012029RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012030 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12031 return Smi::FromInt(message->start_position());
12032}
12033
12034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012035RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012036 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12037 return message->script();
12038}
12039
12040
kasper.lund44510672008-07-25 07:37:58 +000012041#ifdef DEBUG
12042// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12043// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012044RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012045 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012046 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012047#define COUNT_ENTRY(Name, argc, ressize) + 1
12048 int entry_count = 0
12049 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12050 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12051 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12052#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012053 Factory* factory = isolate->factory();
12054 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012055 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012056 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012057#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012058 { \
12059 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012060 Handle<String> name; \
12061 /* Inline runtime functions have an underscore in front of the name. */ \
12062 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012063 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012064 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12065 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012066 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012067 Vector<const char>(#Name, StrLength(#Name))); \
12068 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012069 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012070 pair_elements->set(0, *name); \
12071 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012072 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012073 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012074 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012075 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012076 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012077 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012078 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012079 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012080#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012081 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012082 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012083 return *result;
12084}
kasper.lund44510672008-07-25 07:37:58 +000012085#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012086
12087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012088RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012089 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012090 CONVERT_CHECKED(String, format, args[0]);
12091 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012092 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012093 LOGGER->LogRuntime(chars, elms);
12094 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012095}
12096
12097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012098RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099 UNREACHABLE(); // implemented as macro in the parser
12100 return NULL;
12101}
12102
12103
12104// ----------------------------------------------------------------------------
12105// Implementation of Runtime
12106
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012107#define F(name, number_of_args, result_size) \
12108 { Runtime::k##name, Runtime::RUNTIME, #name, \
12109 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012110
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012111
12112#define I(name, number_of_args, result_size) \
12113 { Runtime::kInline##name, Runtime::INLINE, \
12114 "_" #name, NULL, number_of_args, result_size },
12115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012116static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012117 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012118 INLINE_FUNCTION_LIST(I)
12119 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012120};
12121
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012123MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12124 Object* dictionary) {
12125 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012126 ASSERT(dictionary != NULL);
12127 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12128 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012129 Object* name_symbol;
12130 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012131 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012132 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12133 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012134 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012135 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12136 String::cast(name_symbol),
12137 Smi::FromInt(i),
12138 PropertyDetails(NONE, NORMAL));
12139 if (!maybe_dictionary->ToObject(&dictionary)) {
12140 // Non-recoverable failure. Calling code must restart heap
12141 // initialization.
12142 return maybe_dictionary;
12143 }
12144 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012145 }
12146 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012147}
12148
12149
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012150const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12151 Heap* heap = name->GetHeap();
12152 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012153 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012154 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012155 int function_index = Smi::cast(smi_index)->value();
12156 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012157 }
12158 return NULL;
12159}
12160
12161
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012162const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012163 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12164}
12165
12166
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012167void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012168 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012169 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012170 if (failure->IsRetryAfterGC()) {
12171 // Try to do a garbage collection; ignore it if it fails. The C
12172 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012173 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012174 } else {
12175 // Handle last resort GC and make sure to allow future allocations
12176 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012177 isolate->counters()->gc_last_resort_from_js()->Increment();
12178 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012180}
12181
12182
12183} } // namespace v8::internal