blob: 43d34510f4ac4ecce5be2f12d66b3bb33bf88956 [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"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000048#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000051#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000053#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000055#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000056#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
kasperl@chromium.org71affb52009-05-26 05:44:31 +000059namespace v8 {
60namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62
ager@chromium.org3e875802009-06-29 08:26:34 +000063#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000064 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66// Cast the given object to a value of the specified type and store
67// it in a variable with the given name. If the object is not of the
68// expected type call IllegalOperation and return.
69#define CONVERT_CHECKED(Type, name, obj) \
70 RUNTIME_ASSERT(obj->Is##Type()); \
71 Type* name = Type::cast(obj);
72
73#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
75 Handle<Type> name = args.at<Type>(index);
76
kasper.lundbd3ec4e2008-07-09 11:06:54 +000077// Cast the given object to a boolean and store it in a variable with
78// the given name. If the object is not a boolean call IllegalOperation
79// and return.
80#define CONVERT_BOOLEAN_CHECKED(name, obj) \
81 RUNTIME_ASSERT(obj->IsBoolean()); \
82 bool name = (obj)->IsTrue();
83
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000084// Cast the given object to a Smi and store its value in an int variable
85// with the given name. If the object is not a Smi call IllegalOperation
86// and return.
87#define CONVERT_SMI_CHECKED(name, obj) \
88 RUNTIME_ASSERT(obj->IsSmi()); \
89 int name = Smi::cast(obj)->value();
90
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091// Cast the given object to a double and store it in a variable with
92// the given name. If the object is not a number (as opposed to
93// the number not-a-number) call IllegalOperation and return.
94#define CONVERT_DOUBLE_CHECKED(name, obj) \
95 RUNTIME_ASSERT(obj->IsNumber()); \
96 double name = (obj)->Number();
97
98// Call the specified converter on the object *comand store the result in
99// a variable of the specified type with the given name. If the
100// object is not a Number call IllegalOperation and return.
101#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
102 RUNTIME_ASSERT(obj->IsNumber()); \
103 type name = NumberTo##Type(obj);
104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000106MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
107 JSObject* boilerplate) {
108 StackLimitCheck check(isolate);
109 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 if (!maybe_result->ToObject(&result)) return maybe_result;
115 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000116 JSObject* copy = JSObject::cast(result);
117
118 // Deep copy local properties.
119 if (copy->HasFastProperties()) {
120 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000121 for (int i = 0; i < properties->length(); i++) {
122 Object* value = properties->get(i);
123 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000124 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000125 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000126 if (!maybe_result->ToObject(&result)) return maybe_result;
127 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000128 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 }
130 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000131 int nof = copy->map()->inobject_properties();
132 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000133 Object* value = copy->InObjectPropertyAt(i);
134 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000135 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000136 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000137 if (!maybe_result->ToObject(&result)) return maybe_result;
138 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000139 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 }
141 }
142 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 if (!maybe_result->ToObject(&result)) return maybe_result;
146 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000147 FixedArray* names = FixedArray::cast(result);
148 copy->GetLocalPropertyNames(names, 0);
149 for (int i = 0; i < names->length(); i++) {
150 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 // Only deep copy fields from the object literal expression.
155 // In particular, don't try to copy the length attribute of
156 // an array.
157 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 Object* value =
159 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000162 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000163 if (!maybe_result->ToObject(&result)) return maybe_result;
164 }
165 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000166 // Creating object copy for literals. No strict mode needed.
167 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000168 if (!maybe_result->ToObject(&result)) return maybe_result;
169 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000170 }
171 }
172 }
173
174 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000176 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000177 switch (copy->GetElementsKind()) {
178 case JSObject::FAST_ELEMENTS: {
179 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000180 if (elements->map() == heap->fixed_cow_array_map()) {
181 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000182#ifdef DEBUG
183 for (int i = 0; i < elements->length(); i++) {
184 ASSERT(!elements->get(i)->IsJSObject());
185 }
186#endif
187 } else {
188 for (int i = 0; i < elements->length(); i++) {
189 Object* value = elements->get(i);
190 if (value->IsJSObject()) {
191 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000192 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
193 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000194 if (!maybe_result->ToObject(&result)) return maybe_result;
195 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196 elements->set(i, result);
197 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000198 }
199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000201 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000202 case JSObject::DICTIONARY_ELEMENTS: {
203 NumberDictionary* element_dictionary = copy->element_dictionary();
204 int capacity = element_dictionary->Capacity();
205 for (int i = 0; i < capacity; i++) {
206 Object* k = element_dictionary->KeyAt(i);
207 if (element_dictionary->IsKey(k)) {
208 Object* value = element_dictionary->ValueAt(i);
209 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000210 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000211 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
212 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000213 if (!maybe_result->ToObject(&result)) return maybe_result;
214 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000215 element_dictionary->ValueAtPut(i, result);
216 }
217 }
218 }
219 break;
220 }
221 default:
222 UNREACHABLE();
223 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 }
225 return copy;
226}
227
228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000229RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000232}
233
234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000235RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238}
239
240
ager@chromium.org236ad962008-09-25 09:45:57 +0000241static Handle<Map> ComputeObjectLiteralMap(
242 Handle<Context> context,
243 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000244 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000246 int properties_length = constant_properties->length();
247 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000250 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000251 for (int p = 0; p != properties_length; p += 2) {
252 Object* key = constant_properties->get(p);
253 uint32_t element_index = 0;
254 if (key->IsSymbol()) {
255 number_of_symbol_keys++;
256 } else if (key->ToArrayIndex(&element_index)) {
257 // An index key does not require space in the property backing store.
258 number_of_properties--;
259 } else {
260 // Bail out as a non-symbol non-index key makes caching impossible.
261 // ASSERT to make sure that the if condition after the loop is false.
262 ASSERT(number_of_symbol_keys != number_of_properties);
263 break;
264 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000265 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 // If we only have symbols and array indices among keys then we can
267 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000268 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000269 if ((number_of_symbol_keys == number_of_properties) &&
270 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000271 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000272 Handle<FixedArray> keys =
273 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 if (number_of_symbol_keys > 0) {
275 int index = 0;
276 for (int p = 0; p < properties_length; p += 2) {
277 Object* key = constant_properties->get(p);
278 if (key->IsSymbol()) {
279 keys->set(index++, key);
280 }
281 }
282 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000283 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000284 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000285 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000286 }
287 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000288 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000290 Handle<Map>(context->object_function()->initial_map()),
291 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000292}
293
294
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000296 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000297 Handle<FixedArray> literals,
298 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000300
301static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000303 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000304 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000305 bool should_have_fast_elements,
306 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000307 // Get the global context from the literals array. This is the
308 // context in which the function was created and we use the object
309 // function from this context to create the object literal. We do
310 // not use the object function from the current global context
311 // because this might be the object function from another context
312 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000313 Handle<Context> context =
314 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 // In case we have function literals, we want the object to be in
317 // slow properties mode for now. We don't go in the map cache because
318 // maps with constant functions can't be shared if the functions are
319 // not the same (which is the common case).
320 bool is_result_from_cache = false;
321 Handle<Map> map = has_function_literal
322 ? Handle<Map>(context->object_function()->initial_map())
323 : ComputeObjectLiteralMap(context,
324 constant_properties,
325 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000327 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000328
329 // Normalize the elements of the boilerplate to save space if needed.
330 if (!should_have_fast_elements) NormalizeElements(boilerplate);
331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 // Add the constant properties to the boilerplate.
333 int length = constant_properties->length();
334 bool should_transform =
335 !is_result_from_cache && boilerplate->HasFastProperties();
336 if (should_transform || has_function_literal) {
337 // Normalize the properties of object to avoid n^2 behavior
338 // when extending the object multiple properties. Indicate the number of
339 // properties to be added.
340 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
341 }
342
343 for (int index = 0; index < length; index +=2) {
344 Handle<Object> key(constant_properties->get(index+0), isolate);
345 Handle<Object> value(constant_properties->get(index+1), isolate);
346 if (value->IsFixedArray()) {
347 // The value contains the constant_properties of a
348 // simple object or array literal.
349 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
350 value = CreateLiteralBoilerplate(isolate, literals, array);
351 if (value.is_null()) return value;
352 }
353 Handle<Object> result;
354 uint32_t element_index = 0;
355 if (key->IsSymbol()) {
356 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
357 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000358 result = SetOwnElement(boilerplate,
359 element_index,
360 value,
361 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000363 Handle<String> name(String::cast(*key));
364 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000365 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
366 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 } else if (key->ToArrayIndex(&element_index)) {
369 // Array index (uint32).
370 result = SetOwnElement(boilerplate,
371 element_index,
372 value,
373 kNonStrictMode);
374 } else {
375 // Non-uint32 number.
376 ASSERT(key->IsNumber());
377 double num = key->Number();
378 char arr[100];
379 Vector<char> buffer(arr, ARRAY_SIZE(arr));
380 const char* str = DoubleToCString(num, buffer);
381 Handle<String> name =
382 isolate->factory()->NewStringFromAscii(CStrVector(str));
383 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
384 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000386 // If setting the property on the boilerplate throws an
387 // exception, the exception is converted to an empty handle in
388 // the handle based operations. In that case, we need to
389 // convert back to an exception.
390 if (result.is_null()) return result;
391 }
392
393 // Transform to fast properties if necessary. For object literals with
394 // containing function literals we defer this operation until after all
395 // computed properties have been assigned so that we can generate
396 // constant function properties.
397 if (should_transform && !has_function_literal) {
398 TransformToFastProperties(boilerplate,
399 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 }
401
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000402 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000403}
404
405
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000407 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408 Handle<FixedArray> literals,
409 Handle<FixedArray> elements) {
410 // Create the JSArray.
411 Handle<JSFunction> constructor(
412 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 const bool is_cow =
416 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000417 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419
420 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000421 if (is_cow) {
422#ifdef DEBUG
423 // Copy-on-write arrays must be shallow (and simple).
424 for (int i = 0; i < content->length(); i++) {
425 ASSERT(!content->get(i)->IsFixedArray());
426 }
427#endif
428 } else {
429 for (int i = 0; i < content->length(); i++) {
430 if (content->get(i)->IsFixedArray()) {
431 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000433 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
434 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000436 if (result.is_null()) return result;
437 content->set(i, *result);
438 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000439 }
440 }
441
442 // Set the elements.
443 Handle<JSArray>::cast(object)->SetContent(*content);
444 return object;
445}
446
447
448static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000450 Handle<FixedArray> literals,
451 Handle<FixedArray> array) {
452 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000453 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000454 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000455 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000456 return CreateObjectLiteralBoilerplate(isolate,
457 literals,
458 elements,
459 true,
460 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000461 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 return CreateObjectLiteralBoilerplate(isolate,
463 literals,
464 elements,
465 false,
466 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000468 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469 default:
470 UNREACHABLE();
471 return Handle<Object>::null();
472 }
473}
474
475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000476RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000477 // Takes a FixedArray of elements containing the literal elements of
478 // the array literal and produces JSArray with those elements.
479 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000480 // which contains the context from which to get the Array function
481 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000483 ASSERT(args.length() == 3);
484 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
485 CONVERT_SMI_CHECKED(literals_index, args[1]);
486 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000488 Handle<Object> object =
489 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000492 // Update the functions literal and return the boilerplate.
493 literals->set(literals_index, *object);
494 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495}
496
497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000498RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000499 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000500 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000501 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
502 CONVERT_SMI_CHECKED(literals_index, args[1]);
503 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000504 CONVERT_SMI_CHECKED(flags, args[3]);
505 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
506 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000507
508 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509 Handle<Object> boilerplate(literals->get(literals_index), isolate);
510 if (*boilerplate == isolate->heap()->undefined_value()) {
511 boilerplate = CreateObjectLiteralBoilerplate(isolate,
512 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000514 should_have_fast_elements,
515 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 if (boilerplate.is_null()) return Failure::Exception();
517 // Update the functions literal and return the boilerplate.
518 literals->set(literals_index, *boilerplate);
519 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521}
522
523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000524RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000527 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
528 CONVERT_SMI_CHECKED(literals_index, args[1]);
529 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 CONVERT_SMI_CHECKED(flags, args[3]);
531 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
532 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000533
534 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000535 Handle<Object> boilerplate(literals->get(literals_index), isolate);
536 if (*boilerplate == isolate->heap()->undefined_value()) {
537 boilerplate = CreateObjectLiteralBoilerplate(isolate,
538 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000539 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 should_have_fast_elements,
541 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542 if (boilerplate.is_null()) return Failure::Exception();
543 // Update the functions literal and return the boilerplate.
544 literals->set(literals_index, *boilerplate);
545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547}
548
549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000550RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 ASSERT(args.length() == 3);
553 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
554 CONVERT_SMI_CHECKED(literals_index, args[1]);
555 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
556
557 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 Handle<Object> boilerplate(literals->get(literals_index), isolate);
559 if (*boilerplate == isolate->heap()->undefined_value()) {
560 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561 if (boilerplate.is_null()) return Failure::Exception();
562 // Update the functions literal and return the boilerplate.
563 literals->set(literals_index, *boilerplate);
564 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000566}
567
568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000569RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000570 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000571 ASSERT(args.length() == 3);
572 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
573 CONVERT_SMI_CHECKED(literals_index, args[1]);
574 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
575
576 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 Handle<Object> boilerplate(literals->get(literals_index), isolate);
578 if (*boilerplate == isolate->heap()->undefined_value()) {
579 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580 if (boilerplate.is_null()) return Failure::Exception();
581 // Update the functions literal and return the boilerplate.
582 literals->set(literals_index, *boilerplate);
583 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000584 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000585 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000586 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589}
590
591
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000592RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
593 ASSERT(args.length() == 2);
594 Object* handler = args[0];
595 Object* prototype = args[1];
596 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000597 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000598 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
599}
600
601
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000602RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
603 ASSERT(args.length() == 1);
604 Object* obj = args[0];
605 return obj->IsJSProxy()
606 ? isolate->heap()->true_value() : isolate->heap()->false_value();
607}
608
609
610RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
611 ASSERT(args.length() == 1);
612 CONVERT_CHECKED(JSProxy, proxy, args[0]);
613 return proxy->handler();
614}
615
616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000617RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000618 ASSERT(args.length() == 2);
619 CONVERT_CHECKED(String, key, args[0]);
620 Object* value = args[1];
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000621 ASSERT(!value->IsFailure());
ager@chromium.org32912102009-01-16 10:38:43 +0000622 // Create a catch context extension object.
623 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000624 isolate->context()->global_context()->
625 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000626 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000628 if (!maybe_object->ToObject(&object)) return maybe_object;
629 }
ager@chromium.org32912102009-01-16 10:38:43 +0000630 // Assign the exception value to the catch variable and make sure
631 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000632 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000633 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
634 JSObject::cast(object)->SetProperty(
635 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000636 if (!maybe_value->ToObject(&value)) return maybe_value;
637 }
ager@chromium.org32912102009-01-16 10:38:43 +0000638 return object;
639}
640
641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000642RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000643 NoHandleAllocation ha;
644 ASSERT(args.length() == 1);
645 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000646 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647 return JSObject::cast(obj)->class_name();
648}
649
ager@chromium.org7c537e22008-10-16 08:43:32 +0000650
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000651RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
652 NoHandleAllocation ha;
653 ASSERT(args.length() == 1);
654 Object* obj = args[0];
655 obj = obj->GetPrototype();
656 while (obj->IsJSObject() &&
657 JSObject::cast(obj)->map()->is_hidden_prototype()) {
658 obj = obj->GetPrototype();
659 }
660 return obj;
661}
662
663
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665 NoHandleAllocation ha;
666 ASSERT(args.length() == 2);
667 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
668 Object* O = args[0];
669 Object* V = args[1];
670 while (true) {
671 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000672 if (prototype->IsNull()) return isolate->heap()->false_value();
673 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674 V = prototype;
675 }
676}
677
678
ager@chromium.org9085a012009-05-11 19:22:57 +0000679// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000680RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000681 NoHandleAllocation ha;
682 ASSERT(args.length() == 2);
683 CONVERT_CHECKED(JSObject, jsobject, args[0]);
684 CONVERT_CHECKED(JSObject, proto, args[1]);
685
686 // Sanity checks. The old prototype (that we are replacing) could
687 // theoretically be null, but if it is not null then check that we
688 // didn't already install a hidden prototype here.
689 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
690 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
691 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
692
693 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000694 Object* map_or_failure;
695 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
696 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
697 return maybe_map_or_failure;
698 }
699 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000700 Map* new_proto_map = Map::cast(map_or_failure);
701
lrn@chromium.org303ada72010-10-27 09:33:13 +0000702 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
703 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
704 return maybe_map_or_failure;
705 }
706 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000707 Map* new_map = Map::cast(map_or_failure);
708
709 // Set proto's prototype to be the old prototype of the object.
710 new_proto_map->set_prototype(jsobject->GetPrototype());
711 proto->set_map(new_proto_map);
712 new_proto_map->set_is_hidden_prototype();
713
714 // Set the object's prototype to proto.
715 new_map->set_prototype(proto);
716 jsobject->set_map(new_map);
717
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000718 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000719}
720
721
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000723 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000724 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000725 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000726 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000727}
728
729
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000730// Recursively traverses hidden prototypes if property is not found
731static void GetOwnPropertyImplementation(JSObject* obj,
732 String* name,
733 LookupResult* result) {
734 obj->LocalLookupRealNamedProperty(name, result);
735
736 if (!result->IsProperty()) {
737 Object* proto = obj->GetPrototype();
738 if (proto->IsJSObject() &&
739 JSObject::cast(proto)->map()->is_hidden_prototype())
740 GetOwnPropertyImplementation(JSObject::cast(proto),
741 name, result);
742 }
743}
744
745
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000746static bool CheckAccessException(LookupResult* result,
747 v8::AccessType access_type) {
748 if (result->type() == CALLBACKS) {
749 Object* callback = result->GetCallbackObject();
750 if (callback->IsAccessorInfo()) {
751 AccessorInfo* info = AccessorInfo::cast(callback);
752 bool can_access =
753 (access_type == v8::ACCESS_HAS &&
754 (info->all_can_read() || info->all_can_write())) ||
755 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
756 (access_type == v8::ACCESS_SET && info->all_can_write());
757 return can_access;
758 }
759 }
760
761 return false;
762}
763
764
765static bool CheckAccess(JSObject* obj,
766 String* name,
767 LookupResult* result,
768 v8::AccessType access_type) {
769 ASSERT(result->IsProperty());
770
771 JSObject* holder = result->holder();
772 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000773 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000774 while (true) {
775 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000776 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000777 // Access check callback denied the access, but some properties
778 // can have a special permissions which override callbacks descision
779 // (currently see v8::AccessControl).
780 break;
781 }
782
783 if (current == holder) {
784 return true;
785 }
786
787 current = JSObject::cast(current->GetPrototype());
788 }
789
790 // API callbacks can have per callback access exceptions.
791 switch (result->type()) {
792 case CALLBACKS: {
793 if (CheckAccessException(result, access_type)) {
794 return true;
795 }
796 break;
797 }
798 case INTERCEPTOR: {
799 // If the object has an interceptor, try real named properties.
800 // Overwrite the result to fetch the correct property later.
801 holder->LookupRealNamedProperty(name, result);
802 if (result->IsProperty()) {
803 if (CheckAccessException(result, access_type)) {
804 return true;
805 }
806 }
807 break;
808 }
809 default:
810 break;
811 }
812
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000813 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000814 return false;
815}
816
817
818// TODO(1095): we should traverse hidden prototype hierachy as well.
819static bool CheckElementAccess(JSObject* obj,
820 uint32_t index,
821 v8::AccessType access_type) {
822 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000823 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000824 return false;
825 }
826
827 return true;
828}
829
830
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000831// Enumerator used as indices into the array returned from GetOwnProperty
832enum PropertyDescriptorIndices {
833 IS_ACCESSOR_INDEX,
834 VALUE_INDEX,
835 GETTER_INDEX,
836 SETTER_INDEX,
837 WRITABLE_INDEX,
838 ENUMERABLE_INDEX,
839 CONFIGURABLE_INDEX,
840 DESCRIPTOR_SIZE
841};
842
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000843// Returns an array with the property description:
844// if args[1] is not a property on args[0]
845// returns undefined
846// if args[1] is a data property on args[0]
847// [false, value, Writeable, Enumerable, Configurable]
848// if args[1] is an accessor on args[0]
849// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000850RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000851 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000852 Heap* heap = isolate->heap();
853 HandleScope scope(isolate);
854 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
855 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000856 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000857 CONVERT_ARG_CHECKED(JSObject, obj, 0);
858 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000859
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000860 // This could be an element.
861 uint32_t index;
862 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000863 switch (obj->HasLocalElement(index)) {
864 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000866
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000867 case JSObject::STRING_CHARACTER_ELEMENT: {
868 // Special handling of string objects according to ECMAScript 5
869 // 15.5.5.2. Note that this might be a string object with elements
870 // other than the actual string value. This is covered by the
871 // subsequent cases.
872 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
873 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000874 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000875
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000876 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000877 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000878 elms->set(WRITABLE_INDEX, heap->false_value());
879 elms->set(ENUMERABLE_INDEX, heap->false_value());
880 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000881 return *desc;
882 }
883
884 case JSObject::INTERCEPTED_ELEMENT:
885 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000886 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000887 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000888 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000889 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000890 elms->set(WRITABLE_INDEX, heap->true_value());
891 elms->set(ENUMERABLE_INDEX, heap->true_value());
892 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000893 return *desc;
894 }
895
896 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000897 Handle<JSObject> holder = obj;
898 if (obj->IsJSGlobalProxy()) {
899 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000900 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000901 ASSERT(proto->IsJSGlobalObject());
902 holder = Handle<JSObject>(JSObject::cast(proto));
903 }
904 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000905 int entry = dictionary->FindEntry(index);
906 ASSERT(entry != NumberDictionary::kNotFound);
907 PropertyDetails details = dictionary->DetailsAt(entry);
908 switch (details.type()) {
909 case CALLBACKS: {
910 // This is an accessor property with getter and/or setter.
911 FixedArray* callbacks =
912 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000914 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
915 elms->set(GETTER_INDEX, callbacks->get(0));
916 }
917 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
918 elms->set(SETTER_INDEX, callbacks->get(1));
919 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000920 break;
921 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000922 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000923 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000924 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000925 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000926 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000927 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000929 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000930 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000931 default:
932 UNREACHABLE();
933 break;
934 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000935 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
936 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000937 return *desc;
938 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000939 }
940 }
941
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000942 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000943 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000944
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000945 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000946 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000947 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000948
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000949 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000950 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000951 }
952
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000953 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
954 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000955
956 bool is_js_accessor = (result.type() == CALLBACKS) &&
957 (result.GetCallbackObject()->IsFixedArray());
958
959 if (is_js_accessor) {
960 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000961 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000962
963 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
964 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
965 elms->set(GETTER_INDEX, structure->get(0));
966 }
967 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
968 elms->set(SETTER_INDEX, structure->get(1));
969 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000970 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000971 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
972 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000973
974 PropertyAttributes attrs;
975 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000976 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000977 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
978 if (!maybe_value->ToObject(&value)) return maybe_value;
979 }
980 elms->set(VALUE_INDEX, value);
981 }
982
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000983 return *desc;
984}
985
986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000987RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000988 ASSERT(args.length() == 1);
989 CONVERT_CHECKED(JSObject, obj, args[0]);
990 return obj->PreventExtensions();
991}
992
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000993
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000994RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000995 ASSERT(args.length() == 1);
996 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000997 if (obj->IsJSGlobalProxy()) {
998 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000999 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001000 ASSERT(proto->IsJSGlobalObject());
1001 obj = JSObject::cast(proto);
1002 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 return obj->map()->is_extensible() ? isolate->heap()->true_value()
1004 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001005}
1006
1007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001008RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001009 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001011 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1012 CONVERT_ARG_CHECKED(String, pattern, 1);
1013 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001014 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1015 if (result.is_null()) return Failure::Exception();
1016 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017}
1018
1019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001020RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001021 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001023 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001024 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025}
1026
1027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001028RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029 ASSERT(args.length() == 1);
1030 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001031 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033}
1034
1035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001036RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001037 ASSERT(args.length() == 2);
1038 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001039 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001040 int index = field->value();
1041 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1042 InstanceType type = templ->map()->instance_type();
1043 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1044 type == OBJECT_TEMPLATE_INFO_TYPE);
1045 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001046 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001047 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1048 } else {
1049 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1050 }
1051 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052}
1053
1054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001055RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001056 ASSERT(args.length() == 1);
1057 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001058 Map* old_map = object->map();
1059 bool needs_access_checks = old_map->is_access_check_needed();
1060 if (needs_access_checks) {
1061 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001062 Object* new_map;
1063 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1064 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1065 }
ager@chromium.org32912102009-01-16 10:38:43 +00001066
1067 Map::cast(new_map)->set_is_access_check_needed(false);
1068 object->set_map(Map::cast(new_map));
1069 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001070 return needs_access_checks ? isolate->heap()->true_value()
1071 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001072}
1073
1074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001075RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001076 ASSERT(args.length() == 1);
1077 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001078 Map* old_map = object->map();
1079 if (!old_map->is_access_check_needed()) {
1080 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001081 Object* new_map;
1082 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1083 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1084 }
ager@chromium.org32912102009-01-16 10:38:43 +00001085
1086 Map::cast(new_map)->set_is_access_check_needed(true);
1087 object->set_map(Map::cast(new_map));
1088 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001090}
1091
1092
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001093static Failure* ThrowRedeclarationError(Isolate* isolate,
1094 const char* type,
1095 Handle<String> name) {
1096 HandleScope scope(isolate);
1097 Handle<Object> type_handle =
1098 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099 Handle<Object> args[2] = { type_handle, name };
1100 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1102 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103}
1104
1105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001106RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001107 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001108 HandleScope scope(isolate);
1109 Handle<GlobalObject> global = Handle<GlobalObject>(
1110 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111
ager@chromium.org3811b432009-10-28 14:53:37 +00001112 Handle<Context> context = args.at<Context>(0);
1113 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001114 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001115 StrictModeFlag strict_mode =
1116 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1117 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118
1119 // Compute the property attributes. According to ECMA-262, section
1120 // 13, page 71, the property must be read-only and
1121 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1122 // property as read-only, so we don't either.
1123 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1124
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001125 // Traverse the name/value pairs and set the properties.
1126 int length = pairs->length();
1127 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001128 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001130 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001131
1132 // We have to declare a global const property. To capture we only
1133 // assign to it when evaluating the assignment for "const x =
1134 // <expr>" the initial value is the hole.
1135 bool is_const_property = value->IsTheHole();
1136
1137 if (value->IsUndefined() || is_const_property) {
1138 // Lookup the property in the global object, and don't set the
1139 // value of the variable if the property is already there.
1140 LookupResult lookup;
1141 global->Lookup(*name, &lookup);
1142 if (lookup.IsProperty()) {
1143 // Determine if the property is local by comparing the holder
1144 // against the global object. The information will be used to
1145 // avoid throwing re-declaration errors when declaring
1146 // variables or constants that exist in the prototype chain.
1147 bool is_local = (*global == lookup.holder());
1148 // Get the property attributes and determine if the property is
1149 // read-only.
1150 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1151 bool is_read_only = (attributes & READ_ONLY) != 0;
1152 if (lookup.type() == INTERCEPTOR) {
1153 // If the interceptor says the property is there, we
1154 // just return undefined without overwriting the property.
1155 // Otherwise, we continue to setting the property.
1156 if (attributes != ABSENT) {
1157 // Check if the existing property conflicts with regards to const.
1158 if (is_local && (is_read_only || is_const_property)) {
1159 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 };
1162 // The property already exists without conflicting: Go to
1163 // the next declaration.
1164 continue;
1165 }
1166 // Fall-through and introduce the absent property by using
1167 // SetProperty.
1168 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001169 // For const properties, we treat a callback with this name
1170 // even in the prototype as a conflicting declaration.
1171 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001173 }
1174 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 if (is_local && (is_read_only || is_const_property)) {
1176 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 }
1179 // The property already exists without conflicting: Go to
1180 // the next declaration.
1181 continue;
1182 }
1183 }
1184 } else {
1185 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001186 Handle<SharedFunctionInfo> shared =
1187 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1190 context,
1191 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192 value = function;
1193 }
1194
1195 LookupResult lookup;
1196 global->LocalLookup(*name, &lookup);
1197
1198 PropertyAttributes attributes = is_const_property
1199 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1200 : base;
1201
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001202 // There's a local property that we need to overwrite because
1203 // we're either declaring a function or there's an interceptor
1204 // that claims the property is absent.
1205 //
1206 // Check for conflicting re-declarations. We cannot have
1207 // conflicting types in case of intercepted properties because
1208 // they are absent.
1209 if (lookup.IsProperty() &&
1210 (lookup.type() != INTERCEPTOR) &&
1211 (lookup.IsReadOnly() || is_const_property)) {
1212 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001213 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001214 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001216 // Safari does not allow the invocation of callback setters for
1217 // function declarations. To mimic this behavior, we do not allow
1218 // the invocation of setters for function values. This makes a
1219 // difference for global functions with the same names as event
1220 // handlers such as "function onload() {}". Firefox does call the
1221 // onload setter in those case and Safari does not. We follow
1222 // Safari for compatibility.
1223 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001224 // Do not change DONT_DELETE to false from true.
1225 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1226 attributes = static_cast<PropertyAttributes>(
1227 attributes | (lookup.GetAttributes() & DONT_DELETE));
1228 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001229 RETURN_IF_EMPTY_HANDLE(isolate,
1230 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001231 name,
1232 value,
1233 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001235 RETURN_IF_EMPTY_HANDLE(isolate,
1236 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001237 name,
1238 value,
1239 attributes,
1240 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 }
1242 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001244 ASSERT(!isolate->has_pending_exception());
1245 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001246}
1247
1248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001249RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001250 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001251 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252
ager@chromium.org7c537e22008-10-16 08:43:32 +00001253 CONVERT_ARG_CHECKED(Context, context, 0);
1254 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001256 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001257 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001258 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001259
1260 // Declarations are always done in the function context.
1261 context = Handle<Context>(context->fcontext());
1262
1263 int index;
1264 PropertyAttributes attributes;
1265 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001266 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 context->Lookup(name, flags, &index, &attributes);
1268
1269 if (attributes != ABSENT) {
1270 // The name was declared before; check for conflicting
1271 // re-declarations: This is similar to the code in parser.cc in
1272 // the AstBuildingParser::Declare function.
1273 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1274 // Functions are not read-only.
1275 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1276 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 }
1279
1280 // Initialize it if necessary.
1281 if (*initial_value != NULL) {
1282 if (index >= 0) {
1283 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001284 // the function context or the arguments object.
1285 if (holder->IsContext()) {
1286 ASSERT(holder.is_identical_to(context));
1287 if (((attributes & READ_ONLY) == 0) ||
1288 context->get(index)->IsTheHole()) {
1289 context->set(index, *initial_value);
1290 }
1291 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001292 // The holder is an arguments object.
1293 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001294 Handle<Object> result = SetElement(arguments, index, initial_value,
1295 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001296 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297 }
1298 } else {
1299 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001300 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001301 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001303 SetProperty(context_ext, name, initial_value,
1304 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 }
1306 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001308 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001309 // The property is not in the function context. It needs to be
1310 // "declared" in the function context's extension context, or in the
1311 // global context.
1312 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001313 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001314 // The function context's extension context exists - use it.
1315 context_ext = Handle<JSObject>(context->extension());
1316 } else {
1317 // The function context's extension context does not exists - allocate
1318 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001319 context_ext = isolate->factory()->NewJSObject(
1320 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001321 // And store it in the extension slot.
1322 context->set_extension(*context_ext);
1323 }
1324 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325
ager@chromium.org7c537e22008-10-16 08:43:32 +00001326 // Declare the property by setting it to the initial value if provided,
1327 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1328 // constant declarations).
1329 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001330 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001331 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001332 // Declaring a const context slot is a conflicting declaration if
1333 // there is a callback with that name in a prototype. It is
1334 // allowed to introduce const variables in
1335 // JSContextExtensionObjects. They are treated specially in
1336 // SetProperty and no setters are invoked for those since they are
1337 // not real JSObjects.
1338 if (initial_value->IsTheHole() &&
1339 !context_ext->IsJSContextExtensionObject()) {
1340 LookupResult lookup;
1341 context_ext->Lookup(*name, &lookup);
1342 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001343 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001344 }
1345 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001346 RETURN_IF_EMPTY_HANDLE(isolate,
1347 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001348 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001349 }
1350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001351 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352}
1353
1354
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001355RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001357 // args[0] == name
1358 // args[1] == strict_mode
1359 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360
1361 // Determine if we need to assign to the variable if it already
1362 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001363 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1364 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365
1366 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001367 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001368 RUNTIME_ASSERT(args[1]->IsSmi());
1369 StrictModeFlag strict_mode =
1370 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1371 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372
1373 // According to ECMA-262, section 12.2, page 62, the property must
1374 // not be deletable.
1375 PropertyAttributes attributes = DONT_DELETE;
1376
1377 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001378 // there, there is a property with this name in the prototype chain.
1379 // We follow Safari and Firefox behavior and only set the property
1380 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001381 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001382 // Note that objects can have hidden prototypes, so we need to traverse
1383 // the whole chain of hidden prototypes to do a 'local' lookup.
1384 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001386 while (true) {
1387 real_holder->LocalLookup(*name, &lookup);
1388 if (lookup.IsProperty()) {
1389 // Determine if this is a redeclaration of something read-only.
1390 if (lookup.IsReadOnly()) {
1391 // If we found readonly property on one of hidden prototypes,
1392 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001393 if (real_holder != isolate->context()->global()) break;
1394 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001395 }
1396
1397 // Determine if this is a redeclaration of an intercepted read-only
1398 // property and figure out if the property exists at all.
1399 bool found = true;
1400 PropertyType type = lookup.type();
1401 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001403 Handle<JSObject> holder(real_holder);
1404 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1405 real_holder = *holder;
1406 if (intercepted == ABSENT) {
1407 // The interceptor claims the property isn't there. We need to
1408 // make sure to introduce it.
1409 found = false;
1410 } else if ((intercepted & READ_ONLY) != 0) {
1411 // The property is present, but read-only. Since we're trying to
1412 // overwrite it with a variable declaration we must throw a
1413 // re-declaration error. However if we found readonly property
1414 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001415 if (real_holder != isolate->context()->global()) break;
1416 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001417 }
1418 }
1419
1420 if (found && !assign) {
1421 // The global property is there and we're not assigning any value
1422 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001423 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001424 }
1425
1426 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001427 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001428 return real_holder->SetProperty(
1429 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001430 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001431
1432 Object* proto = real_holder->GetPrototype();
1433 if (!proto->IsJSObject())
1434 break;
1435
1436 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1437 break;
1438
1439 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440 }
1441
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001442 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001443 if (assign) {
1444 return global->SetProperty(*name, args[2], attributes, strict_mode);
1445 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447}
1448
1449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001450RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001451 // All constants are declared with an initial value. The name
1452 // of the constant is the first argument and the initial value
1453 // is the second.
1454 RUNTIME_ASSERT(args.length() == 2);
1455 CONVERT_ARG_CHECKED(String, name, 0);
1456 Handle<Object> value = args.at<Object>(1);
1457
1458 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001459 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 // According to ECMA-262, section 12.2, page 62, the property must
1462 // not be deletable. Since it's a const, it must be READ_ONLY too.
1463 PropertyAttributes attributes =
1464 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1465
1466 // Lookup the property locally in the global object. If it isn't
1467 // there, we add the property and take special precautions to always
1468 // add it as a local property even in case of callbacks in the
1469 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001470 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 LookupResult lookup;
1472 global->LocalLookup(*name, &lookup);
1473 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001474 return global->SetLocalPropertyIgnoreAttributes(*name,
1475 *value,
1476 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477 }
1478
1479 // Determine if this is a redeclaration of something not
1480 // read-only. In case the result is hidden behind an interceptor we
1481 // need to ask it for the property attributes.
1482 if (!lookup.IsReadOnly()) {
1483 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001485 }
1486
1487 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1488
1489 // Throw re-declaration error if the intercepted property is present
1490 // but not read-only.
1491 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001492 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001493 }
1494
1495 // Restore global object from context (in case of GC) and continue
1496 // with setting the value because the property is either absent or
1497 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001498 HandleScope handle_scope(isolate);
1499 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001501 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 // property through an interceptor and only do it if it's
1503 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001504 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001505 RETURN_IF_EMPTY_HANDLE(isolate,
1506 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001507 name,
1508 value,
1509 attributes,
1510 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001511 return *value;
1512 }
1513
1514 // Set the value, but only we're assigning the initial value to a
1515 // constant. For now, we determine this by checking if the
1516 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001517 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001518 PropertyType type = lookup.type();
1519 if (type == FIELD) {
1520 FixedArray* properties = global->properties();
1521 int index = lookup.GetFieldIndex();
1522 if (properties->get(index)->IsTheHole()) {
1523 properties->set(index, *value);
1524 }
1525 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001526 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1527 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528 }
1529 } else {
1530 // Ignore re-initialization of constants that have already been
1531 // assigned a function value.
1532 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1533 }
1534
1535 // Use the set value as the result of the operation.
1536 return *value;
1537}
1538
1539
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001540RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001541 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 ASSERT(args.length() == 3);
1543
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001544 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545 ASSERT(!value->IsTheHole());
1546 CONVERT_ARG_CHECKED(Context, context, 1);
1547 Handle<String> name(String::cast(args[2]));
1548
1549 // Initializations are always done in the function context.
1550 context = Handle<Context>(context->fcontext());
1551
1552 int index;
1553 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001554 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001555 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 context->Lookup(name, flags, &index, &attributes);
1557
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001558 // In most situations, the property introduced by the const
1559 // declaration should be present in the context extension object.
1560 // However, because declaration and initialization are separate, the
1561 // property might have been deleted (if it was introduced by eval)
1562 // before we reach the initialization point.
1563 //
1564 // Example:
1565 //
1566 // function f() { eval("delete x; const x;"); }
1567 //
1568 // In that case, the initialization behaves like a normal assignment
1569 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001571 // Property was found in a context.
1572 if (holder->IsContext()) {
1573 // The holder cannot be the function context. If it is, there
1574 // should have been a const redeclaration error when declaring
1575 // the const property.
1576 ASSERT(!holder.is_identical_to(context));
1577 if ((attributes & READ_ONLY) == 0) {
1578 Handle<Context>::cast(holder)->set(index, *value);
1579 }
1580 } else {
1581 // The holder is an arguments object.
1582 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001583 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001584 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001585 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001586 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001587 }
1588 return *value;
1589 }
1590
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001591 // The property could not be found, we introduce it in the global
1592 // context.
1593 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 Handle<JSObject> global = Handle<JSObject>(
1595 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001596 // Strict mode not needed (const disallowed in strict mode).
1597 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001598 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001599 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001600 return *value;
1601 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001603 // The property was present in a context extension object.
1604 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001606 if (*context_ext == context->extension()) {
1607 // This is the property that was introduced by the const
1608 // declaration. Set it if it hasn't been set before. NOTE: We
1609 // cannot use GetProperty() to get the current value as it
1610 // 'unholes' the value.
1611 LookupResult lookup;
1612 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1613 ASSERT(lookup.IsProperty()); // the property was declared
1614 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1615
1616 PropertyType type = lookup.type();
1617 if (type == FIELD) {
1618 FixedArray* properties = context_ext->properties();
1619 int index = lookup.GetFieldIndex();
1620 if (properties->get(index)->IsTheHole()) {
1621 properties->set(index, *value);
1622 }
1623 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001624 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1625 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001626 }
1627 } else {
1628 // We should not reach here. Any real, named property should be
1629 // either a field or a dictionary slot.
1630 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 }
1632 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001633 // The property was found in a different context extension object.
1634 // Set it if it is not a read-only property.
1635 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001636 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001637 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001638 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001639 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001641 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001642
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643 return *value;
1644}
1645
1646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001647RUNTIME_FUNCTION(MaybeObject*,
1648 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001650 ASSERT(args.length() == 2);
1651 CONVERT_ARG_CHECKED(JSObject, object, 0);
1652 CONVERT_SMI_CHECKED(properties, args[1]);
1653 if (object->HasFastProperties()) {
1654 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1655 }
1656 return *object;
1657}
1658
1659
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001660RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001661 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001662 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001663 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1664 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001665 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001666 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001667 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001668 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001669 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001670 RUNTIME_ASSERT(index >= 0);
1671 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001672 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001673 Handle<Object> result = RegExpImpl::Exec(regexp,
1674 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001675 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001676 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001677 if (result.is_null()) return Failure::Exception();
1678 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001679}
1680
1681
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001682RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001683 ASSERT(args.length() == 3);
1684 CONVERT_SMI_CHECKED(elements_count, args[0]);
1685 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001686 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001687 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001688 Object* new_object;
1689 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001690 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001691 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1692 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001693 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001694 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1695 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001696 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1697 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001698 {
1699 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001701 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001702 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001703 }
1704 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001705 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001706 array->set_elements(elements);
1707 array->set_length(Smi::FromInt(elements_count));
1708 // Write in-object properties after the length of the array.
1709 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1710 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1711 return array;
1712}
1713
1714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001715RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001716 AssertNoAllocation no_alloc;
1717 ASSERT(args.length() == 5);
1718 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1719 CONVERT_CHECKED(String, source, args[1]);
1720
1721 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001723
1724 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001725 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001726
1727 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001728 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001729
1730 Map* map = regexp->map();
1731 Object* constructor = map->constructor();
1732 if (constructor->IsJSFunction() &&
1733 JSFunction::cast(constructor)->initial_map() == map) {
1734 // If we still have the original map, set in-object properties directly.
1735 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1736 // TODO(lrn): Consider skipping write barrier on booleans as well.
1737 // Both true and false should be in oldspace at all times.
1738 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1739 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1740 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1741 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1742 Smi::FromInt(0),
1743 SKIP_WRITE_BARRIER);
1744 return regexp;
1745 }
1746
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001748 PropertyAttributes final =
1749 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1750 PropertyAttributes writable =
1751 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001752 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001753 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001755 source,
1756 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001758 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001759 global,
1760 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001761 ASSERT(!result->IsFailure());
1762 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001764 ignoreCase,
1765 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001766 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001767 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001768 multiline,
1769 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001770 ASSERT(!result->IsFailure());
1771 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001773 Smi::FromInt(0),
1774 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001775 ASSERT(!result->IsFailure());
1776 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777 return regexp;
1778}
1779
1780
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001781RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001782 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001783 ASSERT(args.length() == 1);
1784 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1785 // This is necessary to enable fast checks for absence of elements
1786 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001787 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001788 return Smi::FromInt(0);
1789}
1790
1791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001792static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1793 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001794 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001795 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001796 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1797 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1798 Handle<JSFunction> optimized =
1799 isolate->factory()->NewFunction(key,
1800 JS_OBJECT_TYPE,
1801 JSObject::kHeaderSize,
1802 code,
1803 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001804 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001805 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001806 return optimized;
1807}
1808
1809
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001810RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001812 ASSERT(args.length() == 1);
1813 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1814
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001815 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1816 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1817 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1818 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1819 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1820 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1821 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001822
1823 return *holder;
1824}
1825
1826
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001827RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001828 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001829 Context* global_context =
1830 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001831 return global_context->global()->global_receiver();
1832}
1833
1834
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001835RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837 ASSERT(args.length() == 4);
1838 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1839 int index = Smi::cast(args[1])->value();
1840 Handle<String> pattern = args.at<String>(2);
1841 Handle<String> flags = args.at<String>(3);
1842
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001843 // Get the RegExp function from the context in the literals array.
1844 // This is the RegExp function from the context in which the
1845 // function was created. We do not use the RegExp function from the
1846 // current global context because this might be the RegExp function
1847 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001848 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001849 Handle<JSFunction>(
1850 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001851 // Compute the regular expression literal.
1852 bool has_pending_exception;
1853 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001854 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1855 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001856 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001858 return Failure::Exception();
1859 }
1860 literals->set(index, *regexp);
1861 return *regexp;
1862}
1863
1864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001865RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001866 NoHandleAllocation ha;
1867 ASSERT(args.length() == 1);
1868
1869 CONVERT_CHECKED(JSFunction, f, args[0]);
1870 return f->shared()->name();
1871}
1872
1873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001874RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001875 NoHandleAllocation ha;
1876 ASSERT(args.length() == 2);
1877
1878 CONVERT_CHECKED(JSFunction, f, args[0]);
1879 CONVERT_CHECKED(String, name, args[1]);
1880 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001881 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001882}
1883
1884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001885RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001886 NoHandleAllocation ha;
1887 ASSERT(args.length() == 1);
1888
1889 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001890 Object* obj = f->RemovePrototype();
1891 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001892
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001893 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001894}
1895
1896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001897RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001898 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001899 ASSERT(args.length() == 1);
1900
1901 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001902 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1903 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904
1905 return *GetScriptWrapper(Handle<Script>::cast(script));
1906}
1907
1908
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001909RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001910 NoHandleAllocation ha;
1911 ASSERT(args.length() == 1);
1912
1913 CONVERT_CHECKED(JSFunction, f, args[0]);
1914 return f->shared()->GetSourceCode();
1915}
1916
1917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001918RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 NoHandleAllocation ha;
1920 ASSERT(args.length() == 1);
1921
1922 CONVERT_CHECKED(JSFunction, fun, args[0]);
1923 int pos = fun->shared()->start_position();
1924 return Smi::FromInt(pos);
1925}
1926
1927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001928RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001929 ASSERT(args.length() == 2);
1930
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001931 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001932 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1933
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001934 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1935
1936 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001937 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001938}
1939
1940
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001941RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001942 NoHandleAllocation ha;
1943 ASSERT(args.length() == 2);
1944
1945 CONVERT_CHECKED(JSFunction, fun, args[0]);
1946 CONVERT_CHECKED(String, name, args[1]);
1947 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001948 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949}
1950
1951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001952RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 NoHandleAllocation ha;
1954 ASSERT(args.length() == 2);
1955
1956 CONVERT_CHECKED(JSFunction, fun, args[0]);
1957 CONVERT_CHECKED(Smi, length, args[1]);
1958 fun->shared()->set_length(length->value());
1959 return length;
1960}
1961
1962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001963RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001964 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001965 ASSERT(args.length() == 2);
1966
1967 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001968 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001969 Object* obj;
1970 { MaybeObject* maybe_obj =
1971 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1972 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001974 return args[0]; // return TOS
1975}
1976
1977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001978RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001979 NoHandleAllocation ha;
1980 ASSERT(args.length() == 1);
1981
1982 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001983 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1984 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001985}
1986
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001988RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001989 NoHandleAllocation ha;
1990 ASSERT(args.length() == 1);
1991
1992 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001993 return f->IsBuiltin() ? isolate->heap()->true_value() :
1994 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001995}
1996
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001999 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002000 ASSERT(args.length() == 2);
2001
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002002 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002003 Handle<Object> code = args.at<Object>(1);
2004
2005 Handle<Context> context(target->context());
2006
2007 if (!code->IsNull()) {
2008 RUNTIME_ASSERT(code->IsJSFunction());
2009 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002010 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002011
2012 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 return Failure::Exception();
2014 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002015 // Since we don't store the source for this we should never
2016 // optimize this.
2017 shared->code()->set_optimizable(false);
2018
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002019 // Set the code, scope info, formal parameter count,
2020 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002021 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002022 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002023 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002024 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002025 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002026 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002027 // Set the source code of the target function to undefined.
2028 // SetCode is only used for built-in constructors like String,
2029 // Array, and Object, and some web code
2030 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002031 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002032 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002033 // Clear the optimization hints related to the compiled code as these are no
2034 // longer valid when the code is overwritten.
2035 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036 context = Handle<Context>(fun->context());
2037
2038 // Make sure we get a fresh copy of the literal vector to avoid
2039 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002040 int number_of_literals = fun->NumberOfLiterals();
2041 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002042 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002043 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002044 // Insert the object, regexp and array functions in the literals
2045 // array prefix. These are the functions that will be used when
2046 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002047 literals->set(JSFunction::kLiteralGlobalContextIndex,
2048 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002050 // It's okay to skip the write barrier here because the literals
2051 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002052 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002053 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002054 }
2055
2056 target->set_context(*context);
2057 return *target;
2058}
2059
2060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002061RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002062 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002063 ASSERT(args.length() == 2);
2064 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2065 CONVERT_SMI_CHECKED(num, args[1]);
2066 RUNTIME_ASSERT(num >= 0);
2067 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002068 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002069}
2070
2071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002072MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2073 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002074 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002075 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002076 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002077 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002078 }
2079 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002080 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002081}
2082
2083
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002084RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002085 NoHandleAllocation ha;
2086 ASSERT(args.length() == 2);
2087
2088 CONVERT_CHECKED(String, subject, args[0]);
2089 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002090 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002091
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002092 uint32_t i = 0;
2093 if (index->IsSmi()) {
2094 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002095 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002096 i = value;
2097 } else {
2098 ASSERT(index->IsHeapNumber());
2099 double value = HeapNumber::cast(index)->value();
2100 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002101 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002102
2103 // Flatten the string. If someone wants to get a char at an index
2104 // in a cons string, it is likely that more indices will be
2105 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002106 Object* flat;
2107 { MaybeObject* maybe_flat = subject->TryFlatten();
2108 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2109 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002110 subject = String::cast(flat);
2111
2112 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002113 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002114 }
2115
2116 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002117}
2118
2119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002120RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002121 NoHandleAllocation ha;
2122 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002123 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002124}
2125
lrn@chromium.org25156de2010-04-06 13:10:27 +00002126
2127class FixedArrayBuilder {
2128 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002129 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2130 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002131 length_(0) {
2132 // Require a non-zero initial size. Ensures that doubling the size to
2133 // extend the array will work.
2134 ASSERT(initial_capacity > 0);
2135 }
2136
2137 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2138 : array_(backing_store),
2139 length_(0) {
2140 // Require a non-zero initial size. Ensures that doubling the size to
2141 // extend the array will work.
2142 ASSERT(backing_store->length() > 0);
2143 }
2144
2145 bool HasCapacity(int elements) {
2146 int length = array_->length();
2147 int required_length = length_ + elements;
2148 return (length >= required_length);
2149 }
2150
2151 void EnsureCapacity(int elements) {
2152 int length = array_->length();
2153 int required_length = length_ + elements;
2154 if (length < required_length) {
2155 int new_length = length;
2156 do {
2157 new_length *= 2;
2158 } while (new_length < required_length);
2159 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002160 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002161 array_->CopyTo(0, *extended_array, 0, length_);
2162 array_ = extended_array;
2163 }
2164 }
2165
2166 void Add(Object* value) {
2167 ASSERT(length_ < capacity());
2168 array_->set(length_, value);
2169 length_++;
2170 }
2171
2172 void Add(Smi* value) {
2173 ASSERT(length_ < capacity());
2174 array_->set(length_, value);
2175 length_++;
2176 }
2177
2178 Handle<FixedArray> array() {
2179 return array_;
2180 }
2181
2182 int length() {
2183 return length_;
2184 }
2185
2186 int capacity() {
2187 return array_->length();
2188 }
2189
2190 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002191 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002192 result_array->set_length(Smi::FromInt(length_));
2193 return result_array;
2194 }
2195
2196 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2197 target_array->set_elements(*array_);
2198 target_array->set_length(Smi::FromInt(length_));
2199 return target_array;
2200 }
2201
2202 private:
2203 Handle<FixedArray> array_;
2204 int length_;
2205};
2206
2207
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002208// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002209const int kStringBuilderConcatHelperLengthBits = 11;
2210const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002211
2212template <typename schar>
2213static inline void StringBuilderConcatHelper(String*,
2214 schar*,
2215 FixedArray*,
2216 int);
2217
lrn@chromium.org25156de2010-04-06 13:10:27 +00002218typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2219 StringBuilderSubstringLength;
2220typedef BitField<int,
2221 kStringBuilderConcatHelperLengthBits,
2222 kStringBuilderConcatHelperPositionBits>
2223 StringBuilderSubstringPosition;
2224
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002225
2226class ReplacementStringBuilder {
2227 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002228 ReplacementStringBuilder(Heap* heap,
2229 Handle<String> subject,
2230 int estimated_part_count)
2231 : heap_(heap),
2232 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002233 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002234 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002235 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002236 // Require a non-zero initial size. Ensures that doubling the size to
2237 // extend the array will work.
2238 ASSERT(estimated_part_count > 0);
2239 }
2240
lrn@chromium.org25156de2010-04-06 13:10:27 +00002241 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2242 int from,
2243 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002244 ASSERT(from >= 0);
2245 int length = to - from;
2246 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002247 if (StringBuilderSubstringLength::is_valid(length) &&
2248 StringBuilderSubstringPosition::is_valid(from)) {
2249 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2250 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002251 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002252 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002253 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002254 builder->Add(Smi::FromInt(-length));
2255 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002256 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002257 }
2258
2259
2260 void EnsureCapacity(int elements) {
2261 array_builder_.EnsureCapacity(elements);
2262 }
2263
2264
2265 void AddSubjectSlice(int from, int to) {
2266 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002267 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002268 }
2269
2270
2271 void AddString(Handle<String> string) {
2272 int length = string->length();
2273 ASSERT(length > 0);
2274 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002275 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002276 is_ascii_ = false;
2277 }
2278 IncrementCharacterCount(length);
2279 }
2280
2281
2282 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002283 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002284 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002285 }
2286
2287 Handle<String> joined_string;
2288 if (is_ascii_) {
2289 joined_string = NewRawAsciiString(character_count_);
2290 AssertNoAllocation no_alloc;
2291 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2292 char* char_buffer = seq->GetChars();
2293 StringBuilderConcatHelper(*subject_,
2294 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002295 *array_builder_.array(),
2296 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002297 } else {
2298 // Non-ASCII.
2299 joined_string = NewRawTwoByteString(character_count_);
2300 AssertNoAllocation no_alloc;
2301 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2302 uc16* char_buffer = seq->GetChars();
2303 StringBuilderConcatHelper(*subject_,
2304 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002305 *array_builder_.array(),
2306 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002307 }
2308 return joined_string;
2309 }
2310
2311
2312 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002313 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002314 V8::FatalProcessOutOfMemory("String.replace result too large.");
2315 }
2316 character_count_ += by;
2317 }
2318
lrn@chromium.org25156de2010-04-06 13:10:27 +00002319 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002320 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002321 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002322
lrn@chromium.org25156de2010-04-06 13:10:27 +00002323 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002324 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002325 CALL_HEAP_FUNCTION(heap_->isolate(),
2326 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002327 }
2328
2329
2330 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002331 CALL_HEAP_FUNCTION(heap_->isolate(),
2332 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002333 }
2334
2335
2336 void AddElement(Object* element) {
2337 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002338 ASSERT(array_builder_.capacity() > array_builder_.length());
2339 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002340 }
2341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002342 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002343 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002344 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002345 int character_count_;
2346 bool is_ascii_;
2347};
2348
2349
2350class CompiledReplacement {
2351 public:
2352 CompiledReplacement()
2353 : parts_(1), replacement_substrings_(0) {}
2354
2355 void Compile(Handle<String> replacement,
2356 int capture_count,
2357 int subject_length);
2358
2359 void Apply(ReplacementStringBuilder* builder,
2360 int match_from,
2361 int match_to,
2362 Handle<JSArray> last_match_info);
2363
2364 // Number of distinct parts of the replacement pattern.
2365 int parts() {
2366 return parts_.length();
2367 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002368
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002369 private:
2370 enum PartType {
2371 SUBJECT_PREFIX = 1,
2372 SUBJECT_SUFFIX,
2373 SUBJECT_CAPTURE,
2374 REPLACEMENT_SUBSTRING,
2375 REPLACEMENT_STRING,
2376
2377 NUMBER_OF_PART_TYPES
2378 };
2379
2380 struct ReplacementPart {
2381 static inline ReplacementPart SubjectMatch() {
2382 return ReplacementPart(SUBJECT_CAPTURE, 0);
2383 }
2384 static inline ReplacementPart SubjectCapture(int capture_index) {
2385 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2386 }
2387 static inline ReplacementPart SubjectPrefix() {
2388 return ReplacementPart(SUBJECT_PREFIX, 0);
2389 }
2390 static inline ReplacementPart SubjectSuffix(int subject_length) {
2391 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2392 }
2393 static inline ReplacementPart ReplacementString() {
2394 return ReplacementPart(REPLACEMENT_STRING, 0);
2395 }
2396 static inline ReplacementPart ReplacementSubString(int from, int to) {
2397 ASSERT(from >= 0);
2398 ASSERT(to > from);
2399 return ReplacementPart(-from, to);
2400 }
2401
2402 // If tag <= 0 then it is the negation of a start index of a substring of
2403 // the replacement pattern, otherwise it's a value from PartType.
2404 ReplacementPart(int tag, int data)
2405 : tag(tag), data(data) {
2406 // Must be non-positive or a PartType value.
2407 ASSERT(tag < NUMBER_OF_PART_TYPES);
2408 }
2409 // Either a value of PartType or a non-positive number that is
2410 // the negation of an index into the replacement string.
2411 int tag;
2412 // The data value's interpretation depends on the value of tag:
2413 // tag == SUBJECT_PREFIX ||
2414 // tag == SUBJECT_SUFFIX: data is unused.
2415 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2416 // tag == REPLACEMENT_SUBSTRING ||
2417 // tag == REPLACEMENT_STRING: data is index into array of substrings
2418 // of the replacement string.
2419 // tag <= 0: Temporary representation of the substring of the replacement
2420 // string ranging over -tag .. data.
2421 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2422 // substring objects.
2423 int data;
2424 };
2425
2426 template<typename Char>
2427 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2428 Vector<Char> characters,
2429 int capture_count,
2430 int subject_length) {
2431 int length = characters.length();
2432 int last = 0;
2433 for (int i = 0; i < length; i++) {
2434 Char c = characters[i];
2435 if (c == '$') {
2436 int next_index = i + 1;
2437 if (next_index == length) { // No next character!
2438 break;
2439 }
2440 Char c2 = characters[next_index];
2441 switch (c2) {
2442 case '$':
2443 if (i > last) {
2444 // There is a substring before. Include the first "$".
2445 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2446 last = next_index + 1; // Continue after the second "$".
2447 } else {
2448 // Let the next substring start with the second "$".
2449 last = next_index;
2450 }
2451 i = next_index;
2452 break;
2453 case '`':
2454 if (i > last) {
2455 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2456 }
2457 parts->Add(ReplacementPart::SubjectPrefix());
2458 i = next_index;
2459 last = i + 1;
2460 break;
2461 case '\'':
2462 if (i > last) {
2463 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2464 }
2465 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2466 i = next_index;
2467 last = i + 1;
2468 break;
2469 case '&':
2470 if (i > last) {
2471 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2472 }
2473 parts->Add(ReplacementPart::SubjectMatch());
2474 i = next_index;
2475 last = i + 1;
2476 break;
2477 case '0':
2478 case '1':
2479 case '2':
2480 case '3':
2481 case '4':
2482 case '5':
2483 case '6':
2484 case '7':
2485 case '8':
2486 case '9': {
2487 int capture_ref = c2 - '0';
2488 if (capture_ref > capture_count) {
2489 i = next_index;
2490 continue;
2491 }
2492 int second_digit_index = next_index + 1;
2493 if (second_digit_index < length) {
2494 // Peek ahead to see if we have two digits.
2495 Char c3 = characters[second_digit_index];
2496 if ('0' <= c3 && c3 <= '9') { // Double digits.
2497 int double_digit_ref = capture_ref * 10 + c3 - '0';
2498 if (double_digit_ref <= capture_count) {
2499 next_index = second_digit_index;
2500 capture_ref = double_digit_ref;
2501 }
2502 }
2503 }
2504 if (capture_ref > 0) {
2505 if (i > last) {
2506 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2507 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002508 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002509 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2510 last = next_index + 1;
2511 }
2512 i = next_index;
2513 break;
2514 }
2515 default:
2516 i = next_index;
2517 break;
2518 }
2519 }
2520 }
2521 if (length > last) {
2522 if (last == 0) {
2523 parts->Add(ReplacementPart::ReplacementString());
2524 } else {
2525 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2526 }
2527 }
2528 }
2529
2530 ZoneList<ReplacementPart> parts_;
2531 ZoneList<Handle<String> > replacement_substrings_;
2532};
2533
2534
2535void CompiledReplacement::Compile(Handle<String> replacement,
2536 int capture_count,
2537 int subject_length) {
2538 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002539 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002540 AssertNoAllocation no_alloc;
2541 ParseReplacementPattern(&parts_,
2542 replacement->ToAsciiVector(),
2543 capture_count,
2544 subject_length);
2545 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002546 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002547 AssertNoAllocation no_alloc;
2548
2549 ParseReplacementPattern(&parts_,
2550 replacement->ToUC16Vector(),
2551 capture_count,
2552 subject_length);
2553 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002554 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002555 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002556 int substring_index = 0;
2557 for (int i = 0, n = parts_.length(); i < n; i++) {
2558 int tag = parts_[i].tag;
2559 if (tag <= 0) { // A replacement string slice.
2560 int from = -tag;
2561 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002562 replacement_substrings_.Add(
2563 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002564 parts_[i].tag = REPLACEMENT_SUBSTRING;
2565 parts_[i].data = substring_index;
2566 substring_index++;
2567 } else if (tag == REPLACEMENT_STRING) {
2568 replacement_substrings_.Add(replacement);
2569 parts_[i].data = substring_index;
2570 substring_index++;
2571 }
2572 }
2573}
2574
2575
2576void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2577 int match_from,
2578 int match_to,
2579 Handle<JSArray> last_match_info) {
2580 for (int i = 0, n = parts_.length(); i < n; i++) {
2581 ReplacementPart part = parts_[i];
2582 switch (part.tag) {
2583 case SUBJECT_PREFIX:
2584 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2585 break;
2586 case SUBJECT_SUFFIX: {
2587 int subject_length = part.data;
2588 if (match_to < subject_length) {
2589 builder->AddSubjectSlice(match_to, subject_length);
2590 }
2591 break;
2592 }
2593 case SUBJECT_CAPTURE: {
2594 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002595 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002596 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2597 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2598 if (from >= 0 && to > from) {
2599 builder->AddSubjectSlice(from, to);
2600 }
2601 break;
2602 }
2603 case REPLACEMENT_SUBSTRING:
2604 case REPLACEMENT_STRING:
2605 builder->AddString(replacement_substrings_[part.data]);
2606 break;
2607 default:
2608 UNREACHABLE();
2609 }
2610 }
2611}
2612
2613
2614
lrn@chromium.org303ada72010-10-27 09:33:13 +00002615MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002616 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002617 String* subject,
2618 JSRegExp* regexp,
2619 String* replacement,
2620 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002621 ASSERT(subject->IsFlat());
2622 ASSERT(replacement->IsFlat());
2623
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002624 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002625
2626 int length = subject->length();
2627 Handle<String> subject_handle(subject);
2628 Handle<JSRegExp> regexp_handle(regexp);
2629 Handle<String> replacement_handle(replacement);
2630 Handle<JSArray> last_match_info_handle(last_match_info);
2631 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2632 subject_handle,
2633 0,
2634 last_match_info_handle);
2635 if (match.is_null()) {
2636 return Failure::Exception();
2637 }
2638 if (match->IsNull()) {
2639 return *subject_handle;
2640 }
2641
2642 int capture_count = regexp_handle->CaptureCount();
2643
2644 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002645 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002646 CompiledReplacement compiled_replacement;
2647 compiled_replacement.Compile(replacement_handle,
2648 capture_count,
2649 length);
2650
2651 bool is_global = regexp_handle->GetFlags().is_global();
2652
2653 // Guessing the number of parts that the final result string is built
2654 // from. Global regexps can match any number of times, so we guess
2655 // conservatively.
2656 int expected_parts =
2657 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002658 ReplacementStringBuilder builder(isolate->heap(),
2659 subject_handle,
2660 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002661
2662 // Index of end of last match.
2663 int prev = 0;
2664
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002665 // Number of parts added by compiled replacement plus preceeding
2666 // string and possibly suffix after last match. It is possible for
2667 // all components to use two elements when encoded as two smis.
2668 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002669 bool matched = true;
2670 do {
2671 ASSERT(last_match_info_handle->HasFastElements());
2672 // Increase the capacity of the builder before entering local handle-scope,
2673 // so its internal buffer can safely allocate a new handle if it grows.
2674 builder.EnsureCapacity(parts_added_per_loop);
2675
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002676 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002677 int start, end;
2678 {
2679 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002680 FixedArray* match_info_array =
2681 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002682
2683 ASSERT_EQ(capture_count * 2 + 2,
2684 RegExpImpl::GetLastCaptureCount(match_info_array));
2685 start = RegExpImpl::GetCapture(match_info_array, 0);
2686 end = RegExpImpl::GetCapture(match_info_array, 1);
2687 }
2688
2689 if (prev < start) {
2690 builder.AddSubjectSlice(prev, start);
2691 }
2692 compiled_replacement.Apply(&builder,
2693 start,
2694 end,
2695 last_match_info_handle);
2696 prev = end;
2697
2698 // Only continue checking for global regexps.
2699 if (!is_global) break;
2700
2701 // Continue from where the match ended, unless it was an empty match.
2702 int next = end;
2703 if (start == end) {
2704 next = end + 1;
2705 if (next > length) break;
2706 }
2707
2708 match = RegExpImpl::Exec(regexp_handle,
2709 subject_handle,
2710 next,
2711 last_match_info_handle);
2712 if (match.is_null()) {
2713 return Failure::Exception();
2714 }
2715 matched = !match->IsNull();
2716 } while (matched);
2717
2718 if (prev < length) {
2719 builder.AddSubjectSlice(prev, length);
2720 }
2721
2722 return *(builder.ToString());
2723}
2724
2725
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002726template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002727MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002728 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002729 String* subject,
2730 JSRegExp* regexp,
2731 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002732 ASSERT(subject->IsFlat());
2733
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002734 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002735
2736 Handle<String> subject_handle(subject);
2737 Handle<JSRegExp> regexp_handle(regexp);
2738 Handle<JSArray> last_match_info_handle(last_match_info);
2739 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2740 subject_handle,
2741 0,
2742 last_match_info_handle);
2743 if (match.is_null()) return Failure::Exception();
2744 if (match->IsNull()) return *subject_handle;
2745
2746 ASSERT(last_match_info_handle->HasFastElements());
2747
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002748 int start, end;
2749 {
2750 AssertNoAllocation match_info_array_is_not_in_a_handle;
2751 FixedArray* match_info_array =
2752 FixedArray::cast(last_match_info_handle->elements());
2753
2754 start = RegExpImpl::GetCapture(match_info_array, 0);
2755 end = RegExpImpl::GetCapture(match_info_array, 1);
2756 }
2757
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002758 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002759 int new_length = length - (end - start);
2760 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002761 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002762 }
2763 Handle<ResultSeqString> answer;
2764 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002765 answer = Handle<ResultSeqString>::cast(
2766 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002767 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002768 answer = Handle<ResultSeqString>::cast(
2769 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002770 }
2771
2772 // If the regexp isn't global, only match once.
2773 if (!regexp_handle->GetFlags().is_global()) {
2774 if (start > 0) {
2775 String::WriteToFlat(*subject_handle,
2776 answer->GetChars(),
2777 0,
2778 start);
2779 }
2780 if (end < length) {
2781 String::WriteToFlat(*subject_handle,
2782 answer->GetChars() + start,
2783 end,
2784 length);
2785 }
2786 return *answer;
2787 }
2788
2789 int prev = 0; // Index of end of last match.
2790 int next = 0; // Start of next search (prev unless last match was empty).
2791 int position = 0;
2792
2793 do {
2794 if (prev < start) {
2795 // Add substring subject[prev;start] to answer string.
2796 String::WriteToFlat(*subject_handle,
2797 answer->GetChars() + position,
2798 prev,
2799 start);
2800 position += start - prev;
2801 }
2802 prev = end;
2803 next = end;
2804 // Continue from where the match ended, unless it was an empty match.
2805 if (start == end) {
2806 next++;
2807 if (next > length) break;
2808 }
2809 match = RegExpImpl::Exec(regexp_handle,
2810 subject_handle,
2811 next,
2812 last_match_info_handle);
2813 if (match.is_null()) return Failure::Exception();
2814 if (match->IsNull()) break;
2815
2816 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002817 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002818 {
2819 AssertNoAllocation match_info_array_is_not_in_a_handle;
2820 FixedArray* match_info_array =
2821 FixedArray::cast(last_match_info_handle->elements());
2822 start = RegExpImpl::GetCapture(match_info_array, 0);
2823 end = RegExpImpl::GetCapture(match_info_array, 1);
2824 }
2825 } while (true);
2826
2827 if (prev < length) {
2828 // Add substring subject[prev;length] to answer string.
2829 String::WriteToFlat(*subject_handle,
2830 answer->GetChars() + position,
2831 prev,
2832 length);
2833 position += length - prev;
2834 }
2835
2836 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002837 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002838 }
2839
2840 // Shorten string and fill
2841 int string_size = ResultSeqString::SizeFor(position);
2842 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2843 int delta = allocated_string_size - string_size;
2844
2845 answer->set_length(position);
2846 if (delta == 0) return *answer;
2847
2848 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002849 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002850
2851 return *answer;
2852}
2853
2854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002855RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002856 ASSERT(args.length() == 4);
2857
2858 CONVERT_CHECKED(String, subject, args[0]);
2859 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002860 Object* flat_subject;
2861 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2862 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2863 return maybe_flat_subject;
2864 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002865 }
2866 subject = String::cast(flat_subject);
2867 }
2868
2869 CONVERT_CHECKED(String, replacement, args[2]);
2870 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002871 Object* flat_replacement;
2872 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2873 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2874 return maybe_flat_replacement;
2875 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002876 }
2877 replacement = String::cast(flat_replacement);
2878 }
2879
2880 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2881 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2882
2883 ASSERT(last_match_info->HasFastElements());
2884
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002885 if (replacement->length() == 0) {
2886 if (subject->HasOnlyAsciiChars()) {
2887 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002888 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002889 } else {
2890 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002891 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002892 }
2893 }
2894
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002895 return StringReplaceRegExpWithString(isolate,
2896 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002897 regexp,
2898 replacement,
2899 last_match_info);
2900}
2901
2902
ager@chromium.org7c537e22008-10-16 08:43:32 +00002903// Perform string match of pattern on subject, starting at start index.
2904// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002905// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002906int Runtime::StringMatch(Isolate* isolate,
2907 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002908 Handle<String> pat,
2909 int start_index) {
2910 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002911 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002912
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002913 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002914 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002915
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002916 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002917 if (start_index + pattern_length > subject_length) return -1;
2918
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002919 if (!sub->IsFlat()) FlattenString(sub);
2920 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002921
ager@chromium.org7c537e22008-10-16 08:43:32 +00002922 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002923 // Extract flattened substrings of cons strings before determining asciiness.
2924 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002925 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002926 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002927 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002928
ager@chromium.org7c537e22008-10-16 08:43:32 +00002929 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002930 if (seq_pat->IsAsciiRepresentation()) {
2931 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2932 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002933 return SearchString(isolate,
2934 seq_sub->ToAsciiVector(),
2935 pat_vector,
2936 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002937 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002938 return SearchString(isolate,
2939 seq_sub->ToUC16Vector(),
2940 pat_vector,
2941 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002942 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002943 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2944 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002945 return SearchString(isolate,
2946 seq_sub->ToAsciiVector(),
2947 pat_vector,
2948 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002949 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002950 return SearchString(isolate,
2951 seq_sub->ToUC16Vector(),
2952 pat_vector,
2953 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002954}
2955
2956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002957RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002958 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002959 ASSERT(args.length() == 3);
2960
ager@chromium.org7c537e22008-10-16 08:43:32 +00002961 CONVERT_ARG_CHECKED(String, sub, 0);
2962 CONVERT_ARG_CHECKED(String, pat, 1);
2963
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002964 Object* index = args[2];
2965 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002966 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002967
ager@chromium.org870a0b62008-11-04 11:43:05 +00002968 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002969 int position =
2970 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002971 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002972}
2973
2974
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002975template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002976static int StringMatchBackwards(Vector<const schar> subject,
2977 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002978 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002979 int pattern_length = pattern.length();
2980 ASSERT(pattern_length >= 1);
2981 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002982
2983 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002984 for (int i = 0; i < pattern_length; i++) {
2985 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002986 if (c > String::kMaxAsciiCharCode) {
2987 return -1;
2988 }
2989 }
2990 }
2991
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002992 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002993 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002994 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002995 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002996 while (j < pattern_length) {
2997 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002998 break;
2999 }
3000 j++;
3001 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003002 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003003 return i;
3004 }
3005 }
3006 return -1;
3007}
3008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003009RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003010 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003011 ASSERT(args.length() == 3);
3012
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003013 CONVERT_ARG_CHECKED(String, sub, 0);
3014 CONVERT_ARG_CHECKED(String, pat, 1);
3015
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003016 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003017 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003018 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003019
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003020 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003021 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003022
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003023 if (start_index + pat_length > sub_length) {
3024 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003025 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003026
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003027 if (pat_length == 0) {
3028 return Smi::FromInt(start_index);
3029 }
3030
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003031 if (!sub->IsFlat()) FlattenString(sub);
3032 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003033
3034 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3035
3036 int position = -1;
3037
3038 if (pat->IsAsciiRepresentation()) {
3039 Vector<const char> pat_vector = pat->ToAsciiVector();
3040 if (sub->IsAsciiRepresentation()) {
3041 position = StringMatchBackwards(sub->ToAsciiVector(),
3042 pat_vector,
3043 start_index);
3044 } else {
3045 position = StringMatchBackwards(sub->ToUC16Vector(),
3046 pat_vector,
3047 start_index);
3048 }
3049 } else {
3050 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3051 if (sub->IsAsciiRepresentation()) {
3052 position = StringMatchBackwards(sub->ToAsciiVector(),
3053 pat_vector,
3054 start_index);
3055 } else {
3056 position = StringMatchBackwards(sub->ToUC16Vector(),
3057 pat_vector,
3058 start_index);
3059 }
3060 }
3061
3062 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003063}
3064
3065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003066RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003067 NoHandleAllocation ha;
3068 ASSERT(args.length() == 2);
3069
3070 CONVERT_CHECKED(String, str1, args[0]);
3071 CONVERT_CHECKED(String, str2, args[1]);
3072
3073 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003074 int str1_length = str1->length();
3075 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003076
3077 // Decide trivial cases without flattening.
3078 if (str1_length == 0) {
3079 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3080 return Smi::FromInt(-str2_length);
3081 } else {
3082 if (str2_length == 0) return Smi::FromInt(str1_length);
3083 }
3084
3085 int end = str1_length < str2_length ? str1_length : str2_length;
3086
3087 // No need to flatten if we are going to find the answer on the first
3088 // character. At this point we know there is at least one character
3089 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003090 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003091 if (d != 0) return Smi::FromInt(d);
3092
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003093 str1->TryFlatten();
3094 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003095
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003096 StringInputBuffer& buf1 =
3097 *isolate->runtime_state()->string_locale_compare_buf1();
3098 StringInputBuffer& buf2 =
3099 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003100
3101 buf1.Reset(str1);
3102 buf2.Reset(str2);
3103
3104 for (int i = 0; i < end; i++) {
3105 uint16_t char1 = buf1.GetNext();
3106 uint16_t char2 = buf2.GetNext();
3107 if (char1 != char2) return Smi::FromInt(char1 - char2);
3108 }
3109
3110 return Smi::FromInt(str1_length - str2_length);
3111}
3112
3113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003114RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003115 NoHandleAllocation ha;
3116 ASSERT(args.length() == 3);
3117
3118 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003119 Object* from = args[1];
3120 Object* to = args[2];
3121 int start, end;
3122 // We have a fast integer-only case here to avoid a conversion to double in
3123 // the common case where from and to are Smis.
3124 if (from->IsSmi() && to->IsSmi()) {
3125 start = Smi::cast(from)->value();
3126 end = Smi::cast(to)->value();
3127 } else {
3128 CONVERT_DOUBLE_CHECKED(from_number, from);
3129 CONVERT_DOUBLE_CHECKED(to_number, to);
3130 start = FastD2I(from_number);
3131 end = FastD2I(to_number);
3132 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003133 RUNTIME_ASSERT(end >= start);
3134 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003135 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003136 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003137 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003138}
3139
3140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003141RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003142 ASSERT_EQ(3, args.length());
3143
3144 CONVERT_ARG_CHECKED(String, subject, 0);
3145 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3146 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3147 HandleScope handles;
3148
3149 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3150
3151 if (match.is_null()) {
3152 return Failure::Exception();
3153 }
3154 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003155 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003156 }
3157 int length = subject->length();
3158
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003159 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003160 ZoneList<int> offsets(8);
3161 do {
3162 int start;
3163 int end;
3164 {
3165 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003166 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003167 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3168 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3169 }
3170 offsets.Add(start);
3171 offsets.Add(end);
3172 int index = start < end ? end : end + 1;
3173 if (index > length) break;
3174 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3175 if (match.is_null()) {
3176 return Failure::Exception();
3177 }
3178 } while (!match->IsNull());
3179 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003180 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003181 for (int i = 0; i < matches ; i++) {
3182 int from = offsets.at(i * 2);
3183 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003184 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003185 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003186 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003187 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003188 result->set_length(Smi::FromInt(matches));
3189 return *result;
3190}
3191
3192
lrn@chromium.org25156de2010-04-06 13:10:27 +00003193// Two smis before and after the match, for very long strings.
3194const int kMaxBuilderEntriesPerRegExpMatch = 5;
3195
3196
3197static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3198 Handle<JSArray> last_match_info,
3199 int match_start,
3200 int match_end) {
3201 // Fill last_match_info with a single capture.
3202 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3203 AssertNoAllocation no_gc;
3204 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3205 RegExpImpl::SetLastCaptureCount(elements, 2);
3206 RegExpImpl::SetLastInput(elements, *subject);
3207 RegExpImpl::SetLastSubject(elements, *subject);
3208 RegExpImpl::SetCapture(elements, 0, match_start);
3209 RegExpImpl::SetCapture(elements, 1, match_end);
3210}
3211
3212
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003213template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003214static bool SearchStringMultiple(Isolate* isolate,
3215 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003216 Vector<const PatternChar> pattern,
3217 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003218 FixedArrayBuilder* builder,
3219 int* match_pos) {
3220 int pos = *match_pos;
3221 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003222 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003223 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003224 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003225 while (pos <= max_search_start) {
3226 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3227 *match_pos = pos;
3228 return false;
3229 }
3230 // Position of end of previous match.
3231 int match_end = pos + pattern_length;
3232 int new_pos = search.Search(subject, match_end);
3233 if (new_pos >= 0) {
3234 // A match.
3235 if (new_pos > match_end) {
3236 ReplacementStringBuilder::AddSubjectSlice(builder,
3237 match_end,
3238 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003239 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003240 pos = new_pos;
3241 builder->Add(pattern_string);
3242 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003243 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003244 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003245 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003246
lrn@chromium.org25156de2010-04-06 13:10:27 +00003247 if (pos < max_search_start) {
3248 ReplacementStringBuilder::AddSubjectSlice(builder,
3249 pos + pattern_length,
3250 subject_length);
3251 }
3252 *match_pos = pos;
3253 return true;
3254}
3255
3256
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003257static bool SearchStringMultiple(Isolate* isolate,
3258 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003259 Handle<String> pattern,
3260 Handle<JSArray> last_match_info,
3261 FixedArrayBuilder* builder) {
3262 ASSERT(subject->IsFlat());
3263 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003264
3265 // Treating as if a previous match was before first character.
3266 int match_pos = -pattern->length();
3267
3268 for (;;) { // Break when search complete.
3269 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3270 AssertNoAllocation no_gc;
3271 if (subject->IsAsciiRepresentation()) {
3272 Vector<const char> subject_vector = subject->ToAsciiVector();
3273 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003274 if (SearchStringMultiple(isolate,
3275 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003276 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003277 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003278 builder,
3279 &match_pos)) break;
3280 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003281 if (SearchStringMultiple(isolate,
3282 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003283 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003284 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003285 builder,
3286 &match_pos)) break;
3287 }
3288 } else {
3289 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3290 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003291 if (SearchStringMultiple(isolate,
3292 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003293 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003294 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003295 builder,
3296 &match_pos)) break;
3297 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003298 if (SearchStringMultiple(isolate,
3299 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003300 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003301 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003302 builder,
3303 &match_pos)) break;
3304 }
3305 }
3306 }
3307
3308 if (match_pos >= 0) {
3309 SetLastMatchInfoNoCaptures(subject,
3310 last_match_info,
3311 match_pos,
3312 match_pos + pattern->length());
3313 return true;
3314 }
3315 return false; // No matches at all.
3316}
3317
3318
3319static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003320 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003321 Handle<String> subject,
3322 Handle<JSRegExp> regexp,
3323 Handle<JSArray> last_match_array,
3324 FixedArrayBuilder* builder) {
3325 ASSERT(subject->IsFlat());
3326 int match_start = -1;
3327 int match_end = 0;
3328 int pos = 0;
3329 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3330 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3331
3332 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003333 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003334 int subject_length = subject->length();
3335
3336 for (;;) { // Break on failure, return on exception.
3337 RegExpImpl::IrregexpResult result =
3338 RegExpImpl::IrregexpExecOnce(regexp,
3339 subject,
3340 pos,
3341 register_vector);
3342 if (result == RegExpImpl::RE_SUCCESS) {
3343 match_start = register_vector[0];
3344 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3345 if (match_end < match_start) {
3346 ReplacementStringBuilder::AddSubjectSlice(builder,
3347 match_end,
3348 match_start);
3349 }
3350 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003351 HandleScope loop_scope(isolate);
3352 builder->Add(*isolate->factory()->NewSubString(subject,
3353 match_start,
3354 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003355 if (match_start != match_end) {
3356 pos = match_end;
3357 } else {
3358 pos = match_end + 1;
3359 if (pos > subject_length) break;
3360 }
3361 } else if (result == RegExpImpl::RE_FAILURE) {
3362 break;
3363 } else {
3364 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3365 return result;
3366 }
3367 }
3368
3369 if (match_start >= 0) {
3370 if (match_end < subject_length) {
3371 ReplacementStringBuilder::AddSubjectSlice(builder,
3372 match_end,
3373 subject_length);
3374 }
3375 SetLastMatchInfoNoCaptures(subject,
3376 last_match_array,
3377 match_start,
3378 match_end);
3379 return RegExpImpl::RE_SUCCESS;
3380 } else {
3381 return RegExpImpl::RE_FAILURE; // No matches at all.
3382 }
3383}
3384
3385
3386static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003387 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003388 Handle<String> subject,
3389 Handle<JSRegExp> regexp,
3390 Handle<JSArray> last_match_array,
3391 FixedArrayBuilder* builder) {
3392
3393 ASSERT(subject->IsFlat());
3394 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3395 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3396
3397 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003398 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003399
3400 RegExpImpl::IrregexpResult result =
3401 RegExpImpl::IrregexpExecOnce(regexp,
3402 subject,
3403 0,
3404 register_vector);
3405
3406 int capture_count = regexp->CaptureCount();
3407 int subject_length = subject->length();
3408
3409 // Position to search from.
3410 int pos = 0;
3411 // End of previous match. Differs from pos if match was empty.
3412 int match_end = 0;
3413 if (result == RegExpImpl::RE_SUCCESS) {
3414 // Need to keep a copy of the previous match for creating last_match_info
3415 // at the end, so we have two vectors that we swap between.
3416 OffsetsVector registers2(required_registers);
3417 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3418
3419 do {
3420 int match_start = register_vector[0];
3421 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3422 if (match_end < match_start) {
3423 ReplacementStringBuilder::AddSubjectSlice(builder,
3424 match_end,
3425 match_start);
3426 }
3427 match_end = register_vector[1];
3428
3429 {
3430 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003431 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003432 // Arguments array to replace function is match, captures, index and
3433 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003434 Handle<FixedArray> elements =
3435 isolate->factory()->NewFixedArray(3 + capture_count);
3436 Handle<String> match = isolate->factory()->NewSubString(subject,
3437 match_start,
3438 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003439 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003440 for (int i = 1; i <= capture_count; i++) {
3441 int start = register_vector[i * 2];
3442 if (start >= 0) {
3443 int end = register_vector[i * 2 + 1];
3444 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003445 Handle<String> substring = isolate->factory()->NewSubString(subject,
3446 start,
3447 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003448 elements->set(i, *substring);
3449 } else {
3450 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003451 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003452 }
3453 }
3454 elements->set(capture_count + 1, Smi::FromInt(match_start));
3455 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003456 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003457 }
3458 // Swap register vectors, so the last successful match is in
3459 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003460 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003461 prev_register_vector = register_vector;
3462 register_vector = tmp;
3463
3464 if (match_end > match_start) {
3465 pos = match_end;
3466 } else {
3467 pos = match_end + 1;
3468 if (pos > subject_length) {
3469 break;
3470 }
3471 }
3472
3473 result = RegExpImpl::IrregexpExecOnce(regexp,
3474 subject,
3475 pos,
3476 register_vector);
3477 } while (result == RegExpImpl::RE_SUCCESS);
3478
3479 if (result != RegExpImpl::RE_EXCEPTION) {
3480 // Finished matching, with at least one match.
3481 if (match_end < subject_length) {
3482 ReplacementStringBuilder::AddSubjectSlice(builder,
3483 match_end,
3484 subject_length);
3485 }
3486
3487 int last_match_capture_count = (capture_count + 1) * 2;
3488 int last_match_array_size =
3489 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3490 last_match_array->EnsureSize(last_match_array_size);
3491 AssertNoAllocation no_gc;
3492 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3493 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3494 RegExpImpl::SetLastSubject(elements, *subject);
3495 RegExpImpl::SetLastInput(elements, *subject);
3496 for (int i = 0; i < last_match_capture_count; i++) {
3497 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3498 }
3499 return RegExpImpl::RE_SUCCESS;
3500 }
3501 }
3502 // No matches at all, return failure or exception result directly.
3503 return result;
3504}
3505
3506
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003507RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003508 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003509 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003510
3511 CONVERT_ARG_CHECKED(String, subject, 1);
3512 if (!subject->IsFlat()) { FlattenString(subject); }
3513 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3514 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3515 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3516
3517 ASSERT(last_match_info->HasFastElements());
3518 ASSERT(regexp->GetFlags().is_global());
3519 Handle<FixedArray> result_elements;
3520 if (result_array->HasFastElements()) {
3521 result_elements =
3522 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3523 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003524 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003525 }
3526 FixedArrayBuilder builder(result_elements);
3527
3528 if (regexp->TypeTag() == JSRegExp::ATOM) {
3529 Handle<String> pattern(
3530 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003531 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003532 if (SearchStringMultiple(isolate, subject, pattern,
3533 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003534 return *builder.ToJSArray(result_array);
3535 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003536 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003537 }
3538
3539 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3540
3541 RegExpImpl::IrregexpResult result;
3542 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003543 result = SearchRegExpNoCaptureMultiple(isolate,
3544 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003545 regexp,
3546 last_match_info,
3547 &builder);
3548 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003549 result = SearchRegExpMultiple(isolate,
3550 subject,
3551 regexp,
3552 last_match_info,
3553 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003554 }
3555 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003556 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003557 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3558 return Failure::Exception();
3559}
3560
3561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003562RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003563 NoHandleAllocation ha;
3564 ASSERT(args.length() == 2);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003565 CONVERT_SMI_CHECKED(radix, args[1]);
3566 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003567
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003568 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003569 if (args[0]->IsSmi()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003570 int value = Smi::cast(args[0])->value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003571 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003572 // Character array used for conversion.
3573 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003574 return isolate->heap()->
3575 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003576 }
3577 }
3578
3579 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580 CONVERT_DOUBLE_CHECKED(value, args[0]);
3581 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003582 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003583 }
3584 if (isinf(value)) {
3585 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003586 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003588 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003589 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003590 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003591 MaybeObject* result =
3592 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003593 DeleteArray(str);
3594 return result;
3595}
3596
3597
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003598RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003599 NoHandleAllocation ha;
3600 ASSERT(args.length() == 2);
3601
3602 CONVERT_DOUBLE_CHECKED(value, args[0]);
3603 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003604 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605 }
3606 if (isinf(value)) {
3607 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003608 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003609 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003610 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 }
3612 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3613 int f = FastD2I(f_number);
3614 RUNTIME_ASSERT(f >= 0);
3615 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 MaybeObject* res =
3617 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620}
3621
3622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003623RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003624 NoHandleAllocation ha;
3625 ASSERT(args.length() == 2);
3626
3627 CONVERT_DOUBLE_CHECKED(value, args[0]);
3628 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003629 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003630 }
3631 if (isinf(value)) {
3632 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003633 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003635 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003636 }
3637 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3638 int f = FastD2I(f_number);
3639 RUNTIME_ASSERT(f >= -1 && f <= 20);
3640 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003641 MaybeObject* res =
3642 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003644 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003645}
3646
3647
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003648RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 NoHandleAllocation ha;
3650 ASSERT(args.length() == 2);
3651
3652 CONVERT_DOUBLE_CHECKED(value, args[0]);
3653 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003654 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003655 }
3656 if (isinf(value)) {
3657 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003658 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003660 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 }
3662 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3663 int f = FastD2I(f_number);
3664 RUNTIME_ASSERT(f >= 1 && f <= 21);
3665 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003666 MaybeObject* res =
3667 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003668 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003669 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003670}
3671
3672
3673// Returns a single character string where first character equals
3674// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003675static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003676 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003677 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003678 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003679 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003680 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003681 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003682}
3683
3684
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3686 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003687 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 // Handle [] indexing on Strings
3689 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003690 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3691 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003692 }
3693
3694 // Handle [] indexing on String objects
3695 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003696 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3697 Handle<Object> result =
3698 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3699 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 }
3701
3702 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003703 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003704 return prototype->GetElement(index);
3705 }
3706
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003707 return GetElement(object, index);
3708}
3709
3710
lrn@chromium.org303ada72010-10-27 09:33:13 +00003711MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 return object->GetElement(index);
3713}
3714
3715
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003716MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3717 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003718 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003719 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003720
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003721 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003722 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003723 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003724 isolate->factory()->NewTypeError("non_object_property_load",
3725 HandleVector(args, 2));
3726 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003727 }
3728
3729 // Check if the given key is an array index.
3730 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003731 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003732 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003733 }
3734
3735 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003736 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003737 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003738 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003739 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003740 bool has_pending_exception = false;
3741 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003742 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003743 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003744 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003745 }
3746
ager@chromium.org32912102009-01-16 10:38:43 +00003747 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003748 // the element if so.
3749 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003750 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003751 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003752 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753 }
3754}
3755
3756
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003757RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003758 NoHandleAllocation ha;
3759 ASSERT(args.length() == 2);
3760
3761 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003762 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003763
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003764 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003765}
3766
3767
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003768// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003769RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003770 NoHandleAllocation ha;
3771 ASSERT(args.length() == 2);
3772
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003773 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003774 // itself.
3775 //
3776 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003777 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003778 // global proxy object never has properties. This is the case
3779 // because the global proxy object forwards everything to its hidden
3780 // prototype including local lookups.
3781 //
3782 // Additionally, we need to make sure that we do not cache results
3783 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003784 if (args[0]->IsJSObject() &&
3785 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003786 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003787 args[1]->IsString()) {
3788 JSObject* receiver = JSObject::cast(args[0]);
3789 String* key = String::cast(args[1]);
3790 if (receiver->HasFastProperties()) {
3791 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003792 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003793 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3794 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003795 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003796 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003797 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003798 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003799 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003800 LookupResult result;
3801 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003802 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003803 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003804 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003805 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003806 }
3807 } else {
3808 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003809 StringDictionary* dictionary = receiver->property_dictionary();
3810 int entry = dictionary->FindEntry(key);
3811 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003812 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003813 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003814 if (!receiver->IsGlobalObject()) return value;
3815 value = JSGlobalPropertyCell::cast(value)->value();
3816 if (!value->IsTheHole()) return value;
3817 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003818 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003819 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003820 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3821 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003822 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003823 Handle<String> str = args.at<String>(0);
3824 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003825 if (index >= 0 && index < str->length()) {
3826 Handle<Object> result = GetCharAt(str, index);
3827 return *result;
3828 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003829 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003830
3831 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003832 return Runtime::GetObjectProperty(isolate,
3833 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003834 args.at<Object>(1));
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 4b - define a new accessor property.
3840// Steps 9c & 12 - replace an existing data property with an accessor property.
3841// Step 12 - update an existing accessor property with an accessor or generic
3842// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003843RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003844 ASSERT(args.length() == 5);
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, obj, 0);
3847 CONVERT_CHECKED(String, name, args[1]);
3848 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003849 Object* fun = args[3];
3850 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003851 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3852 int unchecked = flag_attr->value();
3853 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3854 RUNTIME_ASSERT(!obj->IsNull());
3855 LookupResult result;
3856 obj->LocalLookupRealNamedProperty(name, &result);
3857
3858 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3859 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3860 // delete it to avoid running into trouble in DefineAccessor, which
3861 // handles this incorrectly if the property is readonly (does nothing)
3862 if (result.IsProperty() &&
3863 (result.type() == FIELD || result.type() == NORMAL
3864 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003865 Object* ok;
3866 { MaybeObject* maybe_ok =
3867 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3868 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3869 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003870 }
3871 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3872}
3873
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003874// Implements part of 8.12.9 DefineOwnProperty.
3875// There are 3 cases that lead here:
3876// Step 4a - define a new data property.
3877// Steps 9b & 12 - replace an existing accessor property with a data property.
3878// Step 12 - update an existing data property with a data or generic
3879// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003880RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003881 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003882 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003883 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3884 CONVERT_ARG_CHECKED(String, name, 1);
3885 Handle<Object> obj_value = args.at<Object>(2);
3886
3887 CONVERT_CHECKED(Smi, flag, args[3]);
3888 int unchecked = flag->value();
3889 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3890
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003891 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3892
3893 // Check if this is an element.
3894 uint32_t index;
3895 bool is_element = name->AsArrayIndex(&index);
3896
3897 // Special case for elements if any of the flags are true.
3898 // If elements are in fast case we always implicitly assume that:
3899 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3900 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3901 is_element) {
3902 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003903 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003904 // We do not need to do access checks here since these has already
3905 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003906 Handle<Object> proto(js_object->GetPrototype());
3907 // If proxy is detached, ignore the assignment. Alternatively,
3908 // we could throw an exception.
3909 if (proto->IsNull()) return *obj_value;
3910 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003911 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003912 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003913 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003914 // Make sure that we never go back to fast case.
3915 dictionary->set_requires_slow_elements();
3916 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003917 Handle<NumberDictionary> extended_dictionary =
3918 NumberDictionarySet(dictionary, index, obj_value, details);
3919 if (*extended_dictionary != *dictionary) {
3920 js_object->set_elements(*extended_dictionary);
3921 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003922 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003923 }
3924
ager@chromium.org5c838252010-02-19 08:53:10 +00003925 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003926 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003927
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003928 // To be compatible with safari we do not change the value on API objects
3929 // in defineProperty. Firefox disagrees here, and actually changes the value.
3930 if (result.IsProperty() &&
3931 (result.type() == CALLBACKS) &&
3932 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003933 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003934 }
3935
ager@chromium.org5c838252010-02-19 08:53:10 +00003936 // Take special care when attributes are different and there is already
3937 // a property. For simplicity we normalize the property which enables us
3938 // to not worry about changing the instance_descriptor and creating a new
3939 // map. The current version of SetObjectProperty does not handle attributes
3940 // correctly in the case where a property is a field and is reset with
3941 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003942 if (result.IsProperty() &&
3943 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003944 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003945 if (js_object->IsJSGlobalProxy()) {
3946 // Since the result is a property, the prototype will exist so
3947 // we don't have to check for null.
3948 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003949 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003950 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003951 // Use IgnoreAttributes version since a readonly property may be
3952 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003953 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3954 *obj_value,
3955 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003956 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003958 return Runtime::ForceSetObjectProperty(isolate,
3959 js_object,
3960 name,
3961 obj_value,
3962 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003963}
3964
3965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003966MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3967 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003968 Handle<Object> key,
3969 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003970 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003971 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003972 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003975 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003976 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003977 isolate->factory()->NewTypeError("non_object_property_store",
3978 HandleVector(args, 2));
3979 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003980 }
3981
3982 // If the object isn't a JavaScript object, we ignore the store.
3983 if (!object->IsJSObject()) return *value;
3984
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003985 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3986
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 // Check if the given key is an array index.
3988 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003989 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3991 // of a string using [] notation. We need to support this too in
3992 // JavaScript.
3993 // In the case of a String object we just need to redirect the assignment to
3994 // the underlying string if the index is in range. Since the underlying
3995 // string does nothing with the assignment then we can ignore such
3996 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003997 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003999 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004000
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004001 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004002 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003 return *value;
4004 }
4005
4006 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004007 Handle<Object> result;
4008 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004009 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004011 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004012 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004013 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004015 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 return *value;
4017 }
4018
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 bool has_pending_exception = false;
4021 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4022 if (has_pending_exception) return Failure::Exception();
4023 Handle<String> name = Handle<String>::cast(converted);
4024
4025 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004026 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004028 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 }
4030}
4031
4032
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004033MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4034 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004035 Handle<Object> key,
4036 Handle<Object> value,
4037 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004038 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004039
4040 // Check if the given key is an array index.
4041 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004042 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004043 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4044 // of a string using [] notation. We need to support this too in
4045 // JavaScript.
4046 // In the case of a String object we just need to redirect the assignment to
4047 // the underlying string if the index is in range. Since the underlying
4048 // string does nothing with the assignment then we can ignore such
4049 // assignments.
4050 if (js_object->IsStringObjectWithCharacterAt(index)) {
4051 return *value;
4052 }
4053
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004054 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004055 }
4056
4057 if (key->IsString()) {
4058 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004059 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004060 } else {
4061 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004062 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004063 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4064 *value,
4065 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004066 }
4067 }
4068
4069 // Call-back into JavaScript to convert the key to a string.
4070 bool has_pending_exception = false;
4071 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4072 if (has_pending_exception) return Failure::Exception();
4073 Handle<String> name = Handle<String>::cast(converted);
4074
4075 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004076 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004077 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004078 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004079 }
4080}
4081
4082
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004083MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4084 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004085 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004086 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004087
4088 // Check if the given key is an array index.
4089 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004090 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004091 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4092 // characters of a string using [] notation. In the case of a
4093 // String object we just need to redirect the deletion to the
4094 // underlying string if the index is in range. Since the
4095 // underlying string does nothing with the deletion, we can ignore
4096 // such deletions.
4097 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004098 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004099 }
4100
4101 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4102 }
4103
4104 Handle<String> key_string;
4105 if (key->IsString()) {
4106 key_string = Handle<String>::cast(key);
4107 } else {
4108 // Call-back into JavaScript to convert the key to a string.
4109 bool has_pending_exception = false;
4110 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4111 if (has_pending_exception) return Failure::Exception();
4112 key_string = Handle<String>::cast(converted);
4113 }
4114
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004115 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004116 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4117}
4118
4119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004120RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004121 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004122 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123
4124 Handle<Object> object = args.at<Object>(0);
4125 Handle<Object> key = args.at<Object>(1);
4126 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004127 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4128 RUNTIME_ASSERT(
4129 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004130 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004131 PropertyAttributes attributes =
4132 static_cast<PropertyAttributes>(unchecked_attributes);
4133
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004134 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004135 if (args.length() == 5) {
4136 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4137 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4138 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004139 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004140 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004141
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004142 return Runtime::SetObjectProperty(isolate,
4143 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004144 key,
4145 value,
4146 attributes,
4147 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004148}
4149
4150
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004151// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004152// This is used to decide if we should transform null and undefined
4153// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004154RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004155 NoHandleAllocation ha;
4156 RUNTIME_ASSERT(args.length() == 1);
4157
4158 Handle<Object> object = args.at<Object>(0);
4159
4160 if (object->IsJSFunction()) {
4161 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004162 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004163 }
4164 return isolate->heap()->undefined_value();
4165}
4166
4167
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004168// Set a local property, even if it is READ_ONLY. If the property does not
4169// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004170RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004171 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004172 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 CONVERT_CHECKED(JSObject, object, args[0]);
4174 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004175 // Compute attributes.
4176 PropertyAttributes attributes = NONE;
4177 if (args.length() == 4) {
4178 CONVERT_CHECKED(Smi, value_obj, args[3]);
4179 int unchecked_value = value_obj->value();
4180 // Only attribute bits should be set.
4181 RUNTIME_ASSERT(
4182 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4183 attributes = static_cast<PropertyAttributes>(unchecked_value);
4184 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004186 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004187 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188}
4189
4190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004191RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004192 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004193 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194
4195 CONVERT_CHECKED(JSObject, object, args[0]);
4196 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004197 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004198 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004199 ? JSObject::STRICT_DELETION
4200 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201}
4202
4203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004204static Object* HasLocalPropertyImplementation(Isolate* isolate,
4205 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004206 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004207 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004208 // Handle hidden prototypes. If there's a hidden prototype above this thing
4209 // then we have to check it for properties, because they are supposed to
4210 // look like they are on this object.
4211 Handle<Object> proto(object->GetPrototype());
4212 if (proto->IsJSObject() &&
4213 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004214 return HasLocalPropertyImplementation(isolate,
4215 Handle<JSObject>::cast(proto),
4216 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004217 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004218 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004219}
4220
4221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004222RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223 NoHandleAllocation ha;
4224 ASSERT(args.length() == 2);
4225 CONVERT_CHECKED(String, key, args[1]);
4226
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004227 uint32_t index;
4228 const bool key_is_array_index = key->AsArrayIndex(&index);
4229
ager@chromium.org9085a012009-05-11 19:22:57 +00004230 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004231 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004232 if (obj->IsJSObject()) {
4233 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004234 // Fast case: either the key is a real named property or it is not
4235 // an array index and there are no interceptors or hidden
4236 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004237 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004238 Map* map = object->map();
4239 if (!key_is_array_index &&
4240 !map->has_named_interceptor() &&
4241 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4242 return isolate->heap()->false_value();
4243 }
4244 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004245 HandleScope scope(isolate);
4246 return HasLocalPropertyImplementation(isolate,
4247 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004248 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004249 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004250 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004251 String* string = String::cast(obj);
4252 if (index < static_cast<uint32_t>(string->length())) {
4253 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004254 }
4255 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004256 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004257}
4258
4259
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004260RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004261 NoHandleAllocation na;
4262 ASSERT(args.length() == 2);
4263
4264 // Only JS objects can have properties.
4265 if (args[0]->IsJSObject()) {
4266 JSObject* object = JSObject::cast(args[0]);
4267 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004268 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004269 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004270 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004271}
4272
4273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004274RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004275 NoHandleAllocation na;
4276 ASSERT(args.length() == 2);
4277
4278 // Only JS objects can have elements.
4279 if (args[0]->IsJSObject()) {
4280 JSObject* object = JSObject::cast(args[0]);
4281 CONVERT_CHECKED(Smi, index_obj, args[1]);
4282 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004283 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004284 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004285 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004286}
4287
4288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004289RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004290 NoHandleAllocation ha;
4291 ASSERT(args.length() == 2);
4292
4293 CONVERT_CHECKED(JSObject, object, args[0]);
4294 CONVERT_CHECKED(String, key, args[1]);
4295
4296 uint32_t index;
4297 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004298 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004299 }
4300
ager@chromium.org870a0b62008-11-04 11:43:05 +00004301 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004302 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004303}
4304
4305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004306RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004307 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004308 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004309 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004310 return *GetKeysFor(object);
4311}
4312
4313
4314// Returns either a FixedArray as Runtime_GetPropertyNames,
4315// or, if the given object has an enum cache that contains
4316// all enumerable properties of the object and its prototypes
4317// have none, the map of the object. This is used to speed up
4318// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004319RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004320 ASSERT(args.length() == 1);
4321
4322 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4323
4324 if (raw_object->IsSimpleEnum()) return raw_object->map();
4325
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004326 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004327 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004328 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4329 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004330
4331 // Test again, since cache may have been built by preceding call.
4332 if (object->IsSimpleEnum()) return object->map();
4333
4334 return *content;
4335}
4336
4337
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004338// Find the length of the prototype chain that is to to handled as one. If a
4339// prototype object is hidden it is to be viewed as part of the the object it
4340// is prototype for.
4341static int LocalPrototypeChainLength(JSObject* obj) {
4342 int count = 1;
4343 Object* proto = obj->GetPrototype();
4344 while (proto->IsJSObject() &&
4345 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4346 count++;
4347 proto = JSObject::cast(proto)->GetPrototype();
4348 }
4349 return count;
4350}
4351
4352
4353// Return the names of the local named properties.
4354// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004355RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004356 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004357 ASSERT(args.length() == 1);
4358 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004359 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004360 }
4361 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4362
4363 // Skip the global proxy as it has no properties and always delegates to the
4364 // real global object.
4365 if (obj->IsJSGlobalProxy()) {
4366 // Only collect names if access is permitted.
4367 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004368 !isolate->MayNamedAccess(*obj,
4369 isolate->heap()->undefined_value(),
4370 v8::ACCESS_KEYS)) {
4371 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4372 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004373 }
4374 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4375 }
4376
4377 // Find the number of objects making up this.
4378 int length = LocalPrototypeChainLength(*obj);
4379
4380 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004381 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004382 int total_property_count = 0;
4383 Handle<JSObject> jsproto = obj;
4384 for (int i = 0; i < length; i++) {
4385 // Only collect names if access is permitted.
4386 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004387 !isolate->MayNamedAccess(*jsproto,
4388 isolate->heap()->undefined_value(),
4389 v8::ACCESS_KEYS)) {
4390 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4391 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004392 }
4393 int n;
4394 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4395 local_property_count[i] = n;
4396 total_property_count += n;
4397 if (i < length - 1) {
4398 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4399 }
4400 }
4401
4402 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004403 Handle<FixedArray> names =
4404 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004405
4406 // Get the property names.
4407 jsproto = obj;
4408 int proto_with_hidden_properties = 0;
4409 for (int i = 0; i < length; i++) {
4410 jsproto->GetLocalPropertyNames(*names,
4411 i == 0 ? 0 : local_property_count[i - 1]);
4412 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4413 proto_with_hidden_properties++;
4414 }
4415 if (i < length - 1) {
4416 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4417 }
4418 }
4419
4420 // Filter out name of hidden propeties object.
4421 if (proto_with_hidden_properties > 0) {
4422 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004423 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004424 names->length() - proto_with_hidden_properties);
4425 int dest_pos = 0;
4426 for (int i = 0; i < total_property_count; i++) {
4427 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004428 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004429 continue;
4430 }
4431 names->set(dest_pos++, name);
4432 }
4433 }
4434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004435 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004436}
4437
4438
4439// Return the names of the local indexed properties.
4440// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004441RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004442 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004443 ASSERT(args.length() == 1);
4444 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004445 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004446 }
4447 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4448
4449 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004450 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004451 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004452 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004453}
4454
4455
4456// Return information on whether an object has a named or indexed interceptor.
4457// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004458RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004459 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004460 ASSERT(args.length() == 1);
4461 if (!args[0]->IsJSObject()) {
4462 return Smi::FromInt(0);
4463 }
4464 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4465
4466 int result = 0;
4467 if (obj->HasNamedInterceptor()) result |= 2;
4468 if (obj->HasIndexedInterceptor()) result |= 1;
4469
4470 return Smi::FromInt(result);
4471}
4472
4473
4474// Return property names from named interceptor.
4475// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004476RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004477 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004478 ASSERT(args.length() == 1);
4479 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4480
4481 if (obj->HasNamedInterceptor()) {
4482 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4483 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4484 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004485 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004486}
4487
4488
4489// Return element names from indexed interceptor.
4490// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004491RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004492 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004493 ASSERT(args.length() == 1);
4494 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4495
4496 if (obj->HasIndexedInterceptor()) {
4497 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4498 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4499 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004500 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004501}
4502
4503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004504RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004505 ASSERT_EQ(args.length(), 1);
4506 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004507 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004508 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004509
4510 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004511 // Do access checks before going to the global object.
4512 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004513 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004514 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004515 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4516 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004517 }
4518
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004519 Handle<Object> proto(object->GetPrototype());
4520 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004521 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004522 object = Handle<JSObject>::cast(proto);
4523 }
4524
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004525 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4526 LOCAL_ONLY);
4527 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4528 // property array and since the result is mutable we have to create
4529 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004530 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004531 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004532 for (int i = 0; i < length; i++) {
4533 Object* entry = contents->get(i);
4534 if (entry->IsString()) {
4535 copy->set(i, entry);
4536 } else {
4537 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004538 HandleScope scope(isolate);
4539 Handle<Object> entry_handle(entry, isolate);
4540 Handle<Object> entry_str =
4541 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004542 copy->set(i, *entry_str);
4543 }
4544 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004545 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004546}
4547
4548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004549RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004550 NoHandleAllocation ha;
4551 ASSERT(args.length() == 1);
4552
4553 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004554 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004555 it.AdvanceToArgumentsFrame();
4556 JavaScriptFrame* frame = it.frame();
4557
4558 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004559 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004560
4561 // Try to convert the key to an index. If successful and within
4562 // index return the the argument from the frame.
4563 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004564 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004565 return frame->GetParameter(index);
4566 }
4567
4568 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004569 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004570 bool exception = false;
4571 Handle<Object> converted =
4572 Execution::ToString(args.at<Object>(0), &exception);
4573 if (exception) return Failure::Exception();
4574 Handle<String> key = Handle<String>::cast(converted);
4575
4576 // Try to convert the string key into an array index.
4577 if (key->AsArrayIndex(&index)) {
4578 if (index < n) {
4579 return frame->GetParameter(index);
4580 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004581 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004582 }
4583 }
4584
4585 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004586 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4587 if (key->Equals(isolate->heap()->callee_symbol())) {
4588 Object* function = frame->function();
4589 if (function->IsJSFunction() &&
4590 JSFunction::cast(function)->shared()->strict_mode()) {
4591 return isolate->Throw(*isolate->factory()->NewTypeError(
4592 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4593 }
4594 return function;
4595 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004596
4597 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004598 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004599}
4600
4601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004602RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004603 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004604
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004605 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004606 Handle<Object> object = args.at<Object>(0);
4607 if (object->IsJSObject()) {
4608 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004609 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004610 MaybeObject* ok = js_object->TransformToFastProperties(0);
4611 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004612 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004613 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004614 return *object;
4615}
4616
4617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004618RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004619 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004620
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004621 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004622 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004623 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004624 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004625 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004626 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004627 return *object;
4628}
4629
4630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004631RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004632 NoHandleAllocation ha;
4633 ASSERT(args.length() == 1);
4634
4635 return args[0]->ToBoolean();
4636}
4637
4638
4639// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4640// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004641RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004642 NoHandleAllocation ha;
4643
4644 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004645 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004646 HeapObject* heap_obj = HeapObject::cast(obj);
4647
4648 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004649 if (heap_obj->map()->is_undetectable()) {
4650 return isolate->heap()->undefined_symbol();
4651 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004652
4653 InstanceType instance_type = heap_obj->map()->instance_type();
4654 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004655 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004656 }
4657
4658 switch (instance_type) {
4659 case ODDBALL_TYPE:
4660 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004661 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004662 }
4663 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004664 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004665 }
4666 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004667 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004668 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004669 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004670 default:
4671 // For any kind of object not handled above, the spec rule for
4672 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004673 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004674 }
4675}
4676
4677
lrn@chromium.org25156de2010-04-06 13:10:27 +00004678static bool AreDigits(const char*s, int from, int to) {
4679 for (int i = from; i < to; i++) {
4680 if (s[i] < '0' || s[i] > '9') return false;
4681 }
4682
4683 return true;
4684}
4685
4686
4687static int ParseDecimalInteger(const char*s, int from, int to) {
4688 ASSERT(to - from < 10); // Overflow is not possible.
4689 ASSERT(from < to);
4690 int d = s[from] - '0';
4691
4692 for (int i = from + 1; i < to; i++) {
4693 d = 10 * d + (s[i] - '0');
4694 }
4695
4696 return d;
4697}
4698
4699
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004700RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701 NoHandleAllocation ha;
4702 ASSERT(args.length() == 1);
4703 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004704 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004705
4706 // Fast case: short integer or some sorts of junk values.
4707 int len = subject->length();
4708 if (subject->IsSeqAsciiString()) {
4709 if (len == 0) return Smi::FromInt(0);
4710
4711 char const* data = SeqAsciiString::cast(subject)->GetChars();
4712 bool minus = (data[0] == '-');
4713 int start_pos = (minus ? 1 : 0);
4714
4715 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004716 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004717 } else if (data[start_pos] > '9') {
4718 // Fast check for a junk value. A valid string may start from a
4719 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4720 // the 'I' character ('Infinity'). All of that have codes not greater than
4721 // '9' except 'I'.
4722 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004723 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004724 }
4725 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4726 // The maximal/minimal smi has 10 digits. If the string has less digits we
4727 // know it will fit into the smi-data type.
4728 int d = ParseDecimalInteger(data, start_pos, len);
4729 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004730 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004731 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004732 } else if (!subject->HasHashCode() &&
4733 len <= String::kMaxArrayIndexSize &&
4734 (len == 1 || data[0] != '0')) {
4735 // String hash is not calculated yet but all the data are present.
4736 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004737 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004738#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004739 subject->Hash(); // Force hash calculation.
4740 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4741 static_cast<int>(hash));
4742#endif
4743 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004744 }
4745 return Smi::FromInt(d);
4746 }
4747 }
4748
4749 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004750 return isolate->heap()->NumberFromDouble(
4751 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004752}
4753
4754
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004755RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756 NoHandleAllocation ha;
4757 ASSERT(args.length() == 1);
4758
4759 CONVERT_CHECKED(JSArray, codes, args[0]);
4760 int length = Smi::cast(codes->length())->value();
4761
4762 // Check if the string can be ASCII.
4763 int i;
4764 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004765 Object* element;
4766 { MaybeObject* maybe_element = codes->GetElement(i);
4767 // We probably can't get an exception here, but just in order to enforce
4768 // the checking of inputs in the runtime calls we check here.
4769 if (!maybe_element->ToObject(&element)) return maybe_element;
4770 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004771 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4772 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4773 break;
4774 }
4775
lrn@chromium.org303ada72010-10-27 09:33:13 +00004776 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004777 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004780 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781 }
4782
lrn@chromium.org303ada72010-10-27 09:33:13 +00004783 Object* object = NULL;
4784 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785 String* result = String::cast(object);
4786 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004787 Object* element;
4788 { MaybeObject* maybe_element = codes->GetElement(i);
4789 if (!maybe_element->ToObject(&element)) return maybe_element;
4790 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004792 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793 }
4794 return result;
4795}
4796
4797
4798// kNotEscaped is generated by the following:
4799//
4800// #!/bin/perl
4801// for (my $i = 0; $i < 256; $i++) {
4802// print "\n" if $i % 16 == 0;
4803// my $c = chr($i);
4804// my $escaped = 1;
4805// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4806// print $escaped ? "0, " : "1, ";
4807// }
4808
4809
4810static bool IsNotEscaped(uint16_t character) {
4811 // Only for 8 bit characters, the rest are always escaped (in a different way)
4812 ASSERT(character < 256);
4813 static const char kNotEscaped[256] = {
4814 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4815 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4816 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4817 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4818 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4819 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4820 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4821 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4822 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4823 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4824 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4825 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4826 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4827 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4828 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4829 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4830 };
4831 return kNotEscaped[character] != 0;
4832}
4833
4834
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004835RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836 const char hex_chars[] = "0123456789ABCDEF";
4837 NoHandleAllocation ha;
4838 ASSERT(args.length() == 1);
4839 CONVERT_CHECKED(String, source, args[0]);
4840
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004841 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004842
4843 int escaped_length = 0;
4844 int length = source->length();
4845 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004846 Access<StringInputBuffer> buffer(
4847 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848 buffer->Reset(source);
4849 while (buffer->has_more()) {
4850 uint16_t character = buffer->GetNext();
4851 if (character >= 256) {
4852 escaped_length += 6;
4853 } else if (IsNotEscaped(character)) {
4854 escaped_length++;
4855 } else {
4856 escaped_length += 3;
4857 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004858 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004859 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004860 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004861 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004862 return Failure::OutOfMemoryException();
4863 }
4864 }
4865 }
4866 // No length change implies no change. Return original string if no change.
4867 if (escaped_length == length) {
4868 return source;
4869 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004870 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004871 { MaybeObject* maybe_o =
4872 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004873 if (!maybe_o->ToObject(&o)) return maybe_o;
4874 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004875 String* destination = String::cast(o);
4876 int dest_position = 0;
4877
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004878 Access<StringInputBuffer> buffer(
4879 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004880 buffer->Rewind();
4881 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004882 uint16_t chr = buffer->GetNext();
4883 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004884 destination->Set(dest_position, '%');
4885 destination->Set(dest_position+1, 'u');
4886 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4887 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4888 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4889 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004891 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004892 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893 dest_position++;
4894 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004895 destination->Set(dest_position, '%');
4896 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4897 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004898 dest_position += 3;
4899 }
4900 }
4901 return destination;
4902}
4903
4904
4905static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4906 static const signed char kHexValue['g'] = {
4907 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4908 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4909 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4910 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4911 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4912 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4913 -1, 10, 11, 12, 13, 14, 15 };
4914
4915 if (character1 > 'f') return -1;
4916 int hi = kHexValue[character1];
4917 if (hi == -1) return -1;
4918 if (character2 > 'f') return -1;
4919 int lo = kHexValue[character2];
4920 if (lo == -1) return -1;
4921 return (hi << 4) + lo;
4922}
4923
4924
ager@chromium.org870a0b62008-11-04 11:43:05 +00004925static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004926 int i,
4927 int length,
4928 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004929 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004930 int32_t hi = 0;
4931 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004932 if (character == '%' &&
4933 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004934 source->Get(i + 1) == 'u' &&
4935 (hi = TwoDigitHex(source->Get(i + 2),
4936 source->Get(i + 3))) != -1 &&
4937 (lo = TwoDigitHex(source->Get(i + 4),
4938 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939 *step = 6;
4940 return (hi << 8) + lo;
4941 } else if (character == '%' &&
4942 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004943 (lo = TwoDigitHex(source->Get(i + 1),
4944 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004945 *step = 3;
4946 return lo;
4947 } else {
4948 *step = 1;
4949 return character;
4950 }
4951}
4952
4953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004954RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004955 NoHandleAllocation ha;
4956 ASSERT(args.length() == 1);
4957 CONVERT_CHECKED(String, source, args[0]);
4958
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004959 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004960
4961 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004962 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004963
4964 int unescaped_length = 0;
4965 for (int i = 0; i < length; unescaped_length++) {
4966 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004967 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004968 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004969 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004970 i += step;
4971 }
4972
4973 // No length change implies no change. Return original string if no change.
4974 if (unescaped_length == length)
4975 return source;
4976
lrn@chromium.org303ada72010-10-27 09:33:13 +00004977 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004978 { MaybeObject* maybe_o =
4979 ascii ?
4980 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4981 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004982 if (!maybe_o->ToObject(&o)) return maybe_o;
4983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004984 String* destination = String::cast(o);
4985
4986 int dest_position = 0;
4987 for (int i = 0; i < length; dest_position++) {
4988 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004989 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004990 i += step;
4991 }
4992 return destination;
4993}
4994
4995
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004996static const unsigned int kQuoteTableLength = 128u;
4997
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004998static const int kJsonQuotesCharactersPerEntry = 8;
4999static const char* const JsonQuotes =
5000 "\\u0000 \\u0001 \\u0002 \\u0003 "
5001 "\\u0004 \\u0005 \\u0006 \\u0007 "
5002 "\\b \\t \\n \\u000b "
5003 "\\f \\r \\u000e \\u000f "
5004 "\\u0010 \\u0011 \\u0012 \\u0013 "
5005 "\\u0014 \\u0015 \\u0016 \\u0017 "
5006 "\\u0018 \\u0019 \\u001a \\u001b "
5007 "\\u001c \\u001d \\u001e \\u001f "
5008 " ! \\\" # "
5009 "$ % & ' "
5010 "( ) * + "
5011 ", - . / "
5012 "0 1 2 3 "
5013 "4 5 6 7 "
5014 "8 9 : ; "
5015 "< = > ? "
5016 "@ A B C "
5017 "D E F G "
5018 "H I J K "
5019 "L M N O "
5020 "P Q R S "
5021 "T U V W "
5022 "X Y Z [ "
5023 "\\\\ ] ^ _ "
5024 "` a b c "
5025 "d e f g "
5026 "h i j k "
5027 "l m n o "
5028 "p q r s "
5029 "t u v w "
5030 "x y z { "
5031 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005032
5033
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005034// For a string that is less than 32k characters it should always be
5035// possible to allocate it in new space.
5036static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5037
5038
5039// Doing JSON quoting cannot make the string more than this many times larger.
5040static const int kJsonQuoteWorstCaseBlowup = 6;
5041
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005042static const int kSpaceForQuotesAndComma = 3;
5043static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005044
5045// Covers the entire ASCII range (all other characters are unchanged by JSON
5046// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005047static const byte JsonQuoteLengths[kQuoteTableLength] = {
5048 6, 6, 6, 6, 6, 6, 6, 6,
5049 2, 2, 2, 6, 2, 2, 6, 6,
5050 6, 6, 6, 6, 6, 6, 6, 6,
5051 6, 6, 6, 6, 6, 6, 6, 6,
5052 1, 1, 2, 1, 1, 1, 1, 1,
5053 1, 1, 1, 1, 1, 1, 1, 1,
5054 1, 1, 1, 1, 1, 1, 1, 1,
5055 1, 1, 1, 1, 1, 1, 1, 1,
5056 1, 1, 1, 1, 1, 1, 1, 1,
5057 1, 1, 1, 1, 1, 1, 1, 1,
5058 1, 1, 1, 1, 1, 1, 1, 1,
5059 1, 1, 1, 1, 2, 1, 1, 1,
5060 1, 1, 1, 1, 1, 1, 1, 1,
5061 1, 1, 1, 1, 1, 1, 1, 1,
5062 1, 1, 1, 1, 1, 1, 1, 1,
5063 1, 1, 1, 1, 1, 1, 1, 1,
5064};
5065
5066
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005067template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005069
5070
5071template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5073 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005074}
5075
5076
5077template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005078MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5079 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005080}
5081
5082
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005083template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005084static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5085 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005086 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005087 const Char* read_cursor = characters.start();
5088 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005089 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005090 int quoted_length = kSpaceForQuotes;
5091 while (read_cursor < end) {
5092 Char c = *(read_cursor++);
5093 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5094 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005095 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005096 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005097 }
5098 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005099 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5100 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005101 Object* new_object;
5102 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005103 return new_alloc;
5104 }
5105 StringType* new_string = StringType::cast(new_object);
5106
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005107 Char* write_cursor = reinterpret_cast<Char*>(
5108 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005109 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005110 *(write_cursor++) = '"';
5111
5112 read_cursor = characters.start();
5113 while (read_cursor < end) {
5114 Char c = *(read_cursor++);
5115 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5116 *(write_cursor++) = c;
5117 } else {
5118 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5119 const char* replacement = JsonQuotes +
5120 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5121 for (int i = 0; i < len; i++) {
5122 *write_cursor++ = *replacement++;
5123 }
5124 }
5125 }
5126 *(write_cursor++) = '"';
5127 return new_string;
5128}
5129
5130
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005131template <typename SinkChar, typename SourceChar>
5132static inline SinkChar* WriteQuoteJsonString(
5133 Isolate* isolate,
5134 SinkChar* write_cursor,
5135 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005136 // SinkChar is only char if SourceChar is guaranteed to be char.
5137 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005138 const SourceChar* read_cursor = characters.start();
5139 const SourceChar* end = read_cursor + characters.length();
5140 *(write_cursor++) = '"';
5141 while (read_cursor < end) {
5142 SourceChar c = *(read_cursor++);
5143 if (sizeof(SourceChar) > 1u &&
5144 static_cast<unsigned>(c) >= kQuoteTableLength) {
5145 *(write_cursor++) = static_cast<SinkChar>(c);
5146 } else {
5147 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5148 const char* replacement = JsonQuotes +
5149 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5150 write_cursor[0] = replacement[0];
5151 if (len > 1) {
5152 write_cursor[1] = replacement[1];
5153 if (len > 2) {
5154 ASSERT(len == 6);
5155 write_cursor[2] = replacement[2];
5156 write_cursor[3] = replacement[3];
5157 write_cursor[4] = replacement[4];
5158 write_cursor[5] = replacement[5];
5159 }
5160 }
5161 write_cursor += len;
5162 }
5163 }
5164 *(write_cursor++) = '"';
5165 return write_cursor;
5166}
5167
5168
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005169template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005170static MaybeObject* QuoteJsonString(Isolate* isolate,
5171 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005172 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005173 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005174 int worst_case_length =
5175 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005176 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005177 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005178 }
5179
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005180 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5181 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005182 Object* new_object;
5183 if (!new_alloc->ToObject(&new_object)) {
5184 return new_alloc;
5185 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005186 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005187 // Even if our string is small enough to fit in new space we still have to
5188 // handle it being allocated in old space as may happen in the third
5189 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5190 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005191 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005192 }
5193 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005194 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005195
5196 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5197 Char* write_cursor = reinterpret_cast<Char*>(
5198 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005199 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005200 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5201 write_cursor,
5202 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005203 int final_length = static_cast<int>(
5204 write_cursor - reinterpret_cast<Char*>(
5205 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005206 isolate->heap()->new_space()->
5207 template ShrinkStringAtAllocationBoundary<StringType>(
5208 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005209 return new_string;
5210}
5211
5212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005213RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005214 NoHandleAllocation ha;
5215 CONVERT_CHECKED(String, str, args[0]);
5216 if (!str->IsFlat()) {
5217 MaybeObject* try_flatten = str->TryFlatten();
5218 Object* flat;
5219 if (!try_flatten->ToObject(&flat)) {
5220 return try_flatten;
5221 }
5222 str = String::cast(flat);
5223 ASSERT(str->IsFlat());
5224 }
5225 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005226 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5227 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005228 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005229 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5230 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005231 }
5232}
5233
5234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005235RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005236 NoHandleAllocation ha;
5237 CONVERT_CHECKED(String, str, args[0]);
5238 if (!str->IsFlat()) {
5239 MaybeObject* try_flatten = str->TryFlatten();
5240 Object* flat;
5241 if (!try_flatten->ToObject(&flat)) {
5242 return try_flatten;
5243 }
5244 str = String::cast(flat);
5245 ASSERT(str->IsFlat());
5246 }
5247 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005248 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5249 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005250 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005251 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5252 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005253 }
5254}
5255
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005256
5257template <typename Char, typename StringType>
5258static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5259 FixedArray* array,
5260 int worst_case_length) {
5261 int length = array->length();
5262
5263 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5264 worst_case_length);
5265 Object* new_object;
5266 if (!new_alloc->ToObject(&new_object)) {
5267 return new_alloc;
5268 }
5269 if (!isolate->heap()->new_space()->Contains(new_object)) {
5270 // Even if our string is small enough to fit in new space we still have to
5271 // handle it being allocated in old space as may happen in the third
5272 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5273 // CEntryStub::GenerateCore.
5274 return isolate->heap()->undefined_value();
5275 }
5276 AssertNoAllocation no_gc;
5277 StringType* new_string = StringType::cast(new_object);
5278 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5279
5280 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5281 Char* write_cursor = reinterpret_cast<Char*>(
5282 new_string->address() + SeqAsciiString::kHeaderSize);
5283 *(write_cursor++) = '[';
5284 for (int i = 0; i < length; i++) {
5285 if (i != 0) *(write_cursor++) = ',';
5286 String* str = String::cast(array->get(i));
5287 if (str->IsTwoByteRepresentation()) {
5288 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5289 write_cursor,
5290 str->ToUC16Vector());
5291 } else {
5292 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5293 write_cursor,
5294 str->ToAsciiVector());
5295 }
5296 }
5297 *(write_cursor++) = ']';
5298
5299 int final_length = static_cast<int>(
5300 write_cursor - reinterpret_cast<Char*>(
5301 new_string->address() + SeqAsciiString::kHeaderSize));
5302 isolate->heap()->new_space()->
5303 template ShrinkStringAtAllocationBoundary<StringType>(
5304 new_string, final_length);
5305 return new_string;
5306}
5307
5308
5309RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5310 NoHandleAllocation ha;
5311 ASSERT(args.length() == 1);
5312 CONVERT_CHECKED(JSArray, array, args[0]);
5313
5314 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5315 FixedArray* elements = FixedArray::cast(array->elements());
5316 int n = elements->length();
5317 bool ascii = true;
5318 int total_length = 0;
5319
5320 for (int i = 0; i < n; i++) {
5321 Object* elt = elements->get(i);
5322 if (!elt->IsString()) return isolate->heap()->undefined_value();
5323 String* element = String::cast(elt);
5324 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5325 total_length += element->length();
5326 if (ascii && element->IsTwoByteRepresentation()) {
5327 ascii = false;
5328 }
5329 }
5330
5331 int worst_case_length =
5332 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5333 + total_length * kJsonQuoteWorstCaseBlowup;
5334
5335 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5336 return isolate->heap()->undefined_value();
5337 }
5338
5339 if (ascii) {
5340 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5341 elements,
5342 worst_case_length);
5343 } else {
5344 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5345 elements,
5346 worst_case_length);
5347 }
5348}
5349
5350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005351RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005352 NoHandleAllocation ha;
5353
5354 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005355 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005356
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005357 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005358
lrn@chromium.org25156de2010-04-06 13:10:27 +00005359 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005360 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005361 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005362}
5363
5364
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005365RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005366 NoHandleAllocation ha;
5367 CONVERT_CHECKED(String, str, args[0]);
5368
5369 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005370 double value = StringToDouble(isolate->unicode_cache(),
5371 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005372
5373 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005374 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005375}
5376
5377
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005378template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005379MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005380 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005381 String* s,
5382 int length,
5383 int input_string_length,
5384 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005385 // We try this twice, once with the assumption that the result is no longer
5386 // than the input and, if that assumption breaks, again with the exact
5387 // length. This may not be pretty, but it is nicer than what was here before
5388 // and I hereby claim my vaffel-is.
5389 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005390 // Allocate the resulting string.
5391 //
5392 // NOTE: This assumes that the upper/lower case of an ascii
5393 // character is also ascii. This is currently the case, but it
5394 // might break in the future if we implement more context and locale
5395 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005396 Object* o;
5397 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005398 ? isolate->heap()->AllocateRawAsciiString(length)
5399 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005400 if (!maybe_o->ToObject(&o)) return maybe_o;
5401 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005402 String* result = String::cast(o);
5403 bool has_changed_character = false;
5404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005405 // Convert all characters to upper case, assuming that they will fit
5406 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005407 Access<StringInputBuffer> buffer(
5408 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005410 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005411 // We can assume that the string is not empty
5412 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005413 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005414 bool has_next = buffer->has_more();
5415 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005416 int char_length = mapping->get(current, next, chars);
5417 if (char_length == 0) {
5418 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005419 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005420 i++;
5421 } else if (char_length == 1) {
5422 // Common case: converting the letter resulted in one character.
5423 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005424 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005425 has_changed_character = true;
5426 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005427 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005428 // We've assumed that the result would be as long as the
5429 // input but here is a character that converts to several
5430 // characters. No matter, we calculate the exact length
5431 // of the result and try the whole thing again.
5432 //
5433 // Note that this leaves room for optimization. We could just
5434 // memcpy what we already have to the result string. Also,
5435 // the result string is the last object allocated we could
5436 // "realloc" it and probably, in the vast majority of cases,
5437 // extend the existing string to be able to hold the full
5438 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005439 int next_length = 0;
5440 if (has_next) {
5441 next_length = mapping->get(next, 0, chars);
5442 if (next_length == 0) next_length = 1;
5443 }
5444 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005445 while (buffer->has_more()) {
5446 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005447 // NOTE: we use 0 as the next character here because, while
5448 // the next character may affect what a character converts to,
5449 // it does not in any case affect the length of what it convert
5450 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005451 int char_length = mapping->get(current, 0, chars);
5452 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005453 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005454 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005455 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005456 return Failure::OutOfMemoryException();
5457 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005458 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005459 // Try again with the real length.
5460 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005461 } else {
5462 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005463 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005464 i++;
5465 }
5466 has_changed_character = true;
5467 }
5468 current = next;
5469 }
5470 if (has_changed_character) {
5471 return result;
5472 } else {
5473 // If we didn't actually change anything in doing the conversion
5474 // we simple return the result and let the converted string
5475 // become garbage; there is no reason to keep two identical strings
5476 // alive.
5477 return s;
5478 }
5479}
5480
5481
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005482namespace {
5483
lrn@chromium.org303ada72010-10-27 09:33:13 +00005484static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5485
5486
5487// Given a word and two range boundaries returns a word with high bit
5488// set in every byte iff the corresponding input byte was strictly in
5489// the range (m, n). All the other bits in the result are cleared.
5490// This function is only useful when it can be inlined and the
5491// boundaries are statically known.
5492// Requires: all bytes in the input word and the boundaries must be
5493// ascii (less than 0x7F).
5494static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5495 // Every byte in an ascii string is less than or equal to 0x7F.
5496 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5497 // Use strict inequalities since in edge cases the function could be
5498 // further simplified.
5499 ASSERT(0 < m && m < n && n < 0x7F);
5500 // Has high bit set in every w byte less than n.
5501 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5502 // Has high bit set in every w byte greater than m.
5503 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5504 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5505}
5506
5507
5508enum AsciiCaseConversion {
5509 ASCII_TO_LOWER,
5510 ASCII_TO_UPPER
5511};
5512
5513
5514template <AsciiCaseConversion dir>
5515struct FastAsciiConverter {
5516 static bool Convert(char* dst, char* src, int length) {
5517#ifdef DEBUG
5518 char* saved_dst = dst;
5519 char* saved_src = src;
5520#endif
5521 // We rely on the distance between upper and lower case letters
5522 // being a known power of 2.
5523 ASSERT('a' - 'A' == (1 << 5));
5524 // Boundaries for the range of input characters than require conversion.
5525 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5526 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5527 bool changed = false;
5528 char* const limit = src + length;
5529#ifdef V8_HOST_CAN_READ_UNALIGNED
5530 // Process the prefix of the input that requires no conversion one
5531 // (machine) word at a time.
5532 while (src <= limit - sizeof(uintptr_t)) {
5533 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5534 if (AsciiRangeMask(w, lo, hi) != 0) {
5535 changed = true;
5536 break;
5537 }
5538 *reinterpret_cast<uintptr_t*>(dst) = w;
5539 src += sizeof(uintptr_t);
5540 dst += sizeof(uintptr_t);
5541 }
5542 // Process the remainder of the input performing conversion when
5543 // required one word at a time.
5544 while (src <= limit - sizeof(uintptr_t)) {
5545 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5546 uintptr_t m = AsciiRangeMask(w, lo, hi);
5547 // The mask has high (7th) bit set in every byte that needs
5548 // conversion and we know that the distance between cases is
5549 // 1 << 5.
5550 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5551 src += sizeof(uintptr_t);
5552 dst += sizeof(uintptr_t);
5553 }
5554#endif
5555 // Process the last few bytes of the input (or the whole input if
5556 // unaligned access is not supported).
5557 while (src < limit) {
5558 char c = *src;
5559 if (lo < c && c < hi) {
5560 c ^= (1 << 5);
5561 changed = true;
5562 }
5563 *dst = c;
5564 ++src;
5565 ++dst;
5566 }
5567#ifdef DEBUG
5568 CheckConvert(saved_dst, saved_src, length, changed);
5569#endif
5570 return changed;
5571 }
5572
5573#ifdef DEBUG
5574 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5575 bool expected_changed = false;
5576 for (int i = 0; i < length; i++) {
5577 if (dst[i] == src[i]) continue;
5578 expected_changed = true;
5579 if (dir == ASCII_TO_LOWER) {
5580 ASSERT('A' <= src[i] && src[i] <= 'Z');
5581 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5582 } else {
5583 ASSERT(dir == ASCII_TO_UPPER);
5584 ASSERT('a' <= src[i] && src[i] <= 'z');
5585 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5586 }
5587 }
5588 ASSERT(expected_changed == changed);
5589 }
5590#endif
5591};
5592
5593
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005594struct ToLowerTraits {
5595 typedef unibrow::ToLowercase UnibrowConverter;
5596
lrn@chromium.org303ada72010-10-27 09:33:13 +00005597 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005598};
5599
5600
5601struct ToUpperTraits {
5602 typedef unibrow::ToUppercase UnibrowConverter;
5603
lrn@chromium.org303ada72010-10-27 09:33:13 +00005604 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005605};
5606
5607} // namespace
5608
5609
5610template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005611MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005612 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005613 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005614 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005615 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005616 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005617 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005618
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005619 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005620 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005621 if (length == 0) return s;
5622
5623 // Simpler handling of ascii strings.
5624 //
5625 // NOTE: This assumes that the upper/lower case of an ascii
5626 // character is also ascii. This is currently the case, but it
5627 // might break in the future if we implement more context and locale
5628 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005629 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005630 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005631 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005632 if (!maybe_o->ToObject(&o)) return maybe_o;
5633 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005634 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005635 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005636 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005637 return has_changed_character ? result : s;
5638 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005639
lrn@chromium.org303ada72010-10-27 09:33:13 +00005640 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005641 { MaybeObject* maybe_answer =
5642 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005643 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5644 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005645 if (answer->IsSmi()) {
5646 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005647 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005648 ConvertCaseHelper(isolate,
5649 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005650 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5651 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005652 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005653 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005654}
5655
5656
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005657RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005658 return ConvertCase<ToLowerTraits>(
5659 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005660}
5661
5662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005663RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005664 return ConvertCase<ToUpperTraits>(
5665 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005666}
5667
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005668
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005669static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5670 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5671}
5672
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005674RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005675 NoHandleAllocation ha;
5676 ASSERT(args.length() == 3);
5677
5678 CONVERT_CHECKED(String, s, args[0]);
5679 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5680 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5681
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005682 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005683 int length = s->length();
5684
5685 int left = 0;
5686 if (trimLeft) {
5687 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5688 left++;
5689 }
5690 }
5691
5692 int right = length;
5693 if (trimRight) {
5694 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5695 right--;
5696 }
5697 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005698 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005699}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005700
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005701
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005702template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005703void FindStringIndices(Isolate* isolate,
5704 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005705 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005706 ZoneList<int>* indices,
5707 unsigned int limit) {
5708 ASSERT(limit > 0);
5709 // Collect indices of pattern in subject, and the end-of-string index.
5710 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005711 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005712 int pattern_length = pattern.length();
5713 int index = 0;
5714 while (limit > 0) {
5715 index = search.Search(subject, index);
5716 if (index < 0) return;
5717 indices->Add(index);
5718 index += pattern_length;
5719 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005720 }
5721}
5722
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005723
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005724RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005725 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005726 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005727 CONVERT_ARG_CHECKED(String, subject, 0);
5728 CONVERT_ARG_CHECKED(String, pattern, 1);
5729 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5730
5731 int subject_length = subject->length();
5732 int pattern_length = pattern->length();
5733 RUNTIME_ASSERT(pattern_length > 0);
5734
5735 // The limit can be very large (0xffffffffu), but since the pattern
5736 // isn't empty, we can never create more parts than ~half the length
5737 // of the subject.
5738
5739 if (!subject->IsFlat()) FlattenString(subject);
5740
5741 static const int kMaxInitialListCapacity = 16;
5742
danno@chromium.org40cb8782011-05-25 07:58:50 +00005743 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005744
5745 // Find (up to limit) indices of separator and end-of-string in subject
5746 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5747 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005748 if (!pattern->IsFlat()) FlattenString(pattern);
5749
5750 // No allocation block.
5751 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005752 AssertNoAllocation nogc;
5753 if (subject->IsAsciiRepresentation()) {
5754 Vector<const char> subject_vector = subject->ToAsciiVector();
5755 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005756 FindStringIndices(isolate,
5757 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005758 pattern->ToAsciiVector(),
5759 &indices,
5760 limit);
5761 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005762 FindStringIndices(isolate,
5763 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005764 pattern->ToUC16Vector(),
5765 &indices,
5766 limit);
5767 }
5768 } else {
5769 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5770 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005771 FindStringIndices(isolate,
5772 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005773 pattern->ToAsciiVector(),
5774 &indices,
5775 limit);
5776 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005777 FindStringIndices(isolate,
5778 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005779 pattern->ToUC16Vector(),
5780 &indices,
5781 limit);
5782 }
5783 }
5784 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005785
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005786 if (static_cast<uint32_t>(indices.length()) < limit) {
5787 indices.Add(subject_length);
5788 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005789
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005790 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005791
5792 // Create JSArray of substrings separated by separator.
5793 int part_count = indices.length();
5794
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005795 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005796 result->set_length(Smi::FromInt(part_count));
5797
5798 ASSERT(result->HasFastElements());
5799
5800 if (part_count == 1 && indices.at(0) == subject_length) {
5801 FixedArray::cast(result->elements())->set(0, *subject);
5802 return *result;
5803 }
5804
5805 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5806 int part_start = 0;
5807 for (int i = 0; i < part_count; i++) {
5808 HandleScope local_loop_handle;
5809 int part_end = indices.at(i);
5810 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005811 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005812 elements->set(i, *substring);
5813 part_start = part_end + pattern_length;
5814 }
5815
5816 return *result;
5817}
5818
5819
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005820// Copies ascii characters to the given fixed array looking up
5821// one-char strings in the cache. Gives up on the first char that is
5822// not in the cache and fills the remainder with smi zeros. Returns
5823// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005824static int CopyCachedAsciiCharsToArray(Heap* heap,
5825 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005826 FixedArray* elements,
5827 int length) {
5828 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005829 FixedArray* ascii_cache = heap->single_character_string_cache();
5830 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005831 int i;
5832 for (i = 0; i < length; ++i) {
5833 Object* value = ascii_cache->get(chars[i]);
5834 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005835 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005836 elements->set(i, value, SKIP_WRITE_BARRIER);
5837 }
5838 if (i < length) {
5839 ASSERT(Smi::FromInt(0) == 0);
5840 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5841 }
5842#ifdef DEBUG
5843 for (int j = 0; j < length; ++j) {
5844 Object* element = elements->get(j);
5845 ASSERT(element == Smi::FromInt(0) ||
5846 (element->IsString() && String::cast(element)->LooksValid()));
5847 }
5848#endif
5849 return i;
5850}
5851
5852
5853// Converts a String to JSArray.
5854// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005855RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005856 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005857 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005858 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005859 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005860
5861 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005862 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005863
5864 Handle<FixedArray> elements;
5865 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005866 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005867 { MaybeObject* maybe_obj =
5868 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005869 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5870 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005871 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005872
5873 Vector<const char> chars = s->ToAsciiVector();
5874 // Note, this will initialize all elements (not only the prefix)
5875 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005876 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5877 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005878 *elements,
5879 length);
5880
5881 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005882 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5883 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005884 }
5885 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005886 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005887 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005888 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5889 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005890 }
5891 }
5892
5893#ifdef DEBUG
5894 for (int i = 0; i < length; ++i) {
5895 ASSERT(String::cast(elements->get(i))->length() == 1);
5896 }
5897#endif
5898
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005899 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005900}
5901
5902
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005903RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005904 NoHandleAllocation ha;
5905 ASSERT(args.length() == 1);
5906 CONVERT_CHECKED(String, value, args[0]);
5907 return value->ToObject();
5908}
5909
5910
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005911bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005912 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005913 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005914 return char_length == 0;
5915}
5916
5917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005918RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005919 NoHandleAllocation ha;
5920 ASSERT(args.length() == 1);
5921
5922 Object* number = args[0];
5923 RUNTIME_ASSERT(number->IsNumber());
5924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005925 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005926}
5927
5928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005929RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005930 NoHandleAllocation ha;
5931 ASSERT(args.length() == 1);
5932
5933 Object* number = args[0];
5934 RUNTIME_ASSERT(number->IsNumber());
5935
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005936 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005937}
5938
5939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005940RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941 NoHandleAllocation ha;
5942 ASSERT(args.length() == 1);
5943
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005944 CONVERT_DOUBLE_CHECKED(number, args[0]);
5945
5946 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5947 if (number > 0 && number <= Smi::kMaxValue) {
5948 return Smi::FromInt(static_cast<int>(number));
5949 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005950 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005951}
5952
5953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005954RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005955 NoHandleAllocation ha;
5956 ASSERT(args.length() == 1);
5957
5958 CONVERT_DOUBLE_CHECKED(number, args[0]);
5959
5960 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5961 if (number > 0 && number <= Smi::kMaxValue) {
5962 return Smi::FromInt(static_cast<int>(number));
5963 }
5964
5965 double double_value = DoubleToInteger(number);
5966 // Map both -0 and +0 to +0.
5967 if (double_value == 0) double_value = 0;
5968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005969 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005970}
5971
5972
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005973RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974 NoHandleAllocation ha;
5975 ASSERT(args.length() == 1);
5976
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005977 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005978 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979}
5980
5981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005982RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005983 NoHandleAllocation ha;
5984 ASSERT(args.length() == 1);
5985
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005986 CONVERT_DOUBLE_CHECKED(number, args[0]);
5987
5988 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5989 if (number > 0 && number <= Smi::kMaxValue) {
5990 return Smi::FromInt(static_cast<int>(number));
5991 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005992 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005993}
5994
5995
ager@chromium.org870a0b62008-11-04 11:43:05 +00005996// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5997// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005998RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005999 NoHandleAllocation ha;
6000 ASSERT(args.length() == 1);
6001
6002 Object* obj = args[0];
6003 if (obj->IsSmi()) {
6004 return obj;
6005 }
6006 if (obj->IsHeapNumber()) {
6007 double value = HeapNumber::cast(obj)->value();
6008 int int_value = FastD2I(value);
6009 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6010 return Smi::FromInt(int_value);
6011 }
6012 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006013 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006014}
6015
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006017RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006018 NoHandleAllocation ha;
6019 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006020 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006021}
6022
6023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006024RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006025 NoHandleAllocation ha;
6026 ASSERT(args.length() == 2);
6027
6028 CONVERT_DOUBLE_CHECKED(x, args[0]);
6029 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006030 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006031}
6032
6033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006034RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006035 NoHandleAllocation ha;
6036 ASSERT(args.length() == 2);
6037
6038 CONVERT_DOUBLE_CHECKED(x, args[0]);
6039 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006040 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006041}
6042
6043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006044RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006045 NoHandleAllocation ha;
6046 ASSERT(args.length() == 2);
6047
6048 CONVERT_DOUBLE_CHECKED(x, args[0]);
6049 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006050 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006051}
6052
6053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006054RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006055 NoHandleAllocation ha;
6056 ASSERT(args.length() == 1);
6057
6058 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006059 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060}
6061
6062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006063RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006064 NoHandleAllocation ha;
6065 ASSERT(args.length() == 0);
6066
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006067 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006068}
6069
6070
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006071RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006072 NoHandleAllocation ha;
6073 ASSERT(args.length() == 2);
6074
6075 CONVERT_DOUBLE_CHECKED(x, args[0]);
6076 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006077 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006078}
6079
6080
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006081RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006082 NoHandleAllocation ha;
6083 ASSERT(args.length() == 2);
6084
6085 CONVERT_DOUBLE_CHECKED(x, args[0]);
6086 CONVERT_DOUBLE_CHECKED(y, args[1]);
6087
ager@chromium.org3811b432009-10-28 14:53:37 +00006088 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006089 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006090 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006091}
6092
6093
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006094RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006095 NoHandleAllocation ha;
6096 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006097 CONVERT_CHECKED(String, str1, args[0]);
6098 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006099 isolate->counters()->string_add_runtime()->Increment();
6100 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006101}
6102
6103
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006104template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006105static inline void StringBuilderConcatHelper(String* special,
6106 sinkchar* sink,
6107 FixedArray* fixed_array,
6108 int array_length) {
6109 int position = 0;
6110 for (int i = 0; i < array_length; i++) {
6111 Object* element = fixed_array->get(i);
6112 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006113 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006114 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006115 int pos;
6116 int len;
6117 if (encoded_slice > 0) {
6118 // Position and length encoded in one smi.
6119 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6120 len = StringBuilderSubstringLength::decode(encoded_slice);
6121 } else {
6122 // Position and length encoded in two smis.
6123 Object* obj = fixed_array->get(++i);
6124 ASSERT(obj->IsSmi());
6125 pos = Smi::cast(obj)->value();
6126 len = -encoded_slice;
6127 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006128 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006129 sink + position,
6130 pos,
6131 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006132 position += len;
6133 } else {
6134 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006135 int element_length = string->length();
6136 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006137 position += element_length;
6138 }
6139 }
6140}
6141
6142
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006143RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006144 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006145 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006146 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006147 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006148 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006149 return Failure::OutOfMemoryException();
6150 }
6151 int array_length = Smi::cast(args[1])->value();
6152 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006153
6154 // This assumption is used by the slice encoding in one or two smis.
6155 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6156
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006157 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006158 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006159 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006160 }
6161 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006162 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006163 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006164 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006165
6166 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006167 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006168 } else if (array_length == 1) {
6169 Object* first = fixed_array->get(0);
6170 if (first->IsString()) return first;
6171 }
6172
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006173 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006174 int position = 0;
6175 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006176 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006177 Object* elt = fixed_array->get(i);
6178 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006179 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006180 int smi_value = Smi::cast(elt)->value();
6181 int pos;
6182 int len;
6183 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006184 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006185 pos = StringBuilderSubstringPosition::decode(smi_value);
6186 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006187 } else {
6188 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006189 len = -smi_value;
6190 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006191 i++;
6192 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006193 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006194 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006195 Object* next_smi = fixed_array->get(i);
6196 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006197 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006198 }
6199 pos = Smi::cast(next_smi)->value();
6200 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006201 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006202 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006204 ASSERT(pos >= 0);
6205 ASSERT(len >= 0);
6206 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006207 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006208 }
6209 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006210 } else if (elt->IsString()) {
6211 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006212 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006213 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006214 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006215 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006216 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006217 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006218 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006219 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006220 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006221 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006222 return Failure::OutOfMemoryException();
6223 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006224 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006225 }
6226
6227 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006228 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006229
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006230 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006231 { MaybeObject* maybe_object =
6232 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006233 if (!maybe_object->ToObject(&object)) return maybe_object;
6234 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006235 SeqAsciiString* answer = SeqAsciiString::cast(object);
6236 StringBuilderConcatHelper(special,
6237 answer->GetChars(),
6238 fixed_array,
6239 array_length);
6240 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006241 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006242 { MaybeObject* maybe_object =
6243 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006244 if (!maybe_object->ToObject(&object)) return maybe_object;
6245 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006246 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6247 StringBuilderConcatHelper(special,
6248 answer->GetChars(),
6249 fixed_array,
6250 array_length);
6251 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006253}
6254
6255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006256RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006257 NoHandleAllocation ha;
6258 ASSERT(args.length() == 3);
6259 CONVERT_CHECKED(JSArray, array, args[0]);
6260 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006261 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006262 return Failure::OutOfMemoryException();
6263 }
6264 int array_length = Smi::cast(args[1])->value();
6265 CONVERT_CHECKED(String, separator, args[2]);
6266
6267 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006268 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006269 }
6270 FixedArray* fixed_array = FixedArray::cast(array->elements());
6271 if (fixed_array->length() < array_length) {
6272 array_length = fixed_array->length();
6273 }
6274
6275 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006276 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006277 } else if (array_length == 1) {
6278 Object* first = fixed_array->get(0);
6279 if (first->IsString()) return first;
6280 }
6281
6282 int separator_length = separator->length();
6283 int max_nof_separators =
6284 (String::kMaxLength + separator_length - 1) / separator_length;
6285 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006286 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006287 return Failure::OutOfMemoryException();
6288 }
6289 int length = (array_length - 1) * separator_length;
6290 for (int i = 0; i < array_length; i++) {
6291 Object* element_obj = fixed_array->get(i);
6292 if (!element_obj->IsString()) {
6293 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006294 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006295 }
6296 String* element = String::cast(element_obj);
6297 int increment = element->length();
6298 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006299 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006300 return Failure::OutOfMemoryException();
6301 }
6302 length += increment;
6303 }
6304
6305 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006306 { MaybeObject* maybe_object =
6307 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006308 if (!maybe_object->ToObject(&object)) return maybe_object;
6309 }
6310 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6311
6312 uc16* sink = answer->GetChars();
6313#ifdef DEBUG
6314 uc16* end = sink + length;
6315#endif
6316
6317 String* first = String::cast(fixed_array->get(0));
6318 int first_length = first->length();
6319 String::WriteToFlat(first, sink, 0, first_length);
6320 sink += first_length;
6321
6322 for (int i = 1; i < array_length; i++) {
6323 ASSERT(sink + separator_length <= end);
6324 String::WriteToFlat(separator, sink, 0, separator_length);
6325 sink += separator_length;
6326
6327 String* element = String::cast(fixed_array->get(i));
6328 int element_length = element->length();
6329 ASSERT(sink + element_length <= end);
6330 String::WriteToFlat(element, sink, 0, element_length);
6331 sink += element_length;
6332 }
6333 ASSERT(sink == end);
6334
6335 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6336 return answer;
6337}
6338
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006339template <typename Char>
6340static void JoinSparseArrayWithSeparator(FixedArray* elements,
6341 int elements_length,
6342 uint32_t array_length,
6343 String* separator,
6344 Vector<Char> buffer) {
6345 int previous_separator_position = 0;
6346 int separator_length = separator->length();
6347 int cursor = 0;
6348 for (int i = 0; i < elements_length; i += 2) {
6349 int position = NumberToInt32(elements->get(i));
6350 String* string = String::cast(elements->get(i + 1));
6351 int string_length = string->length();
6352 if (string->length() > 0) {
6353 while (previous_separator_position < position) {
6354 String::WriteToFlat<Char>(separator, &buffer[cursor],
6355 0, separator_length);
6356 cursor += separator_length;
6357 previous_separator_position++;
6358 }
6359 String::WriteToFlat<Char>(string, &buffer[cursor],
6360 0, string_length);
6361 cursor += string->length();
6362 }
6363 }
6364 if (separator_length > 0) {
6365 // Array length must be representable as a signed 32-bit number,
6366 // otherwise the total string length would have been too large.
6367 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6368 int last_array_index = static_cast<int>(array_length - 1);
6369 while (previous_separator_position < last_array_index) {
6370 String::WriteToFlat<Char>(separator, &buffer[cursor],
6371 0, separator_length);
6372 cursor += separator_length;
6373 previous_separator_position++;
6374 }
6375 }
6376 ASSERT(cursor <= buffer.length());
6377}
6378
6379
6380RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6381 NoHandleAllocation ha;
6382 ASSERT(args.length() == 3);
6383 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6384 RUNTIME_ASSERT(elements_array->HasFastElements());
6385 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6386 CONVERT_CHECKED(String, separator, args[2]);
6387 // elements_array is fast-mode JSarray of alternating positions
6388 // (increasing order) and strings.
6389 // array_length is length of original array (used to add separators);
6390 // separator is string to put between elements. Assumed to be non-empty.
6391
6392 // Find total length of join result.
6393 int string_length = 0;
6394 bool is_ascii = true;
6395 int max_string_length = SeqAsciiString::kMaxLength;
6396 bool overflow = false;
6397 CONVERT_NUMBER_CHECKED(int, elements_length,
6398 Int32, elements_array->length());
6399 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6400 FixedArray* elements = FixedArray::cast(elements_array->elements());
6401 for (int i = 0; i < elements_length; i += 2) {
6402 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6403 CONVERT_CHECKED(String, string, elements->get(i + 1));
6404 int length = string->length();
6405 if (is_ascii && !string->IsAsciiRepresentation()) {
6406 is_ascii = false;
6407 max_string_length = SeqTwoByteString::kMaxLength;
6408 }
6409 if (length > max_string_length ||
6410 max_string_length - length < string_length) {
6411 overflow = true;
6412 break;
6413 }
6414 string_length += length;
6415 }
6416 int separator_length = separator->length();
6417 if (!overflow && separator_length > 0) {
6418 if (array_length <= 0x7fffffffu) {
6419 int separator_count = static_cast<int>(array_length) - 1;
6420 int remaining_length = max_string_length - string_length;
6421 if ((remaining_length / separator_length) >= separator_count) {
6422 string_length += separator_length * (array_length - 1);
6423 } else {
6424 // Not room for the separators within the maximal string length.
6425 overflow = true;
6426 }
6427 } else {
6428 // Nonempty separator and at least 2^31-1 separators necessary
6429 // means that the string is too large to create.
6430 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6431 overflow = true;
6432 }
6433 }
6434 if (overflow) {
6435 // Throw OutOfMemory exception for creating too large a string.
6436 V8::FatalProcessOutOfMemory("Array join result too large.");
6437 }
6438
6439 if (is_ascii) {
6440 MaybeObject* result_allocation =
6441 isolate->heap()->AllocateRawAsciiString(string_length);
6442 if (result_allocation->IsFailure()) return result_allocation;
6443 SeqAsciiString* result_string =
6444 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6445 JoinSparseArrayWithSeparator<char>(elements,
6446 elements_length,
6447 array_length,
6448 separator,
6449 Vector<char>(result_string->GetChars(),
6450 string_length));
6451 return result_string;
6452 } else {
6453 MaybeObject* result_allocation =
6454 isolate->heap()->AllocateRawTwoByteString(string_length);
6455 if (result_allocation->IsFailure()) return result_allocation;
6456 SeqTwoByteString* result_string =
6457 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6458 JoinSparseArrayWithSeparator<uc16>(elements,
6459 elements_length,
6460 array_length,
6461 separator,
6462 Vector<uc16>(result_string->GetChars(),
6463 string_length));
6464 return result_string;
6465 }
6466}
6467
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006468
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006469RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006470 NoHandleAllocation ha;
6471 ASSERT(args.length() == 2);
6472
6473 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6474 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006475 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006476}
6477
6478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006479RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006480 NoHandleAllocation ha;
6481 ASSERT(args.length() == 2);
6482
6483 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6484 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006485 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006486}
6487
6488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006489RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006490 NoHandleAllocation ha;
6491 ASSERT(args.length() == 2);
6492
6493 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6494 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006495 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006496}
6497
6498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006499RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006500 NoHandleAllocation ha;
6501 ASSERT(args.length() == 1);
6502
6503 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006504 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505}
6506
6507
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006508RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006509 NoHandleAllocation ha;
6510 ASSERT(args.length() == 2);
6511
6512 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6513 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006514 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515}
6516
6517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006518RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006519 NoHandleAllocation ha;
6520 ASSERT(args.length() == 2);
6521
6522 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6523 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006524 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525}
6526
6527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006528RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006529 NoHandleAllocation ha;
6530 ASSERT(args.length() == 2);
6531
6532 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6533 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006534 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006535}
6536
6537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006538RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006539 NoHandleAllocation ha;
6540 ASSERT(args.length() == 2);
6541
6542 CONVERT_DOUBLE_CHECKED(x, args[0]);
6543 CONVERT_DOUBLE_CHECKED(y, args[1]);
6544 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6545 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6546 if (x == y) return Smi::FromInt(EQUAL);
6547 Object* result;
6548 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6549 result = Smi::FromInt(EQUAL);
6550 } else {
6551 result = Smi::FromInt(NOT_EQUAL);
6552 }
6553 return result;
6554}
6555
6556
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006557RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006558 NoHandleAllocation ha;
6559 ASSERT(args.length() == 2);
6560
6561 CONVERT_CHECKED(String, x, args[0]);
6562 CONVERT_CHECKED(String, y, args[1]);
6563
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006564 bool not_equal = !x->Equals(y);
6565 // This is slightly convoluted because the value that signifies
6566 // equality is 0 and inequality is 1 so we have to negate the result
6567 // from String::Equals.
6568 ASSERT(not_equal == 0 || not_equal == 1);
6569 STATIC_CHECK(EQUAL == 0);
6570 STATIC_CHECK(NOT_EQUAL == 1);
6571 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006572}
6573
6574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006575RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006576 NoHandleAllocation ha;
6577 ASSERT(args.length() == 3);
6578
6579 CONVERT_DOUBLE_CHECKED(x, args[0]);
6580 CONVERT_DOUBLE_CHECKED(y, args[1]);
6581 if (isnan(x) || isnan(y)) return args[2];
6582 if (x == y) return Smi::FromInt(EQUAL);
6583 if (isless(x, y)) return Smi::FromInt(LESS);
6584 return Smi::FromInt(GREATER);
6585}
6586
6587
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006588// Compare two Smis as if they were converted to strings and then
6589// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006590RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006591 NoHandleAllocation ha;
6592 ASSERT(args.length() == 2);
6593
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006594 // Extract the integer values from the Smis.
6595 CONVERT_CHECKED(Smi, x, args[0]);
6596 CONVERT_CHECKED(Smi, y, args[1]);
6597 int x_value = x->value();
6598 int y_value = y->value();
6599
6600 // If the integers are equal so are the string representations.
6601 if (x_value == y_value) return Smi::FromInt(EQUAL);
6602
6603 // If one of the integers are zero the normal integer order is the
6604 // same as the lexicographic order of the string representations.
6605 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6606
ager@chromium.org32912102009-01-16 10:38:43 +00006607 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006608 // smallest because the char code of '-' is less than the char code
6609 // of any digit. Otherwise, we make both values positive.
6610 if (x_value < 0 || y_value < 0) {
6611 if (y_value >= 0) return Smi::FromInt(LESS);
6612 if (x_value >= 0) return Smi::FromInt(GREATER);
6613 x_value = -x_value;
6614 y_value = -y_value;
6615 }
6616
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006617 // Arrays for the individual characters of the two Smis. Smis are
6618 // 31 bit integers and 10 decimal digits are therefore enough.
6619 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6620 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6621 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6622
6623
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006624 // Convert the integers to arrays of their decimal digits.
6625 int x_index = 0;
6626 int y_index = 0;
6627 while (x_value > 0) {
6628 x_elms[x_index++] = x_value % 10;
6629 x_value /= 10;
6630 }
6631 while (y_value > 0) {
6632 y_elms[y_index++] = y_value % 10;
6633 y_value /= 10;
6634 }
6635
6636 // Loop through the arrays of decimal digits finding the first place
6637 // where they differ.
6638 while (--x_index >= 0 && --y_index >= 0) {
6639 int diff = x_elms[x_index] - y_elms[y_index];
6640 if (diff != 0) return Smi::FromInt(diff);
6641 }
6642
6643 // If one array is a suffix of the other array, the longest array is
6644 // the representation of the largest of the Smis in the
6645 // lexicographic ordering.
6646 return Smi::FromInt(x_index - y_index);
6647}
6648
6649
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006650static Object* StringInputBufferCompare(RuntimeState* state,
6651 String* x,
6652 String* y) {
6653 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6654 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006655 bufx.Reset(x);
6656 bufy.Reset(y);
6657 while (bufx.has_more() && bufy.has_more()) {
6658 int d = bufx.GetNext() - bufy.GetNext();
6659 if (d < 0) return Smi::FromInt(LESS);
6660 else if (d > 0) return Smi::FromInt(GREATER);
6661 }
6662
6663 // x is (non-trivial) prefix of y:
6664 if (bufy.has_more()) return Smi::FromInt(LESS);
6665 // y is prefix of x:
6666 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6667}
6668
6669
6670static Object* FlatStringCompare(String* x, String* y) {
6671 ASSERT(x->IsFlat());
6672 ASSERT(y->IsFlat());
6673 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6674 int prefix_length = x->length();
6675 if (y->length() < prefix_length) {
6676 prefix_length = y->length();
6677 equal_prefix_result = Smi::FromInt(GREATER);
6678 } else if (y->length() > prefix_length) {
6679 equal_prefix_result = Smi::FromInt(LESS);
6680 }
6681 int r;
6682 if (x->IsAsciiRepresentation()) {
6683 Vector<const char> x_chars = x->ToAsciiVector();
6684 if (y->IsAsciiRepresentation()) {
6685 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006686 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006687 } else {
6688 Vector<const uc16> y_chars = y->ToUC16Vector();
6689 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6690 }
6691 } else {
6692 Vector<const uc16> x_chars = x->ToUC16Vector();
6693 if (y->IsAsciiRepresentation()) {
6694 Vector<const char> y_chars = y->ToAsciiVector();
6695 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6696 } else {
6697 Vector<const uc16> y_chars = y->ToUC16Vector();
6698 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6699 }
6700 }
6701 Object* result;
6702 if (r == 0) {
6703 result = equal_prefix_result;
6704 } else {
6705 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6706 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006707 ASSERT(result ==
6708 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006709 return result;
6710}
6711
6712
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006713RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006714 NoHandleAllocation ha;
6715 ASSERT(args.length() == 2);
6716
6717 CONVERT_CHECKED(String, x, args[0]);
6718 CONVERT_CHECKED(String, y, args[1]);
6719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006720 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006721
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006722 // A few fast case tests before we flatten.
6723 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006724 if (y->length() == 0) {
6725 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006726 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006727 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 return Smi::FromInt(LESS);
6729 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006730
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006731 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006732 if (d < 0) return Smi::FromInt(LESS);
6733 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006734
lrn@chromium.org303ada72010-10-27 09:33:13 +00006735 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006736 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006737 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6738 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006739 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006740 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6741 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006742
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006743 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006745}
6746
6747
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006748RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006749 NoHandleAllocation ha;
6750 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006751 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006752
6753 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006754 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006755}
6756
6757
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006758RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006759 NoHandleAllocation ha;
6760 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006761 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762
6763 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006764 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006765}
6766
6767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006768RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006769 NoHandleAllocation ha;
6770 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006771 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772
6773 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006774 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006775}
6776
6777
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006778static const double kPiDividedBy4 = 0.78539816339744830962;
6779
6780
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006781RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006782 NoHandleAllocation ha;
6783 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006784 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006785
6786 CONVERT_DOUBLE_CHECKED(x, args[0]);
6787 CONVERT_DOUBLE_CHECKED(y, args[1]);
6788 double result;
6789 if (isinf(x) && isinf(y)) {
6790 // Make sure that the result in case of two infinite arguments
6791 // is a multiple of Pi / 4. The sign of the result is determined
6792 // by the first argument (x) and the sign of the second argument
6793 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794 int multiplier = (x < 0) ? -1 : 1;
6795 if (y < 0) multiplier *= 3;
6796 result = multiplier * kPiDividedBy4;
6797 } else {
6798 result = atan2(x, y);
6799 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006800 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006801}
6802
6803
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006804RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805 NoHandleAllocation ha;
6806 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006807 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808
6809 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006810 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811}
6812
6813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006814RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815 NoHandleAllocation ha;
6816 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006817 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006818
6819 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006820 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006821}
6822
6823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006824RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006825 NoHandleAllocation ha;
6826 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006827 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006828
6829 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006830 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006831}
6832
6833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006834RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006835 NoHandleAllocation ha;
6836 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006837 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006838
6839 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006840 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006841}
6842
6843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006844RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006845 NoHandleAllocation ha;
6846 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006847 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006848
6849 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006850 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006851}
6852
6853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006854RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006855 NoHandleAllocation ha;
6856 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006857 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006858
6859 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006860
6861 // If the second argument is a smi, it is much faster to call the
6862 // custom powi() function than the generic pow().
6863 if (args[1]->IsSmi()) {
6864 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006865 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006866 }
6867
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006868 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006869 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006870}
6871
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006872// Fast version of Math.pow if we know that y is not an integer and
6873// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006874RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006875 NoHandleAllocation ha;
6876 ASSERT(args.length() == 2);
6877 CONVERT_DOUBLE_CHECKED(x, args[0]);
6878 CONVERT_DOUBLE_CHECKED(y, args[1]);
6879 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006880 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006881 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006882 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006883 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006884 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006885 }
6886}
6887
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006889RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006890 NoHandleAllocation ha;
6891 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006892 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006893
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006894 if (!args[0]->IsHeapNumber()) {
6895 // Must be smi. Return the argument unchanged for all the other types
6896 // to make fuzz-natives test happy.
6897 return args[0];
6898 }
6899
6900 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6901
6902 double value = number->value();
6903 int exponent = number->get_exponent();
6904 int sign = number->get_sign();
6905
danno@chromium.org160a7b02011-04-18 15:51:38 +00006906 if (exponent < -1) {
6907 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6908 if (sign) return isolate->heap()->minus_zero_value();
6909 return Smi::FromInt(0);
6910 }
6911
6912 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6913 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6914 // agument holds for 32-bit smis).
6915 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006916 return Smi::FromInt(static_cast<int>(value + 0.5));
6917 }
6918
6919 // If the magnitude is big enough, there's no place for fraction part. If we
6920 // try to add 0.5 to this number, 1.0 will be added instead.
6921 if (exponent >= 52) {
6922 return number;
6923 }
6924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006925 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006926
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006927 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006928 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006929}
6930
6931
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006932RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006933 NoHandleAllocation ha;
6934 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006935 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006936
6937 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006938 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006939}
6940
6941
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006942RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006943 NoHandleAllocation ha;
6944 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006945 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006946
6947 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006948 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006949}
6950
6951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006952RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006953 NoHandleAllocation ha;
6954 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006955 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006956
6957 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006958 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006959}
6960
6961
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006962static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006963 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6964 181, 212, 243, 273, 304, 334};
6965 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6966 182, 213, 244, 274, 305, 335};
6967
6968 year += month / 12;
6969 month %= 12;
6970 if (month < 0) {
6971 year--;
6972 month += 12;
6973 }
6974
6975 ASSERT(month >= 0);
6976 ASSERT(month < 12);
6977
6978 // year_delta is an arbitrary number such that:
6979 // a) year_delta = -1 (mod 400)
6980 // b) year + year_delta > 0 for years in the range defined by
6981 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6982 // Jan 1 1970. This is required so that we don't run into integer
6983 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006984 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006985 // operations.
6986 static const int year_delta = 399999;
6987 static const int base_day = 365 * (1970 + year_delta) +
6988 (1970 + year_delta) / 4 -
6989 (1970 + year_delta) / 100 +
6990 (1970 + year_delta) / 400;
6991
6992 int year1 = year + year_delta;
6993 int day_from_year = 365 * year1 +
6994 year1 / 4 -
6995 year1 / 100 +
6996 year1 / 400 -
6997 base_day;
6998
6999 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007000 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007001 }
7002
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007003 return day_from_year + day_from_month_leap[month] + day - 1;
7004}
7005
7006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007007RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007008 NoHandleAllocation ha;
7009 ASSERT(args.length() == 3);
7010
7011 CONVERT_SMI_CHECKED(year, args[0]);
7012 CONVERT_SMI_CHECKED(month, args[1]);
7013 CONVERT_SMI_CHECKED(date, args[2]);
7014
7015 return Smi::FromInt(MakeDay(year, month, date));
7016}
7017
7018
7019static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7020static const int kDaysIn4Years = 4 * 365 + 1;
7021static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7022static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7023static const int kDays1970to2000 = 30 * 365 + 7;
7024static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7025 kDays1970to2000;
7026static const int kYearsOffset = 400000;
7027
7028static const char kDayInYear[] = {
7029 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7030 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7031 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7032 22, 23, 24, 25, 26, 27, 28,
7033 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7034 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7035 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7036 22, 23, 24, 25, 26, 27, 28, 29, 30,
7037 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7038 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7039 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7040 22, 23, 24, 25, 26, 27, 28, 29, 30,
7041 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7042 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7043 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7044 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7045 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7046 22, 23, 24, 25, 26, 27, 28, 29, 30,
7047 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7048 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7049 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7050 22, 23, 24, 25, 26, 27, 28, 29, 30,
7051 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7052 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7053
7054 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7055 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7056 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7057 22, 23, 24, 25, 26, 27, 28,
7058 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7059 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7060 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7061 22, 23, 24, 25, 26, 27, 28, 29, 30,
7062 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7063 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7064 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7065 22, 23, 24, 25, 26, 27, 28, 29, 30,
7066 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7067 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7068 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7069 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7070 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7071 22, 23, 24, 25, 26, 27, 28, 29, 30,
7072 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7073 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7074 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7075 22, 23, 24, 25, 26, 27, 28, 29, 30,
7076 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7077 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7078
7079 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7080 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7081 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7082 22, 23, 24, 25, 26, 27, 28, 29,
7083 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7084 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7085 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7086 22, 23, 24, 25, 26, 27, 28, 29, 30,
7087 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7088 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7089 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7090 22, 23, 24, 25, 26, 27, 28, 29, 30,
7091 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7092 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7093 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7094 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7095 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7096 22, 23, 24, 25, 26, 27, 28, 29, 30,
7097 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7098 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7099 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7100 22, 23, 24, 25, 26, 27, 28, 29, 30,
7101 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7102 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7103
7104 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7105 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7106 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7107 22, 23, 24, 25, 26, 27, 28,
7108 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7109 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7110 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7111 22, 23, 24, 25, 26, 27, 28, 29, 30,
7112 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7113 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7114 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7115 22, 23, 24, 25, 26, 27, 28, 29, 30,
7116 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7117 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7118 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7119 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7120 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7121 22, 23, 24, 25, 26, 27, 28, 29, 30,
7122 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7123 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7124 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7125 22, 23, 24, 25, 26, 27, 28, 29, 30,
7126 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7127 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7128
7129static const char kMonthInYear[] = {
7130 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,
7131 0, 0, 0, 0, 0, 0,
7132 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,
7133 1, 1, 1,
7134 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,
7135 2, 2, 2, 2, 2, 2,
7136 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,
7137 3, 3, 3, 3, 3,
7138 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,
7139 4, 4, 4, 4, 4, 4,
7140 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,
7141 5, 5, 5, 5, 5,
7142 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,
7143 6, 6, 6, 6, 6, 6,
7144 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,
7145 7, 7, 7, 7, 7, 7,
7146 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,
7147 8, 8, 8, 8, 8,
7148 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,
7149 9, 9, 9, 9, 9, 9,
7150 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7151 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7152 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7153 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7154
7155 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,
7156 0, 0, 0, 0, 0, 0,
7157 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,
7158 1, 1, 1,
7159 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,
7160 2, 2, 2, 2, 2, 2,
7161 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,
7162 3, 3, 3, 3, 3,
7163 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,
7164 4, 4, 4, 4, 4, 4,
7165 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,
7166 5, 5, 5, 5, 5,
7167 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,
7168 6, 6, 6, 6, 6, 6,
7169 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,
7170 7, 7, 7, 7, 7, 7,
7171 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,
7172 8, 8, 8, 8, 8,
7173 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,
7174 9, 9, 9, 9, 9, 9,
7175 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7176 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7177 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7178 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7179
7180 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,
7181 0, 0, 0, 0, 0, 0,
7182 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,
7183 1, 1, 1, 1,
7184 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,
7185 2, 2, 2, 2, 2, 2,
7186 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,
7187 3, 3, 3, 3, 3,
7188 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,
7189 4, 4, 4, 4, 4, 4,
7190 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,
7191 5, 5, 5, 5, 5,
7192 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,
7193 6, 6, 6, 6, 6, 6,
7194 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,
7195 7, 7, 7, 7, 7, 7,
7196 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,
7197 8, 8, 8, 8, 8,
7198 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,
7199 9, 9, 9, 9, 9, 9,
7200 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7201 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7202 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7203 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7204
7205 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,
7206 0, 0, 0, 0, 0, 0,
7207 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,
7208 1, 1, 1,
7209 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,
7210 2, 2, 2, 2, 2, 2,
7211 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,
7212 3, 3, 3, 3, 3,
7213 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,
7214 4, 4, 4, 4, 4, 4,
7215 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,
7216 5, 5, 5, 5, 5,
7217 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,
7218 6, 6, 6, 6, 6, 6,
7219 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,
7220 7, 7, 7, 7, 7, 7,
7221 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,
7222 8, 8, 8, 8, 8,
7223 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,
7224 9, 9, 9, 9, 9, 9,
7225 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7226 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7227 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7228 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7229
7230
7231// This function works for dates from 1970 to 2099.
7232static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007233 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007234#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007235 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007236#endif
7237
7238 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7239 date %= kDaysIn4Years;
7240
7241 month = kMonthInYear[date];
7242 day = kDayInYear[date];
7243
7244 ASSERT(MakeDay(year, month, day) == save_date);
7245}
7246
7247
7248static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007249 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007250#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007251 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007252#endif
7253
7254 date += kDaysOffset;
7255 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7256 date %= kDaysIn400Years;
7257
7258 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7259
7260 date--;
7261 int yd1 = date / kDaysIn100Years;
7262 date %= kDaysIn100Years;
7263 year += 100 * yd1;
7264
7265 date++;
7266 int yd2 = date / kDaysIn4Years;
7267 date %= kDaysIn4Years;
7268 year += 4 * yd2;
7269
7270 date--;
7271 int yd3 = date / 365;
7272 date %= 365;
7273 year += yd3;
7274
7275 bool is_leap = (!yd1 || yd2) && !yd3;
7276
7277 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007278 ASSERT(is_leap || (date >= 0));
7279 ASSERT((date < 365) || (is_leap && (date < 366)));
7280 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7281 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7282 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007283
7284 if (is_leap) {
7285 day = kDayInYear[2*365 + 1 + date];
7286 month = kMonthInYear[2*365 + 1 + date];
7287 } else {
7288 day = kDayInYear[date];
7289 month = kMonthInYear[date];
7290 }
7291
7292 ASSERT(MakeDay(year, month, day) == save_date);
7293}
7294
7295
7296static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007297 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007298 if (date >= 0 && date < 32 * kDaysIn4Years) {
7299 DateYMDFromTimeAfter1970(date, year, month, day);
7300 } else {
7301 DateYMDFromTimeSlow(date, year, month, day);
7302 }
7303}
7304
7305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007306RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007307 NoHandleAllocation ha;
7308 ASSERT(args.length() == 2);
7309
7310 CONVERT_DOUBLE_CHECKED(t, args[0]);
7311 CONVERT_CHECKED(JSArray, res_array, args[1]);
7312
7313 int year, month, day;
7314 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007316 RUNTIME_ASSERT(res_array->elements()->map() ==
7317 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007318 FixedArray* elms = FixedArray::cast(res_array->elements());
7319 RUNTIME_ASSERT(elms->length() == 3);
7320
7321 elms->set(0, Smi::FromInt(year));
7322 elms->set(1, Smi::FromInt(month));
7323 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007325 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007326}
7327
7328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007329RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007330 NoHandleAllocation ha;
7331 ASSERT(args.length() == 3);
7332
7333 JSFunction* callee = JSFunction::cast(args[0]);
7334 Object** parameters = reinterpret_cast<Object**>(args[1]);
7335 const int length = Smi::cast(args[2])->value();
7336
lrn@chromium.org303ada72010-10-27 09:33:13 +00007337 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007338 { MaybeObject* maybe_result =
7339 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007340 if (!maybe_result->ToObject(&result)) return maybe_result;
7341 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007342 // Allocate the elements if needed.
7343 if (length > 0) {
7344 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007345 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007347 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7348 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007349
7350 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007351 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007352 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007353 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007354
7355 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007356 for (int i = 0; i < length; i++) {
7357 array->set(i, *--parameters, mode);
7358 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007359 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007360 }
7361 return result;
7362}
7363
7364
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007365RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007367 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007368 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007369 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007370 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007372 // Allocate global closures in old space and allocate local closures
7373 // in new space. Additionally pretenure closures that are assigned
7374 // directly to properties.
7375 pretenure = pretenure || (context->global_context() == *context);
7376 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007378 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7379 context,
7380 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381 return *result;
7382}
7383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007384
7385static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7386 int* total_argc) {
7387 // Find frame containing arguments passed to the caller.
7388 JavaScriptFrameIterator it;
7389 JavaScriptFrame* frame = it.frame();
7390 List<JSFunction*> functions(2);
7391 frame->GetFunctions(&functions);
7392 if (functions.length() > 1) {
7393 int inlined_frame_index = functions.length() - 1;
7394 JSFunction* inlined_function = functions[inlined_frame_index];
7395 int args_count = inlined_function->shared()->formal_parameter_count();
7396 ScopedVector<SlotRef> args_slots(args_count);
7397 SlotRef::ComputeSlotMappingForArguments(frame,
7398 inlined_frame_index,
7399 &args_slots);
7400
7401 *total_argc = bound_argc + args_count;
7402 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7403 for (int i = 0; i < args_count; i++) {
7404 Handle<Object> val = args_slots[i].GetValue();
7405 param_data[bound_argc + i] = val.location();
7406 }
7407 return param_data;
7408 } else {
7409 it.AdvanceToArgumentsFrame();
7410 frame = it.frame();
7411 int args_count = frame->ComputeParametersCount();
7412
7413 *total_argc = bound_argc + args_count;
7414 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7415 for (int i = 0; i < args_count; i++) {
7416 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7417 param_data[bound_argc + i] = val.location();
7418 }
7419 return param_data;
7420 }
7421}
7422
7423
7424RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007425 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007426 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007427 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007428 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007429
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007430 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007431 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007432 int bound_argc = 0;
7433 if (!args[1]->IsNull()) {
7434 CONVERT_ARG_CHECKED(JSArray, params, 1);
7435 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007436 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007437 bound_argc = Smi::cast(params->length())->value();
7438 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007440 int total_argc = 0;
7441 SmartPointer<Object**> param_data =
7442 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007443 for (int i = 0; i < bound_argc; i++) {
7444 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007445 param_data[i] = val.location();
7446 }
7447
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007448 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007449 Handle<Object> result =
7450 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007451 if (exception) {
7452 return Failure::Exception();
7453 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007454
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007455 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007456 return *result;
7457}
7458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007459
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007460static void TrySettingInlineConstructStub(Isolate* isolate,
7461 Handle<JSFunction> function) {
7462 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007463 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007464 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007465 }
7466 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007467 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007468 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007469 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007470 function->shared()->set_construct_stub(
7471 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007472 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007473 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007474}
7475
7476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007477RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007478 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007479 ASSERT(args.length() == 1);
7480
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007481 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007482
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007483 // If the constructor isn't a proper function we throw a type error.
7484 if (!constructor->IsJSFunction()) {
7485 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7486 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007487 isolate->factory()->NewTypeError("not_constructor", arguments);
7488 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007489 }
7490
7491 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007492
7493 // If function should not have prototype, construction is not allowed. In this
7494 // case generated code bailouts here, since function has no initial_map.
7495 if (!function->should_have_prototype()) {
7496 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7497 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007498 isolate->factory()->NewTypeError("not_constructor", arguments);
7499 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007500 }
7501
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007502#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007503 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007504 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007505 if (debug->StepInActive()) {
7506 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007507 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007508#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007509
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007510 if (function->has_initial_map()) {
7511 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007512 // The 'Function' function ignores the receiver object when
7513 // called using 'new' and creates a new JSFunction object that
7514 // is returned. The receiver object is only used for error
7515 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007516 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007517 // allocate JSFunctions since it does not properly initialize
7518 // the shared part of the function. Since the receiver is
7519 // ignored anyway, we use the global object as the receiver
7520 // instead of a new JSFunction object. This way, errors are
7521 // reported the same way whether or not 'Function' is called
7522 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007523 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007524 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525 }
7526
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007527 // The function should be compiled for the optimization hints to be
7528 // available. We cannot use EnsureCompiled because that forces a
7529 // compilation through the shared function info which makes it
7530 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007531 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007532 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007533
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007534 if (!function->has_initial_map() &&
7535 shared->IsInobjectSlackTrackingInProgress()) {
7536 // The tracking is already in progress for another function. We can only
7537 // track one initial_map at a time, so we force the completion before the
7538 // function is called as a constructor for the first time.
7539 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007540 }
7541
7542 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007543 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7544 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007545 // Delay setting the stub if inobject slack tracking is in progress.
7546 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007547 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007548 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007549
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007550 isolate->counters()->constructed_objects()->Increment();
7551 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007552
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007553 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007554}
7555
7556
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007557RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007558 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007559 ASSERT(args.length() == 1);
7560
7561 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7562 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007563 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007564
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007565 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007566}
7567
7568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007569RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007570 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007571 ASSERT(args.length() == 1);
7572
7573 Handle<JSFunction> function = args.at<JSFunction>(0);
7574#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007575 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007576 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007577 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007578 PrintF("]\n");
7579 }
7580#endif
7581
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007582 // Compile the target function. Here we compile using CompileLazyInLoop in
7583 // order to get the optimized version. This helps code like delta-blue
7584 // that calls performance-critical routines through constructors. A
7585 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7586 // direct call. Since the in-loop tracking takes place through CallICs
7587 // this means that things called through constructors are never known to
7588 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007589 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007590 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007591 return Failure::Exception();
7592 }
7593
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007594 // All done. Return the compiled code.
7595 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007596 return function->code();
7597}
7598
7599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007600RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007601 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007602 ASSERT(args.length() == 1);
7603 Handle<JSFunction> function = args.at<JSFunction>(0);
7604 // If the function is not optimizable or debugger is active continue using the
7605 // code from the full compiler.
7606 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007607 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007608 if (FLAG_trace_opt) {
7609 PrintF("[failed to optimize ");
7610 function->PrintName();
7611 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7612 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007613 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007614 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007615 function->ReplaceCode(function->shared()->code());
7616 return function->code();
7617 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007618 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007619 return function->code();
7620 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007621 if (FLAG_trace_opt) {
7622 PrintF("[failed to optimize ");
7623 function->PrintName();
7624 PrintF(": optimized compilation failed]\n");
7625 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007626 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007627 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007628}
7629
7630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007631RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007632 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007633 ASSERT(args.length() == 1);
7634 RUNTIME_ASSERT(args[0]->IsSmi());
7635 Deoptimizer::BailoutType type =
7636 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007637 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7638 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007639 int frames = deoptimizer->output_count();
7640
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007641 deoptimizer->MaterializeHeapNumbers();
7642 delete deoptimizer;
7643
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007644 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007645 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007646 for (int i = 0; i < frames - 1; i++) it.Advance();
7647 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007648
7649 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007650 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007651 Handle<Object> arguments;
7652 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007653 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007654 if (arguments.is_null()) {
7655 // FunctionGetArguments can't throw an exception, so cast away the
7656 // doubt with an assert.
7657 arguments = Handle<Object>(
7658 Accessors::FunctionGetArguments(*function,
7659 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007660 ASSERT(*arguments != isolate->heap()->null_value());
7661 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007662 }
7663 frame->SetExpression(i, *arguments);
7664 }
7665 }
7666
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007667 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007668 if (type == Deoptimizer::EAGER) {
7669 RUNTIME_ASSERT(function->IsOptimized());
7670 } else {
7671 RUNTIME_ASSERT(!function->IsOptimized());
7672 }
7673
7674 // Avoid doing too much work when running with --always-opt and keep
7675 // the optimized code around.
7676 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007677 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007678 }
7679
7680 // Count the number of optimized activations of the function.
7681 int activations = 0;
7682 while (!it.done()) {
7683 JavaScriptFrame* frame = it.frame();
7684 if (frame->is_optimized() && frame->function() == *function) {
7685 activations++;
7686 }
7687 it.Advance();
7688 }
7689
7690 // TODO(kasperl): For now, we cannot support removing the optimized
7691 // code when we have recursive invocations of the same function.
7692 if (activations == 0) {
7693 if (FLAG_trace_deopt) {
7694 PrintF("[removing optimized code for: ");
7695 function->PrintName();
7696 PrintF("]\n");
7697 }
7698 function->ReplaceCode(function->shared()->code());
7699 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007700 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007701}
7702
7703
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007704RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007705 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007706 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007707 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007708}
7709
7710
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007711RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007712 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007713 ASSERT(args.length() == 1);
7714 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007715 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007716
7717 Deoptimizer::DeoptimizeFunction(*function);
7718
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007719 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007720}
7721
7722
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007723RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7724 HandleScope scope(isolate);
7725 ASSERT(args.length() == 1);
7726 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7727 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7728 function->MarkForLazyRecompilation();
7729 return isolate->heap()->undefined_value();
7730}
7731
7732
lrn@chromium.org1c092762011-05-09 09:42:16 +00007733RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7734 HandleScope scope(isolate);
7735 ASSERT(args.length() == 1);
7736 if (!V8::UseCrankshaft()) {
7737 return Smi::FromInt(4); // 4 == "never".
7738 }
7739 if (FLAG_always_opt) {
7740 return Smi::FromInt(3); // 3 == "always".
7741 }
7742 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7743 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7744 : Smi::FromInt(2); // 2 == "no".
7745}
7746
7747
7748RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7749 HandleScope scope(isolate);
7750 ASSERT(args.length() == 1);
7751 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7752 return Smi::FromInt(function->shared()->opt_count());
7753}
7754
7755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007756RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007757 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007758 ASSERT(args.length() == 1);
7759 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7760
7761 // We're not prepared to handle a function with arguments object.
7762 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7763
7764 // We have hit a back edge in an unoptimized frame for a function that was
7765 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007766 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007767 // Keep track of whether we've succeeded in optimizing.
7768 bool succeeded = unoptimized->optimizable();
7769 if (succeeded) {
7770 // If we are trying to do OSR when there are already optimized
7771 // activations of the function, it means (a) the function is directly or
7772 // indirectly recursive and (b) an optimized invocation has been
7773 // deoptimized so that we are currently in an unoptimized activation.
7774 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007775 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007776 while (succeeded && !it.done()) {
7777 JavaScriptFrame* frame = it.frame();
7778 succeeded = !frame->is_optimized() || frame->function() != *function;
7779 it.Advance();
7780 }
7781 }
7782
7783 int ast_id = AstNode::kNoNumber;
7784 if (succeeded) {
7785 // The top JS function is this one, the PC is somewhere in the
7786 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007787 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007788 JavaScriptFrame* frame = it.frame();
7789 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007790 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007791 ASSERT(unoptimized->contains(frame->pc()));
7792
7793 // Use linear search of the unoptimized code's stack check table to find
7794 // the AST id matching the PC.
7795 Address start = unoptimized->instruction_start();
7796 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007797 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007798 uint32_t table_length = Memory::uint32_at(table_cursor);
7799 table_cursor += kIntSize;
7800 for (unsigned i = 0; i < table_length; ++i) {
7801 // Table entries are (AST id, pc offset) pairs.
7802 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7803 if (pc_offset == target_pc_offset) {
7804 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7805 break;
7806 }
7807 table_cursor += 2 * kIntSize;
7808 }
7809 ASSERT(ast_id != AstNode::kNoNumber);
7810 if (FLAG_trace_osr) {
7811 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7812 function->PrintName();
7813 PrintF("]\n");
7814 }
7815
7816 // Try to compile the optimized code. A true return value from
7817 // CompileOptimized means that compilation succeeded, not necessarily
7818 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007819 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7820 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007821 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7822 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007823 if (data->OsrPcOffset()->value() >= 0) {
7824 if (FLAG_trace_osr) {
7825 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007826 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007827 }
7828 ASSERT(data->OsrAstId()->value() == ast_id);
7829 } else {
7830 // We may never generate the desired OSR entry if we emit an
7831 // early deoptimize.
7832 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007833 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007834 } else {
7835 succeeded = false;
7836 }
7837 }
7838
7839 // Revert to the original stack checks in the original unoptimized code.
7840 if (FLAG_trace_osr) {
7841 PrintF("[restoring original stack checks in ");
7842 function->PrintName();
7843 PrintF("]\n");
7844 }
7845 StackCheckStub check_stub;
7846 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007847 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007848 Deoptimizer::RevertStackCheckCode(*unoptimized,
7849 *check_code,
7850 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007851
7852 // Allow OSR only at nesting level zero again.
7853 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7854
7855 // If the optimization attempt succeeded, return the AST id tagged as a
7856 // smi. This tells the builtin that we need to translate the unoptimized
7857 // frame to an optimized one.
7858 if (succeeded) {
7859 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7860 return Smi::FromInt(ast_id);
7861 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007862 if (function->IsMarkedForLazyRecompilation()) {
7863 function->ReplaceCode(function->shared()->code());
7864 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007865 return Smi::FromInt(-1);
7866 }
7867}
7868
7869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007870RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007871 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007872 ASSERT(args.length() == 1);
7873 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7874 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7875}
7876
7877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007878RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007879 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007880 ASSERT(args.length() == 1);
7881 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7882 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7883}
7884
7885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007886RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007887 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007888 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007889
kasper.lund7276f142008-07-30 08:49:36 +00007890 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007891 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007892 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007893 { MaybeObject* maybe_result =
7894 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007895 if (!maybe_result->ToObject(&result)) return maybe_result;
7896 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007897
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007898 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007899
kasper.lund7276f142008-07-30 08:49:36 +00007900 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007901}
7902
lrn@chromium.org303ada72010-10-27 09:33:13 +00007903
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007904MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7905 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007906 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007907 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007908 Object* js_object = object;
7909 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007910 MaybeObject* maybe_js_object = js_object->ToObject();
7911 if (!maybe_js_object->ToObject(&js_object)) {
7912 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7913 return maybe_js_object;
7914 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007915 HandleScope scope(isolate);
7916 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007917 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007918 isolate->factory()->NewTypeError("with_expression",
7919 HandleVector(&handle, 1));
7920 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007921 }
7922 }
7923
lrn@chromium.org303ada72010-10-27 09:33:13 +00007924 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007925 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7926 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007927 if (!maybe_result->ToObject(&result)) return maybe_result;
7928 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007929
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007930 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007931 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007932
kasper.lund7276f142008-07-30 08:49:36 +00007933 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007934}
7935
7936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007937RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007938 NoHandleAllocation ha;
7939 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007940 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007941}
7942
7943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007944RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007945 NoHandleAllocation ha;
7946 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007947 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007948}
7949
7950
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007951RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007952 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007953 ASSERT(args.length() == 2);
7954
7955 CONVERT_ARG_CHECKED(Context, context, 0);
7956 CONVERT_ARG_CHECKED(String, name, 1);
7957
7958 int index;
7959 PropertyAttributes attributes;
7960 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007961 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007962
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007963 // If the slot was not found the result is true.
7964 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007965 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007966 }
7967
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007968 // If the slot was found in a context, it should be DONT_DELETE.
7969 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007970 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007971 }
7972
7973 // The slot was found in a JSObject, either a context extension object,
7974 // the global object, or an arguments object. Try to delete it
7975 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7976 // which allows deleting all parameters in functions that mention
7977 // 'arguments', we do this even for the case of slots found on an
7978 // arguments object. The slot was found on an arguments object if the
7979 // index is non-negative.
7980 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7981 if (index >= 0) {
7982 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7983 } else {
7984 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7985 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007986}
7987
7988
ager@chromium.orga1645e22009-09-09 19:27:10 +00007989// A mechanism to return a pair of Object pointers in registers (if possible).
7990// How this is achieved is calling convention-dependent.
7991// All currently supported x86 compiles uses calling conventions that are cdecl
7992// variants where a 64-bit value is returned in two 32-bit registers
7993// (edx:eax on ia32, r1:r0 on ARM).
7994// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7995// In Win64 calling convention, a struct of two pointers is returned in memory,
7996// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007997#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007998struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007999 MaybeObject* x;
8000 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008001};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008002
lrn@chromium.org303ada72010-10-27 09:33:13 +00008003static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008004 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008005 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8006 // In Win64 they are assigned to a hidden first argument.
8007 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008008}
8009#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008010typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008011static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008012 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008013 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008014}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008015#endif
8016
8017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008018static inline MaybeObject* Unhole(Heap* heap,
8019 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008020 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008021 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8022 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008023 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008024}
8025
8026
danno@chromium.org40cb8782011-05-25 07:58:50 +00008027static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8028 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008029 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008030 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008031 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008032 JSFunction* context_extension_function =
8033 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008034 // If the holder isn't a context extension object, we just return it
8035 // as the receiver. This allows arguments objects to be used as
8036 // receivers, but only if they are put in the context scope chain
8037 // explicitly via a with-statement.
8038 Object* constructor = holder->map()->constructor();
8039 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008040 // Fall back to using the global object as the implicit receiver if
8041 // the property turns out to be a local variable allocated in a
8042 // context extension object - introduced via eval. Implicit global
8043 // receivers are indicated with the hole value.
8044 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008045}
8046
8047
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008048static ObjectPair LoadContextSlotHelper(Arguments args,
8049 Isolate* isolate,
8050 bool throw_error) {
8051 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008052 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008053
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008054 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008055 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008056 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008057 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008058 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008059
8060 int index;
8061 PropertyAttributes attributes;
8062 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008063 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008064
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008065 // If the index is non-negative, the slot has been found in a local
8066 // variable or a parameter. Read it from the context object or the
8067 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008068 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008069 // If the "property" we were looking for is a local variable or an
8070 // argument in a context, the receiver is the global object; see
8071 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008072 //
8073 // Use the hole as the receiver to signal that the receiver is
8074 // implicit and that the global receiver should be used.
8075 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008076 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008077 ? Context::cast(*holder)->get(index)
8078 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008079 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008080 }
8081
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008082 // If the holder is found, we read the property from it.
8083 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008084 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008085 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008086 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008087 if (object->IsGlobalObject()) {
8088 receiver = GlobalObject::cast(object)->global_receiver();
8089 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008090 // Use the hole as the receiver to signal that the receiver is
8091 // implicit and that the global receiver should be used.
8092 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008093 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008094 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008095 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008096
8097 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008098 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008099
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008100 // No need to unhole the value here. This is taken care of by the
8101 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008102 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008103 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008104 }
8105
8106 if (throw_error) {
8107 // The property doesn't exist - throw exception.
8108 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008109 isolate->factory()->NewReferenceError("not_defined",
8110 HandleVector(&name, 1));
8111 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008112 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008113 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008114 return MakePair(isolate->heap()->undefined_value(),
8115 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008116 }
8117}
8118
8119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008120RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008121 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008122}
8123
8124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008125RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008126 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008127}
8128
8129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008130RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008131 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008132 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008133
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008134 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008135 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008136 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008137 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
8138 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8139 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008140 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008141
8142 int index;
8143 PropertyAttributes attributes;
8144 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008145 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008146
8147 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008148 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008149 // Ignore if read_only variable.
8150 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008151 // Context is a fixed array and set cannot fail.
8152 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008153 } else if (strict_mode == kStrictMode) {
8154 // Setting read only property in strict mode.
8155 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008156 isolate->factory()->NewTypeError("strict_cannot_assign",
8157 HandleVector(&name, 1));
8158 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008159 }
8160 } else {
8161 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008162 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008163 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008164 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008165 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008166 return Failure::Exception();
8167 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008168 }
8169 return *value;
8170 }
8171
8172 // Slow case: The property is not in a FixedArray context.
8173 // It is either in an JSObject extension context or it was not found.
8174 Handle<JSObject> context_ext;
8175
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008176 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008177 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008178 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008179 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008180 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008181 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008182
8183 if (strict_mode == kStrictMode) {
8184 // Throw in strict mode (assignment to undefined variable).
8185 Handle<Object> error =
8186 isolate->factory()->NewReferenceError(
8187 "not_defined", HandleVector(&name, 1));
8188 return isolate->Throw(*error);
8189 }
8190 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008191 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008192 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008193 }
8194
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008195 // Set the property, but ignore if read_only variable on the context
8196 // extension object itself.
8197 if ((attributes & READ_ONLY) == 0 ||
8198 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008199 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008200 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008201 SetProperty(context_ext, name, value, NONE, strict_mode));
8202 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008203 // Setting read only property in strict mode.
8204 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008205 isolate->factory()->NewTypeError(
8206 "strict_cannot_assign", HandleVector(&name, 1));
8207 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008208 }
8209 return *value;
8210}
8211
8212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008213RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008214 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008215 ASSERT(args.length() == 1);
8216
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008217 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008218}
8219
8220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008221RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008222 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008223 ASSERT(args.length() == 1);
8224
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008225 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008226}
8227
8228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008229RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008230 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008231 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008232}
8233
8234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008235RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008236 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008237 ASSERT(args.length() == 1);
8238
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008239 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008240 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008241 isolate->factory()->NewReferenceError("not_defined",
8242 HandleVector(&name, 1));
8243 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008244}
8245
8246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008247RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008248 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008249
8250 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008251 if (isolate->stack_guard()->IsStackOverflow()) {
8252 NoHandleAllocation na;
8253 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008254 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008255
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008256 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008257}
8258
8259
8260// NOTE: These PrintXXX functions are defined for all builds (not just
8261// DEBUG builds) because we may want to be able to trace function
8262// calls in all modes.
8263static void PrintString(String* str) {
8264 // not uncommon to have empty strings
8265 if (str->length() > 0) {
8266 SmartPointer<char> s =
8267 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8268 PrintF("%s", *s);
8269 }
8270}
8271
8272
8273static void PrintObject(Object* obj) {
8274 if (obj->IsSmi()) {
8275 PrintF("%d", Smi::cast(obj)->value());
8276 } else if (obj->IsString() || obj->IsSymbol()) {
8277 PrintString(String::cast(obj));
8278 } else if (obj->IsNumber()) {
8279 PrintF("%g", obj->Number());
8280 } else if (obj->IsFailure()) {
8281 PrintF("<failure>");
8282 } else if (obj->IsUndefined()) {
8283 PrintF("<undefined>");
8284 } else if (obj->IsNull()) {
8285 PrintF("<null>");
8286 } else if (obj->IsTrue()) {
8287 PrintF("<true>");
8288 } else if (obj->IsFalse()) {
8289 PrintF("<false>");
8290 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008291 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008292 }
8293}
8294
8295
8296static int StackSize() {
8297 int n = 0;
8298 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8299 return n;
8300}
8301
8302
8303static void PrintTransition(Object* result) {
8304 // indentation
8305 { const int nmax = 80;
8306 int n = StackSize();
8307 if (n <= nmax)
8308 PrintF("%4d:%*s", n, n, "");
8309 else
8310 PrintF("%4d:%*s", n, nmax, "...");
8311 }
8312
8313 if (result == NULL) {
8314 // constructor calls
8315 JavaScriptFrameIterator it;
8316 JavaScriptFrame* frame = it.frame();
8317 if (frame->IsConstructor()) PrintF("new ");
8318 // function name
8319 Object* fun = frame->function();
8320 if (fun->IsJSFunction()) {
8321 PrintObject(JSFunction::cast(fun)->shared()->name());
8322 } else {
8323 PrintObject(fun);
8324 }
8325 // function arguments
8326 // (we are intentionally only printing the actually
8327 // supplied parameters, not all parameters required)
8328 PrintF("(this=");
8329 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008330 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008331 for (int i = 0; i < length; i++) {
8332 PrintF(", ");
8333 PrintObject(frame->GetParameter(i));
8334 }
8335 PrintF(") {\n");
8336
8337 } else {
8338 // function result
8339 PrintF("} -> ");
8340 PrintObject(result);
8341 PrintF("\n");
8342 }
8343}
8344
8345
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008346RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008347 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008348 NoHandleAllocation ha;
8349 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008350 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008351}
8352
8353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008354RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008355 NoHandleAllocation ha;
8356 PrintTransition(args[0]);
8357 return args[0]; // return TOS
8358}
8359
8360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008361RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008362 NoHandleAllocation ha;
8363 ASSERT(args.length() == 1);
8364
8365#ifdef DEBUG
8366 if (args[0]->IsString()) {
8367 // If we have a string, assume it's a code "marker"
8368 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008369 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008370 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008371 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8372 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008373 } else {
8374 PrintF("DebugPrint: ");
8375 }
8376 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008377 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008378 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008379 HeapObject::cast(args[0])->map()->Print();
8380 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008381#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008382 // ShortPrint is available in release mode. Print is not.
8383 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008384#endif
8385 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008386 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008387
8388 return args[0]; // return TOS
8389}
8390
8391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008392RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008393 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008394 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008395 isolate->PrintStack();
8396 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008397}
8398
8399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008400RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008402 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008403
8404 // According to ECMA-262, section 15.9.1, page 117, the precision of
8405 // the number in a Date object representing a particular instant in
8406 // time is milliseconds. Therefore, we floor the result of getting
8407 // the OS time.
8408 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008409 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008410}
8411
8412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008413RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008414 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008415 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008416
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008417 CONVERT_ARG_CHECKED(String, str, 0);
8418 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008419
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008420 CONVERT_ARG_CHECKED(JSArray, output, 1);
8421 RUNTIME_ASSERT(output->HasFastElements());
8422
8423 AssertNoAllocation no_allocation;
8424
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008425 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008426 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8427 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008428 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008429 result = DateParser::Parse(str->ToAsciiVector(),
8430 output_array,
8431 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008432 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008433 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008434 result = DateParser::Parse(str->ToUC16Vector(),
8435 output_array,
8436 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008437 }
8438
8439 if (result) {
8440 return *output;
8441 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008442 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008443 }
8444}
8445
8446
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008447RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008448 NoHandleAllocation ha;
8449 ASSERT(args.length() == 1);
8450
8451 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008452 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008453 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008454}
8455
8456
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008457RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008458 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008459 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008460
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008461 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008462}
8463
8464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008465RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008466 NoHandleAllocation ha;
8467 ASSERT(args.length() == 1);
8468
8469 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008470 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008471}
8472
8473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008474RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008475 ASSERT(args.length() == 1);
8476 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008477 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008478 return JSGlobalObject::cast(global)->global_receiver();
8479}
8480
8481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008482RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008483 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008484 ASSERT_EQ(1, args.length());
8485 CONVERT_ARG_CHECKED(String, source, 0);
8486
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008487 source = Handle<String>(source->TryFlattenGetString());
8488 // Optimized fast case where we only have ascii characters.
8489 Handle<Object> result;
8490 if (source->IsSeqAsciiString()) {
8491 result = JsonParser<true>::Parse(source);
8492 } else {
8493 result = JsonParser<false>::Parse(source);
8494 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008495 if (result.is_null()) {
8496 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008497 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008498 return Failure::Exception();
8499 }
8500 return *result;
8501}
8502
8503
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008504bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8505 Handle<Context> context) {
8506 if (context->allow_code_gen_from_strings()->IsFalse()) {
8507 // Check with callback if set.
8508 AllowCodeGenerationFromStringsCallback callback =
8509 isolate->allow_code_gen_callback();
8510 if (callback == NULL) {
8511 // No callback set and code generation disallowed.
8512 return false;
8513 } else {
8514 // Callback set. Let it decide if code generation is allowed.
8515 VMState state(isolate, EXTERNAL);
8516 return callback(v8::Utils::ToLocal(context));
8517 }
8518 }
8519 return true;
8520}
8521
8522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008523RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008524 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008525 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008526 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008527
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008528 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008529 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008530
8531 // Check if global context allows code generation from
8532 // strings. Throw an exception if it doesn't.
8533 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8534 return isolate->Throw(*isolate->factory()->NewError(
8535 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8536 }
8537
8538 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008539 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8540 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008541 true,
8542 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008543 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008544 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008545 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8546 context,
8547 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008548 return *fun;
8549}
8550
8551
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008552static ObjectPair CompileGlobalEval(Isolate* isolate,
8553 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008554 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008555 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008556 Handle<Context> context = Handle<Context>(isolate->context());
8557 Handle<Context> global_context = Handle<Context>(context->global_context());
8558
8559 // Check if global context allows code generation from
8560 // strings. Throw an exception if it doesn't.
8561 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8562 isolate->Throw(*isolate->factory()->NewError(
8563 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8564 return MakePair(Failure::Exception(), NULL);
8565 }
8566
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008567 // Deal with a normal eval call with a string argument. Compile it
8568 // and return the compiled function bound in the local context.
8569 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8570 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008571 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008572 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008573 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008574 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008575 Handle<JSFunction> compiled =
8576 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008577 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008578 return MakePair(*compiled, *receiver);
8579}
8580
8581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008582RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008583 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008584
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008585 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008586 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008587 Handle<Object> receiver; // Will be overwritten.
8588
8589 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008590 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008591#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008592 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008593 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008594 StackFrameLocator locator;
8595 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008596 ASSERT(Context::cast(frame->context()) == *context);
8597#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008598
8599 // Find where the 'eval' symbol is bound. It is unaliased only if
8600 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008601 int index = -1;
8602 PropertyAttributes attributes = ABSENT;
8603 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008604 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8605 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008606 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008607 // Stop search when eval is found or when the global context is
8608 // reached.
8609 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008610 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008611 context = Handle<Context>(Context::cast(context->closure()->context()),
8612 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008613 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008614 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008615 }
8616 }
8617
iposva@chromium.org245aa852009-02-10 00:49:54 +00008618 // If eval could not be resolved, it has been deleted and we need to
8619 // throw a reference error.
8620 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008621 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008622 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008623 isolate->factory()->NewReferenceError("not_defined",
8624 HandleVector(&name, 1));
8625 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008626 }
8627
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008628 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008629 // 'eval' is not bound in the global context. Just call the function
8630 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008631 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008632 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008633 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008634 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008635 }
8636
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008637 // 'eval' is bound in the global context, but it may have been overwritten.
8638 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008639 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008640 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008641 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008642 }
8643
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008644 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008645 return CompileGlobalEval(isolate,
8646 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008647 args.at<Object>(2),
8648 static_cast<StrictModeFlag>(
8649 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008650}
8651
8652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008653RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008654 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008655
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008656 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008657 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008658
8659 // 'eval' is bound in the global context, but it may have been overwritten.
8660 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008661 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008662 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008663 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008664 }
8665
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008666 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008667 return CompileGlobalEval(isolate,
8668 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008669 args.at<Object>(2),
8670 static_cast<StrictModeFlag>(
8671 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008672}
8673
8674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008675RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008676 // This utility adjusts the property attributes for newly created Function
8677 // object ("new Function(...)") by changing the map.
8678 // All it does is changing the prototype property to enumerable
8679 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008680 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008681 ASSERT(args.length() == 1);
8682 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008683
8684 Handle<Map> map = func->shared()->strict_mode()
8685 ? isolate->strict_mode_function_instance_map()
8686 : isolate->function_instance_map();
8687
8688 ASSERT(func->map()->instance_type() == map->instance_type());
8689 ASSERT(func->map()->instance_size() == map->instance_size());
8690 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008691 return *func;
8692}
8693
8694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008695RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008696 // Allocate a block of memory in NewSpace (filled with a filler).
8697 // Use as fallback for allocation in generated code when NewSpace
8698 // is full.
8699 ASSERT(args.length() == 1);
8700 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8701 int size = size_smi->value();
8702 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8703 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008704 Heap* heap = isolate->heap();
8705 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008706 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008707 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008708 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008709 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008710 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008711 }
8712 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008713 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008714}
8715
8716
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008717// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008718// array. Returns true if the element was pushed on the stack and
8719// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008720RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008721 ASSERT(args.length() == 2);
8722 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008723 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008724 RUNTIME_ASSERT(array->HasFastElements());
8725 int length = Smi::cast(array->length())->value();
8726 FixedArray* elements = FixedArray::cast(array->elements());
8727 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008728 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008729 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008730 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008731 // Strict not needed. Used for cycle detection in Array join implementation.
8732 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8733 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008734 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8735 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008736 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008737}
8738
8739
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008740/**
8741 * A simple visitor visits every element of Array's.
8742 * The backend storage can be a fixed array for fast elements case,
8743 * or a dictionary for sparse array. Since Dictionary is a subtype
8744 * of FixedArray, the class can be used by both fast and slow cases.
8745 * The second parameter of the constructor, fast_elements, specifies
8746 * whether the storage is a FixedArray or Dictionary.
8747 *
8748 * An index limit is used to deal with the situation that a result array
8749 * length overflows 32-bit non-negative integer.
8750 */
8751class ArrayConcatVisitor {
8752 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008753 ArrayConcatVisitor(Isolate* isolate,
8754 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008755 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008756 isolate_(isolate),
8757 storage_(Handle<FixedArray>::cast(
8758 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008759 index_offset_(0u),
8760 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008761
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008762 ~ArrayConcatVisitor() {
8763 clear_storage();
8764 }
8765
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008766 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008767 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008768 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008769
8770 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008771 if (index < static_cast<uint32_t>(storage_->length())) {
8772 storage_->set(index, *elm);
8773 return;
8774 }
8775 // Our initial estimate of length was foiled, possibly by
8776 // getters on the arrays increasing the length of later arrays
8777 // during iteration.
8778 // This shouldn't happen in anything but pathological cases.
8779 SetDictionaryMode(index);
8780 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008781 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008782 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008783 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008784 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008785 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008786 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008787 // Dictionary needed to grow.
8788 clear_storage();
8789 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008790 }
8791}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008792
8793 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008794 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8795 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008796 } else {
8797 index_offset_ += delta;
8798 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008799 }
8800
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008801 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008802 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008803 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008804 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008805 Handle<Map> map;
8806 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008807 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008808 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008809 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008810 }
8811 array->set_map(*map);
8812 array->set_length(*length);
8813 array->set_elements(*storage_);
8814 return array;
8815 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008816
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008817 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008818 // Convert storage to dictionary mode.
8819 void SetDictionaryMode(uint32_t index) {
8820 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008821 Handle<FixedArray> current_storage(*storage_);
8822 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008823 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008824 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8825 for (uint32_t i = 0; i < current_length; i++) {
8826 HandleScope loop_scope;
8827 Handle<Object> element(current_storage->get(i));
8828 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008829 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008830 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008831 if (!new_storage.is_identical_to(slow_storage)) {
8832 slow_storage = loop_scope.CloseAndEscape(new_storage);
8833 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008834 }
8835 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008836 clear_storage();
8837 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008838 fast_elements_ = false;
8839 }
8840
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008841 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008842 isolate_->global_handles()->Destroy(
8843 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008844 }
8845
8846 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008847 storage_ = Handle<FixedArray>::cast(
8848 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008849 }
8850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008851 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008852 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008853 // Index after last seen index. Always less than or equal to
8854 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008855 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008856 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008857};
8858
8859
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008860static uint32_t EstimateElementCount(Handle<JSArray> array) {
8861 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8862 int element_count = 0;
8863 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008864 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008865 // Fast elements can't have lengths that are not representable by
8866 // a 32-bit signed integer.
8867 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8868 int fast_length = static_cast<int>(length);
8869 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8870 for (int i = 0; i < fast_length; i++) {
8871 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008872 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008873 break;
8874 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008875 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008876 Handle<NumberDictionary> dictionary(
8877 NumberDictionary::cast(array->elements()));
8878 int capacity = dictionary->Capacity();
8879 for (int i = 0; i < capacity; i++) {
8880 Handle<Object> key(dictionary->KeyAt(i));
8881 if (dictionary->IsKey(*key)) {
8882 element_count++;
8883 }
8884 }
8885 break;
8886 }
8887 default:
8888 // External arrays are always dense.
8889 return length;
8890 }
8891 // As an estimate, we assume that the prototype doesn't contain any
8892 // inherited elements.
8893 return element_count;
8894}
8895
8896
8897
8898template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008899static void IterateExternalArrayElements(Isolate* isolate,
8900 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008901 bool elements_are_ints,
8902 bool elements_are_guaranteed_smis,
8903 ArrayConcatVisitor* visitor) {
8904 Handle<ExternalArrayClass> array(
8905 ExternalArrayClass::cast(receiver->elements()));
8906 uint32_t len = static_cast<uint32_t>(array->length());
8907
8908 ASSERT(visitor != NULL);
8909 if (elements_are_ints) {
8910 if (elements_are_guaranteed_smis) {
8911 for (uint32_t j = 0; j < len; j++) {
8912 HandleScope loop_scope;
8913 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8914 visitor->visit(j, e);
8915 }
8916 } else {
8917 for (uint32_t j = 0; j < len; j++) {
8918 HandleScope loop_scope;
8919 int64_t val = static_cast<int64_t>(array->get(j));
8920 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8921 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8922 visitor->visit(j, e);
8923 } else {
8924 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008925 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008926 visitor->visit(j, e);
8927 }
8928 }
8929 }
8930 } else {
8931 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008932 HandleScope loop_scope(isolate);
8933 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008934 visitor->visit(j, e);
8935 }
8936 }
8937}
8938
8939
8940// Used for sorting indices in a List<uint32_t>.
8941static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8942 uint32_t a = *ap;
8943 uint32_t b = *bp;
8944 return (a == b) ? 0 : (a < b) ? -1 : 1;
8945}
8946
8947
8948static void CollectElementIndices(Handle<JSObject> object,
8949 uint32_t range,
8950 List<uint32_t>* indices) {
8951 JSObject::ElementsKind kind = object->GetElementsKind();
8952 switch (kind) {
8953 case JSObject::FAST_ELEMENTS: {
8954 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8955 uint32_t length = static_cast<uint32_t>(elements->length());
8956 if (range < length) length = range;
8957 for (uint32_t i = 0; i < length; i++) {
8958 if (!elements->get(i)->IsTheHole()) {
8959 indices->Add(i);
8960 }
8961 }
8962 break;
8963 }
8964 case JSObject::DICTIONARY_ELEMENTS: {
8965 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008966 uint32_t capacity = dict->Capacity();
8967 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008968 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008969 Handle<Object> k(dict->KeyAt(j));
8970 if (dict->IsKey(*k)) {
8971 ASSERT(k->IsNumber());
8972 uint32_t index = static_cast<uint32_t>(k->Number());
8973 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008974 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008975 }
8976 }
8977 }
8978 break;
8979 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008980 default: {
8981 int dense_elements_length;
8982 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008983 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008984 dense_elements_length =
8985 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008986 break;
8987 }
8988 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008989 dense_elements_length =
8990 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008991 break;
8992 }
8993 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008994 dense_elements_length =
8995 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008996 break;
8997 }
8998 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008999 dense_elements_length =
9000 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009001 break;
9002 }
9003 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009004 dense_elements_length =
9005 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009006 break;
9007 }
9008 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009009 dense_elements_length =
9010 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009011 break;
9012 }
9013 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009014 dense_elements_length =
9015 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009016 break;
9017 }
9018 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009019 dense_elements_length =
9020 ExternalFloatArray::cast(object->elements())->length();
9021 break;
9022 }
9023 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9024 dense_elements_length =
9025 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009026 break;
9027 }
9028 default:
9029 UNREACHABLE();
9030 dense_elements_length = 0;
9031 break;
9032 }
9033 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9034 if (range <= length) {
9035 length = range;
9036 // We will add all indices, so we might as well clear it first
9037 // and avoid duplicates.
9038 indices->Clear();
9039 }
9040 for (uint32_t i = 0; i < length; i++) {
9041 indices->Add(i);
9042 }
9043 if (length == range) return; // All indices accounted for already.
9044 break;
9045 }
9046 }
9047
9048 Handle<Object> prototype(object->GetPrototype());
9049 if (prototype->IsJSObject()) {
9050 // The prototype will usually have no inherited element indices,
9051 // but we have to check.
9052 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9053 }
9054}
9055
9056
9057/**
9058 * A helper function that visits elements of a JSArray in numerical
9059 * order.
9060 *
9061 * The visitor argument called for each existing element in the array
9062 * with the element index and the element's value.
9063 * Afterwards it increments the base-index of the visitor by the array
9064 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009065 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009066 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009067static bool IterateElements(Isolate* isolate,
9068 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009069 ArrayConcatVisitor* visitor) {
9070 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9071 switch (receiver->GetElementsKind()) {
9072 case JSObject::FAST_ELEMENTS: {
9073 // Run through the elements FixedArray and use HasElement and GetElement
9074 // to check the prototype for missing elements.
9075 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9076 int fast_length = static_cast<int>(length);
9077 ASSERT(fast_length <= elements->length());
9078 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009079 HandleScope loop_scope(isolate);
9080 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009081 if (!element_value->IsTheHole()) {
9082 visitor->visit(j, element_value);
9083 } else if (receiver->HasElement(j)) {
9084 // Call GetElement on receiver, not its prototype, or getters won't
9085 // have the correct receiver.
9086 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009087 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009088 visitor->visit(j, element_value);
9089 }
9090 }
9091 break;
9092 }
9093 case JSObject::DICTIONARY_ELEMENTS: {
9094 Handle<NumberDictionary> dict(receiver->element_dictionary());
9095 List<uint32_t> indices(dict->Capacity() / 2);
9096 // Collect all indices in the object and the prototypes less
9097 // than length. This might introduce duplicates in the indices list.
9098 CollectElementIndices(receiver, length, &indices);
9099 indices.Sort(&compareUInt32);
9100 int j = 0;
9101 int n = indices.length();
9102 while (j < n) {
9103 HandleScope loop_scope;
9104 uint32_t index = indices[j];
9105 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009106 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009107 visitor->visit(index, element);
9108 // Skip to next different index (i.e., omit duplicates).
9109 do {
9110 j++;
9111 } while (j < n && indices[j] == index);
9112 }
9113 break;
9114 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009115 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9116 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9117 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009118 for (uint32_t j = 0; j < length; j++) {
9119 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9120 visitor->visit(j, e);
9121 }
9122 break;
9123 }
9124 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9125 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009126 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009127 break;
9128 }
9129 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9130 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009131 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009132 break;
9133 }
9134 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9135 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009136 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009137 break;
9138 }
9139 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9140 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009141 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009142 break;
9143 }
9144 case JSObject::EXTERNAL_INT_ELEMENTS: {
9145 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009146 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009147 break;
9148 }
9149 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9150 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009151 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009152 break;
9153 }
9154 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9155 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009156 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009157 break;
9158 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009159 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9160 IterateExternalArrayElements<ExternalDoubleArray, double>(
9161 isolate, receiver, false, false, visitor);
9162 break;
9163 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009164 default:
9165 UNREACHABLE();
9166 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009167 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009168 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009169 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009170}
9171
9172
9173/**
9174 * Array::concat implementation.
9175 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009176 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009177 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009178 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009179RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009180 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009181 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009182
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009183 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9184 int argument_count = static_cast<int>(arguments->length()->Number());
9185 RUNTIME_ASSERT(arguments->HasFastElements());
9186 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009187
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009188 // Pass 1: estimate the length and number of elements of the result.
9189 // The actual length can be larger if any of the arguments have getters
9190 // that mutate other arguments (but will otherwise be precise).
9191 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009192
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009193 uint32_t estimate_result_length = 0;
9194 uint32_t estimate_nof_elements = 0;
9195 {
9196 for (int i = 0; i < argument_count; i++) {
9197 HandleScope loop_scope;
9198 Handle<Object> obj(elements->get(i));
9199 uint32_t length_estimate;
9200 uint32_t element_estimate;
9201 if (obj->IsJSArray()) {
9202 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9203 length_estimate =
9204 static_cast<uint32_t>(array->length()->Number());
9205 element_estimate =
9206 EstimateElementCount(array);
9207 } else {
9208 length_estimate = 1;
9209 element_estimate = 1;
9210 }
9211 // Avoid overflows by capping at kMaxElementCount.
9212 if (JSObject::kMaxElementCount - estimate_result_length <
9213 length_estimate) {
9214 estimate_result_length = JSObject::kMaxElementCount;
9215 } else {
9216 estimate_result_length += length_estimate;
9217 }
9218 if (JSObject::kMaxElementCount - estimate_nof_elements <
9219 element_estimate) {
9220 estimate_nof_elements = JSObject::kMaxElementCount;
9221 } else {
9222 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009223 }
9224 }
9225 }
9226
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009227 // If estimated number of elements is more than half of length, a
9228 // fixed array (fast case) is more time and space-efficient than a
9229 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009230 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009231
9232 Handle<FixedArray> storage;
9233 if (fast_case) {
9234 // The backing storage array must have non-existing elements to
9235 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009236 storage = isolate->factory()->NewFixedArrayWithHoles(
9237 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009238 } else {
9239 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9240 uint32_t at_least_space_for = estimate_nof_elements +
9241 (estimate_nof_elements >> 2);
9242 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009243 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009244 }
9245
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009246 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009247
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009248 for (int i = 0; i < argument_count; i++) {
9249 Handle<Object> obj(elements->get(i));
9250 if (obj->IsJSArray()) {
9251 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009252 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009253 return Failure::Exception();
9254 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009255 } else {
9256 visitor.visit(0, obj);
9257 visitor.increase_index_offset(1);
9258 }
9259 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009260
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009261 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009262}
9263
9264
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009265// This will not allocate (flatten the string), but it may run
9266// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009267RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009268 NoHandleAllocation ha;
9269 ASSERT(args.length() == 1);
9270
9271 CONVERT_CHECKED(String, string, args[0]);
9272 StringInputBuffer buffer(string);
9273 while (buffer.has_more()) {
9274 uint16_t character = buffer.GetNext();
9275 PrintF("%c", character);
9276 }
9277 return string;
9278}
9279
ager@chromium.org5ec48922009-05-05 07:25:34 +00009280// Moves all own elements of an object, that are below a limit, to positions
9281// starting at zero. All undefined values are placed after non-undefined values,
9282// and are followed by non-existing element. Does not change the length
9283// property.
9284// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009285RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009286 ASSERT(args.length() == 2);
9287 CONVERT_CHECKED(JSObject, object, args[0]);
9288 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9289 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009290}
9291
9292
9293// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009294RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009295 ASSERT(args.length() == 2);
9296 CONVERT_CHECKED(JSArray, from, args[0]);
9297 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009298 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009299 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009300 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9301 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009302 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009303 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009304 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009305 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009306 Object* new_map;
9307 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009308 to->set_map(Map::cast(new_map));
9309 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009310 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009311 Object* obj;
9312 { MaybeObject* maybe_obj = from->ResetElements();
9313 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9314 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009315 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009316 return to;
9317}
9318
9319
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009320// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009321RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009322 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009323 CONVERT_CHECKED(JSObject, object, args[0]);
9324 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009325 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009326 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009327 } else if (object->IsJSArray()) {
9328 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009329 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009330 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009331 }
9332}
9333
9334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009335RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009336 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009337
9338 ASSERT_EQ(3, args.length());
9339
ager@chromium.orgac091b72010-05-05 07:34:42 +00009340 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009341 Handle<Object> key1 = args.at<Object>(1);
9342 Handle<Object> key2 = args.at<Object>(2);
9343
9344 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009345 if (!key1->ToArrayIndex(&index1)
9346 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009347 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009348 }
9349
ager@chromium.orgac091b72010-05-05 07:34:42 +00009350 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9351 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009352 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009353 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009354 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009356 RETURN_IF_EMPTY_HANDLE(isolate,
9357 SetElement(jsobject, index1, tmp2, kStrictMode));
9358 RETURN_IF_EMPTY_HANDLE(isolate,
9359 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009361 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009362}
9363
9364
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009365// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009366// might have elements. Can either return keys (positive integers) or
9367// intervals (pair of a negative integer (-start-1) followed by a
9368// positive (length)) or undefined values.
9369// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009370RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009371 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009372 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009373 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009374 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009375 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009376 // Create an array and get all the keys into it, then remove all the
9377 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009378 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009379 int keys_length = keys->length();
9380 for (int i = 0; i < keys_length; i++) {
9381 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009382 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009383 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009384 // Zap invalid keys.
9385 keys->set_undefined(i);
9386 }
9387 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009388 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009389 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009390 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009391 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009392 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009393 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009394 uint32_t actual_length =
9395 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009396 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009397 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009398 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009399 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009400 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009401 }
9402}
9403
9404
9405// DefineAccessor takes an optional final argument which is the
9406// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9407// to the way accessors are implemented, it is set for both the getter
9408// and setter on the first call to DefineAccessor and ignored on
9409// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009410RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009411 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9412 // Compute attributes.
9413 PropertyAttributes attributes = NONE;
9414 if (args.length() == 5) {
9415 CONVERT_CHECKED(Smi, attrs, args[4]);
9416 int value = attrs->value();
9417 // Only attribute bits should be set.
9418 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9419 attributes = static_cast<PropertyAttributes>(value);
9420 }
9421
9422 CONVERT_CHECKED(JSObject, obj, args[0]);
9423 CONVERT_CHECKED(String, name, args[1]);
9424 CONVERT_CHECKED(Smi, flag, args[2]);
9425 CONVERT_CHECKED(JSFunction, fun, args[3]);
9426 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9427}
9428
9429
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009430RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009431 ASSERT(args.length() == 3);
9432 CONVERT_CHECKED(JSObject, obj, args[0]);
9433 CONVERT_CHECKED(String, name, args[1]);
9434 CONVERT_CHECKED(Smi, flag, args[2]);
9435 return obj->LookupAccessor(name, flag->value() == 0);
9436}
9437
9438
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009439#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009440RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009441 ASSERT(args.length() == 0);
9442 return Execution::DebugBreakHelper();
9443}
9444
9445
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009446// Helper functions for wrapping and unwrapping stack frame ids.
9447static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009448 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009449 return Smi::FromInt(id >> 2);
9450}
9451
9452
9453static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9454 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9455}
9456
9457
9458// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009459// args[0]: debug event listener function to set or null or undefined for
9460// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009461// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009462RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009463 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009464 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9465 args[0]->IsUndefined() ||
9466 args[0]->IsNull());
9467 Handle<Object> callback = args.at<Object>(0);
9468 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009469 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009470
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009471 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009472}
9473
9474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009475RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009476 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009477 isolate->stack_guard()->DebugBreak();
9478 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009479}
9480
9481
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009482static MaybeObject* DebugLookupResultValue(Heap* heap,
9483 Object* receiver,
9484 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009485 LookupResult* result,
9486 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009487 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009488 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009489 case NORMAL:
9490 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009491 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009492 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009493 }
9494 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009495 case FIELD:
9496 value =
9497 JSObject::cast(
9498 result->holder())->FastPropertyAt(result->GetFieldIndex());
9499 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009500 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009501 }
9502 return value;
9503 case CONSTANT_FUNCTION:
9504 return result->GetConstantFunction();
9505 case CALLBACKS: {
9506 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009507 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009508 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009509 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009510 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009511 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009512 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009513 maybe_value = heap->isolate()->pending_exception();
9514 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009515 if (caught_exception != NULL) {
9516 *caught_exception = true;
9517 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009518 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009519 }
9520 return value;
9521 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009522 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009523 }
9524 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009525 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009526 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009527 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009528 case CONSTANT_TRANSITION:
9529 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009530 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009531 default:
9532 UNREACHABLE();
9533 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009534 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009535 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009536}
9537
9538
ager@chromium.org32912102009-01-16 10:38:43 +00009539// Get debugger related details for an object property.
9540// args[0]: object holding property
9541// args[1]: name of the property
9542//
9543// The array returned contains the following information:
9544// 0: Property value
9545// 1: Property details
9546// 2: Property value is exception
9547// 3: Getter function if defined
9548// 4: Setter function if defined
9549// Items 2-4 are only filled if the property has either a getter or a setter
9550// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009551RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009552 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009553
9554 ASSERT(args.length() == 2);
9555
9556 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9557 CONVERT_ARG_CHECKED(String, name, 1);
9558
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009559 // Make sure to set the current context to the context before the debugger was
9560 // entered (if the debugger is entered). The reason for switching context here
9561 // is that for some property lookups (accessors and interceptors) callbacks
9562 // into the embedding application can occour, and the embedding application
9563 // could have the assumption that its own global context is the current
9564 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009565 SaveContext save(isolate);
9566 if (isolate->debug()->InDebugger()) {
9567 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009568 }
9569
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009570 // Skip the global proxy as it has no properties and always delegates to the
9571 // real global object.
9572 if (obj->IsJSGlobalProxy()) {
9573 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9574 }
9575
9576
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009577 // Check if the name is trivially convertible to an index and get the element
9578 // if so.
9579 uint32_t index;
9580 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009581 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009582 Object* element_or_char;
9583 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009584 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009585 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9586 return maybe_element_or_char;
9587 }
9588 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009589 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009590 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009591 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009592 }
9593
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009594 // Find the number of objects making up this.
9595 int length = LocalPrototypeChainLength(*obj);
9596
9597 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009598 Handle<JSObject> jsproto = obj;
9599 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009600 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009601 jsproto->LocalLookup(*name, &result);
9602 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009603 // LookupResult is not GC safe as it holds raw object pointers.
9604 // GC can happen later in this code so put the required fields into
9605 // local variables using handles when required for later use.
9606 PropertyType result_type = result.type();
9607 Handle<Object> result_callback_obj;
9608 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009609 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9610 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009611 }
9612 Smi* property_details = result.GetPropertyDetails().AsSmi();
9613 // DebugLookupResultValue can cause GC so details from LookupResult needs
9614 // to be copied to handles before this.
9615 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009616 Object* raw_value;
9617 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009618 DebugLookupResultValue(isolate->heap(), *obj, *name,
9619 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009620 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9621 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009622 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009623
9624 // If the callback object is a fixed array then it contains JavaScript
9625 // getter and/or setter.
9626 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9627 result_callback_obj->IsFixedArray();
9628 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009629 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009630 details->set(0, *value);
9631 details->set(1, property_details);
9632 if (hasJavaScriptAccessors) {
9633 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009634 caught_exception ? isolate->heap()->true_value()
9635 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009636 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9637 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9638 }
9639
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009640 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009641 }
9642 if (i < length - 1) {
9643 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9644 }
9645 }
9646
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009647 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009648}
9649
9650
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009651RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009652 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009653
9654 ASSERT(args.length() == 2);
9655
9656 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9657 CONVERT_ARG_CHECKED(String, name, 1);
9658
9659 LookupResult result;
9660 obj->Lookup(*name, &result);
9661 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009662 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009663 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009664 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009665}
9666
9667
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009668// Return the property type calculated from the property details.
9669// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009670RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009671 ASSERT(args.length() == 1);
9672 CONVERT_CHECKED(Smi, details, args[0]);
9673 PropertyType type = PropertyDetails(details).type();
9674 return Smi::FromInt(static_cast<int>(type));
9675}
9676
9677
9678// Return the property attribute calculated from the property details.
9679// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009680RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009681 ASSERT(args.length() == 1);
9682 CONVERT_CHECKED(Smi, details, args[0]);
9683 PropertyAttributes attributes = PropertyDetails(details).attributes();
9684 return Smi::FromInt(static_cast<int>(attributes));
9685}
9686
9687
9688// Return the property insertion index calculated from the property details.
9689// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009690RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009691 ASSERT(args.length() == 1);
9692 CONVERT_CHECKED(Smi, details, args[0]);
9693 int index = PropertyDetails(details).index();
9694 return Smi::FromInt(index);
9695}
9696
9697
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009698// Return property value from named interceptor.
9699// args[0]: object
9700// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009701RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009702 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009703 ASSERT(args.length() == 2);
9704 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9705 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9706 CONVERT_ARG_CHECKED(String, name, 1);
9707
9708 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009709 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009710}
9711
9712
9713// Return element value from indexed interceptor.
9714// args[0]: object
9715// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009716RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009717 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009718 ASSERT(args.length() == 2);
9719 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9720 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9721 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9722
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009723 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009724}
9725
9726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009727RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009728 ASSERT(args.length() >= 1);
9729 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009730 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009731 if (isolate->debug()->break_id() == 0 ||
9732 break_id != isolate->debug()->break_id()) {
9733 return isolate->Throw(
9734 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009735 }
9736
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009737 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009738}
9739
9740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009741RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009742 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009743 ASSERT(args.length() == 1);
9744
9745 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009746 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009747 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9748 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009749 if (!maybe_result->ToObject(&result)) return maybe_result;
9750 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009751
9752 // Count all frames which are relevant to debugging stack trace.
9753 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009754 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009755 if (id == StackFrame::NO_ID) {
9756 // If there is no JavaScript stack frame count is 0.
9757 return Smi::FromInt(0);
9758 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009759 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009760 return Smi::FromInt(n);
9761}
9762
9763
9764static const int kFrameDetailsFrameIdIndex = 0;
9765static const int kFrameDetailsReceiverIndex = 1;
9766static const int kFrameDetailsFunctionIndex = 2;
9767static const int kFrameDetailsArgumentCountIndex = 3;
9768static const int kFrameDetailsLocalCountIndex = 4;
9769static const int kFrameDetailsSourcePositionIndex = 5;
9770static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009771static const int kFrameDetailsAtReturnIndex = 7;
9772static const int kFrameDetailsDebuggerFrameIndex = 8;
9773static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009774
9775// Return an array with frame details
9776// args[0]: number: break id
9777// args[1]: number: frame index
9778//
9779// The array returned contains the following information:
9780// 0: Frame id
9781// 1: Receiver
9782// 2: Function
9783// 3: Argument count
9784// 4: Local count
9785// 5: Source position
9786// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009787// 7: Is at return
9788// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009789// Arguments name, value
9790// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009791// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009792RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009793 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009794 ASSERT(args.length() == 2);
9795
9796 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009797 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009798 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9799 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009800 if (!maybe_check->ToObject(&check)) return maybe_check;
9801 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009802 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009803 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009804
9805 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009806 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009807 if (id == StackFrame::NO_ID) {
9808 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009809 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009810 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009811 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009812 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009813 for (; !it.done(); it.Advance()) {
9814 if (count == index) break;
9815 count++;
9816 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009817 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009818
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009819 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009820 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009821
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009822 // Traverse the saved contexts chain to find the active context for the
9823 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009824 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009825 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009826 save = save->prev();
9827 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009828 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009829
9830 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009831 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009832
9833 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009834 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009835 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009836
9837 // Check for constructor frame.
9838 bool constructor = it.frame()->IsConstructor();
9839
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009840 // Get scope info and read from it for local variable information.
9841 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009842 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009843 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009844
9845 // Get the context.
9846 Handle<Context> context(Context::cast(it.frame()->context()));
9847
9848 // Get the locals names and values into a temporary array.
9849 //
9850 // TODO(1240907): Hide compiler-introduced stack variables
9851 // (e.g. .result)? For users of the debugger, they will probably be
9852 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009853 Handle<FixedArray> locals =
9854 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009855
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009856 // Fill in the names of the locals.
9857 for (int i = 0; i < info.NumberOfLocals(); i++) {
9858 locals->set(i * 2, *info.LocalName(i));
9859 }
9860
9861 // Fill in the values of the locals.
9862 for (int i = 0; i < info.NumberOfLocals(); i++) {
9863 if (is_optimized_frame) {
9864 // If we are inspecting an optimized frame use undefined as the
9865 // value for all locals.
9866 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009867 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009868 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009869 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009870 } else if (i < info.number_of_stack_slots()) {
9871 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009872 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9873 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009874 // Traverse the context chain to the function context as all local
9875 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009876 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009877 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009878 context = Handle<Context>(context->previous());
9879 }
9880 ASSERT(context->is_function_context());
9881 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009882 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009883 }
9884 }
9885
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009886 // Check whether this frame is positioned at return. If not top
9887 // frame or if the frame is optimized it cannot be at a return.
9888 bool at_return = false;
9889 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009890 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009891 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009892
9893 // If positioned just before return find the value to be returned and add it
9894 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009895 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009896 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009897 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009898 Address internal_frame_sp = NULL;
9899 while (!it2.done()) {
9900 if (it2.frame()->is_internal()) {
9901 internal_frame_sp = it2.frame()->sp();
9902 } else {
9903 if (it2.frame()->is_java_script()) {
9904 if (it2.frame()->id() == it.frame()->id()) {
9905 // The internal frame just before the JavaScript frame contains the
9906 // value to return on top. A debug break at return will create an
9907 // internal frame to store the return value (eax/rax/r0) before
9908 // entering the debug break exit frame.
9909 if (internal_frame_sp != NULL) {
9910 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009911 Handle<Object>(Memory::Object_at(internal_frame_sp),
9912 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009913 break;
9914 }
9915 }
9916 }
9917
9918 // Indicate that the previous frame was not an internal frame.
9919 internal_frame_sp = NULL;
9920 }
9921 it2.Advance();
9922 }
9923 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009924
9925 // Now advance to the arguments adapter frame (if any). It contains all
9926 // the provided parameters whereas the function frame always have the number
9927 // of arguments matching the functions parameters. The rest of the
9928 // information (except for what is collected above) is the same.
9929 it.AdvanceToArgumentsFrame();
9930
9931 // Find the number of arguments to fill. At least fill the number of
9932 // parameters for the function and fill more if more parameters are provided.
9933 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009934 if (argument_count < it.frame()->ComputeParametersCount()) {
9935 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009936 }
9937
9938 // Calculate the size of the result.
9939 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009940 2 * (argument_count + info.NumberOfLocals()) +
9941 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009942 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009943
9944 // Add the frame id.
9945 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9946
9947 // Add the function (same as in function frame).
9948 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9949
9950 // Add the arguments count.
9951 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9952
9953 // Add the locals count
9954 details->set(kFrameDetailsLocalCountIndex,
9955 Smi::FromInt(info.NumberOfLocals()));
9956
9957 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009958 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009959 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9960 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009961 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009962 }
9963
9964 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009965 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009966
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009967 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009968 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009970 // Add information on whether this frame is invoked in the debugger context.
9971 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009972 heap->ToBoolean(*save->context() ==
9973 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009974
9975 // Fill the dynamic part.
9976 int details_index = kFrameDetailsFirstDynamicIndex;
9977
9978 // Add arguments name and value.
9979 for (int i = 0; i < argument_count; i++) {
9980 // Name of the argument.
9981 if (i < info.number_of_parameters()) {
9982 details->set(details_index++, *info.parameter_name(i));
9983 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009984 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009985 }
9986
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009987 // Parameter value. If we are inspecting an optimized frame, use
9988 // undefined as the value.
9989 //
9990 // TODO(3141533): We should be able to get the actual parameter
9991 // value for optimized frames.
9992 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009993 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009994 details->set(details_index++, it.frame()->GetParameter(i));
9995 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009996 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009997 }
9998 }
9999
10000 // Add locals name and value from the temporary copy from the function frame.
10001 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10002 details->set(details_index++, locals->get(i));
10003 }
10004
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010005 // Add the value being returned.
10006 if (at_return) {
10007 details->set(details_index++, *return_value);
10008 }
10009
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010010 // Add the receiver (same as in function frame).
10011 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10012 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010013 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010014 if (!receiver->IsJSObject()) {
10015 // If the receiver is NOT a JSObject we have hit an optimization
10016 // where a value object is not converted into a wrapped JS objects.
10017 // To hide this optimization from the debugger, we wrap the receiver
10018 // by creating correct wrapper object based on the calling frame's
10019 // global context.
10020 it.Advance();
10021 Handle<Context> calling_frames_global_context(
10022 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010023 receiver =
10024 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010025 }
10026 details->set(kFrameDetailsReceiverIndex, *receiver);
10027
10028 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010029 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010030}
10031
10032
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010033// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010034static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010035 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010036 Handle<SerializedScopeInfo> serialized_scope_info,
10037 ScopeInfo<>& scope_info,
10038 Handle<Context> context,
10039 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010040 // Fill all context locals to the context extension.
10041 for (int i = Context::MIN_CONTEXT_SLOTS;
10042 i < scope_info.number_of_context_slots();
10043 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010044 int context_index = serialized_scope_info->ContextSlotIndex(
10045 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010046
10047 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010048 if (*scope_info.context_slot_name(i) !=
10049 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010050 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010051 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010052 SetProperty(scope_object,
10053 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010054 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010055 NONE,
10056 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010057 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010058 }
10059 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010060
10061 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010062}
10063
10064
10065// Create a plain JSObject which materializes the local scope for the specified
10066// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010067static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
10068 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010069 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010070 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010071 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10072 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010073
10074 // Allocate and initialize a JSObject with all the arguments, stack locals
10075 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010076 Handle<JSObject> local_scope =
10077 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010078
10079 // First fill all parameters.
10080 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010081 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010082 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010083 SetProperty(local_scope,
10084 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010085 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010086 NONE,
10087 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010088 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010089 }
10090
10091 // Second fill all stack locals.
10092 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010093 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010094 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010095 SetProperty(local_scope,
10096 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010097 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010098 NONE,
10099 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010100 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010101 }
10102
10103 // Third fill all context locals.
10104 Handle<Context> frame_context(Context::cast(frame->context()));
10105 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010106 if (!CopyContextLocalsToScopeObject(isolate,
10107 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010108 function_context, local_scope)) {
10109 return Handle<JSObject>();
10110 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010111
10112 // Finally copy any properties from the function context extension. This will
10113 // be variables introduced by eval.
10114 if (function_context->closure() == *function) {
10115 if (function_context->has_extension() &&
10116 !function_context->IsGlobalContext()) {
10117 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010118 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010119 for (int i = 0; i < keys->length(); i++) {
10120 // Names of variables introduced by eval are strings.
10121 ASSERT(keys->get(i)->IsString());
10122 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010123 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010124 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010125 SetProperty(local_scope,
10126 key,
10127 GetProperty(ext, key),
10128 NONE,
10129 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010130 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010131 }
10132 }
10133 }
10134 return local_scope;
10135}
10136
10137
10138// Create a plain JSObject which materializes the closure content for the
10139// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010140static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10141 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010142 ASSERT(context->is_function_context());
10143
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010144 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010145 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10146 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010147
10148 // Allocate and initialize a JSObject with all the content of theis function
10149 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010150 Handle<JSObject> closure_scope =
10151 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010152
10153 // Check whether the arguments shadow object exists.
10154 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010155 shared->scope_info()->ContextSlotIndex(
10156 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010157 if (arguments_shadow_index >= 0) {
10158 // In this case all the arguments are available in the arguments shadow
10159 // object.
10160 Handle<JSObject> arguments_shadow(
10161 JSObject::cast(context->get(arguments_shadow_index)));
10162 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010163 // We don't expect exception-throwing getters on the arguments shadow.
10164 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010165 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010166 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010167 SetProperty(closure_scope,
10168 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010169 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010170 NONE,
10171 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010172 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010173 }
10174 }
10175
10176 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010177 if (!CopyContextLocalsToScopeObject(isolate,
10178 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010179 context, closure_scope)) {
10180 return Handle<JSObject>();
10181 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010182
10183 // Finally copy any properties from the function context extension. This will
10184 // be variables introduced by eval.
10185 if (context->has_extension()) {
10186 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010187 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010188 for (int i = 0; i < keys->length(); i++) {
10189 // Names of variables introduced by eval are strings.
10190 ASSERT(keys->get(i)->IsString());
10191 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010192 RETURN_IF_EMPTY_HANDLE_VALUE(
10193 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010194 SetProperty(closure_scope,
10195 key,
10196 GetProperty(ext, key),
10197 NONE,
10198 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010199 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010200 }
10201 }
10202
10203 return closure_scope;
10204}
10205
10206
10207// Iterate over the actual scopes visible from a stack frame. All scopes are
10208// backed by an actual context except the local scope, which is inserted
10209// "artifically" in the context chain.
10210class ScopeIterator {
10211 public:
10212 enum ScopeType {
10213 ScopeTypeGlobal = 0,
10214 ScopeTypeLocal,
10215 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010216 ScopeTypeClosure,
10217 // Every catch block contains an implicit with block (its parameter is
10218 // a JSContextExtensionObject) that extends current scope with a variable
10219 // holding exception object. Such with blocks are treated as scopes of their
10220 // own type.
10221 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010222 };
10223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010224 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10225 : isolate_(isolate),
10226 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010227 function_(JSFunction::cast(frame->function())),
10228 context_(Context::cast(frame->context())),
10229 local_done_(false),
10230 at_local_(false) {
10231
10232 // Check whether the first scope is actually a local scope.
10233 if (context_->IsGlobalContext()) {
10234 // If there is a stack slot for .result then this local scope has been
10235 // created for evaluating top level code and it is not a real local scope.
10236 // Checking for the existence of .result seems fragile, but the scope info
10237 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010238 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010239 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010240 at_local_ = index < 0;
10241 } else if (context_->is_function_context()) {
10242 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010243 } else if (context_->closure() != *function_) {
10244 // The context_ is a with block from the outer function.
10245 ASSERT(context_->has_extension());
10246 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010247 }
10248 }
10249
10250 // More scopes?
10251 bool Done() { return context_.is_null(); }
10252
10253 // Move to the next scope.
10254 void Next() {
10255 // If at a local scope mark the local scope as passed.
10256 if (at_local_) {
10257 at_local_ = false;
10258 local_done_ = true;
10259
10260 // If the current context is not associated with the local scope the
10261 // current context is the next real scope, so don't move to the next
10262 // context in this case.
10263 if (context_->closure() != *function_) {
10264 return;
10265 }
10266 }
10267
10268 // The global scope is always the last in the chain.
10269 if (context_->IsGlobalContext()) {
10270 context_ = Handle<Context>();
10271 return;
10272 }
10273
10274 // Move to the next context.
10275 if (context_->is_function_context()) {
10276 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10277 } else {
10278 context_ = Handle<Context>(context_->previous());
10279 }
10280
10281 // If passing the local scope indicate that the current scope is now the
10282 // local scope.
10283 if (!local_done_ &&
10284 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10285 at_local_ = true;
10286 }
10287 }
10288
10289 // Return the type of the current scope.
10290 int Type() {
10291 if (at_local_) {
10292 return ScopeTypeLocal;
10293 }
10294 if (context_->IsGlobalContext()) {
10295 ASSERT(context_->global()->IsGlobalObject());
10296 return ScopeTypeGlobal;
10297 }
10298 if (context_->is_function_context()) {
10299 return ScopeTypeClosure;
10300 }
10301 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010302 // Current scope is either an explicit with statement or a with statement
10303 // implicitely generated for a catch block.
10304 // If the extension object here is a JSContextExtensionObject then
10305 // current with statement is one frome a catch block otherwise it's a
10306 // regular with statement.
10307 if (context_->extension()->IsJSContextExtensionObject()) {
10308 return ScopeTypeCatch;
10309 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010310 return ScopeTypeWith;
10311 }
10312
10313 // Return the JavaScript object with the content of the current scope.
10314 Handle<JSObject> ScopeObject() {
10315 switch (Type()) {
10316 case ScopeIterator::ScopeTypeGlobal:
10317 return Handle<JSObject>(CurrentContext()->global());
10318 break;
10319 case ScopeIterator::ScopeTypeLocal:
10320 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010321 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010322 break;
10323 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010324 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010325 // Return the with object.
10326 return Handle<JSObject>(CurrentContext()->extension());
10327 break;
10328 case ScopeIterator::ScopeTypeClosure:
10329 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010330 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010331 break;
10332 }
10333 UNREACHABLE();
10334 return Handle<JSObject>();
10335 }
10336
10337 // Return the context for this scope. For the local context there might not
10338 // be an actual context.
10339 Handle<Context> CurrentContext() {
10340 if (at_local_ && context_->closure() != *function_) {
10341 return Handle<Context>();
10342 }
10343 return context_;
10344 }
10345
10346#ifdef DEBUG
10347 // Debug print of the content of the current scope.
10348 void DebugPrint() {
10349 switch (Type()) {
10350 case ScopeIterator::ScopeTypeGlobal:
10351 PrintF("Global:\n");
10352 CurrentContext()->Print();
10353 break;
10354
10355 case ScopeIterator::ScopeTypeLocal: {
10356 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010357 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010358 scope_info.Print();
10359 if (!CurrentContext().is_null()) {
10360 CurrentContext()->Print();
10361 if (CurrentContext()->has_extension()) {
10362 Handle<JSObject> extension =
10363 Handle<JSObject>(CurrentContext()->extension());
10364 if (extension->IsJSContextExtensionObject()) {
10365 extension->Print();
10366 }
10367 }
10368 }
10369 break;
10370 }
10371
10372 case ScopeIterator::ScopeTypeWith: {
10373 PrintF("With:\n");
10374 Handle<JSObject> extension =
10375 Handle<JSObject>(CurrentContext()->extension());
10376 extension->Print();
10377 break;
10378 }
10379
ager@chromium.orga1645e22009-09-09 19:27:10 +000010380 case ScopeIterator::ScopeTypeCatch: {
10381 PrintF("Catch:\n");
10382 Handle<JSObject> extension =
10383 Handle<JSObject>(CurrentContext()->extension());
10384 extension->Print();
10385 break;
10386 }
10387
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010388 case ScopeIterator::ScopeTypeClosure: {
10389 PrintF("Closure:\n");
10390 CurrentContext()->Print();
10391 if (CurrentContext()->has_extension()) {
10392 Handle<JSObject> extension =
10393 Handle<JSObject>(CurrentContext()->extension());
10394 if (extension->IsJSContextExtensionObject()) {
10395 extension->Print();
10396 }
10397 }
10398 break;
10399 }
10400
10401 default:
10402 UNREACHABLE();
10403 }
10404 PrintF("\n");
10405 }
10406#endif
10407
10408 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010409 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010410 JavaScriptFrame* frame_;
10411 Handle<JSFunction> function_;
10412 Handle<Context> context_;
10413 bool local_done_;
10414 bool at_local_;
10415
10416 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10417};
10418
10419
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010420RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010421 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010422 ASSERT(args.length() == 2);
10423
10424 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010425 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010426 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10427 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010428 if (!maybe_check->ToObject(&check)) return maybe_check;
10429 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010430 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10431
10432 // Get the frame where the debugging is performed.
10433 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010434 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010435 JavaScriptFrame* frame = it.frame();
10436
10437 // Count the visible scopes.
10438 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010439 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010440 n++;
10441 }
10442
10443 return Smi::FromInt(n);
10444}
10445
10446
10447static const int kScopeDetailsTypeIndex = 0;
10448static const int kScopeDetailsObjectIndex = 1;
10449static const int kScopeDetailsSize = 2;
10450
10451// Return an array with scope details
10452// args[0]: number: break id
10453// args[1]: number: frame index
10454// args[2]: number: scope index
10455//
10456// The array returned contains the following information:
10457// 0: Scope type
10458// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010459RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010460 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010461 ASSERT(args.length() == 3);
10462
10463 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010464 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010465 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10466 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010467 if (!maybe_check->ToObject(&check)) return maybe_check;
10468 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010469 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10470 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10471
10472 // Get the frame where the debugging is performed.
10473 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010474 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010475 JavaScriptFrame* frame = frame_it.frame();
10476
10477 // Find the requested scope.
10478 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010479 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010480 for (; !it.Done() && n < index; it.Next()) {
10481 n++;
10482 }
10483 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010484 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010485 }
10486
10487 // Calculate the size of the result.
10488 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010489 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010490
10491 // Fill in scope details.
10492 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010493 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010494 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010495 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010496
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010497 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010498}
10499
10500
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010501RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010502 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010503 ASSERT(args.length() == 0);
10504
10505#ifdef DEBUG
10506 // Print the scopes for the top frame.
10507 StackFrameLocator locator;
10508 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010509 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010510 it.DebugPrint();
10511 }
10512#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010513 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010514}
10515
10516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010517RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010518 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010519 ASSERT(args.length() == 1);
10520
10521 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010522 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010523 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10524 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010525 if (!maybe_result->ToObject(&result)) return maybe_result;
10526 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010527
10528 // Count all archived V8 threads.
10529 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010530 for (ThreadState* thread =
10531 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010532 thread != NULL;
10533 thread = thread->Next()) {
10534 n++;
10535 }
10536
10537 // Total number of threads is current thread and archived threads.
10538 return Smi::FromInt(n + 1);
10539}
10540
10541
10542static const int kThreadDetailsCurrentThreadIndex = 0;
10543static const int kThreadDetailsThreadIdIndex = 1;
10544static const int kThreadDetailsSize = 2;
10545
10546// Return an array with thread details
10547// args[0]: number: break id
10548// args[1]: number: thread index
10549//
10550// The array returned contains the following information:
10551// 0: Is current thread?
10552// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010553RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010554 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010555 ASSERT(args.length() == 2);
10556
10557 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010558 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010559 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10560 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010561 if (!maybe_check->ToObject(&check)) return maybe_check;
10562 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010563 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10564
10565 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010566 Handle<FixedArray> details =
10567 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010568
10569 // Thread index 0 is current thread.
10570 if (index == 0) {
10571 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010572 details->set(kThreadDetailsCurrentThreadIndex,
10573 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010574 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010575 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010576 } else {
10577 // Find the thread with the requested index.
10578 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010579 ThreadState* thread =
10580 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010581 while (index != n && thread != NULL) {
10582 thread = thread->Next();
10583 n++;
10584 }
10585 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010586 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010587 }
10588
10589 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010590 details->set(kThreadDetailsCurrentThreadIndex,
10591 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010592 details->set(kThreadDetailsThreadIdIndex,
10593 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010594 }
10595
10596 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010597 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010598}
10599
10600
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010601// Sets the disable break state
10602// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010603RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010604 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010605 ASSERT(args.length() == 1);
10606 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 isolate->debug()->set_disable_break(disable_break);
10608 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010609}
10610
10611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010612RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010613 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010614 ASSERT(args.length() == 1);
10615
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010616 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10617 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010618 // Find the number of break points
10619 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010620 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010622 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623 Handle<FixedArray>::cast(break_locations));
10624}
10625
10626
10627// Set a break point in a function
10628// args[0]: function
10629// args[1]: number: break source position (within the function source)
10630// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010631RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010632 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010633 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010634 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10635 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010636 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10637 RUNTIME_ASSERT(source_position >= 0);
10638 Handle<Object> break_point_object_arg = args.at<Object>(2);
10639
10640 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010641 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10642 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010643
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010644 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010645}
10646
10647
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010648Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10649 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010650 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010651 // Iterate the heap looking for SharedFunctionInfo generated from the
10652 // script. The inner most SharedFunctionInfo containing the source position
10653 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010654 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010655 // which is found is not compiled it is compiled and the heap is iterated
10656 // again as the compilation might create inner functions from the newly
10657 // compiled function and the actual requested break point might be in one of
10658 // these functions.
10659 bool done = false;
10660 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010661 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010662 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010663 while (!done) {
10664 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010665 for (HeapObject* obj = iterator.next();
10666 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010667 if (obj->IsSharedFunctionInfo()) {
10668 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10669 if (shared->script() == *script) {
10670 // If the SharedFunctionInfo found has the requested script data and
10671 // contains the source position it is a candidate.
10672 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010673 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010674 start_position = shared->start_position();
10675 }
10676 if (start_position <= position &&
10677 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010678 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010679 // candidate this is the new candidate.
10680 if (target.is_null()) {
10681 target_start_position = start_position;
10682 target = shared;
10683 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010684 if (target_start_position == start_position &&
10685 shared->end_position() == target->end_position()) {
10686 // If a top-level function contain only one function
10687 // declartion the source for the top-level and the function is
10688 // the same. In that case prefer the non top-level function.
10689 if (!shared->is_toplevel()) {
10690 target_start_position = start_position;
10691 target = shared;
10692 }
10693 } else if (target_start_position <= start_position &&
10694 shared->end_position() <= target->end_position()) {
10695 // This containment check includes equality as a function inside
10696 // a top-level function can share either start or end position
10697 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010698 target_start_position = start_position;
10699 target = shared;
10700 }
10701 }
10702 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010703 }
10704 }
10705 }
10706
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010707 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010708 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010709 }
10710
10711 // If the candidate found is compiled we are done. NOTE: when lazy
10712 // compilation of inner functions is introduced some additional checking
10713 // needs to be done here to compile inner functions.
10714 done = target->is_compiled();
10715 if (!done) {
10716 // If the candidate is not compiled compile it to reveal any inner
10717 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010718 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010719 }
10720 }
10721
10722 return *target;
10723}
10724
10725
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010726// Changes the state of a break point in a script and returns source position
10727// where break point was set. NOTE: Regarding performance see the NOTE for
10728// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010729// args[0]: script to set break point in
10730// args[1]: number: break source position (within the script source)
10731// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010732RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010733 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010734 ASSERT(args.length() == 3);
10735 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10736 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10737 RUNTIME_ASSERT(source_position >= 0);
10738 Handle<Object> break_point_object_arg = args.at<Object>(2);
10739
10740 // Get the script from the script wrapper.
10741 RUNTIME_ASSERT(wrapper->value()->IsScript());
10742 Handle<Script> script(Script::cast(wrapper->value()));
10743
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010744 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010745 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746 if (!result->IsUndefined()) {
10747 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10748 // Find position within function. The script position might be before the
10749 // source position of the first function.
10750 int position;
10751 if (shared->start_position() > source_position) {
10752 position = 0;
10753 } else {
10754 position = source_position - shared->start_position();
10755 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010756 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010757 position += shared->start_position();
10758 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010759 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010760 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010761}
10762
10763
10764// Clear a break point
10765// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010766RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010767 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768 ASSERT(args.length() == 1);
10769 Handle<Object> break_point_object_arg = args.at<Object>(0);
10770
10771 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010772 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010773
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010774 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010775}
10776
10777
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010778// Change the state of break on exceptions.
10779// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10780// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010781RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010782 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010783 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010784 RUNTIME_ASSERT(args[0]->IsNumber());
10785 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010786
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010787 // If the number doesn't match an enum value, the ChangeBreakOnException
10788 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010789 ExceptionBreakType type =
10790 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010791 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010792 isolate->debug()->ChangeBreakOnException(type, enable);
10793 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010794}
10795
10796
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010797// Returns the state of break on exceptions
10798// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010799RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010800 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010801 ASSERT(args.length() == 1);
10802 RUNTIME_ASSERT(args[0]->IsNumber());
10803
10804 ExceptionBreakType type =
10805 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010806 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010807 return Smi::FromInt(result);
10808}
10809
10810
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010811// Prepare for stepping
10812// args[0]: break id for checking execution state
10813// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010814// args[2]: number of times to perform the step, for step out it is the number
10815// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010816RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010817 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010818 ASSERT(args.length() == 3);
10819 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010820 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010821 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10822 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010823 if (!maybe_check->ToObject(&check)) return maybe_check;
10824 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010825 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010826 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010827 }
10828
10829 // Get the step action and check validity.
10830 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10831 if (step_action != StepIn &&
10832 step_action != StepNext &&
10833 step_action != StepOut &&
10834 step_action != StepInMin &&
10835 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010836 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010837 }
10838
10839 // Get the number of steps.
10840 int step_count = NumberToInt32(args[2]);
10841 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010842 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010843 }
10844
ager@chromium.orga1645e22009-09-09 19:27:10 +000010845 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010846 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010847
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010848 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010849 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10850 step_count);
10851 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010852}
10853
10854
10855// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010856RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010857 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010858 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010859 isolate->debug()->ClearStepping();
10860 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010861}
10862
10863
10864// Creates a copy of the with context chain. The copy of the context chain is
10865// is linked to the function context supplied.
10866static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10867 Handle<Context> function_context) {
10868 // At the bottom of the chain. Return the function context to link to.
10869 if (context_chain->is_function_context()) {
10870 return function_context;
10871 }
10872
10873 // Recursively copy the with contexts.
10874 Handle<Context> previous(context_chain->previous());
10875 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010876 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010877 return context->GetIsolate()->factory()->NewWithContext(
10878 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010879}
10880
10881
10882// Helper function to find or create the arguments object for
10883// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010884static Handle<Object> GetArgumentsObject(Isolate* isolate,
10885 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010886 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010887 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010888 const ScopeInfo<>* sinfo,
10889 Handle<Context> function_context) {
10890 // Try to find the value of 'arguments' to pass as parameter. If it is not
10891 // found (that is the debugged function does not reference 'arguments' and
10892 // does not support eval) then create an 'arguments' object.
10893 int index;
10894 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010895 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010896 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010897 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010898 }
10899 }
10900
10901 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010902 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10903 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010904 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010905 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010906 }
10907 }
10908
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010909 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010910 Handle<JSObject> arguments =
10911 isolate->factory()->NewArgumentsObject(function, length);
10912 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010913
10914 AssertNoAllocation no_gc;
10915 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010916 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010917 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010918 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010919 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010920 return arguments;
10921}
10922
10923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010924static const char kSourceStr[] =
10925 "(function(arguments,__source__){return eval(__source__);})";
10926
10927
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010928// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010929// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010930// extension part has all the parameters and locals of the function on the
10931// stack frame. A function which calls eval with the code to evaluate is then
10932// compiled in this context and called in this context. As this context
10933// replaces the context of the function on the stack frame a new (empty)
10934// function is created as well to be used as the closure for the context.
10935// This function and the context acts as replacements for the function on the
10936// stack frame presenting the same view of the values of parameters and
10937// local variables as if the piece of JavaScript was evaluated at the point
10938// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010939RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010940 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010941
10942 // Check the execution state and decode arguments frame and source to be
10943 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010944 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010945 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010946 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10947 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010948 if (!maybe_check_result->ToObject(&check_result)) {
10949 return maybe_check_result;
10950 }
10951 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010952 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10953 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010954 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010955 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010956
10957 // Handle the processing of break.
10958 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959
10960 // Get the frame where the debugging is performed.
10961 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010962 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010963 JavaScriptFrame* frame = it.frame();
10964 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010965 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010966 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010967
10968 // Traverse the saved contexts chain to find the active context for the
10969 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010970 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010971 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010972 save = save->prev();
10973 }
10974 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010975 SaveContext savex(isolate);
10976 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010977
10978 // Create the (empty) function replacing the function on the stack frame for
10979 // the purpose of evaluating in the context created below. It is important
10980 // that this function does not describe any parameters and local variables
10981 // in the context. If it does then this will cause problems with the lookup
10982 // in Context::Lookup, where context slots for parameters and local variables
10983 // are looked at before the extension object.
10984 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010985 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10986 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010987 go_between->set_context(function->context());
10988#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010989 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010990 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10991 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10992#endif
10993
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010994 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010995 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10996 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010997
10998 // Allocate a new context for the debug evaluation and set the extension
10999 // object build.
11000 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011001 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11002 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011003 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011004 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011005 Handle<Context> frame_context(Context::cast(frame->context()));
11006 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011007 context = CopyWithContextChain(frame_context, context);
11008
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011009 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011010 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011011 Handle<JSObject>::cast(additional_context), false);
11012 }
11013
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011014 // Wrap the evaluation statement in a new function compiled in the newly
11015 // created context. The function has one parameter which has to be called
11016 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011017 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011018 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011019
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011020 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011021 isolate->factory()->NewStringFromAscii(
11022 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011023
11024 // Currently, the eval code will be executed in non-strict mode,
11025 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011026 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011027 Compiler::CompileEval(function_source,
11028 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011029 context->IsGlobalContext(),
11030 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011031 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011032 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011033 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011034
11035 // Invoke the result of the compilation to get the evaluation function.
11036 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011037 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011038 Handle<Object> evaluation_function =
11039 Execution::Call(compiled_function, receiver, 0, NULL,
11040 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011041 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011042
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011043 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
11044 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011045 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011046
11047 // Invoke the evaluation function and return the result.
11048 const int argc = 2;
11049 Object** argv[argc] = { arguments.location(),
11050 Handle<Object>::cast(source).location() };
11051 Handle<Object> result =
11052 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11053 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011054 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011055
11056 // Skip the global proxy as it has no properties and always delegates to the
11057 // real global object.
11058 if (result->IsJSGlobalProxy()) {
11059 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11060 }
11061
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011062 return *result;
11063}
11064
11065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011066RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011067 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011068
11069 // Check the execution state and decode arguments frame and source to be
11070 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011071 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011072 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011073 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11074 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011075 if (!maybe_check_result->ToObject(&check_result)) {
11076 return maybe_check_result;
11077 }
11078 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011079 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011080 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011081 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011082
11083 // Handle the processing of break.
11084 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011085
11086 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011087 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011088 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011089 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011090 top = top->prev();
11091 }
11092 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011093 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011094 }
11095
11096 // Get the global context now set to the top context from before the
11097 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011098 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011099
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011100 bool is_global = true;
11101
11102 if (additional_context->IsJSObject()) {
11103 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011104 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11105 isolate->factory()->empty_string(),
11106 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011107 go_between->set_context(*context);
11108 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011109 isolate->factory()->NewFunctionContext(
11110 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011111 context->set_extension(JSObject::cast(*additional_context));
11112 is_global = false;
11113 }
11114
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011115 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011116 // Currently, the eval code will be executed in non-strict mode,
11117 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011118 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011119 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011120 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011121 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011122 Handle<JSFunction>(
11123 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11124 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011125
11126 // Invoke the result of the compilation to get the evaluation function.
11127 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011128 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011129 Handle<Object> result =
11130 Execution::Call(compiled_function, receiver, 0, NULL,
11131 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011132 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011133 return *result;
11134}
11135
11136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011137RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011138 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011139 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011140
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011141 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011142 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011143
11144 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011145 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011146 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11147 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11148 // because using
11149 // instances->set(i, *GetScriptWrapper(script))
11150 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11151 // already have deferenced the instances handle.
11152 Handle<JSValue> wrapper = GetScriptWrapper(script);
11153 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011154 }
11155
11156 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011157 Handle<JSObject> result =
11158 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011159 Handle<JSArray>::cast(result)->SetContent(*instances);
11160 return *result;
11161}
11162
11163
11164// Helper function used by Runtime_DebugReferencedBy below.
11165static int DebugReferencedBy(JSObject* target,
11166 Object* instance_filter, int max_references,
11167 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011168 JSFunction* arguments_function) {
11169 NoHandleAllocation ha;
11170 AssertNoAllocation no_alloc;
11171
11172 // Iterate the heap.
11173 int count = 0;
11174 JSObject* last = NULL;
11175 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011176 HeapObject* heap_obj = NULL;
11177 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011178 (max_references == 0 || count < max_references)) {
11179 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011180 if (heap_obj->IsJSObject()) {
11181 // Skip context extension objects and argument arrays as these are
11182 // checked in the context of functions using them.
11183 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011184 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011185 obj->map()->constructor() == arguments_function) {
11186 continue;
11187 }
11188
11189 // Check if the JS object has a reference to the object looked for.
11190 if (obj->ReferencesObject(target)) {
11191 // Check instance filter if supplied. This is normally used to avoid
11192 // references from mirror objects (see Runtime_IsInPrototypeChain).
11193 if (!instance_filter->IsUndefined()) {
11194 Object* V = obj;
11195 while (true) {
11196 Object* prototype = V->GetPrototype();
11197 if (prototype->IsNull()) {
11198 break;
11199 }
11200 if (instance_filter == prototype) {
11201 obj = NULL; // Don't add this object.
11202 break;
11203 }
11204 V = prototype;
11205 }
11206 }
11207
11208 if (obj != NULL) {
11209 // Valid reference found add to instance array if supplied an update
11210 // count.
11211 if (instances != NULL && count < instances_size) {
11212 instances->set(count, obj);
11213 }
11214 last = obj;
11215 count++;
11216 }
11217 }
11218 }
11219 }
11220
11221 // Check for circular reference only. This can happen when the object is only
11222 // referenced from mirrors and has a circular reference in which case the
11223 // object is not really alive and would have been garbage collected if not
11224 // referenced from the mirror.
11225 if (count == 1 && last == target) {
11226 count = 0;
11227 }
11228
11229 // Return the number of referencing objects found.
11230 return count;
11231}
11232
11233
11234// Scan the heap for objects with direct references to an object
11235// args[0]: the object to find references to
11236// args[1]: constructor function for instances to exclude (Mirror)
11237// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011238RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011239 ASSERT(args.length() == 3);
11240
11241 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011242 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011243
11244 // Check parameters.
11245 CONVERT_CHECKED(JSObject, target, args[0]);
11246 Object* instance_filter = args[1];
11247 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11248 instance_filter->IsJSObject());
11249 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11250 RUNTIME_ASSERT(max_references >= 0);
11251
11252 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011253 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011254 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011255 JSFunction* arguments_function =
11256 JSFunction::cast(arguments_boilerplate->map()->constructor());
11257
11258 // Get the number of referencing objects.
11259 int count;
11260 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011261 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011262
11263 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011264 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011265 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011266 if (!maybe_object->ToObject(&object)) return maybe_object;
11267 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011268 FixedArray* instances = FixedArray::cast(object);
11269
11270 // Fill the referencing objects.
11271 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011272 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011273
11274 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011275 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011276 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11277 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011278 if (!maybe_result->ToObject(&result)) return maybe_result;
11279 }
11280 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011281 return result;
11282}
11283
11284
11285// Helper function used by Runtime_DebugConstructedBy below.
11286static int DebugConstructedBy(JSFunction* constructor, int max_references,
11287 FixedArray* instances, int instances_size) {
11288 AssertNoAllocation no_alloc;
11289
11290 // Iterate the heap.
11291 int count = 0;
11292 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011293 HeapObject* heap_obj = NULL;
11294 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011295 (max_references == 0 || count < max_references)) {
11296 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011297 if (heap_obj->IsJSObject()) {
11298 JSObject* obj = JSObject::cast(heap_obj);
11299 if (obj->map()->constructor() == constructor) {
11300 // Valid reference found add to instance array if supplied an update
11301 // count.
11302 if (instances != NULL && count < instances_size) {
11303 instances->set(count, obj);
11304 }
11305 count++;
11306 }
11307 }
11308 }
11309
11310 // Return the number of referencing objects found.
11311 return count;
11312}
11313
11314
11315// Scan the heap for objects constructed by a specific function.
11316// args[0]: the constructor to find instances of
11317// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011318RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011319 ASSERT(args.length() == 2);
11320
11321 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011322 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011323
11324 // Check parameters.
11325 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11326 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11327 RUNTIME_ASSERT(max_references >= 0);
11328
11329 // Get the number of referencing objects.
11330 int count;
11331 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11332
11333 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011334 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011335 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011336 if (!maybe_object->ToObject(&object)) return maybe_object;
11337 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011338 FixedArray* instances = FixedArray::cast(object);
11339
11340 // Fill the referencing objects.
11341 count = DebugConstructedBy(constructor, max_references, instances, count);
11342
11343 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011344 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011345 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11346 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011347 if (!maybe_result->ToObject(&result)) return maybe_result;
11348 }
11349 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011350 return result;
11351}
11352
11353
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011354// Find the effective prototype object as returned by __proto__.
11355// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011356RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011357 ASSERT(args.length() == 1);
11358
11359 CONVERT_CHECKED(JSObject, obj, args[0]);
11360
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011361 // Use the __proto__ accessor.
11362 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011363}
11364
11365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011366RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011367 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011368 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011369 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011370}
11371
11372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011373RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011374#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011375 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011376 ASSERT(args.length() == 1);
11377 // Get the function and make sure it is compiled.
11378 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011379 Handle<SharedFunctionInfo> shared(func->shared());
11380 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011381 return Failure::Exception();
11382 }
11383 func->code()->PrintLn();
11384#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011385 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011386}
ager@chromium.org9085a012009-05-11 19:22:57 +000011387
11388
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011389RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011390#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011391 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011392 ASSERT(args.length() == 1);
11393 // Get the function and make sure it is compiled.
11394 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011395 Handle<SharedFunctionInfo> shared(func->shared());
11396 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011397 return Failure::Exception();
11398 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011399 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011400#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011401 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011402}
11403
11404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011405RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011406 NoHandleAllocation ha;
11407 ASSERT(args.length() == 1);
11408
11409 CONVERT_CHECKED(JSFunction, f, args[0]);
11410 return f->shared()->inferred_name();
11411}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011412
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011413
11414static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011415 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011416 AssertNoAllocation no_allocations;
11417
11418 int counter = 0;
11419 int buffer_size = buffer->length();
11420 HeapIterator iterator;
11421 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11422 ASSERT(obj != NULL);
11423 if (!obj->IsSharedFunctionInfo()) {
11424 continue;
11425 }
11426 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11427 if (shared->script() != script) {
11428 continue;
11429 }
11430 if (counter < buffer_size) {
11431 buffer->set(counter, shared);
11432 }
11433 counter++;
11434 }
11435 return counter;
11436}
11437
11438// For a script finds all SharedFunctionInfo's in the heap that points
11439// to this script. Returns JSArray of SharedFunctionInfo wrapped
11440// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011441RUNTIME_FUNCTION(MaybeObject*,
11442 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011443 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011444 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011445 CONVERT_CHECKED(JSValue, script_value, args[0]);
11446
11447 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11448
11449 const int kBufferSize = 32;
11450
11451 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011452 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011453 int number = FindSharedFunctionInfosForScript(*script, *array);
11454 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011455 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011456 FindSharedFunctionInfosForScript(*script, *array);
11457 }
11458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011459 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011460 result->set_length(Smi::FromInt(number));
11461
11462 LiveEdit::WrapSharedFunctionInfos(result);
11463
11464 return *result;
11465}
11466
11467// For a script calculates compilation information about all its functions.
11468// The script source is explicitly specified by the second argument.
11469// The source of the actual script is not used, however it is important that
11470// all generated code keeps references to this particular instance of script.
11471// Returns a JSArray of compilation infos. The array is ordered so that
11472// each function with all its descendant is always stored in a continues range
11473// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011474RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011475 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011476 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011477 CONVERT_CHECKED(JSValue, script, args[0]);
11478 CONVERT_ARG_CHECKED(String, source, 1);
11479 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11480
11481 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11482
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011483 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011484 return Failure::Exception();
11485 }
11486
11487 return result;
11488}
11489
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011490// Changes the source of the script to a new_source.
11491// If old_script_name is provided (i.e. is a String), also creates a copy of
11492// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011493RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011494 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011495 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011496 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11497 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011498 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011499
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011500 CONVERT_CHECKED(Script, original_script_pointer,
11501 original_script_value->value());
11502 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011503
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011504 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11505 new_source,
11506 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011507
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011508 if (old_script->IsScript()) {
11509 Handle<Script> script_handle(Script::cast(old_script));
11510 return *(GetScriptWrapper(script_handle));
11511 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011512 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011513 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011514}
11515
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011517RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011518 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011519 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011520 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11521 return LiveEdit::FunctionSourceUpdated(shared_info);
11522}
11523
11524
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011525// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011526RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011527 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011528 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011529 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11530 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11531
ager@chromium.orgac091b72010-05-05 07:34:42 +000011532 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011533}
11534
11535// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011536RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011537 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011538 HandleScope scope(isolate);
11539 Handle<Object> function_object(args[0], isolate);
11540 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011541
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011542 if (function_object->IsJSValue()) {
11543 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11544 if (script_object->IsJSValue()) {
11545 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011546 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011547 }
11548
11549 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11550 } else {
11551 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11552 // and we check it in this function.
11553 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011554
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011555 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011556}
11557
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011558
11559// In a code of a parent function replaces original function as embedded object
11560// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011561RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011562 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011563 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011564
11565 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11566 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11567 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11568
11569 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11570 subst_wrapper);
11571
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011572 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011573}
11574
11575
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011576// Updates positions of a shared function info (first parameter) according
11577// to script source change. Text change is described in second parameter as
11578// array of groups of 3 numbers:
11579// (change_begin, change_end, change_end_new_position).
11580// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011581RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011582 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011583 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011584 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11585 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11586
ager@chromium.orgac091b72010-05-05 07:34:42 +000011587 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011588}
11589
11590
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011591// For array of SharedFunctionInfo's (each wrapped in JSValue)
11592// checks that none of them have activations on stacks (of any thread).
11593// Returns array of the same length with corresponding results of
11594// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011595RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011596 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011597 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011598 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011599 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011600
ager@chromium.org357bf652010-04-12 11:30:10 +000011601 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011602}
11603
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011604// Compares 2 strings line-by-line, then token-wise and returns diff in form
11605// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11606// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011607RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011608 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011609 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011610 CONVERT_ARG_CHECKED(String, s1, 0);
11611 CONVERT_ARG_CHECKED(String, s2, 1);
11612
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011613 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011614}
11615
11616
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011617// A testing entry. Returns statement position which is the closest to
11618// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011619RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011620 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011621 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011622 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11623 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11624
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011626
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011627 if (code->kind() != Code::FUNCTION &&
11628 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011629 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011630 }
11631
11632 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011633 int closest_pc = 0;
11634 int distance = kMaxInt;
11635 while (!it.done()) {
11636 int statement_position = static_cast<int>(it.rinfo()->data());
11637 // Check if this break point is closer that what was previously found.
11638 if (source_position <= statement_position &&
11639 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011640 closest_pc =
11641 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011642 distance = statement_position - source_position;
11643 // Check whether we can't get any closer.
11644 if (distance == 0) break;
11645 }
11646 it.next();
11647 }
11648
11649 return Smi::FromInt(closest_pc);
11650}
11651
11652
ager@chromium.org357bf652010-04-12 11:30:10 +000011653// Calls specified function with or without entering the debugger.
11654// This is used in unit tests to run code as if debugger is entered or simply
11655// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011656RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011657 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011658 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011659 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11660 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11661
11662 Handle<Object> result;
11663 bool pending_exception;
11664 {
11665 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011666 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011667 &pending_exception);
11668 } else {
11669 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011670 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011671 &pending_exception);
11672 }
11673 }
11674 if (!pending_exception) {
11675 return *result;
11676 } else {
11677 return Failure::Exception();
11678 }
11679}
11680
11681
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011682// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011683RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011684 CONVERT_CHECKED(String, arg, args[0]);
11685 SmartPointer<char> flags =
11686 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11687 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011688 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011689}
11690
11691
11692// Performs a GC.
11693// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011694RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011695 isolate->heap()->CollectAllGarbage(true);
11696 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011697}
11698
11699
11700// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011702 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011703 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011704 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011705 }
11706 return Smi::FromInt(usage);
11707}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011708
11709
11710// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011711RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011712#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011713 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011714#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011715 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011716#endif
11717}
11718
11719
11720// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011721RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011722#ifdef LIVE_OBJECT_LIST
11723 return LiveObjectList::Capture();
11724#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011725 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011726#endif
11727}
11728
11729
11730// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011731RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011732#ifdef LIVE_OBJECT_LIST
11733 CONVERT_SMI_CHECKED(id, args[0]);
11734 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011735 return success ? isolate->heap()->true_value() :
11736 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011737#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011738 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011739#endif
11740}
11741
11742
11743// Generates the response to a debugger request for a dump of the objects
11744// contained in the difference between the captured live object lists
11745// specified by id1 and id2.
11746// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11747// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011748RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011749#ifdef LIVE_OBJECT_LIST
11750 HandleScope scope;
11751 CONVERT_SMI_CHECKED(id1, args[0]);
11752 CONVERT_SMI_CHECKED(id2, args[1]);
11753 CONVERT_SMI_CHECKED(start, args[2]);
11754 CONVERT_SMI_CHECKED(count, args[3]);
11755 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11756 EnterDebugger enter_debugger;
11757 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11758#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011759 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011760#endif
11761}
11762
11763
11764// Gets the specified object as requested by the debugger.
11765// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011766RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011767#ifdef LIVE_OBJECT_LIST
11768 CONVERT_SMI_CHECKED(obj_id, args[0]);
11769 Object* result = LiveObjectList::GetObj(obj_id);
11770 return result;
11771#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011772 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011773#endif
11774}
11775
11776
11777// Gets the obj id for the specified address if valid.
11778// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011779RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011780#ifdef LIVE_OBJECT_LIST
11781 HandleScope scope;
11782 CONVERT_ARG_CHECKED(String, address, 0);
11783 Object* result = LiveObjectList::GetObjId(address);
11784 return result;
11785#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011786 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011787#endif
11788}
11789
11790
11791// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011792RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011793#ifdef LIVE_OBJECT_LIST
11794 HandleScope scope;
11795 CONVERT_SMI_CHECKED(obj_id, args[0]);
11796 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11797 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11798 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11799 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11800 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11801
11802 Handle<JSObject> instance_filter;
11803 if (args[1]->IsJSObject()) {
11804 instance_filter = args.at<JSObject>(1);
11805 }
11806 bool verbose = false;
11807 if (args[2]->IsBoolean()) {
11808 verbose = args[2]->IsTrue();
11809 }
11810 int start = 0;
11811 if (args[3]->IsSmi()) {
11812 start = Smi::cast(args[3])->value();
11813 }
11814 int limit = Smi::kMaxValue;
11815 if (args[4]->IsSmi()) {
11816 limit = Smi::cast(args[4])->value();
11817 }
11818
11819 return LiveObjectList::GetObjRetainers(obj_id,
11820 instance_filter,
11821 verbose,
11822 start,
11823 limit,
11824 filter_obj);
11825#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011826 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011827#endif
11828}
11829
11830
11831// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011832RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011833#ifdef LIVE_OBJECT_LIST
11834 HandleScope scope;
11835 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11836 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11837 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11838
11839 Handle<JSObject> instance_filter;
11840 if (args[2]->IsJSObject()) {
11841 instance_filter = args.at<JSObject>(2);
11842 }
11843
11844 Object* result =
11845 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11846 return result;
11847#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011848 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011849#endif
11850}
11851
11852
11853// Generates the response to a debugger request for a list of all
11854// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011855RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011856#ifdef LIVE_OBJECT_LIST
11857 CONVERT_SMI_CHECKED(start, args[0]);
11858 CONVERT_SMI_CHECKED(count, args[1]);
11859 return LiveObjectList::Info(start, count);
11860#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011861 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011862#endif
11863}
11864
11865
11866// Gets a dump of the specified object as requested by the debugger.
11867// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011868RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011869#ifdef LIVE_OBJECT_LIST
11870 HandleScope scope;
11871 CONVERT_SMI_CHECKED(obj_id, args[0]);
11872 Object* result = LiveObjectList::PrintObj(obj_id);
11873 return result;
11874#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011875 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011876#endif
11877}
11878
11879
11880// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011881RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011882#ifdef LIVE_OBJECT_LIST
11883 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011884 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011885#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011886 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011887#endif
11888}
11889
11890
11891// Generates the response to a debugger request for a summary of the types
11892// of objects in the difference between the captured live object lists
11893// specified by id1 and id2.
11894// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11895// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011896RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011897#ifdef LIVE_OBJECT_LIST
11898 HandleScope scope;
11899 CONVERT_SMI_CHECKED(id1, args[0]);
11900 CONVERT_SMI_CHECKED(id2, args[1]);
11901 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11902
11903 EnterDebugger enter_debugger;
11904 return LiveObjectList::Summarize(id1, id2, filter_obj);
11905#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011906 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011907#endif
11908}
11909
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011910#endif // ENABLE_DEBUGGER_SUPPORT
11911
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011912
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011913#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011914RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011915 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011916 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011917
11918 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011919 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11920 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011921 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011922}
11923
11924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011925RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011926 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011927 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011928
11929 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011930 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11931 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011932 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011933}
11934
11935#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011936
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011937// Finds the script object from the script data. NOTE: This operation uses
11938// heap traversal to find the function generated for the source position
11939// for the requested break point. For lazily compiled functions several heap
11940// traversals might be required rendering this operation as a rather slow
11941// operation. However for setting break points which is normally done through
11942// some kind of user interaction the performance is not crucial.
11943static Handle<Object> Runtime_GetScriptFromScriptName(
11944 Handle<String> script_name) {
11945 // Scan the heap for Script objects to find the script with the requested
11946 // script data.
11947 Handle<Script> script;
11948 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011949 HeapObject* obj = NULL;
11950 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011951 // If a script is found check if it has the script data requested.
11952 if (obj->IsScript()) {
11953 if (Script::cast(obj)->name()->IsString()) {
11954 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11955 script = Handle<Script>(Script::cast(obj));
11956 }
11957 }
11958 }
11959 }
11960
11961 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011962 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011963
11964 // Return the script found.
11965 return GetScriptWrapper(script);
11966}
11967
11968
11969// Get the script object from script data. NOTE: Regarding performance
11970// see the NOTE for GetScriptFromScriptData.
11971// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011972RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011973 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011974
11975 ASSERT(args.length() == 1);
11976
11977 CONVERT_CHECKED(String, script_name, args[0]);
11978
11979 // Find the requested script.
11980 Handle<Object> result =
11981 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11982 return *result;
11983}
11984
11985
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011986// Determines whether the given stack frame should be displayed in
11987// a stack trace. The caller is the error constructor that asked
11988// for the stack trace to be collected. The first time a construct
11989// call to this function is encountered it is skipped. The seen_caller
11990// in/out parameter is used to remember if the caller has been seen
11991// yet.
11992static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11993 bool* seen_caller) {
11994 // Only display JS frames.
11995 if (!raw_frame->is_java_script())
11996 return false;
11997 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11998 Object* raw_fun = frame->function();
11999 // Not sure when this can happen but skip it just in case.
12000 if (!raw_fun->IsJSFunction())
12001 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012002 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012003 *seen_caller = true;
12004 return false;
12005 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012006 // Skip all frames until we've seen the caller. Also, skip the most
12007 // obvious builtin calls. Some builtin calls (such as Number.ADD
12008 // which is invoked using 'call') are very difficult to recognize
12009 // so we're leaving them in for now.
12010 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012011}
12012
12013
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012014// Collect the raw data for a stack trace. Returns an array of 4
12015// element segments each containing a receiver, function, code and
12016// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012017RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012018 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012019 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012020 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12021
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012022 HandleScope scope(isolate);
12023 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012024
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012025 limit = Max(limit, 0); // Ensure that limit is not negative.
12026 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012027 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012028 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012029
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012030 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012031 // If the caller parameter is a function we skip frames until we're
12032 // under it before starting to collect.
12033 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012034 int cursor = 0;
12035 int frames_seen = 0;
12036 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012037 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012038 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012039 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012040 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012041 // Set initial size to the maximum inlining level + 1 for the outermost
12042 // function.
12043 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012044 frame->Summarize(&frames);
12045 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012046 if (cursor + 4 > elements->length()) {
12047 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12048 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012049 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012050 for (int i = 0; i < cursor; i++) {
12051 new_elements->set(i, elements->get(i));
12052 }
12053 elements = new_elements;
12054 }
12055 ASSERT(cursor + 4 <= elements->length());
12056
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012057 Handle<Object> recv = frames[i].receiver();
12058 Handle<JSFunction> fun = frames[i].function();
12059 Handle<Code> code = frames[i].code();
12060 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012061 elements->set(cursor++, *recv);
12062 elements->set(cursor++, *fun);
12063 elements->set(cursor++, *code);
12064 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012065 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012066 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012067 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012068 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012069 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012070 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012071 return *result;
12072}
12073
12074
ager@chromium.org3811b432009-10-28 14:53:37 +000012075// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012076RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012077 ASSERT_EQ(args.length(), 0);
12078
12079 NoHandleAllocation ha;
12080
12081 const char* version_string = v8::V8::GetVersion();
12082
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012083 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12084 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012085}
12086
12087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012088RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012089 ASSERT(args.length() == 2);
12090 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
12091 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012092 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012093 OS::Abort();
12094 UNREACHABLE();
12095 return NULL;
12096}
12097
12098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012099RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012100 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012101 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012102 Object* key = args[1];
12103
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012104 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012105 Object* o = cache->get(finger_index);
12106 if (o == key) {
12107 // The fastest case: hit the same place again.
12108 return cache->get(finger_index + 1);
12109 }
12110
12111 for (int i = finger_index - 2;
12112 i >= JSFunctionResultCache::kEntriesIndex;
12113 i -= 2) {
12114 o = cache->get(i);
12115 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012116 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012117 return cache->get(i + 1);
12118 }
12119 }
12120
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012121 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012122 ASSERT(size <= cache->length());
12123
12124 for (int i = size - 2; i > finger_index; i -= 2) {
12125 o = cache->get(i);
12126 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012127 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012128 return cache->get(i + 1);
12129 }
12130 }
12131
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012132 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012133 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012134
12135 Handle<JSFunctionResultCache> cache_handle(cache);
12136 Handle<Object> key_handle(key);
12137 Handle<Object> value;
12138 {
12139 Handle<JSFunction> factory(JSFunction::cast(
12140 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12141 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012142 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012143 // This handle is nor shared, nor used later, so it's safe.
12144 Object** argv[] = { key_handle.location() };
12145 bool pending_exception = false;
12146 value = Execution::Call(factory,
12147 receiver,
12148 1,
12149 argv,
12150 &pending_exception);
12151 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012152 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012153
12154#ifdef DEBUG
12155 cache_handle->JSFunctionResultCacheVerify();
12156#endif
12157
12158 // Function invocation may have cleared the cache. Reread all the data.
12159 finger_index = cache_handle->finger_index();
12160 size = cache_handle->size();
12161
12162 // If we have spare room, put new data into it, otherwise evict post finger
12163 // entry which is likely to be the least recently used.
12164 int index = -1;
12165 if (size < cache_handle->length()) {
12166 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12167 index = size;
12168 } else {
12169 index = finger_index + JSFunctionResultCache::kEntrySize;
12170 if (index == cache_handle->length()) {
12171 index = JSFunctionResultCache::kEntriesIndex;
12172 }
12173 }
12174
12175 ASSERT(index % 2 == 0);
12176 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12177 ASSERT(index < cache_handle->length());
12178
12179 cache_handle->set(index, *key_handle);
12180 cache_handle->set(index + 1, *value);
12181 cache_handle->set_finger_index(index);
12182
12183#ifdef DEBUG
12184 cache_handle->JSFunctionResultCacheVerify();
12185#endif
12186
12187 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012188}
12189
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012191RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012192 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012193 CONVERT_ARG_CHECKED(String, type, 0);
12194 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012195 return *isolate->factory()->NewJSMessageObject(
12196 type,
12197 arguments,
12198 0,
12199 0,
12200 isolate->factory()->undefined_value(),
12201 isolate->factory()->undefined_value(),
12202 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012203}
12204
12205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012206RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012207 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12208 return message->type();
12209}
12210
12211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012212RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012213 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12214 return message->arguments();
12215}
12216
12217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012218RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012219 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12220 return Smi::FromInt(message->start_position());
12221}
12222
12223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012224RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012225 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12226 return message->script();
12227}
12228
12229
kasper.lund44510672008-07-25 07:37:58 +000012230#ifdef DEBUG
12231// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12232// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012233RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012234 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012235 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012236#define COUNT_ENTRY(Name, argc, ressize) + 1
12237 int entry_count = 0
12238 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12239 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12240 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12241#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012242 Factory* factory = isolate->factory();
12243 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012244 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012245 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012246#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012247 { \
12248 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012249 Handle<String> name; \
12250 /* Inline runtime functions have an underscore in front of the name. */ \
12251 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012252 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012253 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12254 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012255 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012256 Vector<const char>(#Name, StrLength(#Name))); \
12257 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012258 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012259 pair_elements->set(0, *name); \
12260 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012261 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012262 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012263 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012264 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012265 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012266 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012267 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012268 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012270 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012271 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012272 return *result;
12273}
kasper.lund44510672008-07-25 07:37:58 +000012274#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012275
12276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012277RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012278 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012279 CONVERT_CHECKED(String, format, args[0]);
12280 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012281 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012282 LOGGER->LogRuntime(chars, elms);
12283 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012284}
12285
12286
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012287RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012288 UNREACHABLE(); // implemented as macro in the parser
12289 return NULL;
12290}
12291
12292
12293// ----------------------------------------------------------------------------
12294// Implementation of Runtime
12295
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012296#define F(name, number_of_args, result_size) \
12297 { Runtime::k##name, Runtime::RUNTIME, #name, \
12298 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012299
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012300
12301#define I(name, number_of_args, result_size) \
12302 { Runtime::kInline##name, Runtime::INLINE, \
12303 "_" #name, NULL, number_of_args, result_size },
12304
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012305static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012306 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012307 INLINE_FUNCTION_LIST(I)
12308 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012309};
12310
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012311
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012312MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12313 Object* dictionary) {
12314 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012315 ASSERT(dictionary != NULL);
12316 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12317 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012318 Object* name_symbol;
12319 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012320 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012321 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12322 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012323 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012324 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12325 String::cast(name_symbol),
12326 Smi::FromInt(i),
12327 PropertyDetails(NONE, NORMAL));
12328 if (!maybe_dictionary->ToObject(&dictionary)) {
12329 // Non-recoverable failure. Calling code must restart heap
12330 // initialization.
12331 return maybe_dictionary;
12332 }
12333 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012334 }
12335 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012336}
12337
12338
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012339const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12340 Heap* heap = name->GetHeap();
12341 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012342 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012343 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012344 int function_index = Smi::cast(smi_index)->value();
12345 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012346 }
12347 return NULL;
12348}
12349
12350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012351const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012352 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12353}
12354
12355
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012356void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012357 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012358 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012359 if (failure->IsRetryAfterGC()) {
12360 // Try to do a garbage collection; ignore it if it fails. The C
12361 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012362 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012363 } else {
12364 // Handle last resort GC and make sure to allow future allocations
12365 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012366 isolate->counters()->gc_last_resort_from_js()->Increment();
12367 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012368 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012369}
12370
12371
12372} } // namespace v8::internal